src/JsonAdapter.bend

ber-core-store@0.1.1.0 · 70 lines · 0 definitions

1import Base
2import bend-kit-json@0.3.0.0/json.bend as Json
3
4# Sole owner of JSON operations. Consumers import THIS module for all
5# encode/parse/get work; they import the kit package ONLY for the Val type in
6# annotations (Bend cannot alias types across modules — same convention as
7# MyLsmStore.Sess).
8# TRUST BOUNDARY: Json.parse is structural recursion. Json.encode is @unsafe
9# upstream (work-list walk, documented in kit source); canonical-bytes
10# (equal content => identical text) is covered by json_bytes_probe and the
11# differential check vs Python json, not by proof. If kit ships a safe
12# encoder, only this file changes.
13
14# Wraps text as a JSON string value.
15def make_str(+text: String) -> Json.Val:
16  Json.Str{text}
17
18# Wraps a value list as a JSON array.
19def make_arr(items: List<&2, Json.Val>) -> Json.Val:
20  Json.Arr{items}
21
22# Builds one object field pair.
23def make_kv(+field_key: String, field_value: Json.Val) -> Sigma<&2, &2, String, _ => Json.Val>:
24  (field_key, field_value)
25
26# Inserts one field pair into the map.
27def fold_pair(field_map: Map<&2, Json.Val>, field_pair: Sigma<&2, &2, String, _ => Json.Val>) -> Map<&2, Json.Val>:
28  match field_pair:
29    case (field_key, field_value):
30      Map.set(&2, Json.Val, field_map, field_key, field_value)
31
32# Folds a field list into a map; the list shrinks first.
33def fold_fields(remaining_fields: List<&2, Sigma<&2, &2, String, _ => Json.Val>>, field_map: Map<&2, Json.Val>) -> Map<&2, Json.Val>:
34  match remaining_fields:
35    case Nil{}:
36      field_map
37    case Con{field_pair, tail_fields}:
38      fold_fields(tail_fields, fold_pair(field_map, field_pair))
39
40# Builds an object; keys come out sorted by construction.
41def make_obj(fields: List<&2, Sigma<&2, &2, String, _ => Json.Val>>) -> Json.Val:
42  Json.Obj{fold_fields(fields, Map.new(&2, Json.Val))}
43
44# Parses stored text; None on malformed input.
45def parse_text(+stored_text: String) -> Maybe<&2, Json.Val>:
46  Json.parse(stored_text)
47
48# Looks up an object field; None when absent or not an object.
49def get_field(+document: Json.Val, +field_name: String) -> Maybe<&2, Json.Val>:
50  Json.get(document, field_name)
51
52# Unwraps a string value; None otherwise.
53def as_str(json_value: Json.Val) -> Maybe<&2, String>:
54  match json_value:
55    case Json.Str{text}:
56      Some{text}
57    case _:
58      None{}
59
60# Unwraps an array value; None otherwise.
61def as_arr(json_value: Json.Val) -> Maybe<&2, List<&2, Json.Val>>:
62  match json_value:
63    case Json.Arr{items}:
64      Some{items}
65    case _:
66      None{}
67
68# Encodes with keys sorted; the canonical bytes.
69def encode_canonical(+document: Json.Val) -> String:
70  Json.encode(document)