@rindle/client 0.2.0 → 0.3.1

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.
package/dist/view.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ColType, FlatChange, ResultType, WireSchema } from "./types.ts";
1
+ import type { ColType, FlatChange, QueryId, ResultType, WireSchema } from "./types.ts";
2
2
  /** Per-level column types (parallel to the WireSchema), used to JSON.parse json columns on
3
3
  * projection. Built by the Store from the typed schema; absent ⇒ no parsing (bare values). */
4
4
  export interface ViewTypes {
@@ -9,6 +9,15 @@ export interface ViewTypes {
9
9
  export interface ArrayView<R> {
10
10
  /** The current materialized result (reference-stable where data is unchanged). */
11
11
  readonly data: readonly R[];
12
+ /** The engine query id the Store assigned this view (1:1 with the view). The same `qid` the raw
13
+ * change stream ({@link Store.subscribeChanges}) tags each frame with, so a consumer can
14
+ * correlate this query with its `ChangeEvent`s (e.g. to bind a narrator) straight off
15
+ * `materialize(query).qid` — no separate handle needed. */
16
+ readonly qid: QueryId;
17
+ /** The query's view `WireSchema` (the position→name source for {@link resolveChange}), captured
18
+ * from its `hello` frame. `null` while PENDING — a remote backend's `hello` arrives async; an
19
+ * in-process backend (wasm/replica) populates it synchronously during `materialize`. */
20
+ readonly schema: WireSchema | null;
12
21
  /** The query's SERVER-CHANNEL state (`unknown` while loading, `complete` once server-authoritative;
13
22
  * the `error` variant is reserved and currently unproduced). A pending optimistic mutation no
14
23
  * longer moves this — it is a separate axis (FOLDED-MUTATIONS-DESIGN §7). `complete` for backends
@@ -26,6 +35,10 @@ export interface ArrayView<R> {
26
35
  export interface SingularArrayView<R> {
27
36
  /** The single current row, or `null` when the query matches nothing. */
28
37
  readonly data: R | null;
38
+ /** The engine query id — see {@link ArrayView.qid}. */
39
+ readonly qid: QueryId;
40
+ /** The query's view `WireSchema` — see {@link ArrayView.schema}. */
41
+ readonly schema: WireSchema | null;
29
42
  /** The query's lifecycle state — see {@link ArrayView.resultType}. */
30
43
  readonly resultType: ResultType;
31
44
  /** Subscribe; fires immediately with the current row, then after each applied batch (and after
@@ -40,12 +53,15 @@ export declare class SingularView<R> implements SingularArrayView<R> {
40
53
  private readonly inner;
41
54
  constructor(inner: ArrayView<R>);
42
55
  get data(): R | null;
56
+ get qid(): QueryId;
57
+ get schema(): WireSchema | null;
43
58
  get resultType(): ResultType;
44
59
  subscribe(listener: (data: R | null) => void): () => void;
45
60
  destroy(): void;
46
61
  }
47
62
  export declare class FlatArrayView<R = unknown> implements ArrayView<R> {
48
- private schema;
63
+ private readonly _qid;
64
+ private _schema;
49
65
  private types?;
50
66
  private seeded;
51
67
  private top;
@@ -53,7 +69,9 @@ export declare class FlatArrayView<R = unknown> implements ArrayView<R> {
53
69
  private cached;
54
70
  private rt;
55
71
  private readonly listeners;
56
- constructor(schema?: WireSchema, types?: ViewTypes);
72
+ constructor(schema?: WireSchema, types?: ViewTypes, qid?: QueryId);
73
+ get qid(): QueryId;
74
+ get schema(): WireSchema | null;
57
75
  get resultType(): ResultType;
58
76
  /** Set the query's lifecycle state (the Store routes the backend's per-query signal here).
59
77
  * Notifies subscribers on a change so a status-bound listener (React `useQueryStatus`) re-reads,
@@ -72,14 +90,34 @@ export declare class FlatArrayView<R = unknown> implements ArrayView<R> {
72
90
  seed(rows: readonly R[]): void;
73
91
  /** Apply a batch (the hydrate snapshot or one transaction's events) in order, then
74
92
  * notify subscribers once. Order is significant (FLAT-CHANGES-DESIGN.md §5.4). A no-op
75
- * while pending (changes never precede the `hello` that resets the schema). */
76
- applyChanges(events: FlatChange[]): void;
93
+ * while pending (changes never precede the `hello` that resets the schema).
94
+ *
95
+ * `enrichRemoves` ⇒ before a removed node is dropped, reconstruct its full subtree and attach it
96
+ * to the `remove` op's `node` (in place, so the same event object the Store fans out to its
97
+ * change subscribers carries it). Off by default — paid only when a consumer asked for it, and
98
+ * only on a real eviction (an rc-decrement that keeps the row leaves `node` absent).
99
+ *
100
+ * `deferNotify` ⇒ fold but do NOT notify; the caller is responsible for calling {@link flush}
101
+ * later. The Store uses this to fold every view in one commit before notifying any subscriber
102
+ * (cross-view-atomic notification — `Store.onCommitBoundary`); standalone use leaves it off, so
103
+ * a bare view still fires its subscribers after each applied batch.
104
+ *
105
+ * Returns whether the batch changed the view (so a deferring caller knows it must be flushed). */
106
+ applyChanges(events: FlatChange[], enrichRemoves?: boolean, deferNotify?: boolean): boolean;
107
+ /** Notify subscribers with the current data. The deferred half of {@link applyChanges} (when
108
+ * `deferNotify` was set): the Store calls this at the commit-notify barrier — after every view
109
+ * touched by the same commit has folded — so a subscriber that re-reads a sibling view inside
110
+ * its callback observes post-commit data, never a torn mid-commit state. */
111
+ flush(): void;
77
112
  get data(): readonly R[];
78
113
  subscribe(listener: (data: readonly R[]) => void): () => void;
79
114
  destroy(): void;
80
115
  private applyAt;
81
116
  private applyOp;
82
117
  private applyAdd;
118
+ /** Drop one path to `row`. Returns the evicted {@link Node} (its full subtree intact) when the
119
+ * last path went away — `null` when another path still holds it (rc decremented, nothing left
120
+ * the result). */
83
121
  private applyRemove;
84
122
  private applyEdit;
85
123
  private project;
@@ -1 +1 @@
1
- {"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../src/view.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../src/view.ts"],"names":[],"mappings":"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"}
package/dist/view.js CHANGED
@@ -18,6 +18,12 @@ export class SingularView {
18
18
  get data() {
19
19
  return this.inner.data[0] ?? null;
20
20
  }
21
+ get qid() {
22
+ return this.inner.qid;
23
+ }
24
+ get schema() {
25
+ return this.inner.schema;
26
+ }
21
27
  get resultType() {
22
28
  return this.inner.resultType;
23
29
  }
@@ -67,14 +73,35 @@ function buildNode(wnode, schema) {
67
73
  function cloneNode(n) {
68
74
  return { row: n.row.slice(), rc: n.rc, rels: n.rels.map((r) => r.map(cloneNode)), out: null };
69
75
  }
76
+ /** Reconstruct a positional {@link WireNode} (row + its populated child slots) from a maintained
77
+ * {@link Node} — the inverse of {@link buildNode}. Used to attach a removed subtree to a `remove`
78
+ * op so a change consumer (a narrator) can resolve its nested subs, which a bare positional remove
79
+ * (just the leaving row) cannot carry. Only in-view (`child !== null`), non-empty slots are emitted,
80
+ * matching how an `add` node ships only populated relationships. */
81
+ function toWireNode(node, schema) {
82
+ const rels = [];
83
+ for (const rel of schema.relationships) {
84
+ if (rel.child === null)
85
+ continue;
86
+ const childList = node.rels[rel.slot] ?? [];
87
+ if (childList.length === 0)
88
+ continue;
89
+ rels.push({ rel: rel.slot, children: childList.map((c) => toWireNode(c, rel.child)) });
90
+ }
91
+ return { row: node.row, rels };
92
+ }
70
93
  function rowsEqual(a, b) {
71
94
  return a.length === b.length && a.every((v, i) => Object.is(v, b[i]));
72
95
  }
73
96
  const EMPTY = Object.freeze([]);
74
97
  export class FlatArrayView {
98
+ // The engine query id (Store-assigned, 1:1 with this view), exposed read-only via {@link qid}.
99
+ // `0` ⇒ unbound (a bare view never registered with a Store); the Store passes it at construction.
100
+ _qid;
75
101
  // `null` ⇒ PENDING (no schema yet): a remote backend's `hello` arrives async, so the view
76
102
  // exists (and reads as `[]`) before its schema lands. Set by `reset` (first hello / re-hydrate).
77
- schema;
103
+ // Exposed read-only via the {@link schema} getter (the position→name source for `resolveChange`).
104
+ _schema;
78
105
  types;
79
106
  // SSR first-paint seed (SSR-DESIGN.md §6): pre-projected rows installed by `seed`, returned by
80
107
  // `data` WHILE pending (no live schema yet). Cleared on `reset` — the first live `hello` —
@@ -88,9 +115,16 @@ export class FlatArrayView {
88
115
  // (the optimistic backend: `unknown` until hydrated, etc.).
89
116
  rt = "complete";
90
117
  listeners = new Set();
91
- constructor(schema, types) {
92
- this.schema = schema ?? null;
118
+ constructor(schema, types, qid = 0) {
119
+ this._schema = schema ?? null;
93
120
  this.types = types;
121
+ this._qid = qid;
122
+ }
123
+ get qid() {
124
+ return this._qid;
125
+ }
126
+ get schema() {
127
+ return this._schema;
94
128
  }
95
129
  get resultType() {
96
130
  return this.rt;
@@ -110,7 +144,7 @@ export class FlatArrayView {
110
144
  * the caller's view reference and its subscribers survive a re-subscribe. Does NOT notify —
111
145
  * the snapshot that follows (`applyChanges`) does, avoiding an empty-then-filled flicker. */
112
146
  reset(schema, types) {
113
- this.schema = schema;
147
+ this._schema = schema;
114
148
  this.types = types;
115
149
  this.seeded = null; // live data takes over; the seed was first-paint only
116
150
  this.top = [];
@@ -127,24 +161,45 @@ export class FlatArrayView {
127
161
  }
128
162
  /** Apply a batch (the hydrate snapshot or one transaction's events) in order, then
129
163
  * notify subscribers once. Order is significant (FLAT-CHANGES-DESIGN.md §5.4). A no-op
130
- * while pending (changes never precede the `hello` that resets the schema). */
131
- applyChanges(events) {
132
- if (this.schema === null)
133
- return;
164
+ * while pending (changes never precede the `hello` that resets the schema).
165
+ *
166
+ * `enrichRemoves` before a removed node is dropped, reconstruct its full subtree and attach it
167
+ * to the `remove` op's `node` (in place, so the same event object the Store fans out to its
168
+ * change subscribers carries it). Off by default — paid only when a consumer asked for it, and
169
+ * only on a real eviction (an rc-decrement that keeps the row leaves `node` absent).
170
+ *
171
+ * `deferNotify` ⇒ fold but do NOT notify; the caller is responsible for calling {@link flush}
172
+ * later. The Store uses this to fold every view in one commit before notifying any subscriber
173
+ * (cross-view-atomic notification — `Store.onCommitBoundary`); standalone use leaves it off, so
174
+ * a bare view still fires its subscribers after each applied batch.
175
+ *
176
+ * Returns whether the batch changed the view (so a deferring caller knows it must be flushed). */
177
+ applyChanges(events, enrichRemoves = false, deferNotify = false) {
178
+ if (this._schema === null)
179
+ return false;
134
180
  let changed = false;
135
181
  for (const e of events)
136
- changed = this.applyAt(this.top, this.schema, e.path, e.op, 0) || changed;
182
+ changed = this.applyAt(this.top, this._schema, e.path, e.op, 0, enrichRemoves) || changed;
137
183
  if (!changed)
138
- return;
184
+ return false;
139
185
  this.dirty = true;
186
+ if (!deferNotify)
187
+ this.notify();
188
+ return true;
189
+ }
190
+ /** Notify subscribers with the current data. The deferred half of {@link applyChanges} (when
191
+ * `deferNotify` was set): the Store calls this at the commit-notify barrier — after every view
192
+ * touched by the same commit has folded — so a subscriber that re-reads a sibling view inside
193
+ * its callback observes post-commit data, never a torn mid-commit state. */
194
+ flush() {
140
195
  this.notify();
141
196
  }
142
197
  get data() {
143
- if (this.schema === null)
198
+ if (this._schema === null)
144
199
  return this.seeded ?? EMPTY;
145
200
  if (!this.dirty && this.cached !== null)
146
201
  return this.cached;
147
- this.cached = this.top.map((n) => this.project(n, this.schema, this.types));
202
+ this.cached = this.top.map((n) => this.project(n, this._schema, this.types));
148
203
  this.dirty = false;
149
204
  return this.cached;
150
205
  }
@@ -160,9 +215,9 @@ export class FlatArrayView {
160
215
  this.top = [];
161
216
  }
162
217
  // --- apply -------------------------------------------------------------------
163
- applyAt(list, schema, path, op, depth) {
218
+ applyAt(list, schema, path, op, depth, enrichRemoves) {
164
219
  if (depth === path.length) {
165
- return this.applyOp(list, schema, op);
220
+ return this.applyOp(list, schema, op, enrichRemoves);
166
221
  }
167
222
  const seg = path[depth];
168
223
  const child = schema.relationships[seg.rel]?.child;
@@ -172,16 +227,22 @@ export class FlatArrayView {
172
227
  if (!found)
173
228
  throw new Error("flat ArrayView: parent not found at path hop (inconsistent stream)");
174
229
  const node = list[index];
175
- const changed = this.applyAt(node.rels[seg.rel], child, path, op, depth + 1);
230
+ const changed = this.applyAt(node.rels[seg.rel], child, path, op, depth + 1, enrichRemoves);
176
231
  if (changed)
177
232
  node.out = null; // a descendant changed → this node must re-project its rel array
178
233
  return changed;
179
234
  }
180
- applyOp(list, schema, op) {
235
+ applyOp(list, schema, op, enrichRemoves) {
181
236
  if (op.tag === "add")
182
237
  return this.applyAdd(list, schema, op.node);
183
- if (op.tag === "remove")
184
- return this.applyRemove(list, schema, op.row);
238
+ if (op.tag === "remove") {
239
+ const removed = this.applyRemove(list, schema, op.row);
240
+ // Attach the full removed subtree (in place) for an opted-in consumer; absent when the row
241
+ // only lost a reference (rc > 1) and so did not actually leave the result.
242
+ if (removed && enrichRemoves)
243
+ op.node = toWireNode(removed, schema);
244
+ return removed !== null;
245
+ }
185
246
  return this.applyEdit(list, schema, op.old, op.new);
186
247
  }
187
248
  applyAdd(list, schema, wnode) {
@@ -193,16 +254,20 @@ export class FlatArrayView {
193
254
  list.splice(at.index, 0, buildNode(wnode, schema));
194
255
  return true;
195
256
  }
257
+ /** Drop one path to `row`. Returns the evicted {@link Node} (its full subtree intact) when the
258
+ * last path went away — `null` when another path still holds it (rc decremented, nothing left
259
+ * the result). */
196
260
  applyRemove(list, schema, row) {
197
261
  const at = binarySearch(list, row, schema.sort);
198
262
  if (!at.found)
199
263
  throw new Error("flat ArrayView: remove of a non-existent node");
200
- if (list[at.index].rc === 1) {
264
+ const node = list[at.index];
265
+ if (node.rc === 1) {
201
266
  list.splice(at.index, 1);
202
- return true;
267
+ return node;
203
268
  }
204
- list[at.index].rc -= 1;
205
- return false;
269
+ node.rc -= 1;
270
+ return null;
206
271
  }
207
272
  applyEdit(list, schema, oldRow, newRow) {
208
273
  if (rowsEqual(oldRow, newRow))
package/dist/view.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"view.js","sourceRoot":"","sources":["../src/view.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"view.js","sourceRoot":"","sources":["../src/view.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rindle/client",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
package/src/ast.ts CHANGED
@@ -90,5 +90,16 @@ export interface Ast {
90
90
  * with a plain singular join + the same projection instead of a `reduce`. Only meaningful
91
91
  * with `aggregate`; absent ⇒ `false`. */
92
92
  aggregatePrecomputed?: boolean;
93
+ /** Top-level `GROUP BY` columns (names), meaningful only alongside a root {@link Ast.aggregate}
94
+ * (`REDUCE-DESIGN.md` §8). Empty + `aggregate` set ⇒ a **global** aggregate (one `[count]` row);
95
+ * non-empty ⇒ one `[group…, count]` row per distinct value-tuple. Distinct from a relationship
96
+ * aggregate's implicit grouping (the correlation child key). Absent on the wire ⇒ empty. */
97
+ groupBy?: string[];
98
+ /** `HAVING` — a filter over the **post-aggregation** rows of a root {@link Ast.aggregate}
99
+ * (`REDUCE-DESIGN.md` §4: a filter directly above the `reduce`). Its condition addresses the
100
+ * aggregate's *output* columns — the {@link Ast.groupBy} columns and the synthetic `count`
101
+ * column — not base-table columns (those go in {@link Ast.where}, which filters rows *below* the
102
+ * reduce). Absent ⇒ no post-aggregation filter. */
103
+ having?: Condition;
93
104
  orderBy?: OrderPart[];
94
105
  }
package/src/index.ts CHANGED
@@ -9,12 +9,17 @@ export * from "./view.ts"; // ArrayView, SingularArrayView, FlatArrayView, Singu
9
9
  export * from "./store.ts"; // Store, WriteTx, AssembledNode, DehydratedQuery, DehydratedState
10
10
  export * from "./ssr.ts"; // createServerStore, ServerStore, OneShotBackend, OneShotQueryFn, OneShotResult, ServerStoreOptions
11
11
 
12
+ export { resolveChange, subRow } from "./resolve.ts"; // positional FlatChange → named rows (inverse of the wire encoder)
13
+ export type { NamedRow, ResolvedChange } from "./resolve.ts";
14
+
12
15
  export { stableKey } from "./key.ts"; // canonical viewKey for an AST (shared with @rindle/react)
13
16
 
14
17
  export { COMPARATOR_VERSION, compareNumber, compareRows, compareString, compareValue } from "./compare.ts";
15
18
 
16
19
  export type {
17
20
  Backend,
21
+ BackendDevObserver,
22
+ BackendServerDelta,
18
23
  ChangeEvent,
19
24
  ColType,
20
25
  FlatChange,
package/src/operators.ts CHANGED
@@ -37,6 +37,11 @@ export const inList = <V>(values: V[]): Pred<V> => mk("IN", values as LitValue);
37
37
  export const notInList = <V>(values: V[]): Pred<V> => mk("NOT IN", values as LitValue);
38
38
  export const is = <V>(v: V): Pred<V> => mk("IS", v as LitValue);
39
39
  export const isNot = <V>(v: V): Pred<V> => mk("IS NOT", v as LitValue);
40
+ /** `IS NULL` — a field-agnostic null check. `V` is inferred from the field's expected `Arg<V>`
41
+ * (e.g. `where.signedAt(isNull())`), so it fits a column of any type without a cast. */
42
+ export const isNull = <V = never>(): Pred<V> => mk("IS", null);
43
+ /** `IS NOT NULL` — the negation of {@link isNull}; `V` is inferred from the field, like {@link isNull}. */
44
+ export const isNotNull = <V = never>(): Pred<V> => mk("IS NOT", null);
40
45
 
41
46
  /** A field argument: its typed predicate, or a bare value (bare = `eq` sugar). */
42
47
  export type Arg<V> = Pred<V> | V;
package/src/query.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  // - `where<Field>(…)` camelCase sugar (`whereClosed(false)`) is intercepted too.
7
7
  // Both are fully typed via mapped types + template-literal keys.
8
8
 
9
- import type { Ast, Bound, Condition, CorrelatedSubquery, Dir, ExistsOp, LitValue, OrderPart } from "./ast.ts";
9
+ import type { Ast, Bound, Condition, CorrelatedSubquery, Dir, ExistsOp, LitValue, OrderPart, SimpleOp } from "./ast.ts";
10
10
  import { stableKey } from "./key.ts";
11
11
  import type { Arg, Cond } from "./operators.ts";
12
12
  import { fieldCondition } from "./operators.ts";
@@ -49,11 +49,36 @@ type Projected<C extends AnyCols, Sel extends string> = [Sel] extends [never]
49
49
  ? RowOf<C>
50
50
  : Pick<RowOf<C>, Sel & keyof C>;
51
51
 
52
+ /**
53
+ * The accumulating result row of a top-level aggregate (REDUCE-DESIGN.md §8). `Agg` is `false`
54
+ * until {@link QueryBase.count}/{@link QueryBase.groupBy} reshapes the query; then it is the
55
+ * group-by columns intersected with the synthetic `{ count: number }`. {@link AggAcc} treats the
56
+ * `false` state as `{}` so the intersections in `count`/`groupBy` compose either way.
57
+ */
58
+ type AggAcc<Agg> = [Agg] extends [false] ? {} : Agg;
59
+
60
+ /** `having`'s field binder: one accessor per aggregate-OUTPUT column (the group-by columns plus the
61
+ * synthetic numeric `count`), each producing a {@link Cond} over that aggregate row. It is the only
62
+ * way to name `count` in a predicate (it lives on no base table); compose several with `and`/`or`. */
63
+ type HavingProxy<Row> = { [K in keyof Row & string]: (arg: Arg<Row[K]>) => Cond<Row> };
64
+
65
+ /** The `countAs` relationship aliases of a query — the {@link Rels} keys whose value is the scalar
66
+ * `number` a count aggregate surfaces. These are the only aliases {@link QueryBase.having}'s
67
+ * parent-by-child-aggregate overload accepts (a plain `sub` alias carries a row object, not a
68
+ * number, so it is rejected). */
69
+ type AggregateAlias<Rels> = { [K in keyof Rels]: Rels[K] extends number ? K & string : never }[keyof Rels];
70
+
71
+ /** What a query materializes: the post-aggregation row once reshaped by {@link QueryBase.count}
72
+ * (`Agg`), else the projected base row plus its relationship values. */
73
+ type ResultRow<C extends AnyCols, Rels, Sel extends string, Agg> = [Agg] extends [false]
74
+ ? Projected<C, Sel> & Rels
75
+ : Agg;
76
+
52
77
  type FragmentEdge<C extends AnyCols, Rels, Sel extends string, LocalRels> = (
53
78
  q: Query<C, Rels, false, Sel, LocalRels>,
54
79
  ) => Query<C, Rels, boolean, Sel, LocalRels>;
55
80
 
56
- interface QueryBase<C extends AnyCols, Rels, One extends boolean, Sel extends string, LocalRels> {
81
+ interface QueryBase<C extends AnyCols, Rels, One extends boolean, Sel extends string, LocalRels, Agg = false> {
57
82
  /** Present when this local query came from `defineQuery`; used as the remote identity. */
58
83
  readonly name?: string;
59
84
  /** Present when this local query came from `defineQuery`; sent with `name` upstream. */
@@ -219,12 +244,49 @@ interface QueryBase<C extends AnyCols, Rels, One extends boolean, Sel extends st
219
244
  relationship: Relationship<C, CC>,
220
245
  build?: (q: Query<CC>) => Query<CC, unknown>,
221
246
  ): Query<C, Rels & { [P in A]: number }, One, Sel, LocalRels & { [P in A]: number }>;
247
+ /** Reshape this query into a top-level `count(*)` aggregate (`REDUCE-DESIGN.md` §8) — the SQL
248
+ * `SELECT count(*) FROM table [GROUP BY …] [HAVING …]`. Without {@link groupBy} it is a GLOBAL
249
+ * count (one `{ count }` row, value `0` even on empty input); with it, one `{ …group, count }`
250
+ * row per distinct group. The result row becomes the aggregate's OUTPUT — the group-by columns
251
+ * plus a numeric `count` — so chain {@link having} to filter it. Distinct from {@link countAs}
252
+ * (a child-relationship scalar attached to the parent row); this reshapes the query ITSELF. The
253
+ * engine rejects pairing a root aggregate with `select`/`sub`/`countAs`/`orderBy`/`limit`/`one`. */
254
+ count(): Query<C, Rels, One, Sel, LocalRels, AggAcc<Agg> & { count: number }>;
255
+ /** Add a top-level `GROUP BY` column (chain for a compound key); only meaningful with
256
+ * {@link count}. Each grouped column joins the aggregate result row, keyed + sorted by the
257
+ * group key. */
258
+ groupBy<K extends keyof C & string>(
259
+ col: K,
260
+ ): Query<C, Rels, One, Sel, LocalRels, AggAcc<Agg> & Pick<RowOf<C>, K>>;
261
+ /** `HAVING (…)` — filter the **post-aggregation** rows of a {@link count} query (`REDUCE-DESIGN.md`
262
+ * §4: a filter directly above the reduce). `build` receives a field binder over the aggregate's
263
+ * OUTPUT columns — the {@link groupBy} columns and the synthetic `count` — and returns a
264
+ * {@link Cond}; compose several with `and`/`or`. E.g.
265
+ * `.groupBy("status").count().having((h) => h.count(gt(3)))`. Distinct from {@link where}, which
266
+ * filters base rows BELOW the reduce. */
267
+ having(build: (h: HavingProxy<AggAcc<Agg>>) => Cond<AggAcc<Agg>>): Query<C, Rels, One, Sel, LocalRels, Agg>;
268
+ /** `HAVING count(child) <op> n` — filter THIS parent by a child relationship aggregate's count
269
+ * (`PARENT-AGGREGATE-FILTER-DESIGN.md`). `alias` must name a {@link countAs} relationship already
270
+ * on this query; this drops parents whose child count fails `<op> val`, maintained incrementally
271
+ * (a child add/remove crossing the threshold adds/removes the parent). The display `countAs` is
272
+ * untouched — a survivor still shows its real count. Distinct from the {@link having} overload
273
+ * above, which filters a top-level {@link count}'s own output rows.
274
+ *
275
+ * **v1: high-pass predicates only** — predicates *false* at count 0 (`>`, `>=`/`=`/`!=` for
276
+ * `n ≥ 1`). A childless parent forms no group, so the engine rejects (at build) a predicate *true*
277
+ * at count 0 (`<=`, `< n` for `n ≥ 1`, `= 0`, `>= 0`); those need row-widening (deferred). */
278
+ having<A extends AggregateAlias<Rels>>(
279
+ alias: A,
280
+ op: SimpleOp,
281
+ val: number,
282
+ ): Query<C, Rels, One, Sel, LocalRels, Agg>;
222
283
  /** The compiled Zero-wire AST (what a backend's `query` consumes). */
223
284
  ast(): Ast;
224
285
  /** Materialize into a live, typed view. Wired by the Store/backend. A top-level `.one()`
225
- * yields a {@link SingularArrayView}; otherwise an {@link ArrayView}. The row is masked to the
226
- * projection ({@link Projected}) full {@link RowOf} until a column is `select`ed. */
227
- materialize(): MaterializedView<Projected<C, Sel> & Rels, One>;
286
+ * yields a {@link SingularArrayView}; otherwise an {@link ArrayView}. The row is the aggregate
287
+ * output once {@link count} reshaped the query, else masked to the projection ({@link Projected})
288
+ * full {@link RowOf} until a column is `select`ed. */
289
+ materialize(): MaterializedView<ResultRow<C, Rels, Sel, Agg>, One>;
228
290
  }
229
291
 
230
292
  export type Query<
@@ -233,18 +295,21 @@ export type Query<
233
295
  One extends boolean = false,
234
296
  Sel extends string = never,
235
297
  LocalRels = Rels,
298
+ Agg = false,
236
299
  > =
237
- & Omit<QueryBase<C, Rels, One, Sel, LocalRels>, "where">
238
- & { where: QueryBase<C, Rels, One, Sel, LocalRels>["where"] & WhereProxy<C, Rels, One, Sel, LocalRels> }
300
+ & Omit<QueryBase<C, Rels, One, Sel, LocalRels, Agg>, "where">
301
+ & { where: QueryBase<C, Rels, One, Sel, LocalRels, Agg>["where"] & WhereProxy<C, Rels, One, Sel, LocalRels> }
239
302
  & WhereSugar<C, Rels, One, Sel, LocalRels>;
240
303
 
241
- export type AnyQuery = Query<any, any, any, any, any>;
304
+ export type AnyQuery = Query<any, any, any, any, any, any>;
242
305
 
243
306
  export type QueryLocalData<Q extends AnyQuery> =
244
- Q extends Query<infer C, any, infer One, infer Sel, infer LocalRels>
245
- ? One extends true
246
- ? (Projected<C, Sel> & LocalRels) | null
247
- : readonly (Projected<C, Sel> & LocalRels)[]
307
+ Q extends Query<infer C, any, infer One, infer Sel, infer LocalRels, infer Agg>
308
+ ? [Agg] extends [false]
309
+ ? One extends true
310
+ ? (Projected<C, Sel> & LocalRels) | null
311
+ : readonly (Projected<C, Sel> & LocalRels)[]
312
+ : readonly Agg[]
248
313
  : never;
249
314
  const STAMP_NAMED_QUERY: unique symbol = Symbol("rindle.stampNamedQuery");
250
315
 
@@ -632,6 +697,12 @@ interface State {
632
697
  limit?: number;
633
698
  one: boolean;
634
699
  select?: string[];
700
+ // Top-level aggregate (REDUCE-DESIGN.md §8): `aggregate` reshapes the query into a `count(*)`;
701
+ // `groupBy` partitions it; `having` filters the post-aggregation rows. All three are read by the
702
+ // engine only together (see the guard in `compile`).
703
+ aggregate?: "count";
704
+ groupBy: string[];
705
+ having?: Condition;
635
706
  }
636
707
 
637
708
  interface NamedQueryState {
@@ -640,7 +711,7 @@ interface NamedQueryState {
640
711
  }
641
712
 
642
713
  function emptyState(table: string): State {
643
- return { table, wheres: [], orderBy: [], related: [], one: false };
714
+ return { table, wheres: [], orderBy: [], related: [], one: false, groupBy: [] };
644
715
  }
645
716
 
646
717
  function compile(s: State): Ast {
@@ -654,6 +725,18 @@ function compile(s: State): Ast {
654
725
  if (s.limit !== undefined) ast.limit = s.limit;
655
726
  if (s.one) ast.one = true;
656
727
  if (s.select && s.select.length > 0) ast.select = s.select;
728
+ if (s.aggregate !== undefined) ast.aggregate = s.aggregate;
729
+ if (s.groupBy.length > 0) ast.groupBy = s.groupBy;
730
+ if (s.having !== undefined) ast.having = s.having;
731
+ // The engine takes the aggregate lowering ONLY when `aggregate` is set (REDUCE-DESIGN.md §8 /
732
+ // builder `build_pipeline`); `groupBy`/`having` on the row spine would be silently ignored. Fail
733
+ // loudly so a forgotten `.count()` is a clear error, not a query that quietly returns all rows.
734
+ if ((ast.groupBy !== undefined || ast.having !== undefined) && ast.aggregate === undefined) {
735
+ throw new Error(
736
+ "groupBy()/having() require count(): a top-level GROUP BY / HAVING is only honored on an " +
737
+ "aggregate query (REDUCE-DESIGN.md §8) — add .count().",
738
+ );
739
+ }
657
740
  return ast;
658
741
  }
659
742
 
@@ -923,6 +1006,52 @@ function makeQuery(
923
1006
  };
924
1007
  return next({ related: [...s.related, csq] });
925
1008
  },
1009
+ // Top-level aggregate (REDUCE-DESIGN §8): `count` reshapes this query into a `count(*)`;
1010
+ // `groupBy` partitions it; `having` filters the post-aggregation rows. `having`'s callback gets
1011
+ // a field binder over the aggregate's output columns (group cols + the synthetic `count`), so a
1012
+ // predicate can name `count` — which lives on no base table — exactly like `where.<field>(…)`.
1013
+ count: () => next({ aggregate: "count" }),
1014
+ groupBy: (col: string) => next({ groupBy: [...s.groupBy, col] }),
1015
+ having: (a: unknown, op?: SimpleOp, val?: number) => {
1016
+ // Overload 1 — top-level aggregate HAVING: `having((h) => h.count(gt(3)))`. The callback
1017
+ // binds the aggregate's output columns (group cols + the synthetic `count`).
1018
+ if (typeof a === "function") {
1019
+ const build = a as (h: Record<string, (arg: unknown) => Condition>) => Condition;
1020
+ const h = new Proxy({} as Record<string, (arg: unknown) => Condition>, {
1021
+ get: (_t, prop) => (typeof prop === "string" ? (arg: unknown) => fieldCondition(prop, arg) : undefined),
1022
+ });
1023
+ return next({ having: build(h) });
1024
+ }
1025
+ // Overload 2 — filter THIS parent by a child aggregate's count:
1026
+ // `.having("commentCount", ">", 10)` (PARENT-AGGREGATE-FILTER-DESIGN.md). Bind the existing
1027
+ // `countAs(alias, …)` relationship and push a hidden EXISTS whose subquery clones the same
1028
+ // correlation + child + `count` aggregate, plus a `HAVING count <op> val`. The engine lowers
1029
+ // it to an EXISTS over a HAVING-filtered reduce; the display `countAs` is untouched.
1030
+ const alias = a as string;
1031
+ const display = s.related.find(
1032
+ (r) => r.subquery.alias === alias && r.subquery.aggregate === "count",
1033
+ );
1034
+ if (!display) {
1035
+ throw new Error(
1036
+ `having("${alias}", …): this query has no countAs("${alias}", …) relationship to filter ` +
1037
+ `on — attach the child count aggregate first.`,
1038
+ );
1039
+ }
1040
+ const gate: CorrelatedSubquery = {
1041
+ correlation: display.correlation,
1042
+ subquery: {
1043
+ ...display.subquery,
1044
+ alias: `__having_${alias}`,
1045
+ having: {
1046
+ type: "simple",
1047
+ op: op as SimpleOp,
1048
+ left: { type: "column", name: "count" },
1049
+ right: { type: "literal", value: val as LitValue },
1050
+ },
1051
+ },
1052
+ };
1053
+ return next({ wheres: [...s.wheres, { type: "correlatedSubquery", op: "EXISTS", related: gate }] });
1054
+ },
926
1055
  ast: () => {
927
1056
  const a = compile(s);
928
1057
  guardAst?.(a);