~/bend-docscommunity

src/Staging.bend source

src/Staging.bend on the hub · documented module

import Baseimport ./LogicalKey.bend as LogicalKeyimport ./ContentObject.bend as ContentObjectimport ./JsonAdapter.bend as JsonAdapterimport ./Value.bend as Valueimport ./Store.bend as Storeimport bend-kit-json@0.3.0.0/json.bend as Json# Uncommitted working set. Staged values live at stage/{session}/{ns}/{id};# the per-session key manifest lives at stage-index/{session} as a canonical# JSON string list. Point operations only — no prefix scan anywhere.# Kit is named for the Val TYPE only; operations go through JsonAdapter.# Effects are Store Op actions composed in do-blocks.# Addresses the per-session staged-key manifest.def stage_index_key(+session_identifier: String) -> String:  "stage-index/" ++ session_identifier# Encodes the manifest as a canonical JSON string list.def serialize_key_list(staged_keys: List<&2, String>) -> String:  JsonAdapter.encode_canonical(JsonAdapter.make_arr(ContentObject.encode_each_reference(staged_keys)))# Treats a failed decode as an empty manifest.def index_from_strings(strings_maybe: Maybe<&2, List<&2, String>>) -> List<&2, String>:  match strings_maybe:    case None{}:      Nil{}    case Some{key_texts}:      key_texts# Unwraps the manifest array, then decodes.def index_from_document(items_maybe: Maybe<&2, List<&2, Json.Val>>) -> List<&2, String>:  match items_maybe:    case None{}:      Nil{}    case Some{json_items}:      index_from_strings(ContentObject.extract_each_string(json_items))# Parses stored manifest text; malformed reads as empty.def index_from_text(parse_result: Maybe<&2, Json.Val>) -> List<&2, String>:  match parse_result:    case None{}:      Nil{}    case Some{document}:      index_from_document(JsonAdapter.as_arr(document))# Loads the manifest; missing storage reads as empty.def parse_stage_index(stored_maybe: Maybe<&2, String>) -> List<&2, String>:  match stored_maybe:    case None{}:      Nil{}    case Some{stored_text}:      index_from_text(JsonAdapter.parse_text(stored_text))# True short-circuits the membership scan.def decide_contains(head_matches: Bool, recursive_result: Bool) -> Bool:  match head_matches:    case True{}:      True{}    case False{}:      recursive_result# Scans the manifest for the target key.def contains_staged_key(+target_key: String, staged_keys: List<&2, String>) -> Bool:  match staged_keys:    case Nil{}:      False{}    case Con{head_key, remaining_keys}:      decide_contains(String.eq(head_key, target_key), contains_staged_key(target_key, remaining_keys))# Prepends unless already present.def prepend_unless_present(already_present: Bool, target_key: String, staged_keys: List<&2, String>) -> List<&2, String>:  match already_present:    case True{}:      staged_keys    case False{}:      Con{target_key, staged_keys}# Adds the key unless the manifest has it.def add_key_unless_present(+target_key: String, +staged_keys: List<&2, String>) -> List<&2, String>:  prepend_unless_present(contains_staged_key(target_key, staged_keys), target_key, staged_keys)# Loads the session manifest.def load_stage_index(+session_identifier: String) -> Store.Op<&2, List<&2, String>>:  do Store.Op<&2, List<&2, String>>:    stored_maybe : Maybe<&2, String> <- Store.oget(stage_index_key(session_identifier))    return parse_stage_index(stored_maybe)# Stores one staged value and records its key.def record_stage_entry(+session_identifier: String, +namespace_name: String, +record_identifier: String, value_hash: String) -> Store.Op<&2, LogicalKey.LogicalKey>:  do Store.Op<&2, LogicalKey.LogicalKey>:    +full_key_text : String = LogicalKey.encode_logical_key(LogicalKey.Make{namespace_name, record_identifier})    current_index : List<&2, String> <- load_stage_index(session_identifier)    stored_unit : Unit <- Store.oput(LogicalKey.build_stage_storage_key(session_identifier, namespace_name, record_identifier), value_hash)    saved_unit : Unit <- Store.oput(stage_index_key(session_identifier), serialize_key_list(add_key_unless_present(full_key_text, current_index)))    return LogicalKey.Make{namespace_name, record_identifier}# Stages a value for later commit.def put_record(+session_identifier: String, +namespace_name: String, +record_identifier: String, value: Value.Value) -> Store.Op<&2, LogicalKey.LogicalKey>:  do Store.Op<&2, LogicalKey.LogicalKey>:    +value_hash : String <- ContentObject.store_content_object(value, Nil{})    staged_key : LogicalKey.LogicalKey <- record_stage_entry(session_identifier, namespace_name, record_identifier, value_hash)    return staged_key# Stages a tombstone for later commit.def delete_record(+session_identifier: String, +namespace_name: String, +record_identifier: String) -> Store.Op<&2, LogicalKey.LogicalKey>:  do Store.Op<&2, LogicalKey.LogicalKey>:    staged_key : LogicalKey.LogicalKey <- record_stage_entry(session_identifier, namespace_name, record_identifier, "TOMBSTONE")    return staged_key