xyzDB

Querying

Reading is a pipeline: resolve the fast path first, then walk the graph, roll up, or run exact vector search.

FIND vs SCAN

FIND resolves anchor → gravity → scan (fast paths first). SCAN is a filtered lobe walk with a full boolean WHERE; it routes transparently to a ghost when one fits.

FIND "clients" WHERE rfc = "ACME-001"
SCAN "creditos" WHERE status = "overdue" AND amount > 1000 LIMIT 50

Paginate large scans with an opaque CURSOR token (no OFFSET).

FETCH

Read several co-located lobes in one call: one record whose fields are a named section per lobe, keyed by a shared WHERE.

FETCH "clientes", "creditos", "operaciones" WHERE rfc = "ACME-001"
    AS {cliente, creditos, operaciones}

WHERE is required — it's the shared key every lobe co-locates by, so each resolve rides the anchor/gravity fast path. AS renames the sections; omitted, each is named by its lobe.

The pipeline

Chain steps with |. After a FIND/SCAN you can PULL, SET, DELETE, GROUP BY, AGGREGATE, TAKE, SHAPE, NEAREST or FOLLOW.

FIND "clients" WHERE name = "Acme Corp" | PULL depth=2 only=Invoice
FIND "creditos" WHERE rfc = "ACME-001" | SET status = "closed"

Aggregate & group

AGGREGATE supports count(), sum, avg, min, max. SCAN | AGGREGATE streams in O(1) memory; a matching precomputed ghost answers with zero scan.

SCAN "creditos" WHERE _type = "Credit" | GROUP BY status | AGGREGATE count(), sum(monto)

Take & shape

TAKE is the canonical top-N / truncate step: n BY metric keeps the top (or bottom) n groups from an AGGREGATE; n alone truncates any stream — the pipeline form of LIMIT. SHAPE projects each record down to named fields, the read-side mirror of PUT.

SCAN "creditos" WHERE _type = "Credit"
    | GROUP BY rfc
    | AGGREGATE sum(monto) AS exposicion
    | TAKE 100 BY exposicion DESC

SCAN "clients" WHERE tier = "gold" ORDER BY score DESC LIMIT 10
    | SHAPE {name, score}

TOP n BY metric still parses (deprecated alias of TAKE). When a ghost keeps the same metric order, TAKE reads it in O(N) instead of O(M).

NEAREST

Exact top-k over the gravity bucket, canonical phrase form. The query vector is bound out of band as $q, given inline, or taken from another record with REF. Metrics: cosine, dot, l2.

FIND "memories" WHERE topic = "billing"
    | NEAREST 8 BY embedding TO $q USING cosine

SCAN "memories" WHERE topic = "billing" | NEAREST(embedding, REF "mem-42", 5, cosine)   # function alias, more like this

USING defaults to cosine in the phrase form; the function alias NEAREST(field, query, k, metric) parses to the same statement. ORBIT was removed in v1 — NEAREST is the only name now. EMBED "text" needs a remote embedding service (opt-in); rejected in the default agnostic mode.

FOLLOW

Cross-entity expansion: resolve a field's value as the matching record in another lobe.

FIND "pagos" WHERE mes = "2026-06" | FOLLOW credito TO "creditos" ON id

DELETE & PURGE

DELETE removes matched records — WHERE is required on the standalone form. PURGE is the explicit, hard-to-typo verb for emptying a whole lobe on purpose.

FIND "fintech" WHERE status = "cancelled" | DELETE
DELETE "clients" WHERE name = "Old Corp"
PURGE "scratch"  # empties the whole lobe

A WHERE-less DELETE used to empty a lobe silently — now it errors and points you to PURGE.

Filters & operators

WHERE is a boolean tree: = != > >= < <=, IS NULL / IS NOT NULL, IN [a, b], CONTAINS (lists), combined with AND / OR / NOT and parentheses. Nested fields use dot notation.

SCAN "creditos" WHERE (status = "overdue" OR amount > 1000) AND NOT closed
SCAN "orders" WHERE items.0.price >= 50 AND tags CONTAINS "vip"
SCAN "creditos" WHERE status IN ["active", "overdue"]

Note · Null = Null is true (unlike SQL). IN (a, b) parenthesized form still parses.