@rindle/query-compiler 0.4.3

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 (53) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +42 -0
  3. package/dist/ast.d.ts +2 -0
  4. package/dist/ast.d.ts.map +1 -0
  5. package/dist/ast.js +2 -0
  6. package/dist/ast.js.map +1 -0
  7. package/dist/catalog.d.ts +51 -0
  8. package/dist/catalog.d.ts.map +1 -0
  9. package/dist/catalog.js +7 -0
  10. package/dist/catalog.js.map +1 -0
  11. package/dist/complete-ordering.d.ts +3 -0
  12. package/dist/complete-ordering.d.ts.map +1 -0
  13. package/dist/complete-ordering.js +44 -0
  14. package/dist/complete-ordering.js.map +1 -0
  15. package/dist/dialect.d.ts +49 -0
  16. package/dist/dialect.d.ts.map +1 -0
  17. package/dist/dialect.js +35 -0
  18. package/dist/dialect.js.map +1 -0
  19. package/dist/errors.d.ts +13 -0
  20. package/dist/errors.d.ts.map +1 -0
  21. package/dist/errors.js +26 -0
  22. package/dist/errors.js.map +1 -0
  23. package/dist/index.d.ts +31 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +34 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/pg-types.d.ts +20 -0
  28. package/dist/pg-types.d.ts.map +1 -0
  29. package/dist/pg-types.js +107 -0
  30. package/dist/pg-types.js.map +1 -0
  31. package/dist/postgres.d.ts +7 -0
  32. package/dist/postgres.d.ts.map +1 -0
  33. package/dist/postgres.js +134 -0
  34. package/dist/postgres.js.map +1 -0
  35. package/dist/reject.d.ts +3 -0
  36. package/dist/reject.d.ts.map +1 -0
  37. package/dist/reject.js +74 -0
  38. package/dist/reject.js.map +1 -0
  39. package/dist/walker.d.ts +11 -0
  40. package/dist/walker.d.ts.map +1 -0
  41. package/dist/walker.js +350 -0
  42. package/dist/walker.js.map +1 -0
  43. package/package.json +39 -0
  44. package/src/ast.ts +18 -0
  45. package/src/catalog.ts +59 -0
  46. package/src/complete-ordering.ts +48 -0
  47. package/src/dialect.ts +85 -0
  48. package/src/errors.ts +30 -0
  49. package/src/index.ts +74 -0
  50. package/src/pg-types.ts +119 -0
  51. package/src/postgres.ts +152 -0
  52. package/src/reject.ts +71 -0
  53. package/src/walker.ts +418 -0
package/dist/walker.js ADDED
@@ -0,0 +1,350 @@
1
+ // The compiler core — a syntax-directed `Ast → SELECT` lowering, ported one-to-one from
2
+ // `rindle-d2s` (rust/rindle-d2s/src/lib.rs) and bound to our exact wire `Ast`. The one
3
+ // deliberate change from `rindle-d2s` is that filter/paging **values are parameterized**
4
+ // (pushed onto `params`, emitted as placeholders by the dialect) instead of inlined — so the
5
+ // output is injection-safe and plan-cacheable (Invariant 4). Everything else — the walker
6
+ // structure, ordering completion, keyset-paging predicate, empty-fold — matches the oracle.
7
+ import { completeOrdering } from "./complete-ordering.js";
8
+ import { missingAlias, unknownRelationship, unknownTable } from "./errors.js";
9
+ import { rejectUnsupported } from "./reject.js";
10
+ /** Compile `ast` against `catalog` for `dialect`. `singular` ⇒ a `.one()` root (single
11
+ * object or `null`); else a plural root (a JSON array). Pure: mutates only a clone. */
12
+ export function compileWith(ast, catalog, dialect, singular) {
13
+ rejectUnsupported(ast);
14
+ const cloned = structuredClone(ast);
15
+ completeOrdering(cloned, (t) => pkOf(catalog, t));
16
+ const cx = new Cx(catalog, dialect);
17
+ const expr = cx.collection(cloned, singular, null);
18
+ return { sql: `SELECT ${expr} AS "rindle_result"`, params: cx.params };
19
+ }
20
+ /** Compile context: the catalog, dialect, the accumulating params, and an alias counter. */
21
+ class Cx {
22
+ params = [];
23
+ #n = 0;
24
+ // Explicit fields (not constructor parameter properties): Node's strip-only type stripping
25
+ // does not support parameter properties, and this source runs directly from `.ts`.
26
+ #catalog;
27
+ #d;
28
+ constructor(catalog, d) {
29
+ this.#catalog = catalog;
30
+ this.#d = d;
31
+ }
32
+ #alias(table) {
33
+ return `${table}_${this.#n++}`;
34
+ }
35
+ /** A scalar-subquery expression producing the JSON for `ast` as a single object
36
+ * (`singular`) or a `json_group_array`/`jsonb_agg` of objects, correlated to a parent
37
+ * when `correlate` is set (`[parentAlias, Correlation]`). */
38
+ collection(ast, singular, correlate) {
39
+ const table = ast.table;
40
+ const cols = columnsOf(this.#catalog, table);
41
+ const alias = this.#alias(table);
42
+ const scope = { table, alias };
43
+ const row = this.#rowObject(ast, scope, cols);
44
+ const conds = [];
45
+ if (correlate)
46
+ conds.push(correlateSql(this.#d, correlate[0], alias, correlate[1]));
47
+ if (ast.where)
48
+ conds.push(this.#whereSql(ast.where, scope));
49
+ // Keyset paging: keep rows at/after `start` under the already-PK-completed sort — the
50
+ // exact comparator the engine's `Skip` uses.
51
+ if (ast.start)
52
+ conds.push(this.#startSql(ast.start, ast.orderBy ?? [], scope));
53
+ const from = `${this.#d.quoteIdent(table)} AS ${this.#d.quoteIdent(alias)}`;
54
+ return this.#pluralOrSingular(singular, row, from, whereClause(conds), ast.orderBy ?? [], alias, ast.limit);
55
+ }
56
+ /** `json_object('c', a."c", …, 'rel', <child expr>, …)`. A column shadowed by a
57
+ * same-named relationship is dropped (the relationship wins, as in the View). */
58
+ #rowObject(ast, scope, cols) {
59
+ const relNames = new Set((ast.related ?? []).map((r) => r.subquery.alias).filter((a) => a != null));
60
+ const selected = ast.select ? new Set(ast.select) : null;
61
+ const parts = [];
62
+ for (const col of cols) {
63
+ if (relNames.has(col))
64
+ continue;
65
+ if (selected && !selected.has(col))
66
+ continue;
67
+ const colRef = `${this.#d.quoteIdent(scope.alias)}.${this.#d.quoteIdent(col)}`;
68
+ const projected = this.#d.projectColumn(colRef, columnTypeOf(this.#catalog, scope.table, col));
69
+ parts.push(`${jsonKey(col)}, ${projected}`);
70
+ }
71
+ for (const rel of ast.related ?? []) {
72
+ const name = rel.subquery.alias;
73
+ if (name == null)
74
+ throw missingAlias(rel.subquery.table);
75
+ // A relationship aggregate (`count(child)`) is a scalar column, not a nested collection.
76
+ const expr = rel.subquery.aggregate === "count"
77
+ ? this.#countExpr(rel, scope.alias)
78
+ : this.#relationExpr(scope.table, rel, scope.alias);
79
+ parts.push(`${jsonKey(name)}, ${expr}`);
80
+ }
81
+ return this.#d.objectBuild(parts);
82
+ }
83
+ /** One materialized relationship as a nested-JSON column. */
84
+ #relationExpr(parentTable, rel, parentAlias) {
85
+ const name = rel.subquery.alias;
86
+ if (name == null)
87
+ throw missingAlias(rel.subquery.table);
88
+ const singular = cardinalityOf(this.#catalog, parentTable, name) === "one";
89
+ return this.collection(rel.subquery, singular, [parentAlias, rel.correlation]);
90
+ }
91
+ /** A scalar `count(*)` for a relationship aggregate: `(SELECT count(*) FROM child AS a
92
+ * WHERE <correlation> [AND <child.where>])`. `0` when no child matches. */
93
+ #countExpr(rel, parentAlias) {
94
+ const sub = rel.subquery;
95
+ const alias = this.#alias(sub.table);
96
+ const conds = [correlateSql(this.#d, parentAlias, alias, rel.correlation)];
97
+ if (sub.where)
98
+ conds.push(this.#whereSql(sub.where, { table: sub.table, alias }));
99
+ return `(SELECT count(*) FROM ${this.#d.quoteIdent(sub.table)} AS ${this.#d.quoteIdent(alias)} WHERE ${conds.join(" AND ")})`;
100
+ }
101
+ /** A boolean SQL expression for a `where` condition tree. */
102
+ #whereSql(cond, scope) {
103
+ switch (cond.type) {
104
+ case "and":
105
+ return cond.conditions.length === 0
106
+ ? this.#d.trueLit
107
+ : `(${cond.conditions.map((c) => this.#whereSql(c, scope)).join(" AND ")})`;
108
+ case "or":
109
+ return cond.conditions.length === 0
110
+ ? this.#d.falseLit
111
+ : `(${cond.conditions.map((c) => this.#whereSql(c, scope)).join(" OR ")})`;
112
+ case "correlatedSubquery":
113
+ return this.#existsSql(cond, scope.alias);
114
+ case "simple":
115
+ return this.#simpleSql(cond, scope);
116
+ }
117
+ }
118
+ /** `[NOT] EXISTS (SELECT 1 FROM child AS a WHERE <correlation> [AND <child.where>])`.
119
+ * `flip`/`scalar` are IVM routing flags with no effect on the SQL. */
120
+ #existsSql(c, parentAlias) {
121
+ const sub = c.related.subquery;
122
+ const alias = this.#alias(sub.table);
123
+ const conds = [correlateSql(this.#d, parentAlias, alias, c.related.correlation)];
124
+ if (sub.where)
125
+ conds.push(this.#whereSql(sub.where, { table: sub.table, alias }));
126
+ const inner = `SELECT 1 FROM ${this.#d.quoteIdent(sub.table)} AS ${this.#d.quoteIdent(alias)} WHERE ${conds.join(" AND ")}`;
127
+ return c.op === "EXISTS" ? `EXISTS (${inner})` : `NOT EXISTS (${inner})`;
128
+ }
129
+ /** A single comparison. Operators render verbatim except: `IS`/`IS NOT` render the RHS as
130
+ * a SQL keyword (`NULL`/`TRUE`/`FALSE`) not a param; `ILIKE` folds via `lower()`; `IN`/
131
+ * `NOT IN` bind the list (empty ⇒ the constant truth value). */
132
+ #simpleSql(sc, scope) {
133
+ // A literal is bound with the *other* side's column type when that side is a column
134
+ // (drives Postgres casts); `null` ⇒ infer from the JS type.
135
+ const leftColType = this.#colTypeOf(scope, sc.left);
136
+ const rightColType = this.#colTypeOf(scope, sc.right);
137
+ const l = this.#valuePos(scope, sc.left, rightColType);
138
+ const r = () => this.#valuePos(scope, sc.right, leftColType);
139
+ switch (sc.op) {
140
+ case "=":
141
+ return `${l} = ${r()}`;
142
+ case "!=":
143
+ return `${l} != ${r()}`;
144
+ case "<":
145
+ return `${l} < ${r()}`;
146
+ case "<=":
147
+ return `${l} <= ${r()}`;
148
+ case ">":
149
+ return `${l} > ${r()}`;
150
+ case ">=":
151
+ return `${l} >= ${r()}`;
152
+ case "IS":
153
+ return `${l} IS ${this.#isRhs(scope, sc.right)}`;
154
+ case "IS NOT":
155
+ return `${l} IS NOT ${this.#isRhs(scope, sc.right)}`;
156
+ case "LIKE":
157
+ return `${l} LIKE ${r()} ESCAPE '\\'`;
158
+ case "NOT LIKE":
159
+ return `${l} NOT LIKE ${r()} ESCAPE '\\'`;
160
+ case "ILIKE":
161
+ return `lower(${l}) LIKE lower(${r()}) ESCAPE '\\'`;
162
+ case "NOT ILIKE":
163
+ return `lower(${l}) NOT LIKE lower(${r()}) ESCAPE '\\'`;
164
+ case "IN":
165
+ return this.#inSql(scope, l, sc.right, false, leftColType);
166
+ case "NOT IN":
167
+ return this.#inSql(scope, l, sc.right, true, leftColType);
168
+ }
169
+ }
170
+ /** The RHS of `IS`/`IS NOT` — a SQL keyword position (Postgres forbids a param here), so
171
+ * `NULL`/`TRUE`/`FALSE` render literally. Any other RHS (unusual) falls back to a value. */
172
+ #isRhs(scope, vp) {
173
+ if (vp.type === "literal") {
174
+ if (vp.value === null)
175
+ return "NULL";
176
+ if (vp.value === true)
177
+ return this.#d.trueLit;
178
+ if (vp.value === false)
179
+ return this.#d.falseLit;
180
+ }
181
+ return this.#valuePos(scope, vp, null);
182
+ }
183
+ /** The column type of `vp` when it is a column reference; `null` for a literal. */
184
+ #colTypeOf(scope, vp) {
185
+ return vp.type === "column" ? columnTypeOf(this.#catalog, scope.table, vp.name) : null;
186
+ }
187
+ /** A column reference (`a."c"`) or a bound literal (`?` / `$N::text::<type>`). `siblingCol`
188
+ * is the compared column's type, used when `vp` is a literal. */
189
+ #valuePos(scope, vp, siblingCol) {
190
+ if (vp.type === "column") {
191
+ return `${this.#d.quoteIdent(scope.alias)}.${this.#d.quoteIdent(vp.name)}`;
192
+ }
193
+ return this.#d.bindValue(this.params, vp.value, siblingCol, true);
194
+ }
195
+ /** `lhs [NOT] IN (v0, v1, …)`. An empty list folds to the constant truth value; a non-array
196
+ * RHS falls back to `=`/`!=` (as `rindle-d2s`'s `in_sql`). */
197
+ #inSql(scope, lhs, right, negate, lhsCol) {
198
+ if (right.type === "literal" && Array.isArray(right.value)) {
199
+ const items = right.value;
200
+ if (items.length === 0)
201
+ return negate ? this.#d.trueLit : this.#d.falseLit;
202
+ const list = items
203
+ .map((it) => this.#d.bindValue(this.params, it, lhsCol, true))
204
+ .join(", ");
205
+ return `${lhs} ${negate ? "NOT IN" : "IN"} (${list})`;
206
+ }
207
+ const rr = this.#valuePos(scope, right, lhsCol);
208
+ return negate ? `${lhs} != ${rr}` : `${lhs} = ${rr}`;
209
+ }
210
+ /** Emit the plural (`json_group_array`/`jsonb_agg`) or singular (`… LIMIT 1`) form. When a
211
+ * `LIMIT` is present the rows are selected (ordered + limited) in an inner subquery and
212
+ * then array-aggregated in declared order, so both the top-N selection and the array order
213
+ * are correct. */
214
+ #pluralOrSingular(singular, row, from, where, order, alias, limit) {
215
+ if (singular) {
216
+ return `(SELECT ${row} FROM ${from}${where}${this.#orderClause(order, alias)} LIMIT 1)`;
217
+ }
218
+ if (limit !== undefined) {
219
+ const innerOrder = this.#orderClause(order, alias);
220
+ const proj = this.#orderProj(order, alias);
221
+ const agg = this.#aggOrderProjected(order);
222
+ // Re-assert the JSON subtype: the object round-trips through the inner subquery's
223
+ // `AS __r` column, which SQLite would otherwise re-encode as a string.
224
+ const elem = this.#d.reassertJson("__r");
225
+ const lim = Math.max(0, Math.trunc(Number(limit)));
226
+ return `COALESCE((SELECT ${this.#d.groupArray(elem, agg)} FROM (SELECT ${row} AS __r${proj} FROM ${from}${where}${innerOrder} LIMIT ${lim})), ${this.#d.emptyArray})`;
227
+ }
228
+ const agg = this.#aggOrderInline(order, alias);
229
+ return `COALESCE((SELECT ${this.#d.groupArray(row, agg)} FROM ${from}${where}), ${this.#d.emptyArray})`;
230
+ }
231
+ /** ` ORDER BY a."c0" ASC, a."c1" DESC` (empty when `order` is empty). */
232
+ #orderClause(order, alias) {
233
+ return order.length === 0 ? "" : ` ORDER BY ${this.#orderTerms(order, alias)}`;
234
+ }
235
+ /** In-aggregate ordering referencing the FROM columns. */
236
+ #aggOrderInline(order, alias) {
237
+ return order.length === 0 ? "" : ` ORDER BY ${this.#orderTerms(order, alias)}`;
238
+ }
239
+ /** In-aggregate ordering over the inner subquery's projected order columns (`__o0`, …). */
240
+ #aggOrderProjected(order) {
241
+ if (order.length === 0)
242
+ return "";
243
+ return ` ORDER BY ${order.map(([, dir], i) => `__o${i} ${this.#d.orderDir(dir)}`).join(", ")}`;
244
+ }
245
+ /** Project the order columns into the inner subquery: `, a."c0" AS __o0, …`. */
246
+ #orderProj(order, alias) {
247
+ return order
248
+ .map(([field], i) => `, ${this.#d.quoteIdent(alias)}.${this.#d.quoteIdent(field)} AS __o${i}`)
249
+ .join("");
250
+ }
251
+ #orderTerms(order, alias) {
252
+ return order
253
+ .map(([field, dir]) => `${this.#d.quoteIdent(alias)}.${this.#d.quoteIdent(field)} ${this.#d.orderDir(dir)}`)
254
+ .join(", ");
255
+ }
256
+ /** The keyset paging predicate for a `start` bound: keep a row iff the bound sorts before
257
+ * it (`B < R`), or sorts equal with an inclusive bound (`B <= R`), under the already-PK-
258
+ * completed sort. Lexicographic with **null-low** ordering (NULL before any value on ASC,
259
+ * after every value on DESC) — faithful to the engine's `Skip`. */
260
+ #startSql(start, order, scope) {
261
+ // Per sort column: the column ref, direction, bound value (absent/NULL ⇒ null-low), type.
262
+ const cols = order.map(([field, dir]) => ({
263
+ x: `${this.#d.quoteIdent(scope.alias)}.${this.#d.quoteIdent(field)}`,
264
+ asc: dir === "asc",
265
+ b: nullLowBound(start.row[field]),
266
+ col: columnTypeOf(this.#catalog, scope.table, field),
267
+ }));
268
+ if (cols.length === 0)
269
+ return this.#d.trueLit; // no sort columns (unreachable post-completion)
270
+ // `B < R` = OR_i ( AND_{j<i} eq_j AND before_i ). Each `eq`/`before` fragment is
271
+ // (re)emitted exactly where it appears — regenerated, not string-reused — so every
272
+ // placeholder gets its own bound param, in left-to-right order. (`rindle-d2s` can reuse a
273
+ // fragment string because its literals are inlined and side-effect-free; our params are
274
+ // positional, so a reused or discarded fragment would desync placeholders from params.)
275
+ const orTerms = [];
276
+ for (let i = 0; i < cols.length; i++) {
277
+ const conj = [];
278
+ for (let j = 0; j < i; j++)
279
+ conj.push(this.#eqSql(cols[j].x, cols[j].b, cols[j].col));
280
+ conj.push(this.#beforeSql(cols[i].x, cols[i].asc, cols[i].b, cols[i].col));
281
+ orTerms.push(`(${conj.join(" AND ")})`);
282
+ }
283
+ const strictLt = `(${orTerms.join(" OR ")})`;
284
+ if (start.exclusive)
285
+ return strictLt;
286
+ // `B <= R` adds the all-columns-equal term.
287
+ const allEq = cols.map((c) => this.#eqSql(c.x, c.b, c.col)).join(" AND ");
288
+ return `(${strictLt} OR (${allEq}))`;
289
+ }
290
+ /** `x` strictly after the bound value `b` in this column's direction, null-low. `b` is
291
+ * `undefined` for an omitted/NULL bound. */
292
+ #beforeSql(x, asc, b, col) {
293
+ if (b === undefined) {
294
+ // NULL bound: before every non-null `x` on ASC; never before on DESC.
295
+ return asc ? `${x} IS NOT NULL` : this.#d.falseLit;
296
+ }
297
+ const v = this.#d.bindValue(this.params, b, col, true);
298
+ // ASC: `v < x` (NULL `x` ⇒ NULL ⇒ false, i.e. a null row is not after a non-null bound).
299
+ // DESC: a null `x` sorts last, so it is after the bound; else `v > x`.
300
+ return asc ? `${v} < ${x}` : `(${x} IS NULL OR ${v} > ${x})`;
301
+ }
302
+ /** `x` equal to the bound value `b` under the sort's null-identical equality. */
303
+ #eqSql(x, b, col) {
304
+ if (b === undefined)
305
+ return `${x} IS NULL`;
306
+ return `${x} = ${this.#d.bindValue(this.params, b, col, true)}`;
307
+ }
308
+ }
309
+ // ── free helpers (dialect-independent) ────────────────────────────────────────────────────
310
+ /** `parent."p0" = child."c0" AND parent."p1" = child."c1" …`. */
311
+ function correlateSql(d, parentAlias, childAlias, corr) {
312
+ return corr.parentField
313
+ .map((p, i) => {
314
+ const c = corr.childField[i];
315
+ return `${d.quoteIdent(parentAlias)}.${d.quoteIdent(p)} = ${d.quoteIdent(childAlias)}.${d.quoteIdent(c)}`;
316
+ })
317
+ .join(" AND ");
318
+ }
319
+ function whereClause(conds) {
320
+ return conds.length === 0 ? "" : ` WHERE ${conds.join(" AND ")}`;
321
+ }
322
+ /** A `json_object`/`jsonb_build_object` key: a single-quoted string literal. */
323
+ function jsonKey(name) {
324
+ return `'${name.replace(/'/g, "''")}'`;
325
+ }
326
+ /** A paging bound value, with an absent or explicit-NULL value normalized to `undefined`
327
+ * (the null-low sentinel `beforeSql`/`eqSql` treat as "sorts below everything"). */
328
+ function nullLowBound(raw) {
329
+ return raw === undefined || raw === null ? undefined : raw;
330
+ }
331
+ // ── catalog accessors ─────────────────────────────────────────────────────────────────────
332
+ function columnsOf(catalog, table) {
333
+ const t = catalog.tables[table];
334
+ if (!t)
335
+ throw unknownTable(table);
336
+ return t.columns;
337
+ }
338
+ function pkOf(catalog, table) {
339
+ return catalog.tables[table]?.primaryKey ?? [];
340
+ }
341
+ function cardinalityOf(catalog, table, rel) {
342
+ const card = catalog.tables[table]?.relationships[rel];
343
+ if (!card)
344
+ throw unknownRelationship(table, rel);
345
+ return card;
346
+ }
347
+ function columnTypeOf(catalog, table, col) {
348
+ return catalog.tables[table]?.columnTypes[col] ?? null;
349
+ }
350
+ //# sourceMappingURL=walker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"walker.js","sourceRoot":"","sources":["../src/walker.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@rindle/query-compiler",
3
+ "version": "0.4.3",
4
+ "license": "Apache-2.0",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/rindle-sh/rindle.git",
8
+ "directory": "packages/query-compiler"
9
+ },
10
+ "type": "module",
11
+ "description": "Compiles a Rindle query AST to one SQL SELECT (whole nested result as a single JSON column) for a live SQL backend — the server realization of 203-MUTATOR-READS Phase 2 (POSTGRES-READ-COMPILER-DESIGN.md). Postgres dialect drives the BYO-Postgres mutator read; the SQLite dialect drives the daemon-backend mutator read through an interactive mutation session (and doubles as the offline differential oracle).",
12
+ "main": "./dist/index.js",
13
+ "types": "./dist/index.d.ts",
14
+ "sideEffects": false,
15
+ "exports": {
16
+ ".": {
17
+ "@rindle/source": "./src/index.ts",
18
+ "types": "./dist/index.d.ts",
19
+ "default": "./dist/index.js"
20
+ }
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "src",
25
+ "README.md"
26
+ ],
27
+ "dependencies": {
28
+ "@rindle/client": "0.4.3"
29
+ },
30
+ "devDependencies": {
31
+ "@types/node": "^22.10.0",
32
+ "typescript": "^5.7.0"
33
+ },
34
+ "scripts": {
35
+ "build": "tsc -p tsconfig.build.json",
36
+ "typecheck": "tsc --noEmit",
37
+ "test": "tsc --noEmit && node --conditions=@rindle/source --test test/*.test.ts"
38
+ }
39
+ }
package/src/ast.ts ADDED
@@ -0,0 +1,18 @@
1
+ // Re-export the canonical Zero-wire AST types from @rindle/client — the single source of
2
+ // truth for the query shape the builder emits (`client/src/ast.ts`) and the Rust engine
3
+ // deserializes (`rust/src/ast.rs`). The compiler consumes these verbatim, so it can never
4
+ // drift from what the client produces.
5
+ export type {
6
+ Aggregate,
7
+ Ast,
8
+ Bound,
9
+ Condition,
10
+ CorrelatedSubquery,
11
+ Correlation,
12
+ Dir,
13
+ ExistsOp,
14
+ LitValue,
15
+ OrderPart,
16
+ SimpleOp,
17
+ ValuePosition,
18
+ } from "@rindle/client";
package/src/catalog.ts ADDED
@@ -0,0 +1,59 @@
1
+ // The static, declared type catalog (POSTGRES-READ-COMPILER-DESIGN.md §7) — the second
2
+ // input to the compiler, beside the `Ast`. Compilation is a pure function of
3
+ // `(Ast, Catalog)`; the catalog carries the facts the AST does not: column order, primary
4
+ // key, relationship cardinality, and — for the Postgres dialect — the per-column native
5
+ // type detail the `::text::<type>` cast strategy (§6.2) branches on.
6
+
7
+ /** Whether a relationship yields a single child object (`one`) or an array (`many`). */
8
+ export type Cardinality = "one" | "many";
9
+
10
+ /**
11
+ * Per-column type detail the Postgres compiler needs for value-model↔native-type
12
+ * reconciliation (§6.2). Mirrors z2s's `ServerColumnSchema`: the raw Postgres type name
13
+ * plus the two flags the cast switch branches on. The extension over what
14
+ * `rindle-pg-source` derives today (§7, review decision 2): enums and arrays are carried
15
+ * distinctly instead of collapsing into a text fallback.
16
+ *
17
+ * - `type` — the native Postgres type name: `"int4"`, `"text"`, `"bool"`, `"float8"`,
18
+ * `"numeric"`, `"timestamptz"`, `"timestamp"`, `"date"`, `"timetz"`, `"time"`, `"uuid"`,
19
+ * `"json"`/`"jsonb"`, or an **enum type name** (paired with `isEnum: true`).
20
+ * - `isEnum` — `type` names a Postgres enum ⇒ cast via `$N::text::"<type>"`.
21
+ * - `isArray` — the column is an array ⇒ unnest via `jsonb_array_elements_text`.
22
+ *
23
+ * The SQLite oracle dialect ignores this entirely: it binds native values (no casts).
24
+ */
25
+ export interface ColumnType {
26
+ type: string;
27
+ isEnum: boolean;
28
+ isArray: boolean;
29
+ }
30
+
31
+ /**
32
+ * Per-table metadata the compiler needs beyond the `Ast`:
33
+ * - `columns` — the projected column list, **in projection order** (the order
34
+ * `json_object`/`jsonb_build_object` enumerates), matching the View's `Schema`.
35
+ * - `primaryKey` — the PK columns, for ordering-completion (§8): the compiler appends the
36
+ * full PK to every `orderBy` at every level for a total order, exactly as the engine's
37
+ * builder does (`rindle::complete_ordering`).
38
+ * - `columnTypes` — per-column native type detail, keyed by column name (§6.2; Postgres
39
+ * dialect only).
40
+ * - `relationships` — declared relationships → cardinality. This is the one structural
41
+ * fact not carried by the `Ast` (the relationship *shape* — correlation keys, nesting,
42
+ * where/order/limit — lives in the `Ast`'s `related` subqueries).
43
+ */
44
+ export interface TableSchema {
45
+ columns: string[];
46
+ primaryKey: string[];
47
+ columnTypes: Record<string, ColumnType>;
48
+ relationships: Record<string, Cardinality>;
49
+ }
50
+
51
+ /**
52
+ * The catalog: every table the compiler may reference, keyed by table name. Produced
53
+ * statically by `rindle pg prepare` from an ephemeral migration-built Postgres (§7,
54
+ * Phase B); hand-authored for tests. A pure input — the compiler never touches a database
55
+ * to obtain it.
56
+ */
57
+ export interface Catalog {
58
+ tables: Record<string, TableSchema>;
59
+ }
@@ -0,0 +1,48 @@
1
+ // Ordering completion — the parity-critical pass (§8). The engine's builder appends the
2
+ // full primary key (as `asc`) to every `orderBy`, at every level, for a total order; this is
3
+ // a faithful port of `rindle::complete_ordering` (builder.rs:209), which is itself the port
4
+ // of the client builder's `completeOrdering`. Running the *same* completion is what makes the
5
+ // SELECT's row/child order match the engine's `Skip`/`Sort` tie-breaks exactly.
6
+ //
7
+ // Mutates `ast` in place (the caller passes a clone). `getPk(table)` yields a table's PK
8
+ // column names in PK order.
9
+
10
+ import type { Ast, Condition } from "./ast.ts";
11
+
12
+ export function completeOrdering(ast: Ast, getPk: (table: string) => string[]): void {
13
+ const pk = getPk(ast.table);
14
+ for (const csq of ast.related ?? []) {
15
+ completeOrdering(csq.subquery, getPk);
16
+ }
17
+ if (ast.where) {
18
+ completeOrderingInCondition(ast.where, getPk);
19
+ }
20
+ addPrimaryKeys(pk, ast);
21
+ }
22
+
23
+ function completeOrderingInCondition(cond: Condition, getPk: (table: string) => string[]): void {
24
+ switch (cond.type) {
25
+ case "simple":
26
+ return;
27
+ case "correlatedSubquery":
28
+ completeOrdering(cond.related.subquery, getPk);
29
+ return;
30
+ case "and":
31
+ case "or":
32
+ for (const c of cond.conditions) {
33
+ completeOrderingInCondition(c, getPk);
34
+ }
35
+ return;
36
+ }
37
+ }
38
+
39
+ /** Append each PK column not already present (matched by name), as `asc`, in PK order.
40
+ * Already-present PK columns keep their existing position and direction. */
41
+ function addPrimaryKeys(pk: string[], ast: Ast): void {
42
+ const order = (ast.orderBy ??= []);
43
+ for (const pkCol of pk) {
44
+ if (!order.some(([field]) => field === pkCol)) {
45
+ order.push([pkCol, "asc"]);
46
+ }
47
+ }
48
+ }
package/src/dialect.ts ADDED
@@ -0,0 +1,85 @@
1
+ // The dialect seam (§6.1). The walker is dialect-independent; only these leaves differ
2
+ // between SQLite and Postgres: the Postgres leaf carries the §6.2 `::text::<type>` casts and
3
+ // explicit NULLS ordering; the SQLite leaf binds natives with NO casts (the canonical store
4
+ // needs no reconciliation — DAEMON-INTERACTIVE-TXN-DESIGN.md §5.4).
5
+
6
+ import type { Dir } from "./ast.ts";
7
+ import type { ColumnType } from "./catalog.ts";
8
+
9
+ /** A scalar value bindable as a parameter (an array filter value is split into scalars). */
10
+ export type LitScalar = null | boolean | number | string;
11
+
12
+ export interface Dialect {
13
+ readonly name: "postgres" | "sqlite";
14
+
15
+ /** `json_object('k', v, …)` | `jsonb_build_object('k', v, …)`. `parts` are the flat
16
+ * `'key', valueExpr` fragments, in order. */
17
+ objectBuild(parts: string[]): string;
18
+
19
+ /** The array aggregate over `elem` with `orderSql` (e.g. ` ORDER BY __o0 ASC`) inside:
20
+ * `json_group_array(elem ORDER BY …)` | `jsonb_agg(elem ORDER BY …)`. */
21
+ groupArray(elem: string, orderSql: string): string;
22
+
23
+ /** The empty-array default for the `COALESCE` wrapper: `'[]'` | `'[]'::jsonb`. */
24
+ readonly emptyArray: string;
25
+
26
+ /** Re-assert the JSON subtype on a value round-tripped through a subquery's `AS` column
27
+ * (`json(x)` in SQLite; identity in Postgres, where `jsonb` is a real type). */
28
+ reassertJson(x: string): string;
29
+
30
+ /** The truthy/falsy constants for empty `AND`/`OR` folding and boolean keyword positions:
31
+ * `1`/`0` | `TRUE`/`FALSE`. */
32
+ readonly trueLit: string;
33
+ readonly falseLit: string;
34
+
35
+ /** An `ORDER BY` direction with the engine's null-low ordering made explicit where the
36
+ * dialect default differs (§8): SQLite is null-low by default (`ASC`/`DESC`); Postgres's
37
+ * default is the opposite, so it must emit `ASC NULLS FIRST` / `DESC NULLS LAST`. */
38
+ orderDir(dir: Dir): string;
39
+
40
+ /** Project a stored column into the value model's representation for the result JSON.
41
+ * Identity in SQLite; the outbound half of §6.2 in Postgres (e.g. timestamptz → epoch-ms). */
42
+ projectColumn(colRef: string, col: ColumnType | null): string;
43
+
44
+ /** Bind a scalar filter/paging value as a parameter: push onto `params`, return the
45
+ * placeholder SQL. `col` is the compared column's type when known (drives the Postgres
46
+ * `::text::<type>` casts, §6.2); `null` ⇒ infer from the JS type. SQLite ignores `col`
47
+ * and `isComparison` — it binds natives. */
48
+ bindValue(params: unknown[], value: LitScalar, col: ColumnType | null, isComparison: boolean): string;
49
+
50
+ /** Double-quote an identifier, doubling embedded `"`. Identical across dialects (kept on
51
+ * the seam for uniformity). */
52
+ quoteIdent(name: string): string;
53
+ }
54
+
55
+ function quoteIdent(name: string): string {
56
+ return `"${name.replace(/"/g, '""')}"`;
57
+ }
58
+
59
+ /**
60
+ * The SQLite dialect — the daemon backend's session-read target (DAEMON-INTERACTIVE-TXN §5.4)
61
+ * and the offline differential oracle (§9). It binds native values as parameters (no
62
+ * `::text::<type>` casts — SQLite is the canonical store, so there is no driver seam to pin
63
+ * and no second representation to reconcile), relies on SQLite's null-low default ordering
64
+ * (which matches the engine's `null < everything`), and re-asserts the `json()` subtype where
65
+ * objects round-trip through a subquery column. Matches `rindle-d2s`'s raw SQL shapes so the
66
+ * two agree modulo parameterization; the executing connection must run
67
+ * `PRAGMA case_sensitive_like = ON` (every daemon cluster connection does — `open_wal2`).
68
+ */
69
+ export const sqliteDialect: Dialect = {
70
+ name: "sqlite",
71
+ objectBuild: (parts) => `json_object(${parts.join(", ")})`,
72
+ groupArray: (elem, orderSql) => `json_group_array(${elem}${orderSql})`,
73
+ emptyArray: "'[]'",
74
+ reassertJson: (x) => `json(${x})`,
75
+ trueLit: "1",
76
+ falseLit: "0",
77
+ orderDir: (dir) => (dir === "asc" ? "ASC" : "DESC"),
78
+ projectColumn: (colRef) => colRef,
79
+ bindValue: (params, value) => {
80
+ // SQLite has no boolean type; its driver binds 1/0. Everything else binds natively.
81
+ params.push(typeof value === "boolean" ? (value ? 1 : 0) : value);
82
+ return "?";
83
+ },
84
+ quoteIdent,
85
+ };