litedbmodel 1.2.9 → 2.0.0
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/README.md +1 -1
- package/dist/DBModel.d.ts.map +1 -1
- package/dist/DBModel.js +6 -0
- package/dist/DBModel.js.map +1 -1
- package/dist/scp/authoring-sql.d.ts +56 -0
- package/dist/scp/authoring-sql.d.ts.map +1 -0
- package/dist/scp/authoring-sql.js +83 -0
- package/dist/scp/authoring-sql.js.map +1 -0
- package/dist/scp/authoring.d.ts +155 -0
- package/dist/scp/authoring.d.ts.map +1 -0
- package/dist/scp/authoring.js +162 -0
- package/dist/scp/authoring.js.map +1 -0
- package/dist/scp/bridge.d.ts +64 -0
- package/dist/scp/bridge.d.ts.map +1 -0
- package/dist/scp/bridge.js +329 -0
- package/dist/scp/bridge.js.map +1 -0
- package/dist/scp/catalog.d.ts +91 -0
- package/dist/scp/catalog.d.ts.map +1 -0
- package/dist/scp/catalog.js +203 -0
- package/dist/scp/catalog.js.map +1 -0
- package/dist/scp/codegen.d.ts +131 -0
- package/dist/scp/codegen.d.ts.map +1 -0
- package/dist/scp/codegen.js +137 -0
- package/dist/scp/codegen.js.map +1 -0
- package/dist/scp/compile-dialect.d.ts +39 -0
- package/dist/scp/compile-dialect.d.ts.map +1 -0
- package/dist/scp/compile-dialect.js +62 -0
- package/dist/scp/compile-dialect.js.map +1 -0
- package/dist/scp/compile-sqlite.d.ts +114 -0
- package/dist/scp/compile-sqlite.d.ts.map +1 -0
- package/dist/scp/compile-sqlite.js +149 -0
- package/dist/scp/compile-sqlite.js.map +1 -0
- package/dist/scp/dialect.d.ts +141 -0
- package/dist/scp/dialect.d.ts.map +1 -0
- package/dist/scp/dialect.js +194 -0
- package/dist/scp/dialect.js.map +1 -0
- package/dist/scp/errors.d.ts +36 -0
- package/dist/scp/errors.d.ts.map +1 -0
- package/dist/scp/errors.js +72 -0
- package/dist/scp/errors.js.map +1 -0
- package/dist/scp/guard.d.ts +47 -0
- package/dist/scp/guard.d.ts.map +1 -0
- package/dist/scp/guard.js +137 -0
- package/dist/scp/guard.js.map +1 -0
- package/dist/scp/index.cjs +4744 -0
- package/dist/scp/index.d.ts +49 -0
- package/dist/scp/index.d.ts.map +1 -0
- package/dist/scp/index.js +164 -0
- package/dist/scp/index.js.map +1 -0
- package/dist/scp/index.mjs +2000 -0
- package/dist/scp/ir.d.ts +92 -0
- package/dist/scp/ir.d.ts.map +1 -0
- package/dist/scp/ir.js +28 -0
- package/dist/scp/ir.js.map +1 -0
- package/dist/scp/relation.d.ts +136 -0
- package/dist/scp/relation.d.ts.map +1 -0
- package/dist/scp/relation.js +191 -0
- package/dist/scp/relation.js.map +1 -0
- package/dist/scp/render.d.ts +40 -0
- package/dist/scp/render.d.ts.map +1 -0
- package/dist/scp/render.js +170 -0
- package/dist/scp/render.js.map +1 -0
- package/dist/scp/runtime.d.ts +295 -0
- package/dist/scp/runtime.d.ts.map +1 -0
- package/dist/scp/runtime.js +665 -0
- package/dist/scp/runtime.js.map +1 -0
- package/dist/scp/typed-object.d.ts +88 -0
- package/dist/scp/typed-object.d.ts.map +1 -0
- package/dist/scp/typed-object.js +163 -0
- package/dist/scp/typed-object.js.map +1 -0
- package/dist/scp/write-plan.d.ts +161 -0
- package/dist/scp/write-plan.d.ts.map +1 -0
- package/dist/scp/write-plan.js +528 -0
- package/dist/scp/write-plan.js.map +1 -0
- package/dist/scp/write-runtime.d.ts +80 -0
- package/dist/scp/write-runtime.d.ts.map +1 -0
- package/dist/scp/write-runtime.js +167 -0
- package/dist/scp/write-runtime.js.map +1 -0
- package/dist/scp/writes.d.ts +251 -0
- package/dist/scp/writes.d.ts.map +1 -0
- package/dist/scp/writes.js +176 -0
- package/dist/scp/writes.js.map +1 -0
- package/docs/proposal/contracts-architecture-feasibility.md +328 -0
- package/docs/proposal/contracts-architecture.md +579 -0
- package/docs/proposal/litedbmodel-v2-scp-architecture.md +382 -0
- package/docs/proposal/sql-dynamic-expansion-spec.md +175 -0
- package/package.json +27 -5
- package/docs/README_REVIEW.md +0 -23
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* litedbmodel v2 SCP — fragment-tree render + param assembly (WS1, #21).
|
|
4
|
+
*
|
|
5
|
+
* The NORMATIVE reference implementation of `docs/proposal/sql-dynamic-expansion-spec.md`.
|
|
6
|
+
* Given a compiled operation and a bound input scope, it deterministically produces the
|
|
7
|
+
* final SQLite SQL text (`?` placeholders) and the flat params array. Every multi-language
|
|
8
|
+
* runtime (WS3) must reproduce this byte-for-byte; this TS implementation is the golden
|
|
9
|
+
* reference the conformance harness pins.
|
|
10
|
+
*
|
|
11
|
+
* The three moving parts (dynamic-expansion spec):
|
|
12
|
+
* §2 SKIP → fragment existence: a fragment with `when` is present iff `when` evaluates
|
|
13
|
+
* to a present (non-null / true) binding; an absent fragment contributes NO SQL and
|
|
14
|
+
* NO params.
|
|
15
|
+
* §3 empty-WHERE degeneration: if no fragment is present the whole `{where}` splice
|
|
16
|
+
* (including the ` WHERE ` keyword) collapses to the empty string.
|
|
17
|
+
* §4 AND/OR structure + parenthesization: a nested tree renders `(… <connector> …)`.
|
|
18
|
+
* §5 IN-list array expansion: a fragment slot marked `expand` turns its `(?)` into
|
|
19
|
+
* `(?, ?, …)` for each element of the bound array (0 elements → the `1 = 0`
|
|
20
|
+
* always-false degeneration, byte-identical to litedbmodel v1's empty-IN handling).
|
|
21
|
+
*/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.renderOperation = renderOperation;
|
|
24
|
+
const behavior_contracts_1 = require("behavior-contracts");
|
|
25
|
+
const ir_1 = require("./ir");
|
|
26
|
+
const dialect_1 = require("./dialect");
|
|
27
|
+
/** A fragment tree carries a `connector`; a fragment carries `sql`. */
|
|
28
|
+
function isTree(node) {
|
|
29
|
+
return 'connector' in node;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* SKIP existence rule (dynamic-expansion spec §2): a fragment is present iff it is
|
|
33
|
+
* `always`, or its `when` Expression evaluates to a PRESENT binding — `null` and `false`
|
|
34
|
+
* are absent; everything else (including `0`, `""`) is present. This mirrors bc's
|
|
35
|
+
* strict-bool discipline: `when` is expected to be an explicit presence/bool Expression
|
|
36
|
+
* (e.g. `{ne:[{refOpt:["status"]}, null]}` in bc's flat scope), evaluated fail-closed by
|
|
37
|
+
* evaluateExpression.
|
|
38
|
+
*/
|
|
39
|
+
function fragmentPresent(f, scope) {
|
|
40
|
+
if (f.always === true)
|
|
41
|
+
return true;
|
|
42
|
+
if (f.when === undefined)
|
|
43
|
+
return false; // fail-closed: neither always nor when
|
|
44
|
+
const v = (0, behavior_contracts_1.evaluateExpression)(f.when, scope);
|
|
45
|
+
return v !== null && v !== false;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Render one leaf fragment's SQL + params into the accumulators. Handles IN-list
|
|
49
|
+
* expansion (spec §5): the slot at `expand` is an array; its `(?)` in `sql` becomes
|
|
50
|
+
* `(?, ?, …)` and each element is pushed as its own param.
|
|
51
|
+
*/
|
|
52
|
+
function renderFragment(f, scope, params) {
|
|
53
|
+
if (f.expand === undefined) {
|
|
54
|
+
for (const slot of f.params)
|
|
55
|
+
params.push((0, behavior_contracts_1.evaluateExpression)(slot, scope));
|
|
56
|
+
return f.sql;
|
|
57
|
+
}
|
|
58
|
+
// IN-list expansion. Evaluate all slots; the `expand` slot must be an array.
|
|
59
|
+
let sql = f.sql;
|
|
60
|
+
for (let i = 0; i < f.params.length; i++) {
|
|
61
|
+
const v = (0, behavior_contracts_1.evaluateExpression)(f.params[i], scope);
|
|
62
|
+
if (i === f.expand) {
|
|
63
|
+
if (!Array.isArray(v)) {
|
|
64
|
+
throw new Error(`IN-list expansion slot ${i} did not bind to an array (got ${v === null ? 'null' : typeof v})`);
|
|
65
|
+
}
|
|
66
|
+
if (v.length === 0) {
|
|
67
|
+
// Empty-array degeneration (dynamic-expansion spec §5): the whole `col IN (?)`
|
|
68
|
+
// fragment collapses to the always-false sentinel `1 = 0` — byte-identical to
|
|
69
|
+
// litedbmodel v1's DBConditions (an empty IN pushes NO params). The `col IN`
|
|
70
|
+
// prefix and the `(?)` slot are BOTH replaced.
|
|
71
|
+
sql = '1 = 0';
|
|
72
|
+
// no params pushed for this slot
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
// Replace the single `(?)` with `(?, ?, …)` sized to the array; push each element.
|
|
76
|
+
sql = sql.replace('(?)', `(${v.map(() => '?').join(', ')})`);
|
|
77
|
+
for (const el of v)
|
|
78
|
+
params.push(el);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
params.push(v);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return sql;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Render a fragment tree into a WHERE clause body (no leading ` WHERE ` keyword).
|
|
89
|
+
* Present fragments are joined by ` <connector> `; a nested tree is parenthesized
|
|
90
|
+
* (spec §4). Returns the empty string when NO fragment is present (degeneration, §3).
|
|
91
|
+
*
|
|
92
|
+
* Each fragment's `sql` already carries its own leading connector prefix when authored as
|
|
93
|
+
* a chained condition (e.g. `" AND status = ?"`), so this function STRIPS the accumulated
|
|
94
|
+
* connector from the first present fragment to avoid a dangling leading `AND`/`OR`, then
|
|
95
|
+
* joins the rest as-authored. To keep the golden output identical to litedbmodel v1 (which
|
|
96
|
+
* builds `parts.join(' AND ')` with no leading connector), fragment `sql` at the top level
|
|
97
|
+
* is authored WITHOUT a leading connector and joined here.
|
|
98
|
+
*/
|
|
99
|
+
function renderTree(tree, scope, params) {
|
|
100
|
+
const parts = [];
|
|
101
|
+
for (const node of tree.fragments) {
|
|
102
|
+
if (isTree(node)) {
|
|
103
|
+
const inner = renderTree(node, scope, params);
|
|
104
|
+
if (inner !== '')
|
|
105
|
+
parts.push(`(${inner})`);
|
|
106
|
+
}
|
|
107
|
+
else if (fragmentPresent(node, scope)) {
|
|
108
|
+
parts.push(renderFragment(node, scope, params));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (parts.length === 0)
|
|
112
|
+
return '';
|
|
113
|
+
return parts.join(` ${tree.connector} `);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Render a compiled operation to final SQLite SQL + params for a bound input scope.
|
|
117
|
+
*
|
|
118
|
+
* Param order (matches SQL text order, dynamic-expansion spec §6): the compiled `sql`
|
|
119
|
+
* splices the WHERE tree at `{where}`; static params before the marker are emitted first,
|
|
120
|
+
* then the fragment params in tree order, then static params after the marker. WS1's CRUD
|
|
121
|
+
* shapes place all pre-WHERE statics (Insert values, Update SET) before `{where}` and all
|
|
122
|
+
* post-WHERE statics (LIMIT / OFFSET) after — so a single left-to-right walk of the
|
|
123
|
+
* spliced SQL yields the canonical `?` order.
|
|
124
|
+
*/
|
|
125
|
+
function renderOperation(op, input, dialect = dialect_1.SQLITE) {
|
|
126
|
+
const params = [];
|
|
127
|
+
const markerIdx = op.sql.indexOf(ir_1.WHERE_SLOT);
|
|
128
|
+
if (markerIdx === -1) {
|
|
129
|
+
// No dynamic WHERE: all params are static, in position order.
|
|
130
|
+
for (const slot of op.params)
|
|
131
|
+
params.push((0, behavior_contracts_1.evaluateExpression)(slot, input));
|
|
132
|
+
return { sql: finalize(op.sql, dialect), params };
|
|
133
|
+
}
|
|
134
|
+
const before = op.sql.slice(0, markerIdx);
|
|
135
|
+
const after = op.sql.slice(markerIdx + ir_1.WHERE_SLOT.length);
|
|
136
|
+
// Static params are partitioned by whether their `?` sits before or after the marker.
|
|
137
|
+
const beforeQ = countPlaceholders(before);
|
|
138
|
+
const preStatics = op.params.slice(0, beforeQ);
|
|
139
|
+
const postStatics = op.params.slice(beforeQ);
|
|
140
|
+
for (const slot of preStatics)
|
|
141
|
+
params.push((0, behavior_contracts_1.evaluateExpression)(slot, input));
|
|
142
|
+
let whereSql = '';
|
|
143
|
+
if (op.where !== null) {
|
|
144
|
+
const body = renderTree(op.where, input, params);
|
|
145
|
+
if (body !== '')
|
|
146
|
+
whereSql = ` WHERE ${body}`; // degeneration §3: drop keyword when empty
|
|
147
|
+
}
|
|
148
|
+
for (const slot of postStatics)
|
|
149
|
+
params.push((0, behavior_contracts_1.evaluateExpression)(slot, input));
|
|
150
|
+
return { sql: finalize(before + whereSql + after, dialect), params };
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Apply the dialect's final placeholder pass over the FULLY-assembled SQL text (spec §8): for
|
|
154
|
+
* Postgres this converts `?`→`$1,$2,…` in ONE left-to-right pass (the number-reassignment
|
|
155
|
+
* problem is designed out — it runs once, after IN-list expansion + fragment splicing are all
|
|
156
|
+
* done); for SQLite/MySQL it is identity. This is the single place the `?`→`$N` conversion
|
|
157
|
+
* happens, so `params` order (already position-ordered by the walk above) matches `$N` order.
|
|
158
|
+
*/
|
|
159
|
+
function finalize(sql, dialect) {
|
|
160
|
+
return dialect.finalizePlaceholders(sql);
|
|
161
|
+
}
|
|
162
|
+
/** Count `?` placeholders in a static SQL segment (no fragment markers present). */
|
|
163
|
+
function countPlaceholders(sql) {
|
|
164
|
+
let n = 0;
|
|
165
|
+
for (const ch of sql)
|
|
166
|
+
if (ch === '?')
|
|
167
|
+
n++;
|
|
168
|
+
return n;
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/scp/render.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;AA0GH,0CA6BC;AArID,2DAAgF;AAEhF,6BAAkC;AAClC,uCAAiD;AAQjD,uEAAuE;AACvE,SAAS,MAAM,CAAC,IAA6B;IAC3C,OAAO,WAAW,IAAI,IAAI,CAAC;AAC7B,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,eAAe,CAAC,CAAW,EAAE,KAAY;IAChD,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACnC,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC,CAAC,uCAAuC;IAC/E,MAAM,CAAC,GAAG,IAAA,uCAAkB,EAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC5C,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,KAAK,CAAC;AACnC,CAAC;AAED;;;;GAIG;AACH,SAAS,cAAc,CAAC,CAAW,EAAE,KAAY,EAAE,MAAe;IAChE,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC3B,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC,MAAM;YAAE,MAAM,CAAC,IAAI,CAAC,IAAA,uCAAkB,EAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;QAC1E,OAAO,CAAC,CAAC,GAAG,CAAC;IACf,CAAC;IACD,6EAA6E;IAC7E,IAAI,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,MAAM,CAAC,GAAG,IAAA,uCAAkB,EAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QACjD,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC;YACnB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;gBACtB,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,kCAAkC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAClH,CAAC;YACD,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACnB,+EAA+E;gBAC/E,8EAA8E;gBAC9E,6EAA6E;gBAC7E,+CAA+C;gBAC/C,GAAG,GAAG,OAAO,CAAC;gBACd,iCAAiC;YACnC,CAAC;iBAAM,CAAC;gBACN,mFAAmF;gBACnF,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAC7D,KAAK,MAAM,EAAE,IAAI,CAAC;oBAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACtC,CAAC;QACH,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAS,UAAU,CAAC,IAAkB,EAAE,KAAY,EAAE,MAAe;IACnE,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QAClC,IAAI,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YACjB,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;YAC9C,IAAI,KAAK,KAAK,EAAE;gBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC;QAC7C,CAAC;aAAM,IAAI,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC;YACxC,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAClC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;AAC3C,CAAC;AAED;;;;;;;;;GASG;AACH,SAAgB,eAAe,CAAC,EAAqB,EAAE,KAAY,EAAE,UAAmB,gBAAM;IAC5F,MAAM,MAAM,GAAY,EAAE,CAAC;IAC3B,MAAM,SAAS,GAAG,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,eAAU,CAAC,CAAC;IAE7C,IAAI,SAAS,KAAK,CAAC,CAAC,EAAE,CAAC;QACrB,8DAA8D;QAC9D,KAAK,MAAM,IAAI,IAAI,EAAE,CAAC,MAAM;YAAE,MAAM,CAAC,IAAI,CAAC,IAAA,uCAAkB,EAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;QAC3E,OAAO,EAAE,GAAG,EAAE,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACpD,CAAC;IAED,MAAM,MAAM,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,GAAG,eAAU,CAAC,MAAM,CAAC,CAAC;IAE1D,sFAAsF;IACtF,MAAM,OAAO,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,UAAU,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAC/C,MAAM,WAAW,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAE7C,KAAK,MAAM,IAAI,IAAI,UAAU;QAAE,MAAM,CAAC,IAAI,CAAC,IAAA,uCAAkB,EAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;IAE5E,IAAI,QAAQ,GAAG,EAAE,CAAC;IAClB,IAAI,EAAE,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QACjD,IAAI,IAAI,KAAK,EAAE;YAAE,QAAQ,GAAG,UAAU,IAAI,EAAE,CAAC,CAAC,2CAA2C;IAC3F,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,WAAW;QAAE,MAAM,CAAC,IAAI,CAAC,IAAA,uCAAkB,EAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;IAE7E,OAAO,EAAE,GAAG,EAAE,QAAQ,CAAC,MAAM,GAAG,QAAQ,GAAG,KAAK,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;AACvE,CAAC;AAED;;;;;;GAMG;AACH,SAAS,QAAQ,CAAC,GAAW,EAAE,OAAgB;IAC7C,OAAO,OAAO,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC;AAC3C,CAAC;AAED,oFAAoF;AACpF,SAAS,iBAAiB,CAAC,GAAW;IACpC,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,KAAK,MAAM,EAAE,IAAI,GAAG;QAAE,IAAI,EAAE,KAAK,GAAG;YAAE,CAAC,EAAE,CAAC;IAC1C,OAAO,CAAC,CAAC;AACX,CAAC"}
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* litedbmodel v2 SCP — the thin TS runtime (WS3, #23; spec §3 / §10 / §11).
|
|
3
|
+
*
|
|
4
|
+
* Consumes bc's runtime-core (`runBehavior` = plan stage execution + map/wire/skip
|
|
5
|
+
* propagation + Φ output assembly) and adds ONLY the SQL-backend concerns (spec §11):
|
|
6
|
+
* Backend-Compile bridge (WS1↔WS3), per-Catalog Handlers (render → driver execute →
|
|
7
|
+
* row→model assembly), and Error Mapping. It re-implements NO generic execution.
|
|
8
|
+
*
|
|
9
|
+
* ## Execution pipeline (spec §3)
|
|
10
|
+
*
|
|
11
|
+
* validate → fragment select (SKIP) → array expand → Expression eval → bind → SQL execute
|
|
12
|
+
* → assembly
|
|
13
|
+
*
|
|
14
|
+
* bc's `runBehavior` owns the orchestration (which node runs when, map iteration, wire
|
|
15
|
+
* binding, output merge). But the SQL-structural ports (`where` fragment tree, `limit`, …)
|
|
16
|
+
* MUST NOT go through bc's generic port evaluation — a `where` `{arr:[…]}` of comparison
|
|
17
|
+
* Expressions would evaluate to bare booleans (losing the SQL structure), and a SKIP guard
|
|
18
|
+
* over an ABSENT optional input would fail-closed with `UNKNOWN_BINDING`. So the runtime:
|
|
19
|
+
*
|
|
20
|
+
* 1. Backend-Compiles every SQL node up front ({@link import('./bridge').compileNode}) to a
|
|
21
|
+
* WS1 `CompiledOperation` (SQL text + fragment tree + closed-set param slots).
|
|
22
|
+
* 2. Rewrites the IR into a SURROGATE graph: each SQL node keeps its `id` / wiring / `map`
|
|
23
|
+
* shape, but its ports collapse to ONE synthetic `__scope` port — a bc `{obj:…}` that
|
|
24
|
+
* re-exports every binding head the op references (`input` names, wire node ids, the
|
|
25
|
+
* `map` element `as`). bc evaluates `__scope` in ITS scope (so `input`, sibling results
|
|
26
|
+
* and the map element all resolve through bc's own machinery) and hands the plain scope
|
|
27
|
+
* to the handler. No SQL-structural port is ever evaluated by bc.
|
|
28
|
+
* 3. Each handler renders its pre-compiled op against `ports.__scope` via WS1's normative
|
|
29
|
+
* {@link renderOperation} (fragment select + array expand + Expression eval), binds the
|
|
30
|
+
* params through the driver, executes REAL SQL, and returns the row list (assembly).
|
|
31
|
+
*
|
|
32
|
+
* ## Input normalization (SSoT — defaults live in the schema, not code)
|
|
33
|
+
*
|
|
34
|
+
* An OPTIONAL Input Port that the caller omits is normalized to `null` (present-as-null) so
|
|
35
|
+
* a SKIP guard `{ne:[{refOpt:[port]}, null]}` evaluates to `false` and drops its fragment —
|
|
36
|
+
* absent-key SKIP via `refOpt`. This is driven by the component's `inputPorts` schema
|
|
37
|
+
* (`required !== true` ⇒ optional), NOT an ad-hoc `?? null` in engine code: the schema is
|
|
38
|
+
* the single source of truth for which ports are optional.
|
|
39
|
+
*/
|
|
40
|
+
import { type Component, type Handlers, type Scope, type Value } from 'behavior-contracts';
|
|
41
|
+
import type { BehaviorModelContract } from './authoring';
|
|
42
|
+
import type { CompiledOperation } from './ir';
|
|
43
|
+
import { SqlFailure } from './errors';
|
|
44
|
+
import { type RelationDecl, type RelationOp, type RelationDriver } from './relation';
|
|
45
|
+
import { type ReadOptions } from './typed-object';
|
|
46
|
+
import { type TransactionPlan } from './write-plan';
|
|
47
|
+
import { type TransactionResult } from './write-runtime';
|
|
48
|
+
import { type EntityWritesDefinition, type LifecycleContract, type WriteLifecyclePhase } from './writes';
|
|
49
|
+
import { type Dialect, type DialectName } from './dialect';
|
|
50
|
+
/**
|
|
51
|
+
* The minimal synchronous SQLite driver surface the runtime needs (better-sqlite3
|
|
52
|
+
* `Database`). `all` returns the row list of a SELECT / RETURNING statement; `run` executes
|
|
53
|
+
* a non-returning write and reports `changes` + `lastInsertRowid`. In-process, synchronous
|
|
54
|
+
* — the sanctioned in-proc substitute for a docker integration DB (#23 AC).
|
|
55
|
+
*/
|
|
56
|
+
export interface SqliteDb {
|
|
57
|
+
prepare(sql: string): {
|
|
58
|
+
all(...params: unknown[]): unknown[];
|
|
59
|
+
run(...params: unknown[]): {
|
|
60
|
+
changes: number;
|
|
61
|
+
lastInsertRowid: number | bigint;
|
|
62
|
+
};
|
|
63
|
+
reader?: boolean;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Build the SQL handler registry: one handler per SQL Catalog name (spec §11 item 4).
|
|
68
|
+
*
|
|
69
|
+
* Exported so the mode-3 codegen path (WS7f) binds the IDENTICAL SQL handlers into bc's
|
|
70
|
+
* generated `bind(handlers)` accessor — the generated module bakes the surrogate IR literal and
|
|
71
|
+
* calls the SAME `runBehavior`, so pairing it with THIS handler builder makes the codegen output
|
|
72
|
+
* byte-identical to {@link executeBundle} by construction (not a parallel reimplementation).
|
|
73
|
+
*/
|
|
74
|
+
export declare function buildHandlers(db: SqliteDb, compiled: Record<string, CompiledOperation>, dialect: Dialect): Handlers;
|
|
75
|
+
/**
|
|
76
|
+
* Normalize the caller input to `null` (present-as-null) for every OPTIONAL binding the
|
|
77
|
+
* caller omitted, so a SKIP guard using `refOpt` evaluates to `false` and drops its
|
|
78
|
+
* fragment (absent-key SKIP). "Optional" is determined from the SSoT, NOT an ad-hoc code
|
|
79
|
+
* default — a head is optional iff EITHER (a) the component's Input Port schema marks the
|
|
80
|
+
* port `required !== true`, OR (b) the head is SKIP-guarded in a compiled fragment (the
|
|
81
|
+
* SKIP fragment declares its driving input optional — spec §7). A REQUIRED, non-SKIP head
|
|
82
|
+
* that is missing is left absent so a real wiring bug surfaces loudly as bc's
|
|
83
|
+
* `UNKNOWN_BINDING` rather than being silently defaulted.
|
|
84
|
+
*/
|
|
85
|
+
export declare function normalizeInput(component: Component, optionalHeads: Set<string>, input: Scope): Scope;
|
|
86
|
+
/** Execute options: the driver and the entry component (method) to run. */
|
|
87
|
+
export interface ExecuteOptions {
|
|
88
|
+
/** The synchronous SQLite driver (better-sqlite3 `Database`). */
|
|
89
|
+
readonly db: SqliteDb;
|
|
90
|
+
/** The behavior method (component) name to run (default: the first component). */
|
|
91
|
+
readonly entry?: string;
|
|
92
|
+
/**
|
|
93
|
+
* The model's read-relation declarations (spec §4/§5). Compiled ONCE into the bundle's
|
|
94
|
+
* relation ops so the typed-object read surface ({@link read}) can batch-resolve both
|
|
95
|
+
* declarative-select and lazy relations via the SAME compiled op.
|
|
96
|
+
*/
|
|
97
|
+
readonly relations?: readonly RelationDecl[];
|
|
98
|
+
/**
|
|
99
|
+
* The target SQL dialect (spec §4/§10). Defaults to `'sqlite'` (the in-process runtime seam
|
|
100
|
+
* is synchronous SQLite). A `'postgres'`/`'mysql'` bundle is Backend-Compiled dialect-tagged
|
|
101
|
+
* for the dialect golden + a language runtime; the `?`→`$N` (PG) conversion is applied at
|
|
102
|
+
* render time. The SSoT dialect strategy governs every dialect divergence.
|
|
103
|
+
*/
|
|
104
|
+
readonly dialect?: DialectName;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* The Backend-Compiled bundle of ONE behavior method (spec §8): the fully compiled SQL IR a
|
|
108
|
+
* thin per-language runtime (bc runtime-core + a SQL handler) can execute WITHOUT
|
|
109
|
+
* re-implementing litedbmodel's Backend-Compile. It is pure serializable JSON:
|
|
110
|
+
*
|
|
111
|
+
* - `component` — the bc component's WIRING ONLY (body node ids / parent / map `over`+`as` /
|
|
112
|
+
* `cond` / output / plan / inputPorts). The catalog nodes' original Expression-IR ports
|
|
113
|
+
* are replaced by the surrogate `__scope` port so a consumer runtime feeds bc's
|
|
114
|
+
* `runBehavior` the plan/map/wire orchestration with NO SQL-structural port to mis-evaluate.
|
|
115
|
+
* - `operations` — `nodeId → CompiledOperation` (§8: `sql` with the `{where}` splice,
|
|
116
|
+
* `where` fragment tree with existence rules, `params` static slots, `assembly`). Param
|
|
117
|
+
* slots stay as Expression IR (`{coalesce:[…]}`, `{ref:[…]}`) so bc runtime-core owns
|
|
118
|
+
* value/SKIP evaluation per language (they are NOT pre-evaluated to literals).
|
|
119
|
+
* - `optionalHeads` — the input heads normalized to present-as-null (absent-key SKIP), so a
|
|
120
|
+
* consumer runtime reproduces the same normalization from the bundle (not from TS state).
|
|
121
|
+
*
|
|
122
|
+
* `dialect` is the target SQL dialect (`'sqlite'`/`'postgres'`/`'mysql'`); the dialect axis is
|
|
123
|
+
* compiled ONCE, TS-side (spec §10). A PG bundle's `operations[*].sql` still carries `?`
|
|
124
|
+
* placeholders — the `?`→`$N` conversion is the render-time final one-pass, so the bundle stays
|
|
125
|
+
* uniform and dialect-tagged.
|
|
126
|
+
*/
|
|
127
|
+
export interface SqlBundle {
|
|
128
|
+
readonly irVersion: number;
|
|
129
|
+
readonly exprVersion: number;
|
|
130
|
+
readonly dialect: DialectName;
|
|
131
|
+
/** The surrogate component (wiring/plan/output only; catalog ports → `__scope`). */
|
|
132
|
+
readonly component: Component;
|
|
133
|
+
/** Backend-Compiled SQL IR per catalog node id (§8 shape). */
|
|
134
|
+
readonly operations: Record<string, CompiledOperation>;
|
|
135
|
+
/** Optional input heads normalized to present-as-null (absent-key SKIP). */
|
|
136
|
+
readonly optionalHeads: string[];
|
|
137
|
+
/**
|
|
138
|
+
* Pre-compiled read-relation batch ops (spec §8 `relation ops`), keyed by relation name.
|
|
139
|
+
* Derived ONCE (TS-side) from the model relation declarations, dialect-aware (SQLite).
|
|
140
|
+
* Pure JSON (each op's `query` is a {@link CompiledOperation}) so a thin per-language
|
|
141
|
+
* runtime gets the relation batch SQL for free (WS7). BOTH read surfaces (declarative
|
|
142
|
+
* select + lazy) resolve through these ops — the identical compiled op.
|
|
143
|
+
*/
|
|
144
|
+
readonly relations: Record<string, RelationOp>;
|
|
145
|
+
/**
|
|
146
|
+
* The derived write-time-relations transaction plan (spec §6 / §8 `transaction plan`), present
|
|
147
|
+
* ONLY for a Command bundle whose base write declares an `onWrite` lifecycle. Pure JSON:
|
|
148
|
+
* ordered statements + gate-first rules + `$.entity` exposure. A WS7 runtime executes the SAME
|
|
149
|
+
* plan via {@link executeTransactionBundle} (bc-core render + a SQL handler + BEGIN/COMMIT) —
|
|
150
|
+
* no re-derivation per language (spec §6). Absent for read bundles and for Command bundles with
|
|
151
|
+
* no write-time relations (those run through the ordinary {@link executeBundle} path).
|
|
152
|
+
*/
|
|
153
|
+
readonly transaction?: TransactionPlan;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Execute a published behavior contract (WS2 {@link BehaviorModelContract}) end-to-end:
|
|
157
|
+
* Backend-Compile every SQL node → surrogate IR → bc `runBehavior` (plan / map / wire /
|
|
158
|
+
* output) with SQL handlers → REAL SQLite execution → assembled Φ output.
|
|
159
|
+
*
|
|
160
|
+
* This is α's vertical slice: authoring → IR → Backend-Compile → thin runtime → real
|
|
161
|
+
* SQLite → assembly. The returned Value is the component's `output` (Φ merge) with each SQL
|
|
162
|
+
* node's slot filled by its executed row list.
|
|
163
|
+
*
|
|
164
|
+
* @throws {SqlFailure} a mapped driver failure re-surfaced at the boundary (a `fail`-policy
|
|
165
|
+
* node re-throws through `runPlan` as `OP_FAILED`; the runtime unwraps it back to the
|
|
166
|
+
* structured {@link SqlFailure} so the caller sees `kind` / `policy` / `sqliteCode`).
|
|
167
|
+
*/
|
|
168
|
+
export declare function executeBehavior(contract: BehaviorModelContract, input: Scope, options: ExecuteOptions): Value;
|
|
169
|
+
/**
|
|
170
|
+
* Backend-Compile ONE behavior method of a contract into the serializable {@link SqlBundle}
|
|
171
|
+
* (spec §8) — the published multi-language artifact. This runs the WS1↔WS3 bridge and the
|
|
172
|
+
* surrogate rewrite ONCE, on the TS side (spec §10: the dialect axis is compiled once), and
|
|
173
|
+
* emits pure JSON: no TS runtime state is captured, so `JSON.stringify(bundle)` round-trips
|
|
174
|
+
* losslessly and a thin per-language runtime can execute it with bc runtime-core + a SQL
|
|
175
|
+
* handler alone (proven by the bundle round-trip test).
|
|
176
|
+
*/
|
|
177
|
+
export declare function compileBundle(contract: BehaviorModelContract, entry?: string, relations?: readonly RelationDecl[], dialectName?: DialectName): SqlBundle;
|
|
178
|
+
/**
|
|
179
|
+
* Execute a {@link SqlBundle} (the §8 published artifact) end-to-end: feed bc `runBehavior`
|
|
180
|
+
* the bundle's surrogate component (plan / map / wire / output orchestration) with SQL
|
|
181
|
+
* handlers that render the bundle's `CompiledOperation`s and run REAL SQLite. This is the
|
|
182
|
+
* SAME code path a thin per-language runtime follows — it consumes ONLY the serialized
|
|
183
|
+
* bundle + bc runtime-core, never re-running litedbmodel's Backend-Compile. The bundle
|
|
184
|
+
* round-trip test parses this from JSON (no TS state) to prove self-sufficiency (WS7).
|
|
185
|
+
*
|
|
186
|
+
* @throws {SqlFailure} a mapped driver failure re-surfaced at the boundary.
|
|
187
|
+
*/
|
|
188
|
+
export declare function executeBundle(bundle: SqlBundle, input: Scope, options: ExecuteOptions): Value;
|
|
189
|
+
/**
|
|
190
|
+
* Backend-Compile a Command method + its `entityWrites` save contract into a {@link SqlBundle}
|
|
191
|
+
* that carries the derived, gate-first write-time-relations {@link TransactionPlan} (spec §6/§8).
|
|
192
|
+
* The base write op is Backend-Compiled ONCE (the same {@link compileNode} bridge), and
|
|
193
|
+
* {@link deriveTransactionPlan} lowers the lifecycle's §6 effect arrays around it into the ordered
|
|
194
|
+
* statement list. The whole plan is pure JSON (it round-trips inside the bundle), so a WS7 runtime
|
|
195
|
+
* honors the SAME plan via {@link executeTransactionBundle} — no re-derivation.
|
|
196
|
+
*
|
|
197
|
+
* @throws if the method is not a Command, the phase lifecycle is not declared, the scope is not a
|
|
198
|
+
* single base write, or a `$.entity.*` reference lacks a RETURNING body (all fail-closed).
|
|
199
|
+
*/
|
|
200
|
+
export declare function compileWriteBundle(contract: BehaviorModelContract, entry: string, writes: EntityWritesDefinition, phase: WriteLifecyclePhase, dialectName?: DialectName): SqlBundle;
|
|
201
|
+
/**
|
|
202
|
+
* One member of a COMPOSITE (multi-write) Command (WS8a, #28 — spec §6 nested write / §14 tx-DAG):
|
|
203
|
+
* a named base write (its sole Insert/Update/Delete node in `entry`) carrying its OWN save-contract
|
|
204
|
+
* `effects`. A later member references an earlier member's RETURNING row via `$.ref.<name>.<field>`.
|
|
205
|
+
*/
|
|
206
|
+
export interface CompositeWriteEntry {
|
|
207
|
+
/** The Command method whose sole base-write node is this member's body. */
|
|
208
|
+
readonly entry: string;
|
|
209
|
+
/** The member's stable name (downstream members address its row as `$.ref.<name>.<field>`). */
|
|
210
|
+
readonly name: string;
|
|
211
|
+
/** The member's write-time-relations lifecycle for this phase (its gates/derive/edges/emits). */
|
|
212
|
+
readonly lifecycle: LifecycleContract;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Backend-Compile a COMPOSITE (multi-write) Command into a {@link SqlBundle} carrying ONE derived,
|
|
216
|
+
* gate-first, TOPOLOGICALLY-ORDERED transaction plan (spec §6 nested write / §14 "write-time tx DAG
|
|
217
|
+
* 導出"). Each {@link CompositeWriteEntry} contributes a named base write + its effects; a later
|
|
218
|
+
* member depends on an earlier via `$.ref.<name>.*` (e.g. a child INSERT keyed by the parent's
|
|
219
|
+
* RETURNING id). {@link deriveTransactionPlan} builds the data-dependency graph + gate-first
|
|
220
|
+
* constraint and derives the correct ordered plan (deterministic, stable tie-break; a cycle or
|
|
221
|
+
* dangling ref is ESCALATED). The plan is pure JSON — the 5 language runtimes execute it verbatim
|
|
222
|
+
* (they already bind each statement's `binds` row into scope for downstream `$.ref` resolution).
|
|
223
|
+
*
|
|
224
|
+
* @throws if an entry is missing/not a single-write node, or the DAG cannot be derived (cycle /
|
|
225
|
+
* dangling `$.ref` / missing RETURNING on a referenced write) — all fail-closed.
|
|
226
|
+
*/
|
|
227
|
+
export declare function compileCompositeWriteBundle(contract: BehaviorModelContract, entries: readonly CompositeWriteEntry[], phase: WriteLifecyclePhase, dialectName?: DialectName): SqlBundle;
|
|
228
|
+
/**
|
|
229
|
+
* Execute a COMPOSITE (multi-write) Command end-to-end as ONE real SQLite transaction with gate-
|
|
230
|
+
* first short-circuit + DAG-ordered statements (spec §6 / §14): Backend-Compile the members into a
|
|
231
|
+
* bundle with the derived tx-DAG plan, then run {@link executeTransactionBundle}.
|
|
232
|
+
*/
|
|
233
|
+
export declare function executeCompositeCommand(contract: BehaviorModelContract, entries: readonly CompositeWriteEntry[], phase: WriteLifecyclePhase, input: Scope, options: ExecuteOptions): TransactionResult;
|
|
234
|
+
/**
|
|
235
|
+
* Execute a Command end-to-end as ONE real SQLite transaction with gate-first short-circuit
|
|
236
|
+
* (spec §6): Backend-Compile the Command + its save contract into a {@link SqlBundle} with a
|
|
237
|
+
* transaction plan, then run {@link executeTransactionBundle}. This is the v2 public write path
|
|
238
|
+
* ("write-time relations が自動導出 → 1 tx", spec §2.3).
|
|
239
|
+
*
|
|
240
|
+
* @throws {SqlFailure} a mapped driver failure (the transaction ROLLBACKs first).
|
|
241
|
+
*/
|
|
242
|
+
export declare function executeCommand(contract: BehaviorModelContract, writes: EntityWritesDefinition, phase: WriteLifecyclePhase, input: Scope, options: ExecuteOptions & {
|
|
243
|
+
readonly entry: string;
|
|
244
|
+
}): TransactionResult;
|
|
245
|
+
/**
|
|
246
|
+
* Execute a {@link SqlBundle}'s derived transaction plan (spec §6/§8) as ONE real SQLite
|
|
247
|
+
* transaction. This is the SAME code path a thin per-language runtime follows: it consumes ONLY
|
|
248
|
+
* the serialized {@link TransactionPlan} (pure JSON) + the render pipeline + a SQL driver, never
|
|
249
|
+
* re-deriving the plan. The bundle round-trip test parses this from JSON (no TS state) to prove
|
|
250
|
+
* WS7 self-sufficiency.
|
|
251
|
+
*
|
|
252
|
+
* @throws if the bundle carries no transaction plan (it is not a write-time-relations Command
|
|
253
|
+
* bundle), or {@link SqlFailure} on a mapped driver failure.
|
|
254
|
+
*/
|
|
255
|
+
export declare function executeTransactionBundle(bundle: SqlBundle, input: Scope, options: ExecuteOptions): TransactionResult;
|
|
256
|
+
/** Options for the typed-object {@link read} surface: base execution + relation read opts. */
|
|
257
|
+
export interface ReadRuntimeOptions<R = Record<string, unknown>> extends ExecuteOptions, ReadOptions<R> {
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* The v2 typed-object read surface (spec §4/§5/§12): run a read behavior whose output is a
|
|
261
|
+
* row list (a Select), then wrap each raw row in a plain TYPED-OBJECT (own props = data only,
|
|
262
|
+
* NOT a DBModel instance) with read relations attached.
|
|
263
|
+
*
|
|
264
|
+
* - A relation named in `options.with` is DECLARATIVELY selected: batch-prefetched ONCE over
|
|
265
|
+
* the whole page (staged, no N+1) and attached as an OWN prop.
|
|
266
|
+
* - Every OTHER declared relation is LAZY: a prototype getter that, on `await result.author`,
|
|
267
|
+
* fires the SAME compiled relation op over the sibling set (batched — still no N+1).
|
|
268
|
+
* - `options.hydrate` recovers host objects (`(raw) => new Domain(raw)`) — the consumer-side
|
|
269
|
+
* method-UX recovery. It stays in the runtime and never enters the bundle.
|
|
270
|
+
*
|
|
271
|
+
* Both surfaces share the ONE compiled relation op in the bundle (spec §5). The base row list
|
|
272
|
+
* is produced by the SAME {@link executeBundle} path (bc runtime-core + SQL handlers), so the
|
|
273
|
+
* read query itself is fully IR-driven; relations are the runtime's staged-batch concern.
|
|
274
|
+
*
|
|
275
|
+
* @throws if the behavior output is not a row list (the typed-object surface is for reads).
|
|
276
|
+
*/
|
|
277
|
+
export declare function read<R = Record<string, unknown>>(contract: BehaviorModelContract, input: Scope, options: ReadRuntimeOptions<R>): R[];
|
|
278
|
+
/** {@link read} against an already-compiled {@link SqlBundle} (the published §8 artifact). */
|
|
279
|
+
export declare function readBundle<R = Record<string, unknown>>(bundle: SqlBundle, input: Scope, options: ReadRuntimeOptions<R>): R[];
|
|
280
|
+
/**
|
|
281
|
+
* Resolve ONE relation for a page of parent rows by driving bc's PLAN mechanism (spec §5:
|
|
282
|
+
* `deriveExecutionPlan` — result path → stage groups + concurrency). This is the staged-batch
|
|
283
|
+
* path: it builds a bc component with a single `map.batched` node over the parent rows and
|
|
284
|
+
* runs it through {@link runBehavior} (the SAME multi-language execution core WS7 languages
|
|
285
|
+
* use). Because the map is `batched`, bc evaluates every parent's key port and invokes the
|
|
286
|
+
* relation handler EXACTLY ONCE with `{items:[…]}` — so the relation op fires ONE batched
|
|
287
|
+
* query for the whole page (structurally no N+1, enforced by bc's batch contract). The
|
|
288
|
+
* handler runs the IDENTICAL compiled {@link RelationOp} the declarative-select and lazy
|
|
289
|
+
* surfaces use, and `into` attaches each parent's resolved child(ren).
|
|
290
|
+
*
|
|
291
|
+
* Returns the parent rows augmented with the relation under `op.name` (per cardinality).
|
|
292
|
+
*/
|
|
293
|
+
export declare function resolveRelationViaPlan(op: RelationOp, parents: readonly Record<string, unknown>[], db: RelationDriver): Record<string, unknown>[];
|
|
294
|
+
export { SqlFailure };
|
|
295
|
+
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/scp/runtime.ts"],"names":[],"mappings":"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"}
|