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)