Skip to main content

Crate topodb_json

Crate topodb_json 

Source
Expand description

JSON ↔ engine-type conversions shared by TopoDB’s JSON-speaking front ends (currently topodb-mcp; topodb-cli is next).

Every function here is pure (no I/O, no Db access) and returns Result<_, String> — callers are responsible for mapping the String into their own error type (topodb-mcp’s server.rs maps it to an rmcp::ErrorData: invalid_params for bad input, internal_error otherwise). Nothing here ever panics: an unrepresentable value is always an Err, never an unwrap/expect.

Constants§

ALIAS_EDGE_TYPE
ALIAS_LABEL
ALIAS_NAME_PROP
ENTITY_LABEL
Label/prop name constants for the two built-in write shapes (create_memory/create-memory, create_entity/create-entity). Single source of truth shared by every front end (topodb-mcp’s default IndexSpec and write tools, topodb-cli’s create-entity/create-memory subcommands) so writes land on exactly the (label, prop) pairs the default spec indexes — search and lookup work out of the box regardless of which front end wrote the data.
ENTITY_NAME_PROP
MEMORY_CONTENT_PROP
MEMORY_LABEL
SYNONYM_EXPANSION_PROP
SYNONYM_LABEL
SYNONYM_TERM_PROP
UNSUPPORTED
Error string for both directions of an unrepresentable PropValue: Bytes and DateTime have no JSON counterpart over MCP v0, and any JSON shape that isn’t a string/number/bool (array, object, null) has no PropValue counterpart either.

Functions§

default_spec
The ONE canonical default IndexSpec for TopoDB’s built-in write shapes, shared by every front end (topodb-mcp when --spec is omitted; topodb-cli when it creates a brand-new db file). Declares equality on (Entity, name), (Alias, name), and (Synonym, term), and text on (Memory, content), (Entity, name), and (Alias, name), using the shared label and property constants.
edge_to_json
An EdgeRecord → JSON: id/from/to as ULID strings, type for ty (JSON-friendlier than the Rust keyword-adjacent field name), scope per scope_to_json, props per props_to_json, and the temporal bounds valid_from/valid_to (valid_to is null while the edge is open).
json_to_f32_vec
A JSON array of finite numbers → Vec<f32>, for raw embeddings (topodb::Op::SetEmbedding) and vector-search queries. Err if v isn’t a JSON array, or any element isn’t a finite number. (The host computes embeddings; TopoDB stores/searches the raw floats.)
json_to_prop_changes
A JSON object of property changes for topodb::Op::SetNodeProps. A null value REMOVES the key (None); any other JSON scalar SETS it (Some(PropValue), via json_to_prop_value). Err if v isn’t a JSON object, or a non-null value isn’t a representable scalar. The null-removes convention is what lets a caller delete a prop over the wire — plain json_to_props has no way to express removal.
json_to_prop_value
serde_json::ValuePropValue. Strings/bools map directly. A JSON integer maps to Int when it fits i64, and is an error when it doesn’t ((i64::MAX, u64::MAX] — silently downgrading it to a lossy Float would corrupt the value); only a genuine non-integer number maps to Float. This is the inverse of prop_value_to_json’s Int/Float handling. Every other JSON shape (array, object, null — and, structurally, anything that would have needed to round-trip through Bytes/DateTime) is UNSUPPORTED.
json_to_props
A JSON object → Props, propagating the first unrepresentable value as Err. Err if v isn’t a JSON object at all.
merge_required_prop
Builds the Props map for a write tool that has one required, caller-named field (create_memory’s content, create_entity’s name) plus an optional JSON props object of additional metadata. key/value are the required field, already converted to a PropValue; extra is the tool call’s optional props param, converted via json_to_props.
node_to_json
A NodeRecord → JSON: id/label as strings (ULID via Display for id), scope per scope_to_json, and props per props_to_json. Deliberately omits the embedding field — no MCP v0 tool surfaces vector data (that’s a later concern via dedicated embedding tools).
normalize_edge_type
Canonical form for edge types: Unicode-lowercased, with runs of whitespace, hyphens, and underscores collapsed to a single underscore (leading/trailing separators dropped). "Works At", "works-at", and "works_at" all normalize to "works_at" — one relation, one vocabulary entry, instead of three parallel edge types that silently fragment traversal filters. Every front-end write path (link tool, batch link command, CLI) passes edge types through here; read-side type filters should probe both the raw and normalized forms so edges written before normalization stay reachable. Err on a type that normalizes to empty.
prop_value_to_json
PropValueserde_json::Value. Str/Int/Bool map directly; Float maps to a JSON number (Err only for a non-finite float, which JSON has no representation for). Bytes/DateTime are UNSUPPORTED.
props_to_json
Props (a BTreeMap<String, PropValue>) → a JSON object, propagating the first unrepresentable value as Err.
resolve_batch
resolve_scope
Resolves a tool’s optional scope string param to a Scope: Nonedefault (the server’s configured default scope); Some("shared") (case-insensitive) → Scope::Shared; Some(<ulid>)Scope::Id; any other string → a clear Err. Mirrors topodb-mcp’s config::parse_scope “shared” / ULID contract, generalized to the Option (tool-call) case.
scope_label
Human/JSON-facing rendering of a Scope: "shared" or the ULID string. Reused by every front end’s info/db_info-style output and scope round-tripping. (Distinct from scope_to_json, which wraps the same rendering in a serde_json::Value for a JSON response body; this returns a bare String for contexts — like a struct field — that want the label without a Value wrapper.)
scope_to_json
A Scope → its JSON rendering: "shared" or the scope’s ULID string. Mirrors the shared/ULID label convention used across TopoDB’s JSON-facing front ends (e.g. topodb-mcp’s db_info tool).
scope_to_scope_set
A resolved Scope → the singleton ScopeSet a read call needs: Shared admits only the shared scope, Id(id) admits only that one scope id.
scopes_to_scope_set
Several resolved Scopes → the ScopeSet a multi-scope read runs against. Scope::Shared sets the set’s include_shared flag; each Scope::Id becomes a member id. This is the only constructor that can produce a genuinely multi-member ScopeSetscope_to_scope_set always collapses to a singleton, which is why “this project plus shared” was previously unexpressible from any client.
subgraph_to_json
A Subgraph{"nodes": [...], "edges": [...]}, each element per node_to_json/edge_to_json.
upgraded_spec
Maps a db’s persisted spec forward when — and only when — it is exactly a stock default this crate has shipped: any recognized stock generation upgrades to the current default_spec. Any other spec — a --spec customization, however small — is returned unchanged: silently rewriting a declared spec would reindex data behind its owner’s back. Comparison is order-insensitive, matching how the engine’s ensure_index_spec compares specs (it sorts both lists before persisting).