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.
- package/dist/scp/authoring-sql.d.ts +78 -0
- package/dist/scp/authoring-sql.d.ts.map +1 -1
- package/dist/scp/authoring-sql.js +110 -2
- package/dist/scp/authoring-sql.js.map +1 -1
- package/dist/scp/catalog.d.ts +5 -2
- package/dist/scp/catalog.d.ts.map +1 -1
- package/dist/scp/catalog.js +32 -1
- package/dist/scp/catalog.js.map +1 -1
- package/dist/scp/codegen.d.ts +143 -85
- package/dist/scp/codegen.d.ts.map +1 -1
- package/dist/scp/codegen.js +374 -90
- package/dist/scp/codegen.js.map +1 -1
- package/dist/scp/coltype.d.ts +41 -0
- package/dist/scp/coltype.d.ts.map +1 -0
- package/dist/scp/coltype.js +188 -0
- package/dist/scp/coltype.js.map +1 -0
- package/dist/scp/dialect.d.ts +12 -3
- package/dist/scp/dialect.d.ts.map +1 -1
- package/dist/scp/dialect.js +12 -3
- package/dist/scp/dialect.js.map +1 -1
- package/dist/scp/find-filter-guard.d.ts +68 -0
- package/dist/scp/find-filter-guard.d.ts.map +1 -0
- package/dist/scp/find-filter-guard.js +88 -0
- package/dist/scp/find-filter-guard.js.map +1 -0
- package/dist/scp/fragment/assemble.d.ts +61 -0
- package/dist/scp/fragment/assemble.d.ts.map +1 -0
- package/dist/scp/fragment/assemble.js +156 -0
- package/dist/scp/fragment/assemble.js.map +1 -0
- package/dist/scp/fragment/compile-pg.d.ts +107 -0
- package/dist/scp/fragment/compile-pg.d.ts.map +1 -0
- package/dist/scp/fragment/compile-pg.js +142 -0
- package/dist/scp/fragment/compile-pg.js.map +1 -0
- package/dist/scp/fragment/index.d.ts +16 -0
- package/dist/scp/fragment/index.d.ts.map +1 -0
- package/dist/scp/fragment/index.js +34 -0
- package/dist/scp/fragment/index.js.map +1 -0
- package/dist/scp/fragment/model.d.ts +119 -0
- package/dist/scp/fragment/model.d.ts.map +1 -0
- package/dist/scp/fragment/model.js +66 -0
- package/dist/scp/fragment/model.js.map +1 -0
- package/dist/scp/fragment/pg-array-type.d.ts +13 -0
- package/dist/scp/fragment/pg-array-type.d.ts.map +1 -0
- package/dist/scp/fragment/pg-array-type.js +34 -0
- package/dist/scp/fragment/pg-array-type.js.map +1 -0
- package/dist/scp/guard.d.ts +2 -6
- package/dist/scp/guard.d.ts.map +1 -1
- package/dist/scp/guard.js +19 -22
- package/dist/scp/guard.js.map +1 -1
- package/dist/scp/index.cjs +18695 -3921
- package/dist/scp/index.d.ts +41 -24
- package/dist/scp/index.d.ts.map +1 -1
- package/dist/scp/index.js +134 -49
- package/dist/scp/index.js.map +1 -1
- package/dist/scp/index.mjs +4830 -1432
- package/dist/scp/makesql/authoring-compile.d.ts +90 -0
- package/dist/scp/makesql/authoring-compile.d.ts.map +1 -0
- package/dist/scp/makesql/authoring-compile.js +494 -0
- package/dist/scp/makesql/authoring-compile.js.map +1 -0
- package/dist/scp/makesql/compile-crud.d.ts +133 -0
- package/dist/scp/makesql/compile-crud.d.ts.map +1 -0
- package/dist/scp/makesql/compile-crud.js +288 -0
- package/dist/scp/makesql/compile-crud.js.map +1 -0
- package/dist/scp/makesql/compile-relation.d.ts +157 -0
- package/dist/scp/makesql/compile-relation.d.ts.map +1 -0
- package/dist/scp/makesql/compile-relation.js +425 -0
- package/dist/scp/makesql/compile-relation.js.map +1 -0
- package/dist/scp/makesql/compile-select.d.ts +52 -0
- package/dist/scp/makesql/compile-select.d.ts.map +1 -0
- package/dist/scp/makesql/compile-select.js +58 -0
- package/dist/scp/makesql/compile-select.js.map +1 -0
- package/dist/scp/makesql/compile.d.ts +63 -0
- package/dist/scp/makesql/compile.d.ts.map +1 -0
- package/dist/scp/makesql/compile.js +99 -0
- package/dist/scp/makesql/compile.js.map +1 -0
- package/dist/scp/makesql/handler.d.ts +58 -0
- package/dist/scp/makesql/handler.d.ts.map +1 -0
- package/dist/scp/makesql/handler.js +113 -0
- package/dist/scp/makesql/handler.js.map +1 -0
- package/dist/scp/makesql/index.d.ts +33 -0
- package/dist/scp/makesql/index.d.ts.map +1 -0
- package/dist/scp/makesql/index.js +114 -0
- package/dist/scp/makesql/index.js.map +1 -0
- package/dist/scp/makesql/ir.d.ts +42 -0
- package/dist/scp/makesql/ir.d.ts.map +1 -0
- package/dist/scp/makesql/ir.js +66 -0
- package/dist/scp/makesql/ir.js.map +1 -0
- package/dist/scp/makesql/json-array.d.ts +84 -0
- package/dist/scp/makesql/json-array.d.ts.map +1 -0
- package/dist/scp/makesql/json-array.js +118 -0
- package/dist/scp/makesql/json-array.js.map +1 -0
- package/dist/scp/makesql/json-batch.d.ts +102 -0
- package/dist/scp/makesql/json-batch.d.ts.map +1 -0
- package/dist/scp/makesql/json-batch.js +269 -0
- package/dist/scp/makesql/json-batch.js.map +1 -0
- package/dist/scp/makesql/makesql.d.ts +99 -0
- package/dist/scp/makesql/makesql.d.ts.map +1 -0
- package/dist/scp/makesql/makesql.js +122 -0
- package/dist/scp/makesql/makesql.js.map +1 -0
- package/dist/scp/makesql/outtype.d.ts +44 -0
- package/dist/scp/makesql/outtype.d.ts.map +1 -0
- package/dist/scp/makesql/outtype.js +197 -0
- package/dist/scp/makesql/outtype.js.map +1 -0
- package/dist/scp/makesql/pool-executor.d.ts +47 -0
- package/dist/scp/makesql/pool-executor.d.ts.map +1 -0
- package/dist/scp/makesql/pool-executor.js +50 -0
- package/dist/scp/makesql/pool-executor.js.map +1 -0
- package/dist/scp/makesql/static-bundle.d.ts +187 -0
- package/dist/scp/makesql/static-bundle.d.ts.map +1 -0
- package/dist/scp/makesql/static-bundle.js +1113 -0
- package/dist/scp/makesql/static-bundle.js.map +1 -0
- package/dist/scp/makesql/tx.d.ts +216 -0
- package/dist/scp/makesql/tx.d.ts.map +1 -0
- package/dist/scp/makesql/tx.js +788 -0
- package/dist/scp/makesql/tx.js.map +1 -0
- package/dist/scp/makesql/writeouttype.d.ts +66 -0
- package/dist/scp/makesql/writeouttype.d.ts.map +1 -0
- package/dist/scp/makesql/writeouttype.js +195 -0
- package/dist/scp/makesql/writeouttype.js.map +1 -0
- package/dist/scp/relation.d.ts +86 -74
- package/dist/scp/relation.d.ts.map +1 -1
- package/dist/scp/relation.js +186 -120
- package/dist/scp/relation.js.map +1 -1
- package/dist/scp/runtime.d.ts +158 -211
- package/dist/scp/runtime.d.ts.map +1 -1
- package/dist/scp/runtime.js +250 -515
- package/dist/scp/runtime.js.map +1 -1
- package/dist/scp/typed-object.d.ts +12 -1
- package/dist/scp/typed-object.d.ts.map +1 -1
- package/dist/scp/typed-object.js +25 -4
- package/dist/scp/typed-object.js.map +1 -1
- package/docs/proposal/litedbmodel-v2-scp-architecture.md +51 -0
- package/docs/proposal/v0-coverage-matrix.md +157 -0
- package/docs/proposal/v2-completeness-plan.md +90 -0
- package/docs/proposal/v2-sql-parity-checklist.md +162 -0
- package/package.json +3 -3
- package/dist/scp/bridge.d.ts +0 -64
- package/dist/scp/bridge.d.ts.map +0 -1
- package/dist/scp/bridge.js +0 -329
- package/dist/scp/bridge.js.map +0 -1
- package/dist/scp/compile-dialect.d.ts +0 -39
- package/dist/scp/compile-dialect.d.ts.map +0 -1
- package/dist/scp/compile-dialect.js +0 -62
- package/dist/scp/compile-dialect.js.map +0 -1
- package/dist/scp/compile-sqlite.d.ts +0 -114
- package/dist/scp/compile-sqlite.d.ts.map +0 -1
- package/dist/scp/compile-sqlite.js +0 -149
- package/dist/scp/compile-sqlite.js.map +0 -1
- package/dist/scp/ir.d.ts +0 -92
- package/dist/scp/ir.d.ts.map +0 -1
- package/dist/scp/ir.js +0 -28
- package/dist/scp/ir.js.map +0 -1
- package/dist/scp/render.d.ts +0 -40
- package/dist/scp/render.d.ts.map +0 -1
- package/dist/scp/render.js +0 -170
- package/dist/scp/render.js.map +0 -1
- package/dist/scp/write-plan.d.ts +0 -161
- package/dist/scp/write-plan.d.ts.map +0 -1
- package/dist/scp/write-plan.js +0 -528
- package/dist/scp/write-plan.js.map +0 -1
- package/dist/scp/write-runtime.d.ts +0 -80
- package/dist/scp/write-runtime.d.ts.map +0 -1
- package/dist/scp/write-runtime.js +0 -167
- package/dist/scp/write-runtime.js.map +0 -1
package/dist/scp/relation.js
CHANGED
|
@@ -1,189 +1,255 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* litedbmodel v2 SCP —
|
|
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
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
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
|
|
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}
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
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
|
|
23
|
+
* ## ONE relation op, TWO surfaces (spec §5)
|
|
24
24
|
*
|
|
25
|
-
* Both read surfaces trigger the IDENTICAL compiled {@link
|
|
26
|
-
*
|
|
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
|
|
44
|
-
const
|
|
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}
|
|
49
|
-
* batch query selects the child rows whose {@link RelationDecl.targetKey} is in
|
|
50
|
-
* parent-key set.
|
|
51
|
-
*
|
|
52
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
79
|
+
dialect,
|
|
80
|
+
...conn,
|
|
81
|
+
sql,
|
|
65
82
|
};
|
|
66
83
|
}
|
|
67
|
-
/**
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
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
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
return
|
|
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
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
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
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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
|
-
|
|
117
|
-
const
|
|
118
|
-
|
|
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
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
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 }
|
|
136
|
-
*
|
|
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
|
|
197
|
+
const pCols = parentKeyCols(op);
|
|
198
|
+
const keys = dedupeKeys(parents, pCols);
|
|
142
199
|
const batch = new Map();
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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
|
|
151
|
-
|
|
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 =
|
|
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
|
|
222
|
+
return { sql, keys, batch };
|
|
161
223
|
}
|
|
162
|
-
/**
|
|
163
|
-
|
|
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
|
|
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 =
|
|
236
|
+
const s = keyIdentity(tuple);
|
|
171
237
|
if (seen.has(s))
|
|
172
238
|
continue;
|
|
173
239
|
seen.add(s);
|
|
174
|
-
out.push(
|
|
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`/`
|
|
182
|
-
*
|
|
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
|
|
186
|
-
const rows =
|
|
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;
|
package/dist/scp/relation.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relation.js","sourceRoot":"","sources":["../../src/scp/relation.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"relation.js","sourceRoot":"","sources":["../../src/scp/relation.ts"],"names":[],"mappings":"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"}
|