litedbmodel 2.0.0 → 2.0.2

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 (163) hide show
  1. package/dist/scp/authoring-sql.d.ts +78 -0
  2. package/dist/scp/authoring-sql.d.ts.map +1 -1
  3. package/dist/scp/authoring-sql.js +110 -2
  4. package/dist/scp/authoring-sql.js.map +1 -1
  5. package/dist/scp/catalog.d.ts +5 -2
  6. package/dist/scp/catalog.d.ts.map +1 -1
  7. package/dist/scp/catalog.js +32 -1
  8. package/dist/scp/catalog.js.map +1 -1
  9. package/dist/scp/codegen.d.ts +143 -85
  10. package/dist/scp/codegen.d.ts.map +1 -1
  11. package/dist/scp/codegen.js +374 -90
  12. package/dist/scp/codegen.js.map +1 -1
  13. package/dist/scp/coltype.d.ts +41 -0
  14. package/dist/scp/coltype.d.ts.map +1 -0
  15. package/dist/scp/coltype.js +188 -0
  16. package/dist/scp/coltype.js.map +1 -0
  17. package/dist/scp/dialect.d.ts +12 -3
  18. package/dist/scp/dialect.d.ts.map +1 -1
  19. package/dist/scp/dialect.js +12 -3
  20. package/dist/scp/dialect.js.map +1 -1
  21. package/dist/scp/find-filter-guard.d.ts +68 -0
  22. package/dist/scp/find-filter-guard.d.ts.map +1 -0
  23. package/dist/scp/find-filter-guard.js +88 -0
  24. package/dist/scp/find-filter-guard.js.map +1 -0
  25. package/dist/scp/fragment/assemble.d.ts +61 -0
  26. package/dist/scp/fragment/assemble.d.ts.map +1 -0
  27. package/dist/scp/fragment/assemble.js +156 -0
  28. package/dist/scp/fragment/assemble.js.map +1 -0
  29. package/dist/scp/fragment/compile-pg.d.ts +107 -0
  30. package/dist/scp/fragment/compile-pg.d.ts.map +1 -0
  31. package/dist/scp/fragment/compile-pg.js +142 -0
  32. package/dist/scp/fragment/compile-pg.js.map +1 -0
  33. package/dist/scp/fragment/index.d.ts +16 -0
  34. package/dist/scp/fragment/index.d.ts.map +1 -0
  35. package/dist/scp/fragment/index.js +34 -0
  36. package/dist/scp/fragment/index.js.map +1 -0
  37. package/dist/scp/fragment/model.d.ts +119 -0
  38. package/dist/scp/fragment/model.d.ts.map +1 -0
  39. package/dist/scp/fragment/model.js +66 -0
  40. package/dist/scp/fragment/model.js.map +1 -0
  41. package/dist/scp/fragment/pg-array-type.d.ts +13 -0
  42. package/dist/scp/fragment/pg-array-type.d.ts.map +1 -0
  43. package/dist/scp/fragment/pg-array-type.js +34 -0
  44. package/dist/scp/fragment/pg-array-type.js.map +1 -0
  45. package/dist/scp/guard.d.ts +2 -6
  46. package/dist/scp/guard.d.ts.map +1 -1
  47. package/dist/scp/guard.js +19 -22
  48. package/dist/scp/guard.js.map +1 -1
  49. package/dist/scp/index.cjs +18695 -3921
  50. package/dist/scp/index.d.ts +41 -24
  51. package/dist/scp/index.d.ts.map +1 -1
  52. package/dist/scp/index.js +134 -49
  53. package/dist/scp/index.js.map +1 -1
  54. package/dist/scp/index.mjs +4830 -1432
  55. package/dist/scp/makesql/authoring-compile.d.ts +90 -0
  56. package/dist/scp/makesql/authoring-compile.d.ts.map +1 -0
  57. package/dist/scp/makesql/authoring-compile.js +494 -0
  58. package/dist/scp/makesql/authoring-compile.js.map +1 -0
  59. package/dist/scp/makesql/compile-crud.d.ts +133 -0
  60. package/dist/scp/makesql/compile-crud.d.ts.map +1 -0
  61. package/dist/scp/makesql/compile-crud.js +288 -0
  62. package/dist/scp/makesql/compile-crud.js.map +1 -0
  63. package/dist/scp/makesql/compile-relation.d.ts +157 -0
  64. package/dist/scp/makesql/compile-relation.d.ts.map +1 -0
  65. package/dist/scp/makesql/compile-relation.js +425 -0
  66. package/dist/scp/makesql/compile-relation.js.map +1 -0
  67. package/dist/scp/makesql/compile-select.d.ts +52 -0
  68. package/dist/scp/makesql/compile-select.d.ts.map +1 -0
  69. package/dist/scp/makesql/compile-select.js +58 -0
  70. package/dist/scp/makesql/compile-select.js.map +1 -0
  71. package/dist/scp/makesql/compile.d.ts +63 -0
  72. package/dist/scp/makesql/compile.d.ts.map +1 -0
  73. package/dist/scp/makesql/compile.js +99 -0
  74. package/dist/scp/makesql/compile.js.map +1 -0
  75. package/dist/scp/makesql/handler.d.ts +58 -0
  76. package/dist/scp/makesql/handler.d.ts.map +1 -0
  77. package/dist/scp/makesql/handler.js +113 -0
  78. package/dist/scp/makesql/handler.js.map +1 -0
  79. package/dist/scp/makesql/index.d.ts +33 -0
  80. package/dist/scp/makesql/index.d.ts.map +1 -0
  81. package/dist/scp/makesql/index.js +114 -0
  82. package/dist/scp/makesql/index.js.map +1 -0
  83. package/dist/scp/makesql/ir.d.ts +42 -0
  84. package/dist/scp/makesql/ir.d.ts.map +1 -0
  85. package/dist/scp/makesql/ir.js +66 -0
  86. package/dist/scp/makesql/ir.js.map +1 -0
  87. package/dist/scp/makesql/json-array.d.ts +84 -0
  88. package/dist/scp/makesql/json-array.d.ts.map +1 -0
  89. package/dist/scp/makesql/json-array.js +118 -0
  90. package/dist/scp/makesql/json-array.js.map +1 -0
  91. package/dist/scp/makesql/json-batch.d.ts +102 -0
  92. package/dist/scp/makesql/json-batch.d.ts.map +1 -0
  93. package/dist/scp/makesql/json-batch.js +269 -0
  94. package/dist/scp/makesql/json-batch.js.map +1 -0
  95. package/dist/scp/makesql/makesql.d.ts +99 -0
  96. package/dist/scp/makesql/makesql.d.ts.map +1 -0
  97. package/dist/scp/makesql/makesql.js +122 -0
  98. package/dist/scp/makesql/makesql.js.map +1 -0
  99. package/dist/scp/makesql/outtype.d.ts +44 -0
  100. package/dist/scp/makesql/outtype.d.ts.map +1 -0
  101. package/dist/scp/makesql/outtype.js +197 -0
  102. package/dist/scp/makesql/outtype.js.map +1 -0
  103. package/dist/scp/makesql/pool-executor.d.ts +47 -0
  104. package/dist/scp/makesql/pool-executor.d.ts.map +1 -0
  105. package/dist/scp/makesql/pool-executor.js +50 -0
  106. package/dist/scp/makesql/pool-executor.js.map +1 -0
  107. package/dist/scp/makesql/static-bundle.d.ts +187 -0
  108. package/dist/scp/makesql/static-bundle.d.ts.map +1 -0
  109. package/dist/scp/makesql/static-bundle.js +1113 -0
  110. package/dist/scp/makesql/static-bundle.js.map +1 -0
  111. package/dist/scp/makesql/tx.d.ts +216 -0
  112. package/dist/scp/makesql/tx.d.ts.map +1 -0
  113. package/dist/scp/makesql/tx.js +788 -0
  114. package/dist/scp/makesql/tx.js.map +1 -0
  115. package/dist/scp/makesql/writeouttype.d.ts +66 -0
  116. package/dist/scp/makesql/writeouttype.d.ts.map +1 -0
  117. package/dist/scp/makesql/writeouttype.js +195 -0
  118. package/dist/scp/makesql/writeouttype.js.map +1 -0
  119. package/dist/scp/relation.d.ts +86 -74
  120. package/dist/scp/relation.d.ts.map +1 -1
  121. package/dist/scp/relation.js +186 -120
  122. package/dist/scp/relation.js.map +1 -1
  123. package/dist/scp/runtime.d.ts +158 -211
  124. package/dist/scp/runtime.d.ts.map +1 -1
  125. package/dist/scp/runtime.js +250 -515
  126. package/dist/scp/runtime.js.map +1 -1
  127. package/dist/scp/typed-object.d.ts +12 -1
  128. package/dist/scp/typed-object.d.ts.map +1 -1
  129. package/dist/scp/typed-object.js +25 -4
  130. package/dist/scp/typed-object.js.map +1 -1
  131. package/docs/proposal/litedbmodel-v2-scp-architecture.md +51 -0
  132. package/docs/proposal/v0-coverage-matrix.md +157 -0
  133. package/docs/proposal/v2-completeness-plan.md +90 -0
  134. package/docs/proposal/v2-sql-parity-checklist.md +162 -0
  135. package/package.json +3 -3
  136. package/dist/scp/bridge.d.ts +0 -64
  137. package/dist/scp/bridge.d.ts.map +0 -1
  138. package/dist/scp/bridge.js +0 -329
  139. package/dist/scp/bridge.js.map +0 -1
  140. package/dist/scp/compile-dialect.d.ts +0 -39
  141. package/dist/scp/compile-dialect.d.ts.map +0 -1
  142. package/dist/scp/compile-dialect.js +0 -62
  143. package/dist/scp/compile-dialect.js.map +0 -1
  144. package/dist/scp/compile-sqlite.d.ts +0 -114
  145. package/dist/scp/compile-sqlite.d.ts.map +0 -1
  146. package/dist/scp/compile-sqlite.js +0 -149
  147. package/dist/scp/compile-sqlite.js.map +0 -1
  148. package/dist/scp/ir.d.ts +0 -92
  149. package/dist/scp/ir.d.ts.map +0 -1
  150. package/dist/scp/ir.js +0 -28
  151. package/dist/scp/ir.js.map +0 -1
  152. package/dist/scp/render.d.ts +0 -40
  153. package/dist/scp/render.d.ts.map +0 -1
  154. package/dist/scp/render.js +0 -170
  155. package/dist/scp/render.js.map +0 -1
  156. package/dist/scp/write-plan.d.ts +0 -161
  157. package/dist/scp/write-plan.d.ts.map +0 -1
  158. package/dist/scp/write-plan.js +0 -528
  159. package/dist/scp/write-plan.js.map +0 -1
  160. package/dist/scp/write-runtime.d.ts +0 -80
  161. package/dist/scp/write-runtime.d.ts.map +0 -1
  162. package/dist/scp/write-runtime.js +0 -167
  163. package/dist/scp/write-runtime.js.map +0 -1
@@ -1,189 +1,255 @@
1
1
  "use strict";
2
2
  /**
3
- * litedbmodel v2 SCP — Relation ops (Read) + staged batch resolution (WS4, #24).
3
+ * litedbmodel v2 SCP — Read relations: pre-compiled batch op + staged batch resolution (WS4,
4
+ * #24; makeSQL re-expression, epic #43/#45 Phase B).
4
5
  *
5
- * Relations are NOT SQL JOINs by default (spec §5). They are the same
6
- * staged-batch query-composition + object-assembly shape graphddb and v1 `LazyRelation`
7
- * use: collect the parent key set of a result page, run ONE batched child SELECT
8
- * (`fk IN (…)` / per-parent-limited `ROW_NUMBER()` window), then distribute the child rows
9
- * back to their parents. This makes a relation load structurally bounded — one batched
10
- * query per relation edge, NEVER one-per-parent (no N+1).
6
+ * Relations are NOT SQL JOINs by default (spec §5). They are the staged-batch
7
+ * query-composition + object-assembly shape v1's `LazyRelation` uses: collect the parent key
8
+ * set of a result page, run ONE batched child SELECT keyed by the deduped parent keys, then
9
+ * distribute the child rows back to their parents. One batched query per relation edge, NEVER
10
+ * one-per-parent (no N+1).
11
11
  *
12
- * ## The relation op is a pre-compiled artifact (spec §8)
12
+ * ## The relation op is a STATIC makeSQL artifact (design #45)
13
13
  *
14
- * A {@link RelationOp} is compiled ONCE from a model {@link RelationDecl}, dialect-aware
15
- * (SQLite for α), into the SAME {@link CompiledOperation} shape WS1 already emits for a
16
- * Select — so it renders through the SAME normative {@link renderOperation} (fragment tree
17
- * + IN-list `(?, ?, …)` expansion, spec §5). It carries NO functions and lands in the §8
18
- * bundle (`SqlBundle.relations`) as pure JSON, so a thin per-language runtime (WS7) gets
19
- * the relation batch SQL for free. The v1 `LazyRelation` batch-SQL assets (IN-list, the
20
- * `ROW_NUMBER() OVER (PARTITION BY … )` per-parent limit) are reused here as the compiled
21
- * content, not re-invented.
14
+ * A {@link RelationOp} is compiled ONCE from a model {@link RelationDecl} into a STATIC
15
+ * `makeSQL` batch SELECT via the makeSQL relation builders (`./makesql/compile-relation`) —
16
+ * byte-identical to the ORIGINAL `LazyRelation` SQL for PostgreSQL (`= ANY(?::type[])`,
17
+ * `CROSS JOIN LATERAL`, `UNNEST`), and the single-JSON-param server-side form for MySQL/SQLite
18
+ * (`json_each` / `JSON_TABLE`). The deduped key array binds as ONE param with STATIC text (no
19
+ * placeholder-count expansion), so `op.sql` is fixed and value-independent — pure JSON, lands
20
+ * in the bundle, a per-language runtime executes it directly. The REDUCED
21
+ * `CompiledOperation`/`renderOperation`/`IN (?)`-expansion forms are GONE.
22
22
  *
23
- * ## ONE relation op, TWO surfaces (spec §5 / feasibility §9)
23
+ * ## ONE relation op, TWO surfaces (spec §5)
24
24
  *
25
- * Both read surfaces trigger the IDENTICAL compiled {@link RelationOp} via
26
- * {@link runRelationOp} — there is exactly one batch-execution code path:
27
- *
28
- * - **Declarative select** (`with: { author: true }`): the planner resolves sibling
29
- * relations eagerly, dedups the parent key set, prefetch-optimized (staged batch).
30
- * - **Lazy** (`await post.author`): a prototype getter + a non-enumerable Symbol batch
31
- * context (graphddb's `GRAPHDDB_KEY` technique) fires the SAME op at access time over
32
- * the whole sibling set (batch, so still no N+1 — it just can't prefetch).
33
- *
34
- * `runRelationOp` renders `op.query` once for the deduped parent key set and returns the
35
- * child rows grouped by parent key. Both surfaces call it; a test asserts they resolve via
36
- * the same compiled op (same SQL text), not two parallel code paths.
25
+ * Both read surfaces trigger the IDENTICAL compiled op via {@link runRelationOp}:
26
+ * - **Declarative select** (`with: { author: true }`): batch-prefetched over the page.
27
+ * - **Lazy** (`await post.author`): a prototype getter fires the SAME op over the sibling set.
37
28
  */
38
29
  Object.defineProperty(exports, "__esModule", { value: true });
39
30
  exports.RELATION_KEYS_HEAD = void 0;
40
31
  exports.compileRelationOp = compileRelationOp;
41
32
  exports.runRelationOp = runRelationOp;
42
33
  exports.distributeToParent = distributeToParent;
43
- const render_1 = require("./render");
44
- const ir_1 = require("./ir");
34
+ const makesql_1 = require("./makesql/makesql");
35
+ const handler_1 = require("./makesql/handler");
36
+ const compile_relation_1 = require("./makesql/compile-relation");
45
37
  /** The reserved input head the relation batch query binds its deduped key array to. */
46
38
  exports.RELATION_KEYS_HEAD = '__keys';
47
39
  /**
48
- * Compile ONE {@link RelationDecl} into a {@link RelationOp} for SQLite (α dialect). The
49
- * batch query selects the child rows whose {@link RelationDecl.targetKey} is in the deduped
50
- * parent-key set. Reuses the existing IN-list fragment + `renderOperation` expansion (no new
51
- * SQL machinery). A `hasMany` with `limit` compiles to the v1 `ROW_NUMBER()` window form so
52
- * the per-parent cap holds in a single batched statement.
40
+ * Compile ONE {@link RelationDecl} into a STATIC {@link RelationOp} via the makeSQL relation
41
+ * builders. The batch query selects the child rows whose {@link RelationDecl.targetKey} is in
42
+ * the deduped parent-key set. PG stays byte-identical to v1's `LazyRelation`; MySQL/SQLite use
43
+ * the single-JSON-param server-side form. A `hasMany` with `limit` compiles to the per-parent
44
+ * LATERAL (PG) / ROW_NUMBER (MySQL·SQLite) form. The SQL text is FIXED (the array binds as one
45
+ * param regardless of length), so it needs no per-input recompile.
53
46
  */
54
47
  function compileRelationOp(decl) {
55
48
  if (decl.kind !== 'hasMany' && decl.limit !== undefined) {
56
49
  throw new Error(`relation '${decl.name}': a per-parent 'limit' is only valid for hasMany (got ${decl.kind})`);
57
50
  }
58
- const query = decl.limit !== undefined ? compileLimitedBatch(decl) : compilePlainBatch(decl);
51
+ if (decl.limit !== undefined && (!Number.isInteger(decl.limit) || decl.limit < 0)) {
52
+ throw new Error(`relation '${decl.name}': per-parent limit must be a non-negative integer (got ${String(decl.limit)})`);
53
+ }
54
+ if (decl.limit !== undefined && decl.order === undefined) {
55
+ throw new Error(`relation '${decl.name}': a per-parent 'limit' requires an explicit 'order' (the per-parent window needs a deterministic ordering to decide which ${decl.limit} rows each parent keeps)`);
56
+ }
57
+ const dialect = decl.dialect ?? 'sqlite';
58
+ const composite = isCompositeDecl(decl);
59
+ const sql = compiledBatchSql(decl, dialect);
60
+ // CROSS-DB (V0 R1): carry the target connection tag ONLY when set (a same-DB relation stays
61
+ // untagged, so existing bundles are byte-unchanged — the field is additive/optional).
62
+ const conn = decl.connection !== undefined ? { connection: decl.connection } : {};
63
+ if (composite) {
64
+ return {
65
+ name: decl.name,
66
+ kind: decl.kind,
67
+ parentKeys: [...decl.parentKeys],
68
+ targetKeys: [...decl.targetKeys],
69
+ dialect,
70
+ ...conn,
71
+ sql,
72
+ };
73
+ }
59
74
  return {
60
75
  name: decl.name,
61
76
  kind: decl.kind,
62
77
  parentKey: decl.parentKey,
63
78
  targetKey: decl.targetKey,
64
- query,
79
+ dialect,
80
+ ...conn,
81
+ sql,
65
82
  };
66
83
  }
67
- /** The IN-list membership slot binding the deduped key array (`{ref:[RELATION_KEYS_HEAD]}`). */
68
- function keysRef() {
69
- return { ref: [exports.RELATION_KEYS_HEAD] };
84
+ /**
85
+ * A relation decl is COMPOSITE iff it carries `parentKeys`/`targetKeys` arrays. Validates the two
86
+ * are present together, equal-length (paired positionally), and non-empty; and that the single-key
87
+ * `parentKey`/`targetKey` are NOT also set (mutually exclusive). Single-key iff both arrays absent.
88
+ */
89
+ function isCompositeDecl(decl) {
90
+ const hasArrays = decl.parentKeys !== undefined || decl.targetKeys !== undefined;
91
+ if (!hasArrays) {
92
+ if (decl.parentKey === undefined || decl.targetKey === undefined) {
93
+ throw new Error(`relation '${decl.name}': a single-key relation requires 'parentKey' and 'targetKey'`);
94
+ }
95
+ return false;
96
+ }
97
+ if (decl.parentKeys === undefined || decl.targetKeys === undefined) {
98
+ throw new Error(`relation '${decl.name}': a composite-key relation requires BOTH 'parentKeys' and 'targetKeys'`);
99
+ }
100
+ if (decl.parentKeys.length === 0 || decl.parentKeys.length !== decl.targetKeys.length) {
101
+ throw new Error(`relation '${decl.name}': 'parentKeys' and 'targetKeys' must be non-empty and equal-length (got ${decl.parentKeys.length} vs ${decl.targetKeys.length})`);
102
+ }
103
+ if (decl.parentKey !== undefined || decl.targetKey !== undefined) {
104
+ throw new Error(`relation '${decl.name}': cannot mix single-key ('parentKey'/'targetKey') with composite ('parentKeys'/'targetKeys')`);
105
+ }
106
+ return true;
70
107
  }
71
108
  /**
72
- * Plain batch (`belongsTo`/`hasOne`/unlimited `hasMany`):
73
- * `SELECT <cols> FROM <target>{where}[ ORDER BY <o>]` with `{where}` = `targetKey IN (?)`.
74
- * The `(?)` expands to one `?` per deduped key at render time (dynamic-expansion spec §5).
109
+ * Compile the STATIC batch SELECT text: the makeSQL relation builder emits complete tuned SQL
110
+ * whose deduped-key array is ONE param. We compile against a single placeholder key array so
111
+ * the text is fixed; the runtime re-binds the real deduped keys against the SAME text (the
112
+ * single-JSON / `= ANY` forms are length-independent, so the text is stable).
75
113
  */
76
- function compilePlainBatch(decl) {
77
- const cols = decl.select.join(', ');
78
- const inFragment = {
79
- always: true,
80
- sql: `${decl.targetKey} IN (?)`,
81
- params: [keysRef()],
82
- expand: 0,
114
+ function compiledBatchSql(decl, dialect) {
115
+ // A COMPOSITE decl compiles to the STATIC composite form (PG: one array param per key column;
116
+ // MySQL/SQLite: one JSON array-of-tuples param) — length-independent, so the text is fixed. A
117
+ // per-parent `limit` selects the STATIC composite-LIMITED builder (PG LATERAL / MySQL·SQLite
118
+ // ROW_NUMBER window over the SAME static key-set predicate — #47 last completeness gap).
119
+ if (decl.parentKeys !== undefined) {
120
+ const compositeBase = {
121
+ dialect,
122
+ tableName: decl.targetTable,
123
+ select: decl.select.join(', '),
124
+ order: decl.order,
125
+ targetKeys: [...decl.targetKeys],
126
+ deferPgArrayCast: true,
127
+ };
128
+ const node = decl.limit !== undefined
129
+ ? (0, compile_relation_1.compileCompositeKeyStaticLimited)({ ...compositeBase, limit: decl.limit })
130
+ : (0, compile_relation_1.compileCompositeKeyStaticUnlimited)(compositeBase);
131
+ return (0, makesql_1.assembleMakeSQL)(node).sql;
132
+ }
133
+ // A one-element placeholder key set fixes the SQL text (single-JSON-param / `= ANY` forms are
134
+ // value-length-independent). The concrete keys are bound at execute time.
135
+ const placeholderKeys = [null];
136
+ const base = {
137
+ dialect,
138
+ tableName: decl.targetTable,
139
+ select: decl.select.join(', '),
140
+ order: decl.order,
141
+ targetKey: decl.targetKey,
142
+ values: placeholderKeys,
143
+ // The keys are UNKNOWN at symbolic compile (placeholder set), so the PG `= ANY(?::<T>[])`
144
+ // element type is DEFERRED to render (#46) — resolved from the real deduped keys via
145
+ // `inferPgArrayType`, reproducing v1's live-correct cast (`::int[]` for int keys). Baking a
146
+ // compile-time `text[]` here was the #43 regression (`integer = text` on real PG).
147
+ deferPgArrayCast: true,
83
148
  };
84
- const where = { connector: 'AND', fragments: [inFragment] };
85
- let sql = `SELECT ${cols} FROM ${decl.targetTable}${ir_1.WHERE_SLOT}`;
86
- if (decl.order !== undefined)
87
- sql += ` ORDER BY ${decl.order}`;
88
- return { component: 'Select', sql, where, params: [], assembly: { shape: 'items' } };
149
+ const node = decl.limit !== undefined
150
+ ? (0, compile_relation_1.compileSingleKeyLimited)({ ...base, limit: decl.limit })
151
+ : (0, compile_relation_1.compileSingleKeyUnlimited)(base);
152
+ // The builder emits the SQL with ONE `?` (the whole key array). Assemble to the flat text.
153
+ return (0, makesql_1.assembleMakeSQL)(node).sql;
154
+ }
155
+ /** The ordered PARENT key columns of an op (single-key → 1-element list; composite → the tuple). */
156
+ function parentKeyCols(op) {
157
+ return op.parentKeys ?? [op.parentKey];
158
+ }
159
+ /** The ordered CHILD key columns of an op (single-key → 1-element list; composite → the tuple). */
160
+ function targetKeyCols(op) {
161
+ return op.targetKeys ?? [op.targetKey];
162
+ }
163
+ /** The stringified key identity for dedupe/grouping. Single scalar → `String(v)`; tuple → joined. */
164
+ function keyIdentity(values) {
165
+ // A NUL separator no scalar `String(v)` contains, so distinct tuples never collide.
166
+ return values.map((v) => String(v)).join('');
89
167
  }
90
168
  /**
91
- * Per-parent-limited `hasMany` batch — v1's SQLite `ROW_NUMBER()` window form:
92
- *
93
- * WITH ranked AS (
94
- * SELECT <cols>, ROW_NUMBER() OVER (PARTITION BY <targetKey> ORDER BY <order>) AS _rn
95
- * FROM <target>{where} -- {where} = targetKey IN (?)
96
- * )
97
- * SELECT <cols> FROM ranked WHERE _rn <= <limit>
98
- *
99
- * The `{where}` splice keeps the IN-list expansion (spec §5). `_rn` is a synthetic window
100
- * column dropped from the final projection, so the child typed-object own props stay exactly
101
- * `select`. `limit` is inlined as a literal integer (a compiled per-parent cap from the decl,
102
- * NOT a runtime-bound value — the decl is the SSoT), mirroring v1's `_rn <= ${limit}`.
169
+ * Bind the deduped keys to the batch op's params per dialect + arity. Single-key: PG binds the
170
+ * scalar array verbatim (`= ANY(?::t[])`); MySQL/SQLite bind the JSON-encoded array. Composite: PG
171
+ * binds ONE array param PER key column (transposed tuples → `unnest(?::t1[], ?::t2[])`);
172
+ * MySQL/SQLite bind ONE JSON array-of-tuples string. Returns the positional param list.
103
173
  */
104
- function compileLimitedBatch(decl) {
105
- const cols = decl.select.join(', ');
106
- const limit = decl.limit;
107
- if (!Number.isInteger(limit) || limit < 0) {
108
- throw new Error(`relation '${decl.name}': per-parent limit must be a non-negative integer (got ${String(limit)})`);
109
- }
110
- // A per-parent limit REQUIRES a deterministic ORDER BY (the window decides WHICH `limit`
111
- // rows each parent keeps). Absent order = fail-closed authoring error, NOT a silent default
112
- // — the relation declaration is the SSoT for the per-parent ordering.
113
- if (decl.order === undefined) {
114
- throw new Error(`relation '${decl.name}': a per-parent 'limit' requires an explicit 'order' (the ROW_NUMBER() window needs a deterministic ordering to decide which ${limit} rows each parent keeps)`);
174
+ function bindKeys(op, tuples) {
175
+ const composite = op.parentKeys !== undefined;
176
+ if (op.dialect === 'postgres') {
177
+ if (!composite)
178
+ return [tuples.map((t) => t[0])]; // ONE scalar array param
179
+ // Transpose tuples → per-column arrays: `[[1,a],[2,b]] → [[1,2],[a,b]]` — one array param each.
180
+ return parentKeyCols(op).map((_, col) => tuples.map((t) => t[col]));
115
181
  }
116
- const order = decl.order;
117
- const inFragment = {
118
- always: true,
119
- sql: `${decl.targetKey} IN (?)`,
120
- params: [keysRef()],
121
- expand: 0,
122
- };
123
- const where = { connector: 'AND', fragments: [inFragment] };
124
- const sql = `WITH ranked AS (SELECT ${cols}, ROW_NUMBER() OVER (PARTITION BY ${decl.targetKey} ORDER BY ${order}) AS _rn ` +
125
- `FROM ${decl.targetTable}${ir_1.WHERE_SLOT}) ` +
126
- `SELECT ${cols} FROM ranked WHERE _rn <= ${limit}`;
127
- return { component: 'Select', sql, where, params: [], assembly: { shape: 'items' } };
182
+ // MySQL/SQLite: single-key → JSON scalar array; composite → JSON array-of-tuples. ONE param.
183
+ const payload = composite ? tuples.map((t) => [...t]) : tuples.map((t) => t[0]);
184
+ return [JSON.stringify(payload)];
128
185
  }
129
186
  /**
130
- * Run ONE {@link RelationOp} for a set of parent rows: dedup the parent keys, render + execute
131
- * the batched child SELECT ONCE (real SQLite), and group the child rows by their target key.
132
- * This is the single batch primitive BOTH the declarative-select and the lazy surface invoke —
133
- * proving the "same relation op" invariant structurally (there is no second path).
187
+ * Run ONE {@link RelationOp} for a set of parent rows: dedup the parent-key tuples, render the
188
+ * STATIC batch SELECT once (dialect placeholder form) resolving the deferred PG array cast(s) from
189
+ * the REAL keys, execute it with the keys bound (single array / per-column arrays / JSON tuples),
190
+ * then group the child rows by their target-key identity. The single batch primitive BOTH the
191
+ * declarative-select and the lazy surface invoke, single-key AND composite.
134
192
  *
135
- * Returns `{ sql, keys, batch }`: the rendered SQL (so a caller can assert both surfaces
136
- * produced the same text), the deduped keys bound, and the grouping. When there are no
137
- * non-null parent keys the query is NOT issued (an empty batch, matching v1) — this is not a
138
- * fallback default, it is the correct empty-set behavior (an IN over no keys selects nothing).
193
+ * Returns `{ sql, keys, batch }` (`keys` = the deduped parent-key tuples). An empty key set issues
194
+ * NO query (the correct empty-set behavior — the membership over no keys selects nothing).
139
195
  */
140
196
  function runRelationOp(op, parents, db) {
141
- const keys = dedupeKeys(parents, op.parentKey);
197
+ const pCols = parentKeyCols(op);
198
+ const keys = dedupeKeys(parents, pCols);
142
199
  const batch = new Map();
143
- if (keys.length === 0) {
144
- // No parent keys → no batched query issued, empty grouping. Still render the SQL (for
145
- // the same-op assertion) against the empty key set so the IN-list `1 = 0` degeneration
146
- // is observable, but do not touch the driver.
147
- const rendered = (0, render_1.renderOperation)(op.query, { [exports.RELATION_KEYS_HEAD]: [] });
148
- return { sql: rendered.sql, keys, batch };
200
+ // Resolve the deferred PG array cast(s) (#46) from the REAL keys BEFORE the `?`→`$N` render. A
201
+ // single-key op has ONE cast; a composite PG op has ONE cast PER key column — resolve each from
202
+ // its own column's key values, left-to-right (resolvePgArrayCast resolves the first token each
203
+ // call). MySQL/SQLite carry no cast token.
204
+ let cast = op.sql;
205
+ if (op.dialect === 'postgres') {
206
+ for (let col = 0; col < pCols.length; col++)
207
+ cast = (0, compile_relation_1.resolvePgArrayCast)(cast, keys.map((t) => t[col]));
149
208
  }
150
- const rendered = (0, render_1.renderOperation)(op.query, { [exports.RELATION_KEYS_HEAD]: keys });
151
- const rows = db.prepare(rendered.sql).all(...rendered.params);
209
+ const sql = (0, handler_1.renderPlaceholders)(cast, op.dialect);
210
+ if (keys.length === 0)
211
+ return { sql, keys, batch };
212
+ const tCols = targetKeyCols(op);
213
+ const rows = db.prepare(sql).all(...bindKeys(op, keys));
152
214
  for (const row of rows) {
153
- const k = String(row[op.targetKey]);
215
+ const k = keyIdentity(tCols.map((c) => row[c]));
154
216
  const list = batch.get(k);
155
217
  if (list === undefined)
156
218
  batch.set(k, [row]);
157
219
  else
158
220
  list.push(row);
159
221
  }
160
- return { sql: rendered.sql, keys, batch };
222
+ return { sql, keys, batch };
161
223
  }
162
- /** The deduped, non-null parent-key values (insertion order preserved — deterministic). */
163
- function dedupeKeys(parents, parentKey) {
224
+ /**
225
+ * The deduped, non-null parent-key TUPLES (insertion order preserved — deterministic). A tuple is
226
+ * dropped if ANY of its key columns is null/undefined (no partial keys). Deduped on the stringified
227
+ * tuple identity (so `1` and `"1"` collapse exactly as `String(v)`).
228
+ */
229
+ function dedupeKeys(parents, keyCols) {
164
230
  const seen = new Set();
165
231
  const out = [];
166
232
  for (const p of parents) {
167
- const v = p[parentKey];
168
- if (v === undefined || v === null)
233
+ const tuple = keyCols.map((c) => p[c]);
234
+ if (tuple.some((v) => v === undefined || v === null))
169
235
  continue;
170
- const s = String(v);
236
+ const s = keyIdentity(tuple);
171
237
  if (seen.has(s))
172
238
  continue;
173
239
  seen.add(s);
174
- out.push(v);
240
+ out.push(tuple);
175
241
  }
176
242
  return out;
177
243
  }
178
244
  /**
179
245
  * Distribute a resolved {@link RelationBatch} onto ONE parent per the relation cardinality:
180
246
  * `hasMany` → the child list (`[]` when none); `belongsTo`/`hasOne` → the single child (or
181
- * `null`). `null`/`undefined` is the correct absence value (an unresolved single relation),
182
- * NOT an ad-hoc default — it is the declared cardinality's empty representation.
247
+ * `null`). Keyed by the parent's key-tuple identity. `null`/`[]` is the declared cardinality's
248
+ * empty representation, not an ad-hoc default.
183
249
  */
184
250
  function distributeToParent(op, parent, batch) {
185
- const key = parent[op.parentKey];
186
- const rows = key === undefined || key === null ? undefined : batch.get(String(key));
251
+ const tuple = parentKeyCols(op).map((c) => parent[c]);
252
+ const rows = tuple.some((v) => v === undefined || v === null) ? undefined : batch.get(keyIdentity(tuple));
187
253
  if (op.kind === 'hasMany')
188
254
  return rows ?? [];
189
255
  return rows !== undefined && rows.length > 0 ? rows[0] : null;
@@ -1 +1 @@
1
- {"version":3,"file":"relation.js","sourceRoot":"","sources":["../../src/scp/relation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"relation.js","sourceRoot":"","sources":["../../src/scp/relation.ts"],"names":[],"mappings":"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"}