hyf

Context-aware query service for Radroots
git clone https://radroots.dev/git/hyf.git
Log | Files | Refs | README | LICENSE

request_context.mojo (7487B)


      1 from std.collections import List, Optional
      2 
      3 from json import Value
      4 from json.deserialize import get_bool, get_int, get_string
      5 
      6 
      7 def _has_key(value: Value, key: String) -> Bool:
      8     for candidate in value.object_keys():
      9         if candidate == key:
     10             return True
     11     return False
     12 
     13 
     14 def _require_object(value: Value, context: String) raises:
     15     if not value.is_object():
     16         raise Error(context + " must be a JSON object")
     17 
     18 
     19 def _require_allowed_keys(
     20     value: Value, allowed_keys: List[String], context: String
     21 ) raises:
     22     for key in value.object_keys():
     23         var allowed = False
     24         for allowed_key in allowed_keys:
     25             if key == allowed_key:
     26                 allowed = True
     27                 break
     28         if not allowed:
     29             raise Error(context + " contains unexpected field '" + key + "'")
     30 
     31 
     32 def _require_non_empty(value: String, context: String) raises:
     33     if value == "":
     34         raise Error(context + " must not be empty")
     35 
     36 
     37 def _require_positive_int(value: Int, context: String) raises:
     38     if value <= 0:
     39         raise Error(context + " must be greater than zero")
     40 
     41 
     42 def _parse_string_list(value: Value, context: String) raises -> List[String]:
     43     if value.is_null():
     44         return List[String]()
     45     if not value.is_array():
     46         raise Error(context + " must be a JSON array")
     47 
     48     var items = List[String]()
     49     for item in value.array_items():
     50         if not item.is_string():
     51             raise Error(context + " must contain only strings")
     52         _require_non_empty(item.string_value(), context + " item")
     53         items.append(item.string_value())
     54     return items^
     55 
     56 
     57 @fieldwise_init
     58 struct RequestScope(Copyable, Movable):
     59     var listing_ids: List[String]
     60     var farm_ids: List[String]
     61     var account_ids: List[String]
     62     var platform_ids: List[String]
     63     var object_filters: Optional[Value]
     64 
     65 
     66 @fieldwise_init
     67 struct TimeRange(Copyable, Movable):
     68     var start: String
     69     var end: String
     70 
     71 
     72 @fieldwise_init
     73 struct RequestContext(Copyable, Movable):
     74     var consumer: String
     75     var execution_mode_preference: String
     76     var deadline_ms: Int
     77     var scope: Optional[RequestScope]
     78     var time_range: Optional[TimeRange]
     79     var evidence_limit: Int
     80     var consistency: String
     81     var return_provenance: Bool
     82     var explain_plan: Bool
     83 
     84 
     85 def request_context_feature_names() -> List[String]:
     86     return request_context_allowed_keys()
     87 
     88 
     89 def request_context_allowed_keys() -> List[String]:
     90     var features = List[String]()
     91     features.append("consumer")
     92     features.append("execution_mode_preference")
     93     features.append("deadline_ms")
     94     features.append("scope")
     95     features.append("time_range")
     96     features.append("evidence_limit")
     97     features.append("consistency")
     98     features.append("return_provenance")
     99     features.append("explain_plan")
    100     return features^
    101 
    102 
    103 def accepted_request_context_feature_names() -> List[String]:
    104     var features = List[String]()
    105     features.append("consumer")
    106     features.append("execution_mode_preference")
    107     features.append("deadline_ms")
    108     features.append("scope.listing_ids")
    109     features.append("time_range.start")
    110     features.append("time_range.end")
    111     features.append("evidence_limit")
    112     features.append("consistency")
    113     features.append("return_provenance")
    114     features.append("explain_plan")
    115     return features^
    116 
    117 
    118 def effective_request_context_feature_names() -> List[String]:
    119     var features = List[String]()
    120     features.append("execution_mode_preference")
    121     features.append("scope.listing_ids")
    122     features.append("return_provenance")
    123     return features^
    124 
    125 
    126 def default_request_context() -> RequestContext:
    127     return RequestContext(
    128         consumer="unknown",
    129         execution_mode_preference="deterministic",
    130         deadline_ms=2500,
    131         scope=None,
    132         time_range=None,
    133         evidence_limit=10,
    134         consistency="default",
    135         return_provenance=False,
    136         explain_plan=False,
    137     )
    138 
    139 
    140 def assisted_execution_requested(context: RequestContext) -> Bool:
    141     return context.execution_mode_preference == "assisted"
    142 
    143 
    144 def _parse_scope(json: Value) raises -> RequestScope:
    145     _require_object(json, "request context scope")
    146 
    147     var allowed_keys = List[String]()
    148     allowed_keys.append("listing_ids")
    149     _require_allowed_keys(json, allowed_keys, "request context scope")
    150 
    151     var listing_ids_json = Value(None)
    152     if _has_key(json, "listing_ids"):
    153         listing_ids_json = json["listing_ids"].clone()
    154 
    155     return RequestScope(
    156         listing_ids=_parse_string_list(
    157             listing_ids_json, "request context scope listing_ids"
    158         ),
    159         farm_ids=List[String](),
    160         account_ids=List[String](),
    161         platform_ids=List[String](),
    162         object_filters=None,
    163     )
    164 
    165 
    166 def _parse_time_range(json: Value) raises -> TimeRange:
    167     _require_object(json, "request context time_range")
    168 
    169     var allowed_keys = List[String]()
    170     allowed_keys.append("start")
    171     allowed_keys.append("end")
    172     _require_allowed_keys(json, allowed_keys, "request context time_range")
    173 
    174     var start = get_string(json, "start")
    175     _require_non_empty(start, "request context time_range start")
    176 
    177     var end = get_string(json, "end")
    178     _require_non_empty(end, "request context time_range end")
    179 
    180     return TimeRange(start=start, end=end)
    181 
    182 
    183 def parse_request_context(json: Value) raises -> RequestContext:
    184     if json.is_null():
    185         return default_request_context()
    186 
    187     _require_object(json, "request context")
    188 
    189     var allowed_keys = request_context_allowed_keys()
    190     _require_allowed_keys(json, allowed_keys, "request context")
    191 
    192     var context = default_request_context()
    193 
    194     if _has_key(json, "consumer"):
    195         context.consumer = get_string(json, "consumer")
    196         _require_non_empty(context.consumer, "request context consumer")
    197 
    198     if _has_key(json, "execution_mode_preference"):
    199         context.execution_mode_preference = get_string(
    200             json, "execution_mode_preference"
    201         )
    202         if (
    203             context.execution_mode_preference != "deterministic"
    204             and context.execution_mode_preference != "assisted"
    205         ):
    206             raise Error(
    207                 "request context execution_mode_preference must be 'deterministic' or 'assisted'"
    208             )
    209 
    210     if _has_key(json, "deadline_ms"):
    211         context.deadline_ms = get_int(json, "deadline_ms")
    212         _require_positive_int(
    213             context.deadline_ms, "request context deadline_ms"
    214         )
    215 
    216     if _has_key(json, "scope"):
    217         var scope_json = json["scope"].clone()
    218         if not scope_json.is_null():
    219             context.scope = _parse_scope(scope_json)
    220 
    221     if _has_key(json, "time_range"):
    222         var time_range_json = json["time_range"].clone()
    223         if not time_range_json.is_null():
    224             context.time_range = _parse_time_range(time_range_json)
    225 
    226     if _has_key(json, "evidence_limit"):
    227         context.evidence_limit = get_int(json, "evidence_limit")
    228         _require_positive_int(
    229             context.evidence_limit, "request context evidence_limit"
    230         )
    231 
    232     if _has_key(json, "consistency"):
    233         context.consistency = get_string(json, "consistency")
    234         _require_non_empty(
    235             context.consistency, "request context consistency"
    236         )
    237 
    238     if _has_key(json, "return_provenance"):
    239         context.return_provenance = get_bool(json, "return_provenance")
    240 
    241     if _has_key(json, "explain_plan"):
    242         context.explain_plan = get_bool(json, "explain_plan")
    243 
    244     return context^