Skip to main content
Ask once; HeavenBase will route the question, but it still expects you to open the answer.

1. Motivation

Application code should describe data intent without choosing provider clients or merge algorithms. HeavenBase queries are immutable request values that a workspace resolves against its Entity schema, placements, Backends, handlers, and Context policy. Construction performs no I/O. Only execute() and explain() cross the routing boundary.

2. Build an Immutable Query

Every transform returns a new hb.Query; there is no mutable QueryBuilder. Branch with ordinary assignment, as base and nearest do above. to_spec() returns the structurally immutable request consumed by routing. It does not choose a Backend or perform I/O.

3. Read a ResultFrame

Every execute() recomputes and returns a newly detached hb.ResultFrame. Results are not cached or persisted automatically.
Use explicit exits such as rows(), scalar(), to_pandas(), to_pyarrow(), to_numpy(), to_pydantic(), or to_daft(). Frame transforms return new frames, and accessors return caller-owned values. object_id remains available after projection so a compact result can still drive later get, set, or delete calls. Pagination is explicit. frame.total is the exact row count before the final offset and limit, and frame.truncated says whether pagination withheld rows. An unsliced frame uses total=None because len(frame) already describes the whole result. When a preceding near(...) stage is bounded by top_k, the total describes that nearest-neighbor window rather than every Entity row.
Field references build typed expressions and combine with &, |, and ~.
contained_in(...) performs reverse containment: it asks which stored short values occur inside a longer query string. On Array[ShortText], SQL Backends use SparseGramIndex when available and preserve matching keyword evidence in the reserved match metadata column. Text operations may use a portable scan when provider-native semantics cannot be proven. Inspect the plan before trading portability for speed with query-scoped .unsafe().

5. Accept JSON Queries

query_json validates a serializable request and lowers it to the same immutable query value.
Supported top-level clauses are filter, available, near, traverse, select, group_by, aggregate, having, order, offset, limit, and unsafe. Unknown or obsolete keys fail instead of being ignored. where() also accepts Mongo-style filter mappings with registered operators such as $eq, $in, $match, $contained_in, and $array_contains.

6. Count and Aggregate

count() is a source-only terminal query specification. Only source filters, search, traversal, and unsafe policy may precede it.
Grouped aggregation uses field metric expressions:
Use having(...) after aggregate(...) and order_by(...) for result ordering. Routing may execute a provider-native aggregate or an exact portable fold; explain() tells you which. Json fields also expose registered exact folds such as value_counts(), key_counts(), and key_sums(). Registered reducers inspect the complete post-filter value stream rather than deriving statistics from a displayed page. code_reduce(...) is the escape hatch for a genuine one-off reduction:
code_reduce evaluates caller-authored Python in the HeavenBase process with normal builtins. It is enabled by heavenbase.query.allow_code_reduce and is reachable through any query surface that accepts aggregate specs, including MCP. Disable it for untrusted query authors and prefer registered aggregate operations whenever the behavior is reusable.

7. Inspect the Plan

The plan reports storage placement, selected Backend, strategy, handler kind, execution mode, portable proof, and fallback or unsupported reasons. An installed operation or matching tag is not by itself proof of native execution.

8. Keep Writes Outside Query

Queries read. Workspace CRUD owns mutation:
Pass entity=... when an object id may exist under more than one Entity type.

Summary

  • Query values are immutable and lazy.
  • Every execution returns a fresh detached ResultFrame.
  • total and truncated distinguish a complete result from a page.
  • Python and JSON surfaces share one validated request model.
  • Registered reducers cover reusable exact folds; caller-authored code_reduce is an explicit trust boundary.
  • Explain output is the authority for actual routing behavior.

Further Exploration

Related resources:
  • Entities — Define queryable fields
  • Routing — Place and dispatch query fragments
  • Backends — Understand native and portable execution
  • Catalog — Discover objects before typed queries