@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/dist/walk.js CHANGED
@@ -13,6 +13,8 @@ export const CHILDREN = {
13
13
  { key: "source", clause: "source" },
14
14
  { key: "from", clause: "from", depth: 1 },
15
15
  { key: "where", clause: "where", depth: 1 },
16
+ // The body's `frontier` (0.20) reads each seed in the row scope, like `where`.
17
+ { key: "frontier", clause: "follow.frontier", depth: 1 },
16
18
  { key: "follow", clause: "follow", depth: 1 },
17
19
  { key: "orderBy", clause: "orderBy", depth: 1 },
18
20
  { key: "limit", clause: "limit" },
@@ -22,18 +24,18 @@ export const CHILDREN = {
22
24
  { key: "select", clause: "select" },
23
25
  { key: "from", clause: "from" },
24
26
  { key: "where", clause: "where" },
27
+ // A destination block's `frontier` reads the occurrence under the walk's
28
+ // enclosing scope — one level OUT of the block's rows (SEMANTICS §20); any
29
+ // other block's reads its seeds in the row scope, like `where`
30
+ // (`childDepth` tells the two apart by the block's position).
31
+ { key: "frontier", clause: "follow.frontier", depth: -1 },
25
32
  { key: "follow", clause: "follow" },
26
33
  { key: "orderBy", clause: "orderBy" },
27
34
  { key: "limit", clause: "limit" },
28
35
  { key: "offset", clause: "offset" },
29
36
  ],
30
37
  op: [{ key: "receiver" }, { key: "sub", depth: 1 }],
31
- follow: [
32
- { key: "destinations", clause: "follow.destination" },
33
- { key: "where", clause: "follow.where", depth: 1 },
34
- { key: "frontier", clause: "follow.frontier" },
35
- { key: "by", clause: "follow.by" },
36
- ],
38
+ follow: [{ key: "destinations", clause: "follow.destination" }],
37
39
  order: [{ key: "expr" }],
38
40
  field: [{ key: "expr" }],
39
41
  collect: [{ key: "op" }],
@@ -53,10 +55,26 @@ export const CHILDREN = {
53
55
  logical: [{ key: "left" }, { key: "right" }],
54
56
  in: [{ key: "left" }, { key: "right" }],
55
57
  range: [{ key: "lo" }, { key: "hi" }],
58
+ tuple: [{ key: "items" }],
56
59
  };
57
60
  function slot(node, key) {
58
61
  return node[key] ?? null;
59
62
  }
63
+ /** A block is a follow destination block when its `op` is a direct destination
64
+ * of a `follow` node. `path` is the ancestors with the block itself last. */
65
+ function isDestinationBlock(path) {
66
+ const op = path[path.length - 2];
67
+ const owner = path[path.length - 3];
68
+ return op?.kind === "op" && owner?.kind === "follow";
69
+ }
70
+ /** How much deeper a child's scope is: the table's value, except a block's
71
+ * `frontier`, which is one level OUT only for a destination block (the walk's
72
+ * enclosing scope) and the row scope itself for a body with its own `follow`. */
73
+ function childDepth(node, child, path) {
74
+ if (node.kind === "subquery" && child.key === "frontier" && !isDestinationBlock(path))
75
+ return 0;
76
+ return child.depth ?? 0;
77
+ }
60
78
  /** Walk a tree depth-first in canonical source order. */
61
79
  export function visit(root, visitor) {
62
80
  const path = [];
@@ -70,7 +88,7 @@ export function visit(root, visitor) {
70
88
  if (v === null)
71
89
  continue;
72
90
  const c = child.clause ?? clause;
73
- const d = depth + (child.depth ?? 0);
91
+ const d = depth + childDepth(node, child, path);
74
92
  if (Array.isArray(v))
75
93
  for (const x of v)
76
94
  go(x, c, d);
@@ -98,7 +116,7 @@ export function transform(root, f) {
98
116
  if (v === null)
99
117
  continue;
100
118
  const c = child.clause ?? clause;
101
- const d = depth + (child.depth ?? 0);
119
+ const d = depth + childDepth(node, child, path);
102
120
  let next;
103
121
  if (Array.isArray(v)) {
104
122
  let changed = false;
package/dist/walk.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"walk.js","sourceRoot":"","sources":["../src/walk.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"walk.js","sourceRoot":"","sources":["../src/walk.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omgbase/oqx",
3
- "version": "0.18.0",
3
+ "version": "0.20.0",
4
4
  "description": "OQX (omgbase Query eXpressions): a composable query language and engine for JavaScript collections",
5
5
  "keywords": [
6
6
  "query",
package/src/ast.ts CHANGED
@@ -53,6 +53,11 @@ export type Expr =
53
53
  // (`..5` / `5..`); `exclusiveEnd` distinguishes `1...5` from `1..5`. Evaluates
54
54
  // to a runtime range value (see semantics.makeRange); primarily the RHS of `in`.
55
55
  | { kind: "range"; span: Span; lo: Expr | null; hi: Expr | null; exclusiveEnd: boolean }
56
+ // A tuple `(e1, e2, …)` (since 0.20): two or more expressions whose values
57
+ // concatenate with one level of flattening (SEMANTICS §3b) — a value and a
58
+ // receiver (`(a, b) { … }`, `follow (a, b) { depth 2 }`). One expression in
59
+ // parentheses is grouping and leaves no node.
60
+ | { kind: "tuple"; span: Span; items: Expr[] }
56
61
  // A value-position directive (since 0.17): `recv first { … }.pay`, and what a
57
62
  // bracket lookup `x[…]` desugars to. `isExpr` is false for it — an op is an
58
63
  // expression only by position; discriminate on `kind === "op"`.
@@ -104,16 +109,13 @@ export interface OpNode {
104
109
  * per frontier row, inside which `^` is that row. Discriminate on `kind === "op"`. */
105
110
  export type FollowDestination = Expr | OpNode;
106
111
 
107
- /** The recursive `follow` clause. */
112
+ /** The recursive `follow` clause (since 0.20 just the destinations: a
113
+ * destination's `where`, `frontier` and `depth` live in its own block). */
108
114
  export interface Follow {
109
115
  kind: "follow";
110
116
  span: Span;
111
117
  destinations: FollowDestination[]; // ≥ 1, in source order; the walk is their union
112
118
  distinct: boolean;
113
- where: Expr | null; // successor predicate: which successors keep participating
114
- frontier: Expr | null; // boundary predicate: cut a relation that could continue
115
- depth: number | null; // 1..8 cap; null = the hard cap
116
- by: Expr | null; // identity expression for cycle detection / dedup
117
119
  }
118
120
 
119
121
  /** A nested (sub)query body — the `{ … }` of a directive. */
@@ -125,6 +127,16 @@ export interface Subquery {
125
127
  select: SelectItem[];
126
128
  orderBy: OrderSpec[] | null;
127
129
  follow: Follow | null;
130
+ /** `frontier P` / `depth n` (since 0.20). In a `follow` destination block
131
+ * `frontier` marks the occurrences reached through this destination for
132
+ * which `P` holds (not expanded; `P` read one level out, under the walk's
133
+ * enclosing scope), and `depth n` makes the destination expand a frontier
134
+ * row only while that row's `$depth < n` (1..8; `null` = the hard cap 8).
135
+ * In any other block `frontier` is legal only with a `follow` and marks the
136
+ * walk's SEEDS, read in the seed's scope like `where` (as on `Query`);
137
+ * `depth` is destination-only. Both `null` when absent. */
138
+ frontier: Expr | null;
139
+ depth: number | null;
128
140
  /** `values` — scalar projection mode: the (single) projected expression is the
129
141
  * row's result itself rather than being wrapped in a `{ name: value }` record,
130
142
  * so `name values` yields `["Bob", …]` and `$it values` yields the rows. */
@@ -159,6 +171,11 @@ export interface Query {
159
171
  orderBy: OrderSpec[] | null;
160
172
  consumer: Consumer;
161
173
  follow: Follow | null;
174
+ /** `frontier P` (since 0.20) — legal only when the body has a `follow`: a
175
+ * seed for which `P` holds (read in the seed's own scope, `^` the enclosing
176
+ * scope, like `where`) is a frontier (`$stop == "frontier"`, not expanded).
177
+ * `null` without one. */
178
+ frontier: Expr | null;
162
179
  /** `distinct` — dedup the result rows by their projected value (see OpNode). */
163
180
  distinct: boolean;
164
181
  /** `values` — scalar projection mode (see Subquery). */
@@ -176,7 +193,7 @@ export type AstKind = AstNode["kind"];
176
193
 
177
194
  /** The expression kinds (`Expr["kind"]`), for `isExpr`. */
178
195
  const EXPR_KINDS: ReadonlySet<string> = new Set([
179
- "lit", "ident", "outer", "binding", "member", "call", "unary", "required", "binary", "logical", "in", "range",
196
+ "lit", "ident", "outer", "binding", "member", "call", "unary", "required", "binary", "logical", "in", "range", "tuple",
180
197
  ]);
181
198
 
182
199
  /** Whether a node is a scalar `Expr` (an `op` in expression position is not: it
package/src/build.ts CHANGED
@@ -26,6 +26,8 @@ export const binary = (op: BinaryOp, left: Expr, right: Expr): Expr => ({ kind:
26
26
  export const logical = (op: LogicalOp, left: Expr, right: Expr): Expr => ({ kind: "logical", span: span(), op, left, right });
27
27
  export const inOp = (left: Expr, right: Expr): Expr => ({ kind: "in", span: span(), left, right });
28
28
  export const range = (lo: Expr | null, hi: Expr | null, exclusiveEnd = false): Expr => ({ kind: "range", span: span(), lo, hi, exclusiveEnd });
29
+ /** `(e1, e2, …)` — a tuple of two or more expressions (SEMANTICS §3b). */
30
+ export const tuple = (items: Expr[]): Expr => ({ kind: "tuple", span: span(), items });
29
31
 
30
32
  export const scalar = (expr: Expr): Where => ({ kind: "scalar", span: span(), expr });
31
33
  export const and = (parts: Where[]): Where => ({ kind: "and", span: span(), parts });
@@ -40,7 +42,7 @@ export const order = (expr: Expr, desc = false): OrderSpec => ({ kind: "order",
40
42
  export function subquery(parts: Partial<Omit<Subquery, "kind" | "span">> = {}): Subquery {
41
43
  return {
42
44
  kind: "subquery", span: span(),
43
- from: [], where: null, select: [], orderBy: null, follow: null, values: false, limit: null, offset: null,
45
+ from: [], where: null, select: [], orderBy: null, follow: null, frontier: null, depth: null, values: false, limit: null, offset: null,
44
46
  ...parts,
45
47
  };
46
48
  }
@@ -53,11 +55,10 @@ export function op(
53
55
  return { kind: "op", span: span(), receiver, op: consumer, sub, countCmp: opts.countCmp ?? null, distinct: opts.distinct ?? false };
54
56
  }
55
57
 
56
- export function follow(
57
- destinations: FollowDestination[],
58
- opts: Partial<Omit<Follow, "kind" | "span" | "destinations">> = {},
59
- ): Follow {
60
- return { kind: "follow", span: span(), destinations, distinct: false, where: null, frontier: null, depth: null, by: null, ...opts };
58
+ /** `follow [distinct] <destinations>`; a destination's `where`/`frontier`/`depth`
59
+ * belong to its block (`op(recv, "collect", subquery({ depth: 2 }))`). */
60
+ export function follow(destinations: FollowDestination[], opts: { distinct?: boolean } = {}): Follow {
61
+ return { kind: "follow", span: span(), destinations, distinct: opts.distinct ?? false };
61
62
  }
62
63
 
63
64
  /** A top-level query over `source`; every other clause defaults to empty/absent
@@ -65,7 +66,7 @@ export function follow(
65
66
  export function query(source: Expr, parts: Partial<Omit<Query, "kind" | "span" | "source">> = {}): Query {
66
67
  return {
67
68
  kind: "query", span: span(), source,
68
- from: [], where: null, select: [], orderBy: null, consumer: "collect", follow: null,
69
+ from: [], where: null, select: [], orderBy: null, consumer: "collect", follow: null, frontier: null,
69
70
  distinct: false, values: false, limit: null, offset: null,
70
71
  ...parts,
71
72
  };
package/src/context.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  // The tier-2 seam: a DataContext binds OQX's query semantics to a concrete data
2
2
  // model. The engine never touches host objects directly — it asks the context to
3
3
  // resolve named roots, read properties/relations, coerce a relation result into
4
- // rows, compute identity (for `follow` dedup), and optionally supply custom
5
- // scalar functions/methods. This is what lets the same query semantics run over
4
+ // rows (and say which objects are one row rather than a collection), name a
5
+ // row's identity (`$key`: `follow` dedup, `distinct`, `is`), and optionally
6
+ // supply custom scalar functions/methods. This is what lets the same query semantics run over
6
7
  // plain objects, a lazy ORM graph, or a remote API without changing the engine.
7
8
  //
8
9
  // (Performant execution over a real store is the tier-3 seam — see planner.ts —
@@ -45,6 +46,13 @@ export interface DataContext {
45
46
  get(row: unknown, key: string): unknown;
46
47
  /** Coerce a relation/source value into rows (may be lazy). */
47
48
  toRows(value: unknown): Iterable<unknown>;
49
+ /** Optional: whether an object this context handed out in row position is
50
+ * ONE row — a record, not a collection (SEMANTICS §3, since 0.20) — so a block
51
+ * over it yields one result rather than a one-element list (`doc { title }`
52
+ * is a record; `docs { title }` a list). Asked only for non-array objects;
53
+ * absent, any non-iterable object is one row and any iterable (a `Set`, a
54
+ * lazy handle with `Symbol.iterator`) is a collection. */
55
+ isSingle?(value: unknown): boolean;
48
56
  /** Optional: a value this context handed out as a stand-in for a collection
49
57
  * it has not read yet (a lazy table handle), resolved to what it stands for.
50
58
  * The engine calls it on every value it is about to observe AS A VALUE — an
@@ -57,8 +65,15 @@ export interface DataContext {
57
65
  * seen by the language. Absent = identity; a context whose handle already
58
66
  * behaves as the collection (a `Proxy` over an array) needs none. */
59
67
  materialize?(value: unknown): unknown;
60
- /** Identity of a row for `follow` cycle detection / dedup. */
61
- identity(row: unknown): unknown;
68
+ /** Optional: the identity a row is known by — `$key` (SEMANTICS §16, since
69
+ * 0.20): what `follow` cycle detection, the per-step union, `follow distinct`,
70
+ * `distinct` over unprojected rows and `is` compare, and what reading `$key`
71
+ * on the row returns. Absent, a row's identity is its structural value (an
72
+ * entry's is its key either way). A store-backed context answers its row id. */
73
+ identityOf?(row: unknown): unknown;
74
+ /** @deprecated The pre-0.20 spelling of `identityOf`; read when `identityOf`
75
+ * is absent. Removed in the next minor. */
76
+ identity?(row: unknown): unknown;
62
77
  /** Optional custom free function; return `{ handled: false }` to defer. */
63
78
  callFunction?(name: string, args: unknown[]): CallResult;
64
79
  /** Optional custom method; return `{ handled: false }` to defer. */
@@ -92,8 +107,9 @@ export interface DefaultContextOptions {
92
107
  /** The default context: ordinary JavaScript objects. Named roots come from a
93
108
  * plain `{ name: collection }` map, which is also the root object (`^$it` from
94
109
  * a top-level row); properties are OWN keys only (an array exposes only its
95
- * integer indices, a primitive has none); identity is `.id` when present, else
96
- * the row itself (the engine keys it structurally). */
110
+ * integer indices, a primitive has none); it names no identity of its own, so a
111
+ * row's `$key` is its structural value (SEMANTICS §16) unless a query projects
112
+ * one (`$key: id`). */
97
113
  export class DefaultContext implements DataContext {
98
114
  private roots: Record<string, unknown>;
99
115
  readonly regexDialect: RegexDialect;
@@ -121,11 +137,6 @@ export class DefaultContext implements DataContext {
121
137
  return coerceCollection(value);
122
138
  }
123
139
 
124
- identity(row: unknown): unknown {
125
- if (row != null && typeof row === "object" && "id" in row) return (row as Record<string, unknown>).id;
126
- return row;
127
- }
128
-
129
140
  callFunction(name: string, args: unknown[]): CallResult {
130
141
  const fn = Object.hasOwn(BUILTIN_FUNCTIONS, name) ? BUILTIN_FUNCTIONS[name] : undefined;
131
142
  return fn ? { handled: true, value: fn(args) } : { handled: false };