@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
@@ -0,0 +1,107 @@
1
+ // Postgres type classification — the predicates that decide which `::text::<type>` cast a
2
+ // value gets (§6.2). Ported verbatim from mono's `zero-cache/src/types/pg-data-type.ts` (the
3
+ // maps + `formatTypeForLookup`), plus the temporal helpers the projection reconciliation needs.
4
+ // Keeping these faithful to z2s is what keeps the filter-side casts bug-for-bug aligned.
5
+ // The map *values* are irrelevant to the predicates (they test key membership); kept as in
6
+ // mono for fidelity and in case the value-type mapping is needed later.
7
+ const pgToZqlNumericTypeMap = Object.freeze({
8
+ smallint: "number",
9
+ integer: "number",
10
+ int: "number",
11
+ int2: "number",
12
+ int4: "number",
13
+ int8: "number",
14
+ bigint: "number",
15
+ smallserial: "number",
16
+ serial: "number",
17
+ serial2: "number",
18
+ serial4: "number",
19
+ serial8: "number",
20
+ bigserial: "number",
21
+ decimal: "number",
22
+ numeric: "number",
23
+ real: "number",
24
+ "double precision": "number",
25
+ float: "number",
26
+ float4: "number",
27
+ float8: "number",
28
+ });
29
+ const pgToZqlNativeStringTypeMap = Object.freeze({
30
+ bpchar: "string",
31
+ character: "string",
32
+ "character varying": "string",
33
+ text: "string",
34
+ varchar: "string",
35
+ });
36
+ const pgToZqlTextRepresentedTypeMap = Object.freeze({
37
+ cidr: "string",
38
+ ean13: "string",
39
+ inet: "string",
40
+ isbn: "string",
41
+ isbn13: "string",
42
+ ismn: "string",
43
+ ismn13: "string",
44
+ issn: "string",
45
+ issn13: "string",
46
+ macaddr: "string",
47
+ macaddr8: "string",
48
+ pg_lsn: "string",
49
+ upc: "string",
50
+ uuid: "string",
51
+ });
52
+ const pgToZqlStringTypeMap = Object.freeze({
53
+ ...pgToZqlNativeStringTypeMap,
54
+ ...pgToZqlTextRepresentedTypeMap,
55
+ });
56
+ /** Strips args (the `(32)` in `char(32)`) and lowercases — mono's `formatTypeForLookup`.
57
+ * Every predicate normalizes through this, so `VARCHAR(255)` / `UUID` classify correctly. */
58
+ export function formatTypeForLookup(pgType) {
59
+ const startOfArgs = pgType.indexOf("(");
60
+ if (startOfArgs === -1)
61
+ return pgType.toLowerCase();
62
+ return pgType.toLowerCase().substring(0, startOfArgs);
63
+ }
64
+ export function isPgNumberType(pgType) {
65
+ return Object.hasOwn(pgToZqlNumericTypeMap, formatTypeForLookup(pgType));
66
+ }
67
+ export function isPgNativeStringType(pgType) {
68
+ return Object.hasOwn(pgToZqlNativeStringTypeMap, formatTypeForLookup(pgType));
69
+ }
70
+ export function isPgTextRepresentedType(pgType) {
71
+ return Object.hasOwn(pgToZqlTextRepresentedTypeMap, formatTypeForLookup(pgType));
72
+ }
73
+ export function isPgStringType(pgType) {
74
+ return Object.hasOwn(pgToZqlStringTypeMap, formatTypeForLookup(pgType));
75
+ }
76
+ // ── temporal helpers (projection reconciliation, §6.2) ──────────────────────────────────────
77
+ const TEMPORAL_TYPES = new Set([
78
+ "date",
79
+ "time",
80
+ "time without time zone",
81
+ "time with time zone",
82
+ "timetz",
83
+ "timestamp",
84
+ "timestamp without time zone",
85
+ "timestamp with time zone",
86
+ "timestamptz",
87
+ ]);
88
+ /** A temporal type projected as epoch-ms (outbound) and reconciled via `to_timestamp`/interval
89
+ * (inbound). Everything else projects raw. */
90
+ export function isTemporalType(pgType) {
91
+ return TEMPORAL_TYPES.has(formatTypeForLookup(pgType));
92
+ }
93
+ // Offset-bearing time-of-day types: `EXTRACT(EPOCH FROM …)` can go negative (e.g. 01:00+02 =
94
+ // 23:00 UTC prev day = -3600s), so the outbound projection normalizes into 0..86_400_000 ms.
95
+ const TIME_OF_DAY_TZ_TYPES = new Set(["timetz", "time with time zone"]);
96
+ /**
97
+ * Whether an outbound temporal projection needs the `mod 1 day` normalization. **Deliberately
98
+ * narrower than z2s's `selectIdent`**, which (via a switch fall-through) also normalizes
99
+ * `timestamptz` — that would collapse a full timestamp to time-of-day. The design (§6.2) is
100
+ * explicit that `timestamptz` projects as plain epoch-ms and only the offset-bearing
101
+ * *time-of-day* types are modular-normalized; the §9 parity harness against the engine's value
102
+ * model is the check that keeps this honest.
103
+ */
104
+ export function needsTimeOfDayNormalization(pgType) {
105
+ return TIME_OF_DAY_TZ_TYPES.has(formatTypeForLookup(pgType));
106
+ }
107
+ //# sourceMappingURL=pg-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pg-types.js","sourceRoot":"","sources":["../src/pg-types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { Dialect } from "./dialect.ts";
2
+ /**
3
+ * The Postgres dialect — the BYO-Postgres server-mutator read target. Emits `(sql, params)`
4
+ * with `$N::text::<type>` parameters and never imports a driver (Invariant 7).
5
+ */
6
+ export declare const postgresDialect: Dialect;
7
+ //# sourceMappingURL=postgres.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../src/postgres.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,OAAO,EAAa,MAAM,cAAc,CAAC;AAqHvD;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,OAY7B,CAAC"}
@@ -0,0 +1,134 @@
1
+ // The Postgres dialect leaf (§6.1/§6.2) — the product target. The walker is shared with the
2
+ // SQLite oracle; this file supplies only the Postgres-specific leaves:
3
+ //
4
+ // - JSON assembly via `jsonb_build_object` / `jsonb_agg` / `'[]'::jsonb` (the design's §6.1
5
+ // choice — the direct analogue of `rindle-d2s`'s `json_object`, NOT z2s's `row_to_json`);
6
+ // - explicit `ASC NULLS FIRST` / `DESC NULLS LAST` (§8 — Postgres's default is the opposite
7
+ // of the engine's null-low order);
8
+ // - the outbound projection reconciliation (temporal → epoch-ms);
9
+ // - the inbound filter/paging cast strategy `$N::text::<type>`, ported verbatim from z2s's
10
+ // `sql.ts` — the `::text` intermediate pins the driver's parameter description to text, and
11
+ // the `::<type>` half is value-model↔native reconciliation (§6.2). Values are parameterized.
12
+ //
13
+ // NOTE: `$N` numbering is per-occurrence (no de-duplication of repeated values). z2s reuses a
14
+ // placeholder for a repeated (value,type); that is a plan-cache optimization, not correctness —
15
+ // deferred (203 §7 posture).
16
+ import { formatTypeForLookup, isPgNativeStringType, isPgNumberType, isPgStringType, isPgTextRepresentedType, isTemporalType, needsTimeOfDayNormalization, } from "./pg-types.js";
17
+ function quoteIdent(name) {
18
+ return `"${name.replace(/"/g, '""')}"`;
19
+ }
20
+ /** The Postgres cast for a literal whose type is inferred from its JS value (no column). */
21
+ function pgTypeForLiteralType(litType) {
22
+ // `double precision` is IEEE-754 like a JS number, so it round-trips any zql number exactly.
23
+ return litType === "boolean" ? "boolean" : litType === "number" ? "double precision" : "text";
24
+ }
25
+ /**
26
+ * The inbound value↔native cast for a filter/paging value against a known column type — the
27
+ * verbatim port of z2s's `formatCommonToSingularAndPlural` (`sql.ts:194`). `vp` is the value
28
+ * placeholder (`$N`, or `value` inside an array unnest). `isComparison` widens strings to bare
29
+ * `text` and numbers to `double precision` so neither is forced to the column's width/precision.
30
+ */
31
+ function pgCast(vp, type, isEnum, isComparison) {
32
+ const t = formatTypeForLookup(type);
33
+ // Temporal: epoch-ms ↔ native. The zone-naive spellings get `AT TIME ZONE 'UTC'`.
34
+ if (t === "timestamptz" || t === "timestamp with time zone") {
35
+ return `to_timestamp(${vp}::text::numeric / 1000.0)`;
36
+ }
37
+ if (t === "date" || t === "timestamp" || t === "timestamp without time zone") {
38
+ return `to_timestamp(${vp}::text::numeric / 1000.0) AT TIME ZONE 'UTC'`;
39
+ }
40
+ if (t === "timetz" || t === "time with time zone") {
41
+ return `(${vp}::text::int * interval'1ms')::time`;
42
+ }
43
+ if (t === "time" || t === "time without time zone") {
44
+ return `(${vp}::text::int * interval'1ms')::time AT TIME ZONE 'UTC'`;
45
+ }
46
+ if (t === "uuid")
47
+ return `${vp}::text::uuid`;
48
+ if (isEnum)
49
+ return `${vp}::text::"${type}"`;
50
+ if (isPgNativeStringType(type))
51
+ return isComparison ? `${vp}::text` : `${vp}::text::${type}`;
52
+ if (isPgTextRepresentedType(type))
53
+ return `${vp}::text::${type}`;
54
+ if (isPgNumberType(type)) {
55
+ return isComparison ? `${vp}::text::double precision` : `${vp}::text::${type}`;
56
+ }
57
+ return `${vp}::text::${type}`;
58
+ }
59
+ /** The text-pinned serialization of a bound value — z2s's `stringify` (`sql.ts:120`). Strings
60
+ * and enum/string columns bind their raw text; everything else binds its JSON text form so the
61
+ * `$N::text::…` cast re-parses it authoritatively. */
62
+ function stringifyForColumn(value, col) {
63
+ if (value === null)
64
+ return null;
65
+ if (col.isArray)
66
+ return JSON.stringify(value);
67
+ if (col.isEnum || isPgStringType(col.type))
68
+ return String(value);
69
+ return JSON.stringify(value);
70
+ }
71
+ function bindValue(params, value, col, isComparison) {
72
+ const idx = params.length + 1;
73
+ // Free literal (no column context): infer the cast from the JS type.
74
+ if (col === null) {
75
+ if (value === null) {
76
+ params.push(null);
77
+ return `$${idx}`;
78
+ }
79
+ const litType = typeof value;
80
+ params.push(litType === "string" ? value : JSON.stringify(value));
81
+ return `$${idx}::text::${pgTypeForLiteralType(litType)}`;
82
+ }
83
+ params.push(stringifyForColumn(value, col));
84
+ if (value === null && col.isArray)
85
+ return `$${idx}`;
86
+ if (col.isArray) {
87
+ // Unnest a JSON array param, casting each element (z2s's `formatPlural`, `sql.ts:260`).
88
+ return `ARRAY(SELECT ${pgCast("value", col.type, col.isEnum, isComparison)} FROM jsonb_array_elements_text($${idx}::text::jsonb))`;
89
+ }
90
+ return pgCast(`$${idx}`, col.type, col.isEnum, isComparison);
91
+ }
92
+ /**
93
+ * Project a stored column into the value model's representation (§6.2 outbound half). Temporal
94
+ * columns become **integer epoch-ms** — the value model always snaps to whole milliseconds, so
95
+ * `::bigint` rounds off the native µs resolution (unlike z2s, which projects the non-normalized
96
+ * path as an unsnapped float). Time-of-day-with-offset types additionally wrap `mod 1 day`.
97
+ * Enums (their label), uuid, numeric, json, and the scalar types project raw. See
98
+ * `needsTimeOfDayNormalization` for the deliberate divergence from z2s on `timestamptz`.
99
+ *
100
+ * The rounding mode (`::bigint` = round-half-to-even) must match pg-source's projector for exact
101
+ * parity — it is the one shared value-model contract (§10), not an independent choice here.
102
+ */
103
+ function projectColumn(colRef, col) {
104
+ if (!col || col.isEnum || !isTemporalType(col.type))
105
+ return colRef;
106
+ const normalize = needsTimeOfDayNormalization(col.type);
107
+ const toMs = (epoch) => normalize ? `((${epoch})::bigint + 86400000) % 86400000` : `(${epoch})::bigint`;
108
+ if (col.isArray) {
109
+ return `CASE WHEN ${colRef} IS NULL THEN NULL ELSE ARRAY(SELECT ${toMs(`EXTRACT(EPOCH FROM unnest(${colRef})) * 1000`)}) END`;
110
+ }
111
+ return toMs(`EXTRACT(EPOCH FROM ${colRef}) * 1000`);
112
+ }
113
+ function orderDir(dir) {
114
+ // Engine order is null-low; Postgres's default is the opposite, so make it explicit (§8).
115
+ return dir === "asc" ? "ASC NULLS FIRST" : "DESC NULLS LAST";
116
+ }
117
+ /**
118
+ * The Postgres dialect — the BYO-Postgres server-mutator read target. Emits `(sql, params)`
119
+ * with `$N::text::<type>` parameters and never imports a driver (Invariant 7).
120
+ */
121
+ export const postgresDialect = {
122
+ name: "postgres",
123
+ objectBuild: (parts) => `jsonb_build_object(${parts.join(", ")})`,
124
+ groupArray: (elem, orderSql) => `jsonb_agg(${elem}${orderSql})`,
125
+ emptyArray: "'[]'::jsonb",
126
+ reassertJson: (x) => x, // jsonb is a real type; no re-assert needed
127
+ trueLit: "TRUE",
128
+ falseLit: "FALSE",
129
+ orderDir,
130
+ projectColumn,
131
+ bindValue,
132
+ quoteIdent,
133
+ };
134
+ //# sourceMappingURL=postgres.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres.js","sourceRoot":"","sources":["../src/postgres.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Ast } from "./ast.ts";
2
+ export declare function rejectUnsupported(ast: Ast): void;
3
+ //# sourceMappingURL=reject.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reject.d.ts","sourceRoot":"","sources":["../src/reject.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,GAAG,EAAa,MAAM,UAAU,CAAC;AAG/C,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAahD"}
package/dist/reject.js ADDED
@@ -0,0 +1,74 @@
1
+ // Reject AST features the compiler does not lower, anywhere in the tree — so an unhandled
2
+ // field fails loudly rather than producing silently-wrong SQL. Faithful port of
3
+ // `rindle-d2s`'s `reject_unsupported` family (lib.rs:194).
4
+ //
5
+ // `start` (a paging bound) is lowered as a keyset predicate, but only on the **materialized
6
+ // collections** the compiler emits (the root and each `related` child). It is *not* honored
7
+ // inside an EXISTS/NOT EXISTS subquery, nor inside a `count(child)` aggregate — a `start`
8
+ // there is rejected here rather than silently dropped.
9
+ import { unsupported } from "./errors.js";
10
+ export function rejectUnsupported(ast) {
11
+ for (const rel of ast.related ?? []) {
12
+ if (rel.subquery.aggregate) {
13
+ // A `count(child)` aggregate reduces its rows away: a `start`/`limit`/nested `related`
14
+ // would change the IVM count but `count_expr` ignores them — reject rather than diverge.
15
+ rejectAggregateSubquery(rel.subquery);
16
+ }
17
+ else {
18
+ rejectUnsupported(rel.subquery); // collection: start honored, recurse
19
+ }
20
+ }
21
+ if (ast.where) {
22
+ rejectUnsupportedCond(ast.where);
23
+ }
24
+ }
25
+ function rejectAggregateSubquery(ast) {
26
+ if (ast.start)
27
+ throw unsupported("start inside a count aggregate");
28
+ if (ast.limit !== undefined)
29
+ throw unsupported("limit inside a count aggregate");
30
+ if (ast.related && ast.related.length > 0) {
31
+ throw unsupported("nested related inside a count aggregate");
32
+ }
33
+ if (ast.where)
34
+ rejectUnsupportedCond(ast.where);
35
+ }
36
+ function rejectUnsupportedCond(cond) {
37
+ switch (cond.type) {
38
+ case "simple":
39
+ return;
40
+ case "correlatedSubquery":
41
+ rejectStartAnywhere(cond.related.subquery); // EXISTS: its `start` is not honored
42
+ return;
43
+ case "and":
44
+ case "or":
45
+ for (const c of cond.conditions)
46
+ rejectUnsupportedCond(c);
47
+ return;
48
+ }
49
+ }
50
+ /** Reject a `start` bound *anywhere* in `ast` (the EXISTS subtrees the compiler does not
51
+ * page). Conservative: rejects even positions a clever lowering might honor. */
52
+ function rejectStartAnywhere(ast) {
53
+ if (ast.start)
54
+ throw unsupported("start (paging) inside an EXISTS subquery");
55
+ for (const rel of ast.related ?? [])
56
+ rejectStartAnywhere(rel.subquery);
57
+ if (ast.where)
58
+ rejectStartAnywhereCond(ast.where);
59
+ }
60
+ function rejectStartAnywhereCond(cond) {
61
+ switch (cond.type) {
62
+ case "simple":
63
+ return;
64
+ case "correlatedSubquery":
65
+ rejectStartAnywhere(cond.related.subquery);
66
+ return;
67
+ case "and":
68
+ case "or":
69
+ for (const c of cond.conditions)
70
+ rejectStartAnywhereCond(c);
71
+ return;
72
+ }
73
+ }
74
+ //# sourceMappingURL=reject.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reject.js","sourceRoot":"","sources":["../src/reject.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,gFAAgF;AAChF,2DAA2D;AAC3D,EAAE;AACF,4FAA4F;AAC5F,4FAA4F;AAC5F,0FAA0F;AAC1F,uDAAuD;AAGvD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,UAAU,iBAAiB,CAAC,GAAQ;IACxC,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;QACpC,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC;YAC3B,uFAAuF;YACvF,yFAAyF;YACzF,uBAAuB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACxC,CAAC;aAAM,CAAC;YACN,iBAAiB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,qCAAqC;QACxE,CAAC;IACH,CAAC;IACD,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;QACd,qBAAqB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC;AACH,CAAC;AAED,SAAS,uBAAuB,CAAC,GAAQ;IACvC,IAAI,GAAG,CAAC,KAAK;QAAE,MAAM,WAAW,CAAC,gCAAgC,CAAC,CAAC;IACnE,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS;QAAE,MAAM,WAAW,CAAC,gCAAgC,CAAC,CAAC;IACjF,IAAI,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1C,MAAM,WAAW,CAAC,yCAAyC,CAAC,CAAC;IAC/D,CAAC;IACD,IAAI,GAAG,CAAC,KAAK;QAAE,qBAAqB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AAClD,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAe;IAC5C,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,QAAQ;YACX,OAAO;QACT,KAAK,oBAAoB;YACvB,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,qCAAqC;YACjF,OAAO;QACT,KAAK,KAAK,CAAC;QACX,KAAK,IAAI;YACP,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,UAAU;gBAAE,qBAAqB,CAAC,CAAC,CAAC,CAAC;YAC1D,OAAO;IACX,CAAC;AACH,CAAC;AAED;iFACiF;AACjF,SAAS,mBAAmB,CAAC,GAAQ;IACnC,IAAI,GAAG,CAAC,KAAK;QAAE,MAAM,WAAW,CAAC,0CAA0C,CAAC,CAAC;IAC7E,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,IAAI,EAAE;QAAE,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACvE,IAAI,GAAG,CAAC,KAAK;QAAE,uBAAuB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACpD,CAAC;AAED,SAAS,uBAAuB,CAAC,IAAe;IAC9C,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,QAAQ;YACX,OAAO;QACT,KAAK,oBAAoB;YACvB,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YAC3C,OAAO;QACT,KAAK,KAAK,CAAC;QACX,KAAK,IAAI;YACP,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,UAAU;gBAAE,uBAAuB,CAAC,CAAC,CAAC,CAAC;YAC5D,OAAO;IACX,CAAC;AACH,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { Ast } from "./ast.ts";
2
+ import type { Catalog } from "./catalog.ts";
3
+ import type { Dialect } from "./dialect.ts";
4
+ export interface Compiled {
5
+ sql: string;
6
+ params: unknown[];
7
+ }
8
+ /** Compile `ast` against `catalog` for `dialect`. `singular` ⇒ a `.one()` root (single
9
+ * object or `null`); else a plural root (a JSON array). Pure: mutates only a clone. */
10
+ export declare function compileWith(ast: Ast, catalog: Catalog, dialect: Dialect, singular: boolean): Compiled;
11
+ //# sourceMappingURL=walker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"walker.d.ts","sourceRoot":"","sources":["../src/walker.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,GAAG,EAQJ,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,OAAO,EAAc,MAAM,cAAc,CAAC;AACxD,OAAO,KAAK,EAAE,OAAO,EAAa,MAAM,cAAc,CAAC;AAgBvD,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,OAAO,EAAE,CAAC;CACnB;AAED;wFACwF;AACxF,wBAAgB,WAAW,CACzB,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,OAAO,GAChB,QAAQ,CAOV"}