@omgbase/oqx 0.18.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +149 -64
  3. package/dist/ast.d.ts +21 -5
  4. package/dist/ast.d.ts.map +1 -1
  5. package/dist/ast.js +1 -1
  6. package/dist/ast.js.map +1 -1
  7. package/dist/build.d.ts +7 -1
  8. package/dist/build.d.ts.map +1 -1
  9. package/dist/build.js +7 -3
  10. package/dist/build.js.map +1 -1
  11. package/dist/context.d.ts +19 -5
  12. package/dist/context.d.ts.map +1 -1
  13. package/dist/context.js +6 -9
  14. package/dist/context.js.map +1 -1
  15. package/dist/engine.d.ts +12 -1
  16. package/dist/engine.d.ts.map +1 -1
  17. package/dist/engine.js +235 -83
  18. package/dist/engine.js.map +1 -1
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +2 -1
  21. package/dist/index.js.map +1 -1
  22. package/dist/optimize/analysis.d.ts +3 -2
  23. package/dist/optimize/analysis.d.ts.map +1 -1
  24. package/dist/optimize/analysis.js +14 -15
  25. package/dist/optimize/analysis.js.map +1 -1
  26. package/dist/parser.d.ts.map +1 -1
  27. package/dist/parser.js +196 -114
  28. package/dist/parser.js.map +1 -1
  29. package/dist/print.d.ts.map +1 -1
  30. package/dist/print.js +13 -13
  31. package/dist/print.js.map +1 -1
  32. package/dist/resolve.d.ts.map +1 -1
  33. package/dist/resolve.js +11 -8
  34. package/dist/resolve.js.map +1 -1
  35. package/dist/version.d.ts +1 -1
  36. package/dist/version.js +1 -1
  37. package/dist/walk.d.ts +5 -3
  38. package/dist/walk.d.ts.map +1 -1
  39. package/dist/walk.js +26 -8
  40. package/dist/walk.js.map +1 -1
  41. package/package.json +1 -1
  42. package/src/ast.ts +23 -6
  43. package/src/build.ts +8 -7
  44. package/src/context.ts +22 -11
  45. package/src/engine.ts +236 -90
  46. package/src/index.ts +2 -1
  47. package/src/optimize/analysis.ts +13 -12
  48. package/src/parser.ts +180 -96
  49. package/src/print.ts +12 -10
  50. package/src/resolve.ts +11 -7
  51. package/src/version.ts +1 -1
  52. package/src/walk.ts +32 -11
package/CHANGELOG.md CHANGED
@@ -4,6 +4,30 @@ All notable changes to `@omgbase/oqx` are recorded here. The format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow
5
5
  [Semantic Versioning](https://semver.org/) (pre-1.0: a minor bump may break).
6
6
 
7
+ ## [0.20.0] - 2026-10-11
8
+
9
+ ### Minor
10
+ - OQX 0.20 (`spec/oqx` 0.19 → 0.20; 1188 → 1258 fixtures, three new suites `tuples`, `identity`, `cardinality`):
11
+
12
+ - **`follow` loses its options block.** A brace after *any* destination opens that destination's block (`follow children { depth 2 }`, `follow a, children { id != "root" }`, `follow entries(kids) { where … }`), with the 0.17 body rules. Two clauses belong to a destination block alone, after `where` in the fixed order: `depth <1..8>` (this destination expands a frontier row only while its `$depth < n`) and `frontier <expr>` (an occurrence reached through this destination for which it holds is a frontier; read with `^` the walk's enclosing scope; seeds are never frontiers). The former `where` option is the block's `where`; `by` is gone. When several destinations reach a row in one step the first governs the occurrence. **The body that carries the `follow` may carry `frontier <expr>` too** (Brendan, 2026-10-11): it applies to the SEEDS — a seed for which it holds (read in the seed's own scope, `^` the enclosing scope, like `where`) is `$stop == "frontier"` and is not expanded, while it stays in the result — so every block that feeds rows into the walk says which of its rows are frontiers, and the frontier relevant to the current `$it` is defined separately from each destination's. The clause order of every body is `select from where frontier follow order by limit offset` (a destination block's adds `depth` after `frontier`); a body-level `frontier` without a `follow` is the parse error `` `frontier` needs a `follow` ``, a body-level `depth` an error naming the destination block; inside a destination block `frontier` is always the destination's. AST: `follow` keeps only `destinations`/`distinct`; `subquery` gains `frontier`/`depth`, `query` gains `frontier`; `print` writes `follow x collect { where … depth 2 }` and a body's `frontier` between `where` and `follow`.
13
+ - **Tuples.** `(e1, e2, …)` with two or more elements is a value and a receiver: the elements concatenated with one level of flattening (a collection contributes its items, a row itself; an absent element nothing, a `null` is kept; duplicates kept). `size((a, b))`, `"x" in (tags, aliases)`, `(mom, dad, siblings) { name values }`, `follow (before, after) { depth 2 }` (one destination over the union). New AST node `tuple { items }`.
14
+ - **Identity is `$key`.** One meaning — the key a row is known by — for `follow` cycle detection, the per-step union, `follow distinct`, `distinct` over unprojected rows, `is`, and reading `$key` on any row. The default is the host's identity through a new `DataContext` seam (TS: optional `identityOf(row)`, replacing the required `identity`, which stays as a deprecated alias for one minor; Rust: `identity` now has a structural default), else the row's structural value; an entry's identity is its key. The language never names an `id` property: the "`id` if present" rule is removed, and the in-memory `DefaultContext` names no identity. A block may project `$key: <expr>` to give the rows it yields that identity (`select name, $key: email from people follow next { $key: email }`); in a destination block `$key:` is not a column. Caveat: identities compare as values across the whole walk, so destinations that can reach the same rows should project the same `$key`.
15
+ - **Result shape by receiver cardinality.** In row position an array is a collection and a non-array object is one row: a `collect` over it — `doc { title }`, `title from doc`, a nested `d: dst { title }` — yields the one record (or absent when filtered out; `doc { status == "active" }` is a conditional reach-through), not a one-element list; `values` the one value; `first`/`single` that object. A scalar in row position is an eval error (`` `s` is a string ("abc"), not a collection or an object ``) instead of a one-row collection — `list(s)` says it explicitly. A `from` re-projection or a `follow` makes the result plural. Hosts say which of their objects are collections through the new optional `DataContext.isSingle` (TS; default: a non-iterable object is one row) / `is_single` (Rust; default `true`). TS `OqxResult` for `collect` gains `single: boolean` (`unwrap` yields the record or `null`); Rust gains `OqxResult::Record(Option<Value>)`.
16
+ - **Sugar closures.** `x { … }` ≡ `x collect { … }` wherever a value is accepted, function arguments included (`size(children { is checked })`); `x distinct { … }` ≡ `x collect distinct { … }`.
17
+
18
+ omgbase binding (surface stays 3.0; the dialect follows the language):
19
+
20
+ - `DataContext.identityOf` (TS) / `identity` (Rust) answers a store row's id for every kind (`doc_id`, `block_id`, `node_id`, `edge_id`), so `$key` on any hit is its id and walks dedup by it as before; the binding no longer relies on the removed `id`-property rule.
21
+ - The statically single relations `doc`, `block` and `dst` hand out an absent-single marker when they have no row, so `dst { title }` on a link row is one record and, on an external or dangling link, absent — not `[]`; as a value the marker is absent (`dst == null`, `has(dst)`, `dst.title` unchanged). The Rust context's `is_single` marks the lazy root scans as collections.
22
+ - The `graph` tool compiles to `follow distinct <dir>_links collect { from <dst|doc> depth <n> }`; `query_syntax`, the `query` tool description, both help cards, `docs/query-language.md`, `docs/graph-and-query.md`, `docs/mcp-api.md` and the OQX tutorial describe the 0.20 forms (body-level `frontier` included); the planners treat a destination block's `frontier`/`depth` as its own, never push a tuple down, and a body with `frontier` plans like one with a `follow` — in memory (pinned on both sides). `spec/surface` `query-follow::body-frontier-keeps-seeds-unexpanded` walks the processes with the unverified one kept but not expanded.
23
+ - `spec/surface` fixtures using the old options block are rewritten to the destination-block forms (`… collect { from dst depth 2 }`; `by type` → `{ $key: type from dst }`) and regenerated; `spec/cli` and `interop.json` regenerated with them.
24
+ - `@omgbase/oqx-syntax`: `LANGUAGE_VERSION` 0.20; `FOLLOW_OPTIONS` → `DESTINATION_CLAUSES` (`frontier`, `depth`; `by` is no longer a word of the language), assets regenerated.
25
+
26
+ ## [0.19.0] - 2026-10-10
27
+
28
+ ### Minor
29
+ - OQX language 0.19 — outer-reference `follow` destinations take the implicit `collect`. A `follow` destination whose receiver is headed by an outer reference (`^docs`, `^^root.rel`, `0^docs`, `^$it.docs`, with any member chain) can never be a plain destination (plain destinations are relations of the current row), so a `{` right after it now opens a **destination block** with the implicit `collect`: `follow refs(before), ^docs { where ^$path in list(after) }` walks `before` references forward and, backward, every document whose `after` names the frontier row — exactly `^docs collect { … }` with the 0.17 body rules (where-first, projections). Until 0.18 that query failed with the outer-reference error, because the 0.17 carve-out reserved a brace after the last destination for the options block. Any other receiver (a bare relation, a call like `refs(before)` or `entries(kids)`, a binding) keeps that reading: a brace after it is the options block when it is the last destination (`follow children { depth 2 }`, `follow a, children { depth 2 }`) and the "a destination block needs its consumer" error when the brace holds a predicate. An options block may still follow a trailing destination block (`follow ^docs { where … } { depth 2 }`). A plain `follow ^children` (no brace, no consumer) is still an error; its message now names both block spellings: `` `follow` takes a relation of the current row (`follow <relation>`); an outer reference walks a root collection only as a destination block — `follow ^docs { where … }` or `follow ^docs collect { … }` ``. Fixtures: 25 new cases across `follow`, `sugar`, `errors-parse` and `ast` (1188 total); the 0.17 sugar case "an outer-reference destination with a brace is the outer-reference error" is replaced by its positive form. `LANGUAGE_VERSION` is 0.19 in both engines and in `@omgbase/oqx-syntax`; the `query_syntax` reference (`@omgbase/core`, `omgbase-surface`) describes the new rule.
30
+
7
31
  ## [0.18.0] - 2026-10-10
8
32
 
9
33
  ### Minor
package/README.md CHANGED
@@ -34,7 +34,7 @@ const company = "Globocorp";
34
34
  const employees = oqx`
35
35
  name, id, title
36
36
  from ${people}
37
- where jobs exists { where employer == ${company} && !end_date }
37
+ where jobs exists { where employer == ${company} and not end_date }
38
38
  `;
39
39
  // → [{ name: "Bob", id: 124, title: "Engineer" }, …] (current Globocorp employees)
40
40
  ```
@@ -56,8 +56,8 @@ once, and every one is optional except `from` at the top level:
56
56
  ```
57
57
  [ [select] projection ] name, id, title: label (or: select distinct …, … values)
58
58
  from <collection> from ${people}
59
- [ where <predicate> ] where age >= 18 && jobs exists { where !end }
60
- [ follow <dest>, … ] follow children { depth 4 } (or: follow before, after; follow ^people collect { … })
59
+ [ where <predicate> ] where age >= 18 and jobs exists { where not end }
60
+ [ follow <dest>, … ] follow children { depth 4 } (or: follow before, after; follow ^people { where … })
61
61
  [ order by <expr> … ] order by age desc, name
62
62
  [ limit N ] limit 10
63
63
  [ offset N ] offset 20
@@ -200,19 +200,22 @@ const flags = { beta: { on: true }, legacy: { on: false } };
200
200
  oqx`$key values from entries(${flags}) where on`; // ["beta"] (bare `on` reads the value)
201
201
 
202
202
  oqx`name, on: entries(prefs) collect { $key values where $it } from ${users}`; // as a nested receiver
203
- oqx`name from ${users} where entries(prefs) exists { where $key == "dark" && $it }`;
203
+ oqx`name from ${users} where entries(prefs) exists { where $key == "dark" and $it }`;
204
204
  ```
205
205
 
206
206
  `entries(array)` yields numeric index keys, a `Map` yields its entries, and
207
- absence/scalars yield nothing. `$key` exists **only** in an entry scope — an
208
- ordinary row or array element has no implicit index; `entries(arr)` is how you
207
+ absence/scalars yield nothing. An entry's `$key` is its key — and since
208
+ language 0.20 `$key` is the **identity** every row is known by (§9): an
209
+ ordinary row's `$key` is the host's identity, structurally the row itself for
210
+ plain data; an array element has no implicit index — `entries(arr)` is how you
209
211
  ask for one. As a plain value (not a source) `entries(x)` is an array of
210
212
  `{ key, value }` records.
211
213
 
212
214
  ### 3. Predicates (where)
213
215
 
214
216
  `where` filters rows. The predicate language has comparisons (`== != < <= > >=`),
215
- boolean operators (`&& || !`) with grouping `( )`, membership (`in`), arithmetic
217
+ boolean operators — the words `and`, `or`, `not`; the symbols `&& || !` are
218
+ accepted synonyms — with grouping `( )`, membership (`in`), arithmetic
216
219
  (`+ - * / %`), and bare truthiness. The `where` keyword is always written — a
217
220
  leading expression without it is a projection, and a bare comparison in that
218
221
  position is an error that points you at `where`.
@@ -319,7 +322,7 @@ from a row nested one level deeper. A receiver may start with `^` too, which is
319
322
  how a nested consumer runs over a named root or an enclosing row's relation:
320
323
 
321
324
  ```js
322
- execute("name, peers: ^people collect { name where city == ^city && name != ^name } from people", { people });
325
+ execute("name, peers: ^people collect { name where city == ^city and name != ^name } from people", { people });
323
326
  ```
324
327
 
325
328
  **Correlated subqueries.** Because inner and outer rows often share names, the
@@ -334,7 +337,7 @@ const family = [
334
337
  ];
335
338
  oqx`
336
339
  name,
337
- siblings: ${family} collect { name where parent == ^parent && name != ^name }
340
+ siblings: ${family} collect { name where parent == ^parent and name != ^name }
338
341
  from ${family}
339
342
  `;
340
343
  // [{ name: "Ada", siblings: [{ name: "Ben" }] },
@@ -357,7 +360,7 @@ Methods on a value: `contains`, `startsWith`, `endsWith`, `matches` (regex),
357
360
  ```js
358
361
  oqx`name from ${people} where title.startsWith("Eng")`; // → Bob
359
362
  oqx`name from ${people} where title.lower() == "director"`; // → Alice
360
- oqx`name from ${people} where has(age) && !has(nickname)`; // present vs absent
363
+ oqx`name from ${people} where has(age) and not has(nickname)`; // present vs absent
361
364
  oqx`name from ${people} where tags.contains("admin")`; // array membership
362
365
  ```
363
366
 
@@ -591,8 +594,10 @@ Reached rows expose recursion **intrinsics** in `select` / `order by`:
591
594
  graph beyond — a boundary or the depth cap), `$ordinal` (a deterministic 1..N
592
595
  rank over the walk, ordered by depth then path), and `$stop`
593
596
  (`"interior"` / `"leaf"` / `"frontier"` / `"depth"` / `"cycle"`, precedence
594
- cycle > frontier > depth > leaf > interior — only `interior` rows expand). Options
595
- go in a trailing block:
597
+ cycle > frontier > depth > leaf > interior — only `interior` rows expand). A
598
+ brace after a destination opens that destination's **block** (language 0.20),
599
+ whose body has two clauses of its own after `where`: `depth <n>` and
600
+ `frontier <pred>`:
596
601
 
597
602
  ```js
598
603
  oqx`id, stop: $stop from ${tree} follow children { depth 2 } order by $ordinal`;
@@ -604,10 +609,10 @@ a nested block (`kids: children collect { … }`) a bare `$depth` is the nested
604
609
  row's own `$depth` property (absent unless the data carries one), and the
605
610
  occurrence's depth is `^$depth`. The same holds everywhere the metadata is not
606
611
  present — outside a `follow`, `$depth`/`$ordinal`/`$stop`/`$leaf`/`$frontier`
607
- are ordinary property reads (a row `{ "$depth": 3 }` projects `3`), and `$key`
608
- is likewise an ordinary property read outside an `entries()` scope. Where the
609
- metadata exists it wins over a same-named property (language 0.13; before, the
610
- six names read absent everywhere they were not metadata).
612
+ are ordinary property reads (a row `{ "$depth": 3 }` projects `3`). `$key` is
613
+ the exception: it is the row's identity everywhere (below). Where the metadata
614
+ exists it wins over a same-named property (language 0.13; before, the six names
615
+ read absent everywhere they were not metadata).
611
616
 
612
617
  The walk is **per-path**: a node reached by N distinct paths yields N
613
618
  occurrences, and revisiting an identity already on the current path is admitted
@@ -616,42 +621,107 @@ runaway. `follow distinct` collapses occurrences to reached nodes (the minimal
616
621
  `(depth, path)` per identity).
617
622
 
618
623
  **Destinations** (language 0.14) are comma-separated; the walk is their union.
619
- A **plain destination** is a relation of the current row (`children`, `doc.out`
620
- — an outer reference `^rel` or a literal is a parse error). A **destination
621
- block** is a receiver followed by `collect`, `first` or `single` (optionally
622
- `distinct`) and a block — the same directive you would write in `select`,
623
- re-evaluated per frontier row with `^` bound to that row. Its receiver *may* be
624
- an outer reference, so a walk can compute successors from a named root:
624
+ A **plain destination** is a relation of the current row (`children`, `doc.out`,
625
+ `entries(kids)`, a tuple `(before, after)` — one destination over the union of
626
+ its elements; an outer reference `^rel` on its own or a literal is a parse
627
+ error). A **destination block** is a receiver followed by a block — `children {
628
+ depth 2 }`, `^people { where manager == ^id }`, `(before, after) { depth 2 }`,
629
+ or with its consumer, `^chain first distinct { … }` — the same directive you
630
+ would write in `select`, re-evaluated per frontier row with `^` bound to that
631
+ row. Its receiver *may* be an outer reference, so a walk can compute successors
632
+ from a named root. Since language 0.20 **a brace after any destination opens
633
+ that destination's block** (there is no options block any more):
625
634
 
626
635
  ```js
627
636
  const people = [{ id: 1, manager: null }, { id: 2, manager: 1 }, { id: 3, manager: 1 }, { id: 4, manager: 2 }];
628
- oqx`id values from ${people} where id == 1 follow ^people collect { where manager == ^id } order by $ordinal`;
637
+ oqx`id values from ${people} where id == 1 follow ^people { where manager == ^id } order by $ordinal`;
629
638
  // [1, 2, 3, 4] — the reporting tree under person 1 (`^people` names the root from a top-level walk)
639
+ oqx`id values from ${people} where id == 1 follow ^people { where manager == ^id depth 2 } order by $ordinal`;
640
+ // [1, 2, 3] — `depth` is a clause of the destination block, after its `where`
630
641
 
631
642
  const chain = [{ id: "a" }, { id: "b", prev: "a" }, { id: "c", prev: "b" }];
632
- oqx`id values from ${chain} where id == "b" follow distinct ^chain collect { where id == ^prev }, ^chain collect { where prev == ^id } order by $ordinal`;
643
+ oqx`id values from ${chain} where id == "b" follow distinct ^chain { where id == ^prev }, ^chain { where prev == ^id } order by $ordinal`;
633
644
  // ["b", "a", "c"] — both directions of a chain; a block may order, bound and `distinct` its rows
634
645
  ```
635
646
 
636
- A row's successors are, per destination in order, that destination's rows,
637
- filtered by the follow `where`, then **unioned by identity within the step**: a
638
- node reached by two destinations (or twice by one relation) in the same step is
639
- a single successor. `exists`/`none`/`count` are not destinations (they are
647
+ A row's successors are, per destination in order, that destination's rows
648
+ (shaped by the block's projection, if any), then **unioned by identity within
649
+ the step**: a node reached by two destinations (or twice by one relation) in the
650
+ same step is a single successor, and the destination that reached it first
651
+ governs it. `exists`/`none`/`count` are not destinations (they are
640
652
  where-position tests).
641
653
 
642
- The block accepts: `where <succ>` (which successors keep participating),
643
- `frontier <pred>` (cut a relation that could continue, whichever destination
644
- reached it), `depth <n>` (1–8), and `by <expr>` (the identity used for cycle
645
- detection + `distinct` — default `.id` or the object reference). The follow
646
- `where` is **correlated**: it reads the candidate successor's scope whose parent
647
- is the frontier row's — a bare name is the candidate's own property, `^name` is
648
- the row being expanded, `^^name` the walk's enclosing scope (language 0.14;
649
- before, `^` skipped the frontier row). So `follow doc.in { where
650
- before.contains(^$path) }` steps only into rows that name the row they were
651
- reached from. `frontier` and `by` are not correlated: they read the occurrence
652
- with `^` the enclosing scope, as the body does. Give `follow` a stable identity
653
- (`.id` or `by`) when your relation returns fresh objects rather than shared
654
- references.
654
+ A destination block's body is an ordinary block — `where <succ>` (which
655
+ successors keep participating), a projection, `order by`, `limit`/`offset`,
656
+ `distinct` — plus two clauses after `where`: `frontier <pred>` (an occurrence
657
+ this destination reached for which it holds is a frontier — cut, not expanded)
658
+ and `depth <n>` (1–8: this destination expands a frontier row only while its
659
+ `$depth < n`; a destination block's clause alone). The block's `where` is **correlated**: it reads
660
+ the candidate successor's scope whose parent is the frontier row's — a bare name
661
+ is the candidate's own property, `^name` is the row being expanded, `^^name` the
662
+ walk's enclosing scope (language 0.14; before, `^` skipped the frontier row). So
663
+ `follow doc.in { where before.contains(^$path) }` steps only into rows that
664
+ name the row they were reached from. `frontier` is not correlated: it reads the
665
+ occurrence with `^` the enclosing scope, as the body does; seeds are reached
666
+ through no destination and are never frontiers by a destination's rule. **The
667
+ body that carries the `follow` may write `frontier <pred>` too**, after its
668
+ `where` and before `follow`: it applies to the seeds — a matching seed stays in
669
+ the result with `$stop == "frontier"` and is not expanded (`id from tree frontier
670
+ !active follow children { depth 2 }`); read in the seed's scope like the body's
671
+ `where`. Each destination's `frontier` is its own; without a `follow`, a
672
+ body-level `frontier` is a parse error.
673
+
674
+ **Identity is `$key`** (language 0.20). Cycle detection, the per-step union,
675
+ `follow distinct`, `distinct` over unprojected rows and `is` all compare one
676
+ thing — the identity a row is known by — and reading `$key` on any row returns
677
+ it. The default is the host's (`DataContext.identityOf`), else the row's
678
+ **structural value**; `DefaultContext` names none, so over plain objects two
679
+ objects with the same `id` are two nodes. A block may project `$key: <expr>` to
680
+ give the rows it yields that identity — the body's `select` names the seeds, a
681
+ destination block its successors (where `$key:` is not a column; the rows keep
682
+ their shape):
683
+
684
+ ```js
685
+ const n1 = { id: 1 }, n2 = { id: 2, next: [n1] }; n1.next = [n2]; // a cyclic graph of fresh references
686
+ oqx`id, stop: $stop, $key: id from ${[n1]} follow next { $key: id } order by $ordinal`;
687
+ // [{ id: 1, stop: "interior", $key: 1 }, { id: 2, stop: "interior", $key: 2 }, { id: 1, stop: "cycle", $key: 1 }]
688
+ oqx`name, $key: email from ${people} follow next { $key: email }`; // known by email at every step
689
+ ```
690
+
691
+ Identities are compared as values across the whole walk, so destinations that
692
+ can reach the same rows should project the same `$key`, or a cycle through both
693
+ may run to the depth cap. Give a cyclic graph of fresh objects a `$key` (or a
694
+ context with `identityOf`) rather than rely on the structural default.
695
+
696
+ ### 9b. Cardinality and tuples (0.20)
697
+
698
+ In row position an **array** is a collection and a non-array **object** is one
699
+ row: a block over it yields **one record** (or absent, when the row is filtered
700
+ out) rather than a one-element list, `values` the one value, `first`/`single`
701
+ that object — `doc { title }` is `{ title }`, `doc { status == "active" }` is the
702
+ object or absent (a conditional reach-through), `title from doc` the same record.
703
+ A scalar in row position is an eval error (`list(s)` says "one element"
704
+ explicitly); a `from` re-projection or a `follow` is plural. A host says which
705
+ of its objects are collections through `DataContext.isSingle` (a lazy handle);
706
+ by default a non-iterable object is one row.
707
+
708
+ ```js
709
+ oqx`${settings} { theme }`; // { theme: "dark" } (one object → one record)
710
+ oqx`${[settings]} { theme }`; // [{ theme: "dark" }] (a collection → a list)
711
+ oqx`from list(${settings})`; // [settings] (the explicit one-element collection)
712
+ ```
713
+
714
+ A **tuple** `(e1, e2, …)` — two or more expressions in parentheses — is a value
715
+ and a receiver: its elements concatenated with one level of flattening (a
716
+ collection contributes its items, a row itself; an absent element nothing, a
717
+ `null` is kept; duplicates kept). One parenthesized expression is grouping.
718
+
719
+ ```js
720
+ oqx`n: size((tags, aliases)) from ${people}`; // one count over both lists
721
+ oqx`name from ${people} where "x" in (tags, aliases)`; // membership in the union
722
+ oqx`n: (mom, dad, siblings) { name values } from ${people}`; // one block over the union
723
+ oqx`id from ${g} follow (before, after) { depth 2 }`; // one destination over the union
724
+ ```
655
725
 
656
726
  ### 10. Sugar (0.17)
657
727
 
@@ -661,11 +731,15 @@ optimizer and any pushdown planner see it), so nothing here has semantics of its
661
731
  own except the postfix `!` and the infix `is`:
662
732
 
663
733
  ```js
664
- // A receiver block without a consumer is `collect`; a block whose LEADING
665
- // expression is syntactically a predicate drops `where`.
734
+ // A receiver block without a consumer is `collect` — wherever a value stands
735
+ // (language 0.20): a select item, a where leaf, a follow destination, a call
736
+ // argument; `x distinct { … }` is `x collect distinct { … }`. A block whose
737
+ // LEADING expression is syntactically a predicate drops `where`.
666
738
  oqx`name, current: jobs { !end_date } from ${people}`
667
739
  // ≡ name, current: jobs collect { where !end_date } from ${people}
668
740
  oqx`${people} { age > 40 }` // ≡ ${people} collect { where age > 40 }
741
+ oqx`n: size(jobs { !end_date }) from ${people}` // a block as a call argument
742
+ oqx`${people} distinct { city }` // ≡ ${people} collect distinct { city }
669
743
  oqx`${people} count { jobs exists { } }` // a consumer test is predicate-shaped too
670
744
  oqx`${people} first { name }` // a bare name still projects — unchanged
671
745
  oqx`${people} first { is active }` // the bare-field filter: `is x` ≡ `!!x`, `not x` ≡ `!x`
@@ -678,15 +752,15 @@ oqx`name, first_job: jobs[0], primary: jobs[pay > 2]! from ${people}`
678
752
  // jobs[pay > 2]! ≡ jobs single { where pay > 2 }! (zero or many matches ⇒ an eval error)
679
753
 
680
754
  // Postfix `!` — required: the value, or an eval error naming the expression
681
- // (and the row's id). Never a filter, never a coercion: 0! and ""! are values.
755
+ // (and the row's `$key` when scalar). Never a filter, never a coercion: 0! and ""! are values.
682
756
  oqx`select id!, title from ${docs}` // insist on an identity before a write
683
757
  // Tightest precedence: `refs(c)[0]!.name` requires the lookup, `refs(c)[0].name!` the name.
684
758
 
685
- // `is` / `is not` compare IDENTITY (a row's id when present, else structurally):
759
+ // `is` / `is not` compare IDENTITY (`$key`: the host's, else structural — §9):
686
760
  oqx`name from ${people} where manager is null` // absent (same as == null)
687
761
  oqx`${people} count { ^people exists { $it is ^$it } }` // rows compare; `==` leaves that unspecified
688
- // `and` / `or` are exact synonyms of `&&` / `||`: `title or path` coalesces.
689
- // `print` writes the words (language 0.18); `!` stays `!`.
762
+ // `and` / `or` / `not` are the canonical connectives; `&&` / `||` / `!` are exact
763
+ // synonyms (`title or path` coalesces). `print` writes the words (language 0.18); `!` stays `!`.
690
764
 
691
765
  // A select item may use the items to its left (inlined like a `where` alias):
692
766
  oqx`boss: ^people[id == ^manager], bossName: boss.name from ${people}`
@@ -694,7 +768,12 @@ oqx`boss: ^people[id == ^manager], bossName: boss.name from ${people}`
694
768
 
695
769
  Reserved words, never a bare field name: `from where select is not and or` and
696
770
  the literal words `true false null`. The top level is unchanged — `age > 15
697
- from ${people}` stays an error, because `where` would precede `from`.
771
+ from ${people}` stays an error, because `where` would precede `from`. One
772
+ carve-out: after a `follow` destination that is a relation of the current row
773
+ (a bare name, a call, a binding) a brace is still the **options** block (`follow
774
+ children { depth 2 }`), never a collect; only over an outer-reference receiver,
775
+ which cannot be a plain destination, is the brace a destination block with the
776
+ implicit `collect` (`follow ^people { where … }`, language 0.19).
698
777
 
699
778
  ### Cheat-sheet
700
779
 
@@ -702,11 +781,11 @@ from ${people}` stays an error, because `where` would precede `from`.
702
781
  select … from … where … follow … order by … limit N offset N the fixed clause order (each at most once)
703
782
  name, alias: expr, nested: rel collect { … } projection (`select` may be dropped only here, in first position)
704
783
  from ${source} source collection (required at the top level)
705
- where a == b && rel exists { where … } || !c predicate tree + nested ops (`and`/`or` ≡ `&&`/`||`)
784
+ where a == b and rel exists { where … } or not c predicate tree + nested ops (`&&`/`||`/`!` are accepted synonyms)
706
785
  rel { pay > 2 } / rel { employer } a block without a consumer is collect; a leading predicate is where-first, a bare name projects
707
786
  rel[p] / rel[p]! / rel[0] / rel[0]! first match / exactly one (required) / positional / required positional
708
787
  x! required: the value, or an error when absent (tightest; `a!.b` vs `a.b!`)
709
- is x / not x / x is y / x is not y truthiness (≡ !!x / !x) / identity (a row's id, else structural; absent ≡ null)
788
+ is x / not x / x is y / x is not y truthiness (≡ !!x / !x) / identity ($key: the host's, else structural; absent ≡ null)
710
789
  where alias / a: expr, b: a `where` and later items may use this body's select aliases (resolved before evaluation; an alias shadows a field)
711
790
  where rel none { … } zero rows (≡ !rel exists { … }; "all" = none over the complement)
712
791
  where x in lo..hi / lo...hi / ..hi / lo.. range membership (incl. / excl. / open-ended)
@@ -721,9 +800,12 @@ from entries(obj) … $key / $it a record's properties as a co
721
800
  entries(rel) exists { … } a free-function call may be a receiver
722
801
  order by expr desc, expr2 ordering
723
802
  limit n / offset n bound the row set (after where/order/distinct, before the consumer)
724
- follow rel { where … frontier … depth n by … } recursion ($depth/$stop/$leaf/$frontier); `^name` in the where is the frontier row
725
- follow before, after several destinations: the union of their rows (per step, by identity)
726
- follow ^people collect { where manager == ^id } a destination block: successors computed per frontier row (`^` = that row)
803
+ follow rel { where … frontier … depth n } recursion ($depth/$stop/$leaf/$frontier/$key); the brace is the destination's block, `^name` in its where the frontier row
804
+ follow before, after / follow (before, after) several destinations: the union of their rows (per step, by identity) / one tuple destination
805
+ follow ^people { where manager == ^id } a destination block: successors computed per frontier row (`^` = that row; `collect` implicit, 0.20)
806
+ $key / $key: expr the identity a row is known by (the host's, else structural) / give the rows a block yields that identity
807
+ (a, b) / rel distinct { … } a tuple: the elements, one level flat (a value and a receiver) / collect distinct (0.20)
808
+ obj { title } one object → one record (or absent); a collection → a list; a scalar → an error (0.20)
727
809
  ${source} <collect|exists|none|count|first|single> { … } whole-query consumer
728
810
  ```
729
811
 
@@ -836,9 +918,12 @@ than approximate it. The conformance suite verifies this.
836
918
 
837
919
  The engine never touches host objects directly; it asks a `DataContext` to
838
920
  resolve named roots, read properties/relations, coerce results to rows, and
839
- compute identity (and, optionally, to supply a `rootObject()` — the root
921
+ optionally to name a row's identity (`identityOf` — `$key`; the default is the
922
+ row's structural value), to say which of its objects are collections rather
923
+ than one row (`isSingle`; by default a non-iterable object is one row, so a
924
+ block over it is one record), and to supply a `rootObject()` — the root
840
925
  scope's row, what `$it` is at the root and `^$it` from a top-level row; without
841
- one the root row is absent). Implement it to query an ORM graph, a remote API,
926
+ one the root row is absent. Implement it to query an ORM graph, a remote API,
842
927
  or lazily loaded relations — the query *semantics* stay in OQX. Name resolution is simple
843
928
  for a context: a bare `field`, a `.field` segment, and a `^field` outer
844
929
  reference each become one `get(row, key)` against exactly the row of the scope
@@ -851,7 +936,7 @@ const graph = {
851
936
  root: (name) => name === "tree" ? [nodes.get(1)] : undefined,
852
937
  get: (row, key) => key === "children" ? row.childIds.map(id => nodes.get(id)) : row[key],
853
938
  toRows: (v) => v == null ? [] : Array.isArray(v) ? v : [v],
854
- identity: (row) => row.id, // for follow dedup
939
+ identityOf: (row) => row.id, // `$key`: for follow dedup, distinct, `is` (optional; default: structural)
855
940
  };
856
941
  run(parse("id, depth: $depth from tree follow children"), { context: graph });
857
942
  ```
@@ -884,7 +969,7 @@ const ctx = {
884
969
  return builtins.callMethod(name, recv, args);
885
970
  },
886
971
  };
887
- run(parse("id from tree where age(born) > 18 && title.slug() == 'x'"), { context: ctx });
972
+ run(parse("id from tree where age(born) > 18 and title.slug() == 'x'"), { context: ctx });
888
973
  ```
889
974
 
890
975
  The simplest route is to `extends DefaultContext` and `super.callFunction(...)`
@@ -910,7 +995,7 @@ import { parse, PlannedEngine } from "@omgbase/oqx";
910
995
  import { SqliteTable } from "@omgbase/oqx/sqlite";
911
996
 
912
997
  const planner = new SqliteTable(db, "emp", { columns: ["id", "name", "dept", "level"] });
913
- new PlannedEngine(planner).run(parse('name from emp where dept == "eng" && level >= 5'), []);
998
+ new PlannedEngine(planner).run(parse('name from emp where dept == "eng" and level >= 5'), []);
914
999
  // → `dept`/`level` pushed to SQL; anything untranslatable finishes in-memory
915
1000
  ```
916
1001
 
@@ -941,7 +1026,7 @@ results and on errors.
941
1026
 
942
1027
  **What is optimized**
943
1028
 
944
- - **Correlated equality → hash probe.** A top-level `&&` conjunct of the block's
1029
+ - **Correlated equality → hash probe.** A top-level `and` conjunct of the block's
945
1030
  `where` of the form `local == outer` (either side) — `local` a bare identifier
946
1031
  or member chain on the block's row (`customer_id`, `meta.id`, `$it`),
947
1032
  `outer` anything that reads nothing from that row (`^customer_id`, `^^x.id`,
@@ -963,7 +1048,7 @@ results and on errors.
963
1048
  by`) are answered from the bucket's size after the bound without entering a
964
1049
  row.
965
1050
 
966
- **The sound rule.** `&&` is strictly left to right and short-circuiting (§13),
1051
+ **The sound rule.** `and` is strictly left to right and short-circuiting (§13),
967
1052
  so a probe may skip a row only if everything the scan would have evaluated for
968
1053
  it could neither raise nor bind: an equality is hoisted only when **every
969
1054
  conjunct to its left is raise-free** — no function or method call, no `single`,
@@ -973,7 +1058,7 @@ too. A conjunct that could raise *right* of the equality is simply evaluated
973
1058
  over the bucket, where the scan would have evaluated it on the same rows. A
974
1059
  block whose `where` lifts anywhere is never probed (a lift could change what
975
1060
  the outer side reads between rows). Otherwise the block scans as before, so
976
- `where nope(x) && id == ^id` still raises `unknown function`.
1061
+ `where nope(x) and id == ^id` still raises `unknown function`.
977
1062
 
978
1063
  Property reads are treated as total (§23: evaluation is otherwise total). A
979
1064
  `DataContext.get` that throws is caught where the engine relies on reads it
@@ -1082,7 +1167,7 @@ adapter lives on the `@omgbase/oqx/sqlite` subpath.
1082
1167
  (the optimizer rules for nested blocks, default `DEFAULT_RULES`; `[]` is the
1083
1168
  naive scan) and `trace` (a `(event: TraceEvent) => void` sink for index /
1084
1169
  probe / memo / cardinality / fallback events). See [Performance](#performance-relational-patterns).
1085
- - `DataContext` — the tier-2 interface: `root`, `get`, `toRows`, `identity`,
1170
+ - `DataContext` — the tier-2 interface: `root`, `get`, `toRows`, `identityOf`, `isSingle`,
1086
1171
  plus optional `callFunction` / `callMethod` (above), an optional
1087
1172
  `indexFor(collection, path)` returning a `RowIndex` for a pre-built equality
1088
1173
  index (`lookup` → positions; optionally `lookupRows` → rows, probed without
@@ -1095,7 +1180,7 @@ adapter lives on the `@omgbase/oqx/sqlite` subpath.
1095
1180
  "native")`; `BUILTIN_METHODS.matches` is always the baseline.
1096
1181
  - `CallResult` — `{ handled: boolean; value?: unknown }`, returned by those hooks.
1097
1182
  - `DefaultContext` — `new DefaultContext(roots?, options?)`; plain-object
1098
- access, `.id` identity, and the builtin function/method tables. `options`:
1183
+ access, structural identity (`$key` is the row itself unless projected), and the builtin function/method tables. `options`:
1099
1184
  `{ regexDialect?: RegexDialect }` (see the regex baseline, §4).
1100
1185
  - `compileRegex(pattern, flags?, dialect?)` — the `matches()` compiler: a
1101
1186
  `RegExp`, or an `OqxError` for a bad pattern/flag. `RegexDialect` /
@@ -1142,7 +1227,7 @@ adapter lives on the `@omgbase/oqx/sqlite` subpath.
1142
1227
  import { parse, run, IndexedCollection, PlannedEngine } from "@omgbase/oqx";
1143
1228
  const planner = new IndexedCollection("people", people, ["city", "title"]);
1144
1229
  const engine = new PlannedEngine(planner, planner.context());
1145
- run(parse('name from people where city == "NYC" && age > 30'), { engine });
1230
+ run(parse('name from people where city == "NYC" and age > 30'), { engine });
1146
1231
  // city probe from the index; `age > 30` finished in-memory over the candidates
1147
1232
  ```
1148
1233
 
package/dist/ast.d.ts CHANGED
@@ -76,6 +76,10 @@ export type Expr = {
76
76
  lo: Expr | null;
77
77
  hi: Expr | null;
78
78
  exclusiveEnd: boolean;
79
+ } | {
80
+ kind: "tuple";
81
+ span: Span;
82
+ items: Expr[];
79
83
  } | OpNode;
80
84
  /** One `order by` term. */
81
85
  export interface OrderSpec {
@@ -123,16 +127,13 @@ export interface OpNode {
123
127
  * destination block — a select-position directive (`collect`/`first`/`single`) re-evaluated
124
128
  * per frontier row, inside which `^` is that row. Discriminate on `kind === "op"`. */
125
129
  export type FollowDestination = Expr | OpNode;
126
- /** The recursive `follow` clause. */
130
+ /** The recursive `follow` clause (since 0.20 just the destinations: a
131
+ * destination's `where`, `frontier` and `depth` live in its own block). */
127
132
  export interface Follow {
128
133
  kind: "follow";
129
134
  span: Span;
130
135
  destinations: FollowDestination[];
131
136
  distinct: boolean;
132
- where: Expr | null;
133
- frontier: Expr | null;
134
- depth: number | null;
135
- by: Expr | null;
136
137
  }
137
138
  /** A nested (sub)query body — the `{ … }` of a directive. */
138
139
  export interface Subquery {
@@ -143,6 +144,16 @@ export interface Subquery {
143
144
  select: SelectItem[];
144
145
  orderBy: OrderSpec[] | null;
145
146
  follow: Follow | null;
147
+ /** `frontier P` / `depth n` (since 0.20). In a `follow` destination block
148
+ * `frontier` marks the occurrences reached through this destination for
149
+ * which `P` holds (not expanded; `P` read one level out, under the walk's
150
+ * enclosing scope), and `depth n` makes the destination expand a frontier
151
+ * row only while that row's `$depth < n` (1..8; `null` = the hard cap 8).
152
+ * In any other block `frontier` is legal only with a `follow` and marks the
153
+ * walk's SEEDS, read in the seed's scope like `where` (as on `Query`);
154
+ * `depth` is destination-only. Both `null` when absent. */
155
+ frontier: Expr | null;
156
+ depth: number | null;
146
157
  /** `values` — scalar projection mode: the (single) projected expression is the
147
158
  * row's result itself rather than being wrapped in a `{ name: value }` record,
148
159
  * so `name values` yields `["Bob", …]` and `$it values` yields the rows. */
@@ -186,6 +197,11 @@ export interface Query {
186
197
  orderBy: OrderSpec[] | null;
187
198
  consumer: Consumer;
188
199
  follow: Follow | null;
200
+ /** `frontier P` (since 0.20) — legal only when the body has a `follow`: a
201
+ * seed for which `P` holds (read in the seed's own scope, `^` the enclosing
202
+ * scope, like `where`) is a frontier (`$stop == "frontier"`, not expanded).
203
+ * `null` without one. */
204
+ frontier: Expr | null;
189
205
  /** `distinct` — dedup the result rows by their projected value (see OpNode). */
190
206
  distinct: boolean;
191
207
  /** `values` — scalar projection mode (see Subquery). */
package/dist/ast.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../src/ast.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../src/ast.ts"],"names":[],"mappings":"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"}
package/dist/ast.js CHANGED
@@ -12,7 +12,7 @@
12
12
  // empty span `[0, 0]` (see `build.ts`).
13
13
  /** The expression kinds (`Expr["kind"]`), for `isExpr`. */
14
14
  const EXPR_KINDS = new Set([
15
- "lit", "ident", "outer", "binding", "member", "call", "unary", "required", "binary", "logical", "in", "range",
15
+ "lit", "ident", "outer", "binding", "member", "call", "unary", "required", "binary", "logical", "in", "range", "tuple",
16
16
  ]);
17
17
  /** Whether a node is a scalar `Expr` (an `op` in expression position is not: it
18
18
  * is an expression only by position, see AST.md §1). */
package/dist/ast.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ast.js","sourceRoot":"","sources":["../src/ast.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,8EAA8E;AAC9E,gFAAgF;AAChF,+EAA+E;AAC/E,2EAA2E;AAC3E,gFAAgF;AAChF,wDAAwD;AACxD,EAAE;AACF,iFAAiF;AACjF,gFAAgF;AAChF,4EAA4E;AAC5E,wCAAwC;AAqKxC,2DAA2D;AAC3D,MAAM,UAAU,GAAwB,IAAI,GAAG,CAAC;IAC9C,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO;CAC9G,CAAC,CAAC;AAEH;wDACwD;AACxD,MAAM,UAAU,MAAM,CAAC,IAAa;IAClC,OAAO,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC"}
1
+ {"version":3,"file":"ast.js","sourceRoot":"","sources":["../src/ast.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,8EAA8E;AAC9E,gFAAgF;AAChF,+EAA+E;AAC/E,2EAA2E;AAC3E,gFAAgF;AAChF,wDAAwD;AACxD,EAAE;AACF,iFAAiF;AACjF,gFAAgF;AAChF,4EAA4E;AAC5E,wCAAwC;AAsLxC,2DAA2D;AAC3D,MAAM,UAAU,GAAwB,IAAI,GAAG,CAAC;IAC9C,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO;CACvH,CAAC,CAAC;AAEH;wDACwD;AACxD,MAAM,UAAU,MAAM,CAAC,IAAa;IAClC,OAAO,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC"}
package/dist/build.d.ts CHANGED
@@ -16,6 +16,8 @@ export declare const binary: (op: BinaryOp, left: Expr, right: Expr) => Expr;
16
16
  export declare const logical: (op: LogicalOp, left: Expr, right: Expr) => Expr;
17
17
  export declare const inOp: (left: Expr, right: Expr) => Expr;
18
18
  export declare const range: (lo: Expr | null, hi: Expr | null, exclusiveEnd?: boolean) => Expr;
19
+ /** `(e1, e2, …)` — a tuple of two or more expressions (SEMANTICS §3b). */
20
+ export declare const tuple: (items: Expr[]) => Expr;
19
21
  export declare const scalar: (expr: Expr) => Where;
20
22
  export declare const and: (parts: Where[]) => Where;
21
23
  export declare const or: (parts: Where[]) => Where;
@@ -30,7 +32,11 @@ export declare function op(receiver: Expr, consumer: Consumer, sub?: Subquery, o
30
32
  distinct?: boolean;
31
33
  countCmp?: CountCmp | null;
32
34
  }): OpNode;
33
- export declare function follow(destinations: FollowDestination[], opts?: Partial<Omit<Follow, "kind" | "span" | "destinations">>): Follow;
35
+ /** `follow [distinct] <destinations>`; a destination's `where`/`frontier`/`depth`
36
+ * belong to its block (`op(recv, "collect", subquery({ depth: 2 }))`). */
37
+ export declare function follow(destinations: FollowDestination[], opts?: {
38
+ distinct?: boolean;
39
+ }): Follow;
34
40
  /** A top-level query over `source`; every other clause defaults to empty/absent
35
41
  * and the consumer to `collect`. */
36
42
  export declare function query(source: Expr, parts?: Partial<Omit<Query, "kind" | "span" | "source">>): Query;
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"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"}