Skip to main content

Module select

Module select 

Source
Expand description

Query-directed planning (spec/mutate/README.md §11.8, mutate 3.1; spec/surface 4.1): an OQX selector plus effect templates compiled into the concrete effect list the planner lowers. The selector is a producer of effects, never a second write engine — the plan that comes out has today’s shape plus a frozen Selection. The reference is packages/core/src/mutate/select.ts; every rule and message here mirrors it.

Pipeline. parse(select) → check_root_spellings → the static admission (compile: consumer, root, clauses, reserved aliases, the templates’ shapes) → the AST rewrite (one select item per { oqx } slot appended after the user’s items, named __omg_sel_<t>_<slot>, on the raw tree so the runner’s resolve_aliases inlines a user alias a template reads) → the runner’s AST entry (crate::query::query_ast, limit = bound + 1) → the hits → the row binding (bind: hits in result order × templates in order, k = h·T + t), which the store’s lowering loop consumes unchanged, so the conflict tracker gives the cross-hit semantics for free (two hits writing one scalar with equal values dedupe with a diagnostic, different values are conflicting_effects, inserts into one shared target are positional in hit order).

Expressions. OQX has no expression entry point: each { oqx: e } is parsed through the wrapper select __omg_x: <e> from docs and its one item taken — a top-level item is scope depth 1, exactly the hit’s scope, so ^ and N^ validate as they will evaluate. Parse-error offsets are shifted back by the wrapper’s head (16 code points).

Binding (§11.8’s table). A template’s primary target that is absent (target / into / targets) is the hit by the root’s kind (document / block / node; targets → the one-element list); a { kind, id: { oqx } } or { kind: "document", path: { oqx } } slot evaluates to a string (that member as written) or a row-as-value { id, path } (→ { kind, id } whichever member held the expression); absent / null / [] → target_missing { effect_index, template_index, row, expression }; a list of one or more → new ambiguous_target { …, count } (a one-element list is still a list); any other type → filter_invalid { hint: "selection" }. at.before / at.after, markdown, to, path, separator must be strings; value and a create’s top-level frontmatter values may be any JSON as the runner rendered it (a row value lands as the record { id, path }), never absent. Every error raised from an expanded effect carries effect_index (the expanded position) plus template_index and row.

Sugar (spec/mutate §11.8 “Sugar”, 3.2). In every expression slot a JSON string beginning exactly LEADER (-> ) desugars to { oqx: rest } before the admission — typing follows the value as { oqx } does; a string not beginning -> is literal, always (no escaping, no ${ scanning; -> "-> …" spells a literal that begins with the leader). A leader whose expression is a bare string literal or a template literal without an interpolation folds to the plain literal before planning (-> "x" and "x" give one plan_id). A bare target string (with or without a selector) normalizes before resolution: a path-looking string (a / or ending .md) is { kind: "document", path }, a b_ / d_ / n_ id its kind, "$new.n" the symbol’s kind (an into is settled from the prefix plan’s new_ids, [settle_into_symbols]), "-> expr" the identity the value names (a row → kind by id prefix, a path string → a document), a # locator is refused with a fix. Without a selector a -> / { oqx } slot evaluates in its own target’s row scope: the effects are grouped by resolved target identity and one synthetic query per identity (from <root> where id == "<id>", the slot items appended as __omg_sel_<effectIndex>_<slot>) runs through the AST runner; the plan has no selection, planner_v stays p3 and the intent record gains templates (the effects as written) — a plain request without the leader produces none, so no existing digest moves. A -> slot on a create without a selector, a -> target without a selector, an unparsable expression (offsets relative to the slot string, past the leader) and a leader in expect / field / op are filter_invalid { hint: "selection" }.

Cardinality. expect.max (a non-negative integer; required on a one-shot apply, optional on plan / execute) bounds the selection; the query runs with limit = max + 1 (or SELECTION_CEILING + 1 without a max) and more hits than the bound is selection_too_large { cardinality, max, implicit? } — the engine never plans a partial set. Zero hits are a plan with no effects (execute / apply → commit: null).

Structs§

Bound
What bind produced: the concrete effects and each hit’s (id, path) in result order.
Compiled
A compiled request: the selector as parsed, its root, the admitted templates, the rewritten tree and the bound.
Expansion
What the selector (or the selector-less sugar) produced: the concrete effects, the frozen record (a selector’s), the hits’ identities for error annotation, and the effects as written when a selector-less request evaluated an expression (the plan’s and the intent record’s templates).
SelectRequest
plan / apply / execute with a select — the selector, the templates (the call’s effects) and the optional bound, as given — or, since 3.2, a selector-less call whose effects carry sugar (select is null: the effects are desugared and their -> / { oqx } slots evaluated in their own targets’ row scopes).
Template
One admitted template: the template with every slot removed (the binder copies it and fills the slots), its slots, the default target and the target members written as a bare $new.n.

Enums§

Member
Which target member a bare string sits in: the member decides the provisional kind a $new.n takes until the symbol table settles it (an into is ambiguous — document or block; set’s follows its field; targets[k] is a block).

Constants§

HINT
The hint of every filter_invalid the selector admission raises.
LEADER
§11.8 “Sugar” (3.2): the leader a string slot begins with to be an expression — exactly dash, greater-than, space.
SLOT_PREFIX
The prefix of the slot projections the rewrite appends: __omg_sel_<t>_<slot>.

Functions§

annotate
An error from the lowering of an expanded effect gains template_index and row next to the planner’s effect_index (module docs).
bind
The concrete effects of hits × templates (§11.8’s expansion rule); settle resolves the bare $new.n kinds (settle_symbols).
compile
The static half (§11.8 steps 1 and 2; the reference’s validateExpect + admitRequest): expect, then select and the templates, then the selector’s admission, the templates’ desugar (3.2) and admission, and the rewrite. Nothing is read.
expand
Run the selector and expand it (module docs; the reference’s compileSelection), or — without a selector (3.2) — desugar the effects and evaluate their slots in their own targets’ row scopes (expand_plain). semantic is the embedded phrases of the selector (crate::query::embed_phrases). The store is borrowed mutably only for the prefix plans that settle bare $new.n kinds; nothing is written.
expand_plain
Compile a plain effects list (no selector; the reference’s compilePlain): desugar the -> leaders, then — when nothing is an expression — the shape check as before (3.1-identical, no templates). Otherwise each effect with expression slots is admitted as a template over its own primary target’s row ([scope_of]): the effects are grouped by that row’s identity, one synthetic query per identity — from <root> where id == "<id>" with the slot items appended, named __omg_sel_<effectIndex>_<slot> — runs (limit 2), and the row binds the slots exactly as a selector’s hit would. Bare $new.n kinds are settled last, in request order, each against the effects before it.
no_settle
A settlement that leaves every provisional kind in place (tests; a path with no store at hand).
plan_selected
Expand and plan in one write scope: the store callback the catalog hands to Store::plan_selected, Store::execute_replanned and Store::apply_planned. Without a selector (3.2) the plan carries no selection but records the effects as written as templates when one evaluated an expression.
require_max
The one-shot apply rule (§11.8): a selector must be bounded — the caller never saw the hits (a preview is a plan, which needs no bound). The selector-less sugar path names its targets and needs none.
settle_symbols
The settlement over a store: plan the prefix (nothing written, no id minted) and read the symbols’ kinds off its new_ids. A prefix that does not plan, or a symbol it did not mint, is left provisional — the real plan reports it (target_missing { symbol } for one nothing created).
unbounded_apply
The one-shot apply rule’s refusal with its corrected example (3.3): the same call bounded at the selection’s actual size — the caller never saw the hits, so the engine counts them (the selector compiled, nothing written) and spells the bound.
validate_plain
The plain effects of a request (no selector, no sugar: the catalog’s parse_effects path) shape-checked with the §8 fixes of 3.4 — the reference’s compilePlain over effects without an expression, where the fix context reads the store for the anchor fix.

Type Aliases§

Row
A hit’s (id, path).
Settle
The settlement of bare $new.n targets (3.2): given the effect JSON, the members holding a symbol and the concrete effects before it, rewrite each symbol’s kind to the one the symbol table records — the kind plan over that prefix allocated to $new.n (new_ids[n].kind).