litedbmodel 2.0.2 → 2.2.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 +7 -0
- package/dist/DBConditions.d.ts.map +1 -1
- package/dist/DBConditions.js +16 -1
- package/dist/DBConditions.js.map +1 -1
- package/dist/DBHandler.d.ts.map +1 -1
- package/dist/DBHandler.js +6 -0
- package/dist/DBHandler.js.map +1 -1
- package/dist/DBModel.d.ts +84 -2
- package/dist/DBModel.d.ts.map +1 -1
- package/dist/DBModel.js +312 -29
- package/dist/DBModel.js.map +1 -1
- package/dist/decorators.d.ts +52 -0
- package/dist/decorators.d.ts.map +1 -1
- package/dist/decorators.js +127 -24
- package/dist/decorators.js.map +1 -1
- package/dist/drivers/mysql.d.ts.map +1 -1
- package/dist/drivers/mysql.js +12 -2
- package/dist/drivers/mysql.js.map +1 -1
- package/dist/drivers/postgres.d.ts.map +1 -1
- package/dist/drivers/postgres.js +13 -2
- package/dist/drivers/postgres.js.map +1 -1
- package/dist/drivers/sqlite.d.ts +2 -0
- package/dist/drivers/sqlite.d.ts.map +1 -1
- package/dist/drivers/sqlite.js +49 -4
- package/dist/drivers/sqlite.js.map +1 -1
- package/dist/index.cjs +10741 -0
- package/dist/index.d.cts +1 -0
- package/dist/scp/coltype.d.ts +108 -0
- package/dist/scp/coltype.d.ts.map +1 -1
- package/dist/scp/coltype.js +293 -6
- package/dist/scp/coltype.js.map +1 -1
- package/dist/scp/connection-routing.d.ts +312 -0
- package/dist/scp/connection-routing.d.ts.map +1 -0
- package/dist/scp/connection-routing.js +394 -0
- package/dist/scp/connection-routing.js.map +1 -0
- package/dist/scp/dbmodel-runtime.d.ts +101 -0
- package/dist/scp/dbmodel-runtime.d.ts.map +1 -0
- package/dist/scp/dbmodel-runtime.js +174 -0
- package/dist/scp/dbmodel-runtime.js.map +1 -0
- package/dist/scp/decorator-adapter.d.ts +196 -0
- package/dist/scp/decorator-adapter.d.ts.map +1 -0
- package/dist/scp/decorator-adapter.js +286 -0
- package/dist/scp/decorator-adapter.js.map +1 -0
- package/dist/scp/emit/emitter.d.ts +108 -0
- package/dist/scp/emit/emitter.d.ts.map +1 -0
- package/dist/scp/emit/emitter.js +782 -0
- package/dist/scp/emit/emitter.js.map +1 -0
- package/dist/scp/emit/endpoint.d.ts +248 -0
- package/dist/scp/emit/endpoint.d.ts.map +1 -0
- package/dist/scp/emit/endpoint.js +20 -0
- package/dist/scp/emit/endpoint.js.map +1 -0
- package/dist/scp/emit/index.d.ts +11 -0
- package/dist/scp/emit/index.d.ts.map +1 -0
- package/dist/scp/emit/index.js +13 -0
- package/dist/scp/emit/index.js.map +1 -0
- package/dist/scp/errors.d.ts +45 -1
- package/dist/scp/errors.d.ts.map +1 -1
- package/dist/scp/errors.js +47 -1
- package/dist/scp/errors.js.map +1 -1
- package/dist/scp/exec-context.d.ts +390 -0
- package/dist/scp/exec-context.d.ts.map +1 -0
- package/dist/scp/exec-context.js +540 -0
- package/dist/scp/exec-context.js.map +1 -0
- package/dist/scp/grouping.d.ts +32 -0
- package/dist/scp/grouping.d.ts.map +1 -0
- package/dist/scp/grouping.js +0 -0
- package/dist/scp/grouping.js.map +1 -0
- package/dist/scp/index.cjs +6432 -17579
- package/dist/scp/index.d.cts +1 -0
- package/dist/scp/index.d.mts +1 -0
- package/dist/scp/index.d.ts +51 -52
- package/dist/scp/index.d.ts.map +1 -1
- package/dist/scp/index.js +189 -152
- package/dist/scp/index.js.map +1 -1
- package/dist/scp/index.mjs +6067 -3659
- package/dist/scp/leaf-transport.d.ts +50 -0
- package/dist/scp/leaf-transport.d.ts.map +1 -0
- package/dist/scp/leaf-transport.js +92 -0
- package/dist/scp/leaf-transport.js.map +1 -0
- package/dist/scp/leaves.d.ts +174 -0
- package/dist/scp/leaves.d.ts.map +1 -0
- package/dist/scp/leaves.js +287 -0
- package/dist/scp/leaves.js.map +1 -0
- package/dist/scp/limit-config.d.ts +118 -0
- package/dist/scp/limit-config.d.ts.map +1 -0
- package/dist/scp/limit-config.js +126 -0
- package/dist/scp/limit-config.js.map +1 -0
- package/dist/scp/makesql/compile-relation.d.ts +49 -23
- package/dist/scp/makesql/compile-relation.d.ts.map +1 -1
- package/dist/scp/makesql/compile-relation.js +101 -76
- package/dist/scp/makesql/compile-relation.js.map +1 -1
- package/dist/scp/makesql/compile-select.d.ts +45 -10
- package/dist/scp/makesql/compile-select.d.ts.map +1 -1
- package/dist/scp/makesql/compile-select.js +50 -10
- package/dist/scp/makesql/compile-select.js.map +1 -1
- package/dist/scp/makesql/handler.d.ts +1 -1
- package/dist/scp/makesql/handler.d.ts.map +1 -1
- package/dist/scp/makesql/index.d.ts +7 -10
- package/dist/scp/makesql/index.d.ts.map +1 -1
- package/dist/scp/makesql/index.js +19 -30
- package/dist/scp/makesql/index.js.map +1 -1
- package/dist/scp/makesql/json-array.d.ts +65 -0
- package/dist/scp/makesql/json-array.d.ts.map +1 -1
- package/dist/scp/makesql/json-array.js +99 -10
- package/dist/scp/makesql/json-array.js.map +1 -1
- package/dist/scp/makesql/json-batch.d.ts.map +1 -1
- package/dist/scp/makesql/json-batch.js +21 -19
- package/dist/scp/makesql/json-batch.js.map +1 -1
- package/dist/scp/makesql/makesql.d.ts +1 -1
- package/dist/scp/makesql/makesql.d.ts.map +1 -1
- package/dist/scp/makesql/mysql-returning.d.ts +93 -0
- package/dist/scp/makesql/mysql-returning.d.ts.map +1 -0
- package/dist/scp/makesql/mysql-returning.js +215 -0
- package/dist/scp/makesql/mysql-returning.js.map +1 -0
- package/dist/scp/makesql/outtype.d.ts +75 -34
- package/dist/scp/makesql/outtype.d.ts.map +1 -1
- package/dist/scp/makesql/outtype.js +91 -118
- package/dist/scp/makesql/outtype.js.map +1 -1
- package/dist/scp/makesql/pool-executor.d.ts +135 -13
- package/dist/scp/makesql/pool-executor.d.ts.map +1 -1
- package/dist/scp/makesql/pool-executor.js +229 -21
- package/dist/scp/makesql/pool-executor.js.map +1 -1
- package/dist/scp/makesql/tx.d.ts +107 -22
- package/dist/scp/makesql/tx.d.ts.map +1 -1
- package/dist/scp/makesql/tx.js +451 -97
- package/dist/scp/makesql/tx.js.map +1 -1
- package/dist/scp/makesql/writeouttype.d.ts +7 -8
- package/dist/scp/makesql/writeouttype.d.ts.map +1 -1
- package/dist/scp/makesql/writeouttype.js +8 -7
- package/dist/scp/makesql/writeouttype.js.map +1 -1
- package/dist/scp/middleware.d.ts +287 -0
- package/dist/scp/middleware.d.ts.map +1 -0
- package/dist/scp/middleware.js +358 -0
- package/dist/scp/middleware.js.map +1 -0
- package/dist/scp/relation.d.ts +80 -9
- package/dist/scp/relation.d.ts.map +1 -1
- package/dist/scp/relation.js +198 -78
- package/dist/scp/relation.js.map +1 -1
- package/dist/scp/tx-options.d.ts +136 -0
- package/dist/scp/tx-options.d.ts.map +1 -0
- package/dist/scp/tx-options.js +184 -0
- package/dist/scp/tx-options.js.map +1 -0
- package/dist/scp/write-bundle.d.ts +131 -0
- package/dist/scp/write-bundle.d.ts.map +1 -0
- package/dist/scp/write-bundle.js +160 -0
- package/dist/scp/write-bundle.js.map +1 -0
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/docs/BENCHMARK.md +58 -56
- package/docs/benchmark-chart.svg +166 -166
- package/docs/design/phase-a-execution-context.md +139 -0
- package/package.json +16 -9
- package/dist/scp/authoring-sql.d.ts +0 -134
- package/dist/scp/authoring-sql.d.ts.map +0 -1
- package/dist/scp/authoring-sql.js +0 -191
- package/dist/scp/authoring-sql.js.map +0 -1
- package/dist/scp/authoring.d.ts +0 -155
- package/dist/scp/authoring.d.ts.map +0 -1
- package/dist/scp/authoring.js +0 -162
- package/dist/scp/authoring.js.map +0 -1
- package/dist/scp/catalog.d.ts +0 -94
- package/dist/scp/catalog.d.ts.map +0 -1
- package/dist/scp/catalog.js +0 -234
- package/dist/scp/catalog.js.map +0 -1
- package/dist/scp/codegen.d.ts +0 -189
- package/dist/scp/codegen.d.ts.map +0 -1
- package/dist/scp/codegen.js +0 -421
- package/dist/scp/codegen.js.map +0 -1
- package/dist/scp/find-filter-guard.d.ts +0 -68
- package/dist/scp/find-filter-guard.d.ts.map +0 -1
- package/dist/scp/find-filter-guard.js +0 -88
- package/dist/scp/find-filter-guard.js.map +0 -1
- package/dist/scp/guard.d.ts +0 -43
- package/dist/scp/guard.d.ts.map +0 -1
- package/dist/scp/guard.js +0 -134
- package/dist/scp/guard.js.map +0 -1
- package/dist/scp/makesql/authoring-compile.d.ts +0 -90
- package/dist/scp/makesql/authoring-compile.d.ts.map +0 -1
- package/dist/scp/makesql/authoring-compile.js +0 -494
- package/dist/scp/makesql/authoring-compile.js.map +0 -1
- package/dist/scp/makesql/ir.d.ts +0 -42
- package/dist/scp/makesql/ir.d.ts.map +0 -1
- package/dist/scp/makesql/ir.js +0 -66
- package/dist/scp/makesql/ir.js.map +0 -1
- package/dist/scp/makesql/static-bundle.d.ts +0 -187
- package/dist/scp/makesql/static-bundle.d.ts.map +0 -1
- package/dist/scp/makesql/static-bundle.js +0 -1113
- package/dist/scp/makesql/static-bundle.js.map +0 -1
- package/dist/scp/runtime.d.ts +0 -242
- package/dist/scp/runtime.d.ts.map +0 -1
- package/dist/scp/runtime.js +0 -400
- package/dist/scp/runtime.js.map +0 -1
package/dist/scp/codegen.js
DELETED
|
@@ -1,421 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* litedbmodel v2 SCP — mode-3 codegen (WS7f, #35; spec §9 exec-mode 3 / §10 / §11; makeSQL flip,
|
|
4
|
-
* epic #43/#45 Phase B; #60 milestone 1 — typed-NATIVE READ codegen, bc#77/#90).
|
|
5
|
-
*
|
|
6
|
-
* The static-codegen execution mode ("Codegen・静的(全言語)— IR → 各言語ソース生成 runtime≈0,
|
|
7
|
-
* 入力は可搬IRのみ, bc#13 共有 generator に SQL catalog を供給" — spec §9). It takes a §8 STATIC
|
|
8
|
-
* makeSQL {@link SqlBundle} and, per target language, emits:
|
|
9
|
-
*
|
|
10
|
-
* 1. **Behavior module** — bc's SHARED generator run over the bundle's portable IR through bc's
|
|
11
|
-
* de-interpreted, RUNTIME-FREE emitter. For a READ bundle covered by bc's typed-NATIVE
|
|
12
|
-
* endpoint (`rust-typed-native` / `go-typed-native`, bc#77/#90 — the 1.0 read de-box: fully
|
|
13
|
-
* concrete `HandlerNR<Comp>`/`InNR<Comp>`/`PortsNR<Comp><node>`/`RawRowNR<Comp><node>` structs,
|
|
14
|
-
* ZERO boxed `Value`/`RawValue`, ZERO IR baked into the module), the CODEGEN-ONLY lowering
|
|
15
|
-
* below ({@link lowerReadGraphForTypedNative}) makes the read's shape structurally ELIGIBLE
|
|
16
|
-
* (splits the surrogate `__scope` boxed-obj port into individual scalar ref ports + types the
|
|
17
|
-
* component's `inputPorts` from the schema) before handing it to bc. For a WRITE bundle, or a
|
|
18
|
-
* READ shape typed-native does not (yet) cover, codegen uses bc's existing de-interpreted
|
|
19
|
-
* STRAIGHT-LINE endpoint (`<lang>-straightline`, bc#75) — see {@link typedEmitterFor}.
|
|
20
|
-
* 2. **SQL catalog companion** — the pure-JSON STATIC makeSQL catalog (per-node statement
|
|
21
|
-
* templates / relations / transaction). A codegen consumer's thin SQL layer reads it to
|
|
22
|
-
* evaluate skip + value-specs → assemble → render → execute (identically to the mode-2 runtime).
|
|
23
|
-
*
|
|
24
|
-
* ## #60 milestone 1 scope (CODEGEN-PATH ONLY)
|
|
25
|
-
*
|
|
26
|
-
* This lowering exists SOLELY for the codegen emitter call — it builds a NEW, separate
|
|
27
|
-
* `ComponentGraphIR` from the bundle's `readGraph`; it never mutates `SqlBundle`/`ReadGraph` and
|
|
28
|
-
* never touches the shared `readGraph`/`executeReadGraph` the ir/interpret exec surface (and the
|
|
29
|
-
* frozen conformance corpus) depend on. Those keep consuming the ORIGINAL boxed-`__scope`-port
|
|
30
|
-
* surrogate IR ({@link bundleToPortableIR}), completely unaffected by anything in this file.
|
|
31
|
-
*
|
|
32
|
-
* ## Behavior-identical to the thin-runtime (mode-2), by construction
|
|
33
|
-
*
|
|
34
|
-
* The generated module is observationally equivalent to `runBehavior` (same values, same emitted
|
|
35
|
-
* op sequence, same Failure code/message), and the companion IS the bundle, so a codegen runtime
|
|
36
|
-
* that drives it follows the IDENTICAL static-makeSQL render/execute path {@link executeBundle}
|
|
37
|
-
* uses — SQL text (all dialects) and results are identical, not approximately equal. The TS leg
|
|
38
|
-
* PROVES this by executing via the artifact and asserting exact equality vs {@link executeBundle}
|
|
39
|
-
* (see {@link codegenExecuteBundleForTest}).
|
|
40
|
-
*
|
|
41
|
-
* ## No literal-bake / no boxed fallback
|
|
42
|
-
*
|
|
43
|
-
* typed-native fails CLOSED on an uncovered shape (a `map`/`cond` relation kind it does not cover,
|
|
44
|
-
* or an input head that cannot lower to a native scalar — e.g. an IN-list's array-typed head).
|
|
45
|
-
* Such a shape is NOT silently regenerated on the boxed `-typed`/`-typed-raw` emitter — it THROWS,
|
|
46
|
-
* naming the exact gap, so it can be tracked as a bc coverage gap (bc#86) rather than masked.
|
|
47
|
-
*/
|
|
48
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
49
|
-
exports.TypedNativeCoverageError = exports.CODEGEN_EMITTER = exports.CODEGEN_LANGUAGES = void 0;
|
|
50
|
-
exports.bundleToPortableIR = bundleToPortableIR;
|
|
51
|
-
exports.lowerReadGraphForTypedNative = lowerReadGraphForTypedNative;
|
|
52
|
-
exports.typedEmitterFor = typedEmitterFor;
|
|
53
|
-
exports.codegenEmitterFor = codegenEmitterFor;
|
|
54
|
-
exports.generateCodegenArtifact = generateCodegenArtifact;
|
|
55
|
-
exports.codegenExecuteBundleForTest = codegenExecuteBundleForTest;
|
|
56
|
-
const behavior_contracts_1 = require("behavior-contracts");
|
|
57
|
-
const runtime_1 = require("./runtime");
|
|
58
|
-
const ir_1 = require("./makesql/ir");
|
|
59
|
-
const coltype_1 = require("./coltype");
|
|
60
|
-
/**
|
|
61
|
-
* The languages litedbmodel mode-3 codegen supports — exactly the set bc's shared generator
|
|
62
|
-
* registers (bc#13 SP1 typescript/python + SP2 go/rust/php). {@link codegenEmitterFor}
|
|
63
|
-
* verifies against the LIVE registry so a bc capability drift is caught loudly.
|
|
64
|
-
*/
|
|
65
|
-
exports.CODEGEN_LANGUAGES = ['typescript', 'python', 'go', 'rust', 'php'];
|
|
66
|
-
/**
|
|
67
|
-
* The bc READ emitter litedbmodel drives for each codegen target (#60 milestone 1): the
|
|
68
|
-
* **de-interpreted, RUNTIME-FREE typed-NATIVE** endpoint (bc#77/#90) for go/rust — ZERO boxed
|
|
69
|
-
* `Value`/`RawValue`, ZERO IR baked into the module, concrete `HandlerNR`/`InNR`/`PortsNR`/
|
|
70
|
-
* `RawRowNR` structs. There is **NO literal / straight-line / boxed-typed fallback** for a read: an
|
|
71
|
-
* unspec'd fallback is INVALID (it silently swallows the "this shape can't be natively codegen'd"
|
|
72
|
-
* signal) — a read shape typed-native does not cover MUST fail loudly at generation, naming the gap
|
|
73
|
-
* (report it as a bc#86 coverage gap), never silently regenerate on `-typed`/`-typed-raw`.
|
|
74
|
-
*
|
|
75
|
-
* `-typed-raw` (bc#76, the boxed-wire intermediate) and `-typed` (the boxed-Value intermediate) are
|
|
76
|
-
* RETIRED from litedbmodel's codegen surface entirely (#60 milestone 1) — typed-native supersedes
|
|
77
|
-
* both for every read shape it covers (bc#77/#90: single-componentRef reads AND the `map`
|
|
78
|
-
* relationKind:single|connection shape, bc#86 part 2).
|
|
79
|
-
*
|
|
80
|
-
* - ts: **no typed-native endpoint registered yet** (bc has not shipped `typescript-typed-native`).
|
|
81
|
-
* TS stays on its existing `typescript-typed` (boxed) endpoint until bc adds one — a DECLARED,
|
|
82
|
-
* reported gap (not silently mirrored to go/rust's retirement), tracked as a bc#77 TS follow-up.
|
|
83
|
-
* - **python/php: NOT present.** bc registers no de-boxed typed endpoint for them (capability limit).
|
|
84
|
-
* litedbmodel does NOT substitute the literal (≈ir) emitter — that would be an unspec'd fallback.
|
|
85
|
-
* Codegen for py/php is a bc capability gap that ERRORS (ESCALATE to bc), never a silent literal.
|
|
86
|
-
*
|
|
87
|
-
* WRITES (batchInsert / gate-first tx) are NOT reads — they are NOT routed through this table at
|
|
88
|
-
* all (#60 milestone 1): a write bundle stays on the existing write/tx execution path
|
|
89
|
-
* (`executeTransactionBundle` / the native adapter's hand-written tx mirror), never a codegen
|
|
90
|
-
* module, boxed or typed-raw. {@link generateCodegenArtifact} throws if asked to codegen a write.
|
|
91
|
-
*/
|
|
92
|
-
exports.CODEGEN_EMITTER = {
|
|
93
|
-
typescript: 'typescript-typed',
|
|
94
|
-
go: 'go-typed-native',
|
|
95
|
-
rust: 'rust-typed-native',
|
|
96
|
-
};
|
|
97
|
-
/**
|
|
98
|
-
* The portable {@link ComponentGraphIR} view of a §8 bundle: a read bundle's surrogate IR (each
|
|
99
|
-
* SQL node → a `makeSQL` node), or the single `makeSQL` component IR for a write. This is the
|
|
100
|
-
* ORIGINAL boxed-`__scope`-port form the ir/interpret exec surface's `executeReadGraph` also
|
|
101
|
-
* consumes (via `bundle.readGraph.ir` directly) — {@link generateCodegenArtifact} does NOT use
|
|
102
|
-
* this for a READ bundle (it uses the codegen-only lowered form, {@link lowerReadGraphForTypedNative});
|
|
103
|
-
* this function is kept for callers that want the untouched portable IR (e.g. diagnostics, the
|
|
104
|
-
* write path, or a future straight-line fallback caller).
|
|
105
|
-
*/
|
|
106
|
-
function bundleToPortableIR(bundle) {
|
|
107
|
-
if (bundle.readGraph !== undefined)
|
|
108
|
-
return bundle.readGraph.ir;
|
|
109
|
-
const ir = (0, ir_1.makeSqlComponentIR)(bundle.name);
|
|
110
|
-
// A WRITE bundle's typed de-box (spec §4.1/§9): attach the derived `outputType` (the
|
|
111
|
-
// TransactionResult typed shape) to the single `makeSQL` node's `outType` + the component's
|
|
112
|
-
// `outputType` — exactly how the read graph annotates its surrogate IR. Without it, bc's typed
|
|
113
|
-
// emitters would hard-fail ("nothing to de-box"), which is the correct fail-closed signal; a
|
|
114
|
-
// resolver-less write bundle (no `outputType`) stays un-annotated (interpret/boxed only, as before).
|
|
115
|
-
if (bundle.outputType === undefined)
|
|
116
|
-
return ir;
|
|
117
|
-
const c = ir.components[0];
|
|
118
|
-
const body = c.body.map((n, i) => (i === 0 ? { ...n, outType: bundle.outputType } : n));
|
|
119
|
-
const component = { ...c, body, outputType: bundle.outputType };
|
|
120
|
-
return { ...ir, components: [component] };
|
|
121
|
-
}
|
|
122
|
-
/** The STATIC makeSQL execution catalog carried alongside the generated module. */
|
|
123
|
-
function companionOf(bundle) {
|
|
124
|
-
const base = {
|
|
125
|
-
dialect: bundle.dialect,
|
|
126
|
-
optionalHeads: bundle.optionalHeads,
|
|
127
|
-
relations: bundle.relations,
|
|
128
|
-
...(bundle.readGraph !== undefined ? { readGraph: bundle.readGraph } : {}),
|
|
129
|
-
...(bundle.statement !== undefined ? { statement: bundle.statement } : {}),
|
|
130
|
-
...(bundle.outputType !== undefined ? { outputType: bundle.outputType } : {}),
|
|
131
|
-
};
|
|
132
|
-
return bundle.transaction === undefined ? base : { ...base, transaction: bundle.transaction };
|
|
133
|
-
}
|
|
134
|
-
// ═══════════════════════════════════════════════════════════════════════════════════════════
|
|
135
|
-
// #60 milestone 1 — CODEGEN-ONLY typed-native lowering.
|
|
136
|
-
//
|
|
137
|
-
// bc's typed-native coverage predicate (`coverageRejectReason`, bc#86/#89) requires EVERY
|
|
138
|
-
// componentRef port to be STATICALLY resolvable to a native scalar/string-array/number-literal —
|
|
139
|
-
// the surrogate read graph's single `__scope: {obj:{...}}` port is a BOXED obj literal, which is
|
|
140
|
-
// never statically resolvable (it fails `portIsStatic`), so bc hard-fails ("does not lower to a
|
|
141
|
-
// native Rust type") on EVERY read, covered or not, before this lowering. Splitting `__scope` into
|
|
142
|
-
// individual scalar ref ports (one per referenced head) makes the shape ELIGIBLE; typing the
|
|
143
|
-
// component's `inputPorts` (bc's authoring default is `unknown` for every scanned `$.head`) then
|
|
144
|
-
// lets each port lower to a CONCRETE Rust/Go field instead of falling through to `Value`.
|
|
145
|
-
//
|
|
146
|
-
// This is a NEW, throwaway `ComponentGraphIR` built FROM the bundle's `readGraph` fields
|
|
147
|
-
// (`ir`/`statementsById`, both already computed by the EXISTING `compileReadGraph` — untouched
|
|
148
|
-
// here) — it is never written back onto `SqlBundle`/`ReadGraph`, never serialized, and the
|
|
149
|
-
// ir/interpret exec surface (`executeReadGraph`) never sees it (it keeps reading `readGraph.ir`,
|
|
150
|
-
// the boxed-`__scope` form, directly). Purely a generation-time input to `generateModule`.
|
|
151
|
-
// ═══════════════════════════════════════════════════════════════════════════════════════════
|
|
152
|
-
/** The makeSQL surrogate node's synthetic port name (mirrors `static-bundle.ts`'s private `SCOPE_PORT`
|
|
153
|
-
* — duplicated as a literal here rather than exported, keeping this a codegen-only concern). */
|
|
154
|
-
const SCOPE_PORT = '__scope';
|
|
155
|
-
/** A head could not be typed for typed-native codegen — the read is NOT typed-native-coverable. */
|
|
156
|
-
class TypedNativeCoverageError extends Error {
|
|
157
|
-
component;
|
|
158
|
-
reasons;
|
|
159
|
-
constructor(component, reasons) {
|
|
160
|
-
super(`litedbmodel codegen (#60 m1): component '${component}' is not typed-native-coverable:\n` +
|
|
161
|
-
reasons.map((r) => ` - ${r}`).join('\n') +
|
|
162
|
-
`\n\nbc's typed-native endpoint (bc#77/#90) fails closed on an uncovered shape — this is NOT ` +
|
|
163
|
-
`regenerated on the boxed '-typed'/'-typed-raw' emitter (retired from litedbmodel's codegen ` +
|
|
164
|
-
`surface, #60 milestone 1). Report this as a bc#86 coverage gap (array-typed / non-scalar ` +
|
|
165
|
-
`input heads have no native port type yet), or exclude this case from native-codegen benching.`);
|
|
166
|
-
this.component = component;
|
|
167
|
-
this.reasons = reasons;
|
|
168
|
-
this.name = 'TypedNativeCoverageError';
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
exports.TypedNativeCoverageError = TypedNativeCoverageError;
|
|
172
|
-
/** Extract the `{table, column}` a where-fragment statement's leading SQL token names, for the
|
|
173
|
-
* closed set of fragment shapes `compileSelectNode`/`lowerWhereMember` emit: `<col> <op> ?`
|
|
174
|
-
* (eq/cmp/LIKE/ILIKE). Returns undefined for any other shape (head-count / SQL text mismatch) —
|
|
175
|
-
* the caller treats that head as NOT resolvable (fail-closed), never guesses. */
|
|
176
|
-
const WHERE_FRAGMENT_COLUMN = /^([A-Za-z_][A-Za-z0-9_]*)\s+(?:=|<>|<=|>=|<|>|LIKE|ILIKE)\s*\?$/;
|
|
177
|
-
/** Extract the table name from the head `SELECT … FROM <table>` statement (dialect-tuned, but the
|
|
178
|
-
* `FROM <table>` token is stable across dialects/CTEs — `compileSelectNode`'s head always ends
|
|
179
|
-
* ` FROM <table>[ …]`; a JOIN/CTE-shaped head is out of scope for this narrow codegen deriver and
|
|
180
|
-
* reported as unresolvable rather than mis-parsed). */
|
|
181
|
-
const SELECT_FROM_TABLE = /\bFROM\s+([A-Za-z_][A-Za-z0-9_]*)\b/i;
|
|
182
|
-
/**
|
|
183
|
-
* Derive each input head's bc scalar type from a read node's compiled {@link StaticStatement}s
|
|
184
|
-
* (spec §4.1 schema SoT), for bc's typed-native codegen (#60 m1). Works from the ALREADY-COMPILED
|
|
185
|
-
* statement templates (available on `ReadGraph.statementsById`, which codegen already carries)
|
|
186
|
-
* instead of re-walking the authored component — so this lowering needs NO extra input beyond
|
|
187
|
-
* what `SqlBundle`/`ReadGraph` already expose (no change to `compileReadGraph`/`ReadGraph`).
|
|
188
|
-
*
|
|
189
|
-
* Returns the typed heads found, PLUS `unresolved` — heads referenced by a param that is NOT a
|
|
190
|
-
* bare single-segment `{ref:[head]}` (e.g. `whereIn`'s `{__jsonArray:{ref:[…]},dialect}` array
|
|
191
|
-
* param) or whose owning fragment's SQL text isn't the closed `<col> <op> ?` shape. A non-empty
|
|
192
|
-
* `unresolved` means the read is NOT typed-native-coverable (fail-closed at the caller).
|
|
193
|
-
*/
|
|
194
|
-
function deriveHeadTypesFromStatements(statements, resolveColumnType) {
|
|
195
|
-
const byHead = new Map();
|
|
196
|
-
const unresolved = new Map();
|
|
197
|
-
// The head statement (`SELECT … FROM <table>`) — always statements[0] (compileSelectNode always
|
|
198
|
-
// pushes it first); its table name resolves every WHERE fragment's column type.
|
|
199
|
-
const head = statements[0];
|
|
200
|
-
const tableMatch = head === undefined ? null : SELECT_FROM_TABLE.exec(head.sql);
|
|
201
|
-
const table = tableMatch?.[1];
|
|
202
|
-
for (const stmt of statements) {
|
|
203
|
-
if (stmt.whereFragment !== true)
|
|
204
|
-
continue;
|
|
205
|
-
for (const param of stmt.params) {
|
|
206
|
-
const path = refPathOf(param);
|
|
207
|
-
if (path === undefined || path.length !== 1) {
|
|
208
|
-
// Not a bare single-segment ref (e.g. the `whereIn` `__jsonArray` array param, or a nested
|
|
209
|
-
// literal): if it names a head at all, surface it; otherwise it simply isn't head-typable
|
|
210
|
-
// here (a literal has no head to report).
|
|
211
|
-
const named = headNameOf(param);
|
|
212
|
-
if (named !== undefined) {
|
|
213
|
-
unresolved.set(named, `input head '${named}' is bound by a non-scalar param shape (${JSON.stringify(param)}) — bc's ` +
|
|
214
|
-
`typed-native emitter has no native port type for it (string/int/float/bool scalars only).`);
|
|
215
|
-
}
|
|
216
|
-
continue;
|
|
217
|
-
}
|
|
218
|
-
const headName = path[0];
|
|
219
|
-
if (table === undefined) {
|
|
220
|
-
unresolved.set(headName, `input head '${headName}': could not resolve the owning table from the SELECT head SQL ('${head?.sql ?? '<none>'}')`);
|
|
221
|
-
continue;
|
|
222
|
-
}
|
|
223
|
-
const m = WHERE_FRAGMENT_COLUMN.exec(stmt.sql.trim());
|
|
224
|
-
if (m === null) {
|
|
225
|
-
unresolved.set(headName, `input head '${headName}': WHERE fragment SQL '${stmt.sql}' is not the closed '<col> <op> ?' shape this codegen-only deriver covers`);
|
|
226
|
-
continue;
|
|
227
|
-
}
|
|
228
|
-
const column = m[1];
|
|
229
|
-
const sqlType = resolveColumnType(table, column);
|
|
230
|
-
const scalar = (0, coltype_1.sqlTypeToBcScalar)(sqlType);
|
|
231
|
-
const prior = byHead.get(headName);
|
|
232
|
-
if (prior !== undefined && prior !== scalar) {
|
|
233
|
-
unresolved.set(headName, `input head '${headName}' resolves to conflicting scalar types ('${prior}' vs '${scalar}') across statements`);
|
|
234
|
-
continue;
|
|
235
|
-
}
|
|
236
|
-
byHead.set(headName, scalar);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
return { byHead, unresolved };
|
|
240
|
-
}
|
|
241
|
-
/** A statement param's bare ref path (`{ref:[…]}`/`{refOpt:[…]}`), or undefined if it isn't one. */
|
|
242
|
-
function refPathOf(param) {
|
|
243
|
-
if (param === null || typeof param !== 'object' || Array.isArray(param))
|
|
244
|
-
return undefined;
|
|
245
|
-
const keys = Object.keys(param);
|
|
246
|
-
if (keys.length !== 1 || (keys[0] !== 'ref' && keys[0] !== 'refOpt'))
|
|
247
|
-
return undefined;
|
|
248
|
-
const path = param[keys[0]];
|
|
249
|
-
if (!Array.isArray(path) || path.length === 0 || !path.every((s) => typeof s === 'string'))
|
|
250
|
-
return undefined;
|
|
251
|
-
return path;
|
|
252
|
-
}
|
|
253
|
-
/** The head name a non-bare-ref param shape still names (e.g. `{__jsonArray:{ref:[head]},…}`), for
|
|
254
|
-
* a clearer diagnostic — undefined when no head can be identified at all (a plain literal). */
|
|
255
|
-
function headNameOf(param) {
|
|
256
|
-
if (param === null || typeof param !== 'object' || Array.isArray(param))
|
|
257
|
-
return undefined;
|
|
258
|
-
const obj = param;
|
|
259
|
-
if ('__jsonArray' in obj) {
|
|
260
|
-
const inner = refPathOf(obj.__jsonArray);
|
|
261
|
-
return inner?.[0];
|
|
262
|
-
}
|
|
263
|
-
return undefined;
|
|
264
|
-
}
|
|
265
|
-
/**
|
|
266
|
-
* Lower a read bundle's surrogate `ComponentGraphIR` into a NEW, CODEGEN-ONLY IR eligible for bc's
|
|
267
|
-
* typed-native endpoint (#60 milestone 1): split the single `__scope: {obj:{...}}` boxed port into
|
|
268
|
-
* individual scalar `{ref:[head]}` ports, and type the component's `inputPorts` from the schema
|
|
269
|
-
* (via {@link deriveHeadTypesFromStatements}). Throws {@link TypedNativeCoverageError} if any
|
|
270
|
-
* referenced head cannot be natively typed (e.g. an IN-list's array head) — NO silent `unknown`
|
|
271
|
-
* port, NO fallback. Does NOT mutate `bundle`/`bundle.readGraph` (a fresh IR object is returned);
|
|
272
|
-
* the ir/interpret exec surface's `executeReadGraph` keeps consuming the ORIGINAL `readGraph.ir`.
|
|
273
|
-
*
|
|
274
|
-
* Scope: bc's typed-native predicate itself still governs `map`/`cond`/relationKind/policy
|
|
275
|
-
* coverage (this lowering does not special-case those — `generateModule` fails closed on them with
|
|
276
|
-
* its own detailed diagnostic, which this function does not need to duplicate).
|
|
277
|
-
*/
|
|
278
|
-
function lowerReadGraphForTypedNative(readGraph, resolveColumnType) {
|
|
279
|
-
const ir = readGraph.ir;
|
|
280
|
-
const reasons = [];
|
|
281
|
-
const components = ir.components.map((c) => {
|
|
282
|
-
const inputPortTypes = new Map();
|
|
283
|
-
const body = c.body.map((n) => {
|
|
284
|
-
if ('cond' in n)
|
|
285
|
-
return n;
|
|
286
|
-
const isMapNode = 'map' in n;
|
|
287
|
-
const ref = isMapNode ? n.map : n;
|
|
288
|
-
const scopeVal = ref.ports[SCOPE_PORT];
|
|
289
|
-
if (scopeVal === undefined || typeof scopeVal !== 'object' || scopeVal === null || !('obj' in scopeVal)) {
|
|
290
|
-
// Not the makeSQL surrogate shape this lowering targets (defensive — every read-graph body
|
|
291
|
-
// node IS this shape by construction) — leave the node untouched; bc's own coverage check
|
|
292
|
-
// will report it if it is genuinely uncovered.
|
|
293
|
-
return n;
|
|
294
|
-
}
|
|
295
|
-
const obj = scopeVal.obj;
|
|
296
|
-
const stmts = readGraph.statementsById[n.id] ?? [];
|
|
297
|
-
const { byHead, unresolved } = deriveHeadTypesFromStatements(stmts, resolveColumnType);
|
|
298
|
-
for (const [, reason] of unresolved)
|
|
299
|
-
reasons.push(`node '${n.id}': ${reason}`);
|
|
300
|
-
for (const [head, scalar] of byHead) {
|
|
301
|
-
const prior = inputPortTypes.get(head);
|
|
302
|
-
if (prior !== undefined && prior !== scalar) {
|
|
303
|
-
reasons.push(`input head '${head}' resolves to conflicting scalar types ('${prior}' vs '${scalar}') across nodes`);
|
|
304
|
-
continue;
|
|
305
|
-
}
|
|
306
|
-
inputPortTypes.set(head, scalar);
|
|
307
|
-
}
|
|
308
|
-
// Every head the surrogate scope references must have been typed above (byHead) — a head
|
|
309
|
-
// present in `obj` but absent from `byHead`/`unresolved` indicates a param shape this
|
|
310
|
-
// deriver's statement walk did not visit (e.g. a non-WHERE port); report it too rather than
|
|
311
|
-
// silently emitting an untyped scalar ref port.
|
|
312
|
-
const newPorts = {};
|
|
313
|
-
for (const head of Object.keys(obj)) {
|
|
314
|
-
if (!byHead.has(head) && !unresolved.has(head)) {
|
|
315
|
-
reasons.push(`node '${n.id}': input head '${head}' referenced by the surrogate scope but not resolved by any WHERE fragment — cannot type it for native codegen`);
|
|
316
|
-
continue;
|
|
317
|
-
}
|
|
318
|
-
newPorts[head] = { ref: [head] };
|
|
319
|
-
}
|
|
320
|
-
return isMapNode
|
|
321
|
-
? { ...n, map: { ...n.map, ports: newPorts } }
|
|
322
|
-
: { ...n, ports: newPorts };
|
|
323
|
-
});
|
|
324
|
-
if (reasons.length > 0)
|
|
325
|
-
throw new TypedNativeCoverageError(c.name, reasons);
|
|
326
|
-
// Only emit an `inputPorts` entry for a head the COVERED plane actually references (a
|
|
327
|
-
// native-scalar port on some node's lowered ports). bc's authoring layer registers an
|
|
328
|
-
// `inputPorts` entry for every `$.head` the authored method SOURCE accesses — including a
|
|
329
|
-
// head used ONLY as a WHERE-fragment's LHS COLUMN-name marker (e.g. `whereGe($.created_at,
|
|
330
|
-
// $.since)` accesses `$.created_at` to name the column, never as a bound RHS value), which
|
|
331
|
-
// never appears in the surrogate `__scope` obj at all. Keeping such a stray entry with its
|
|
332
|
-
// original `unknown` schema type would emit an unresolvable `InNR<Comp>.field: Value` (bc's
|
|
333
|
-
// typed-native `InNR` struct declares a field for EVERY declared inputPort) — a compile error,
|
|
334
|
-
// since the covered module imports no `Value` type. Dropping it is sound: the covered plane
|
|
335
|
-
// never reads it (no lowered port references it), so omitting the `InNR` field changes nothing
|
|
336
|
-
// observable — every REAL WHERE-bound head is still typed + present (typed above, in `byHead`).
|
|
337
|
-
const inputPorts = {};
|
|
338
|
-
for (const [name, scalar] of inputPortTypes) {
|
|
339
|
-
const schema = (c.inputPorts ?? {})[name];
|
|
340
|
-
inputPorts[name] = schema === undefined ? { required: true, type: scalar } : { ...schema, type: scalar };
|
|
341
|
-
}
|
|
342
|
-
return { ...c, body, inputPorts };
|
|
343
|
-
});
|
|
344
|
-
return { ...ir, components };
|
|
345
|
-
}
|
|
346
|
-
/**
|
|
347
|
-
* Resolve the READ codegen emitter for a target language, or throw. No fallback: a language
|
|
348
|
-
* without a registered endpoint is a bc capability gap that fails LOUDLY (never a silent
|
|
349
|
-
* substitution of the literal/interpreter/boxed emitter — an unspec'd fallback is invalid).
|
|
350
|
-
*/
|
|
351
|
-
function typedEmitterFor(language, registered) {
|
|
352
|
-
if (!exports.CODEGEN_LANGUAGES.includes(language)) {
|
|
353
|
-
throw new Error(`litedbmodel codegen: language '${language}' is not a supported target (supported: ${exports.CODEGEN_LANGUAGES.join(', ')})`);
|
|
354
|
-
}
|
|
355
|
-
const emitter = exports.CODEGEN_EMITTER[language];
|
|
356
|
-
if (emitter === undefined) {
|
|
357
|
-
throw new Error(`litedbmodel codegen: no READ codegen endpoint for '${language}'. litedbmodel codegen is STATIC ` +
|
|
358
|
-
`de-interpreted codegen (spec §9) with NO literal/interpreter/boxed fallback (an unspec'd fallback ` +
|
|
359
|
-
`is invalid). bc registers a READ endpoint only for ${Object.keys(exports.CODEGEN_EMITTER).join('/')} — a ` +
|
|
360
|
-
`'${language}' endpoint is a bc capability gap. ESCALATE to bc (bc#22 pattern); never substitute ` +
|
|
361
|
-
`the literal emitter.`);
|
|
362
|
-
}
|
|
363
|
-
if (!registered.includes(emitter)) {
|
|
364
|
-
throw new Error(`litedbmodel codegen: bc's shared generator does not register the '${emitter}' emitter for '${language}' ` +
|
|
365
|
-
`(bc registered: ${[...registered].sort().join(', ')}). ESCALATE to bc (bc#22 pattern), never fork locally.`);
|
|
366
|
-
}
|
|
367
|
-
return emitter;
|
|
368
|
-
}
|
|
369
|
-
/**
|
|
370
|
-
* Shape-INDEPENDENT emitter resolution — identical to {@link typedEmitterFor} now that there is
|
|
371
|
-
* exactly one READ endpoint per language (kept as a distinct export for callers that historically
|
|
372
|
-
* used the shape-independent form; both resolve the SAME table).
|
|
373
|
-
*/
|
|
374
|
-
function codegenEmitterFor(language, registered) {
|
|
375
|
-
return typedEmitterFor(language, registered);
|
|
376
|
-
}
|
|
377
|
-
/** Does a resolved emitter id end in bc's typed-native suffix (`-typed-native`)? Only THOSE
|
|
378
|
-
* emitters need (and are eligible for) the `__scope`-obj-splitting lowering — a boxed endpoint
|
|
379
|
-
* (`typescript-typed`) accepts the ORIGINAL surrogate IR just fine (it consumes a boxed `Value`
|
|
380
|
-
* port either way), so lowering it would needlessly narrow TS's coverage (e.g. `whereIn`'s
|
|
381
|
-
* array-typed head, which typed-native cannot cover but the boxed TS endpoint handles today). */
|
|
382
|
-
function isTypedNativeEmitter(emitter) {
|
|
383
|
-
return emitter.endsWith('-typed-native');
|
|
384
|
-
}
|
|
385
|
-
/**
|
|
386
|
-
* Generate the mode-3 READ codegen artifact for ONE §8 READ bundle in ONE target language. For a
|
|
387
|
-
* typed-NATIVE target (go/rust, bc#77/#90), lowers the bundle's surrogate read graph into the
|
|
388
|
-
* typed-native-eligible IR ({@link lowerReadGraphForTypedNative}) first — REAL static native
|
|
389
|
-
* source, RUNTIME-FREE, no baked-IR interpret path. For any OTHER registered endpoint (currently
|
|
390
|
-
* only TS's boxed `typescript-typed`, which has no typed-native counterpart yet), the ORIGINAL
|
|
391
|
-
* portable IR ({@link bundleToPortableIR}) is used unchanged — the lowering is typed-native-only
|
|
392
|
-
* and would needlessly narrow a boxed endpoint's existing coverage. litedbmodel supplies the
|
|
393
|
-
* input (portable IR + catalog); bc owns the emitter.
|
|
394
|
-
*
|
|
395
|
-
* WRITE bundles are OUT OF SCOPE (#60 milestone 1: writes stay on the existing write/tx execution
|
|
396
|
-
* path, never a codegen module) — throws if `bundle.readGraph` is absent.
|
|
397
|
-
*/
|
|
398
|
-
function generateCodegenArtifact(bundle, language, registeredLanguages, resolveColumnType, runtimeImport) {
|
|
399
|
-
if (bundle.readGraph === undefined) {
|
|
400
|
-
throw new Error(`litedbmodel codegen (#60 m1): bundle '${bundle.name}' has no readGraph — WRITE bundles are not ` +
|
|
401
|
-
`codegen-module cases (they stay on the existing write/tx execution path). Only READ bundles ` +
|
|
402
|
-
`are generated through generateCodegenArtifact.`);
|
|
403
|
-
}
|
|
404
|
-
const emitter = typedEmitterFor(language, registeredLanguages);
|
|
405
|
-
// The portable IR exists ONLY transiently here as the generator's input — it is NOT part of the
|
|
406
|
-
// codegen OUTPUT (no artifact field, no file, no binary; the codegen path never reads IR data).
|
|
407
|
-
const ir = isTypedNativeEmitter(emitter)
|
|
408
|
-
? lowerReadGraphForTypedNative(bundle.readGraph, resolveColumnType)
|
|
409
|
-
: bundleToPortableIR(bundle);
|
|
410
|
-
const module = (0, behavior_contracts_1.generateModule)(ir, runtimeImport === undefined ? { language: emitter } : { language: emitter, runtimeImport });
|
|
411
|
-
return { language: language, module, companion: companionOf(bundle), bundle };
|
|
412
|
-
}
|
|
413
|
-
/**
|
|
414
|
-
* The TS codegen EXECUTION path used to PROVE behavior-identity: a codegen runtime reads the SQL
|
|
415
|
-
* catalog companion (the STATIC makeSQL bundle) and evaluates skip + value-specs → assemble →
|
|
416
|
-
* render → execute — which is EXACTLY {@link executeBundle} over the SAME bundle.
|
|
417
|
-
*/
|
|
418
|
-
function codegenExecuteBundleForTest(artifact, input, db) {
|
|
419
|
-
return (0, runtime_1.executeBundle)(artifact.bundle, input, { db });
|
|
420
|
-
}
|
|
421
|
-
//# sourceMappingURL=codegen.js.map
|
package/dist/scp/codegen.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"codegen.js","sourceRoot":"","sources":["../../src/scp/codegen.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* litedbmodel v2 SCP — FIND_FILTER fail-closed authoring guard (#47 Finding B / plan R8).
|
|
3
|
-
*
|
|
4
|
-
* `FIND_FILTER` is a v1 PER-MODEL implicit predicate (a soft-delete / tenant scope) that
|
|
5
|
-
* v1 MERGES into the WHERE of every internal `find()`/`count()` before compiling
|
|
6
|
-
* (`DBModel._buildSelectSQL` / `_count`: `normalizedCond.add(condsToRecord(FIND_FILTER))`).
|
|
7
|
-
* It is not a distinct SQL construct — it manifests purely as extra WHERE fragments.
|
|
8
|
-
*
|
|
9
|
-
* The SCP compile path (`L.Select({ where })` → `compileReadGraph` → `renderReadPrimary`)
|
|
10
|
-
* is AUTHORED from an explicit `where`; it has NO `DBModel` class context, so it CANNOT
|
|
11
|
-
* auto-apply a model's `FIND_FILTER` (there is no model reference at compile time, and no
|
|
12
|
-
* production seam routes a `DBModel` into the SCP compile — grep: `FIND_FILTER` appears only
|
|
13
|
-
* in `DBModel`/`decorators`/`types`, never under `src/scp/`). Auto-apply is therefore
|
|
14
|
-
* impossible without model context the SCP compile does not have.
|
|
15
|
-
*
|
|
16
|
-
* Resolution = the plan's variant chosen fail-closed: a model that DECLARES a `FIND_FILTER`
|
|
17
|
-
* MUST have its scope predicates folded into the authored `L.Select({ where })`; if the
|
|
18
|
-
* author routes such a model through SCP WITHOUT the scope keys, this guard throws loudly
|
|
19
|
-
* ({@link FindFilterLeakError}) rather than silently dropping the filter (which would leak
|
|
20
|
-
* soft-deleted / cross-tenant rows — a correctness bug, not a cosmetic one). When the scope
|
|
21
|
-
* keys ARE present the guard is a no-op (byte-identical to v1's merged WHERE — proven in
|
|
22
|
-
* `test/scp/find-filter-noop.test.ts`).
|
|
23
|
-
*/
|
|
24
|
-
import { type Conds } from '../Column';
|
|
25
|
-
/** A `DBModel`-shaped source: the only field this guard reads is the optional `FIND_FILTER`. */
|
|
26
|
-
export interface FindFilterSource {
|
|
27
|
-
/** The per-model implicit scope predicate (v1 `DBModel.FIND_FILTER`), or null/undefined. */
|
|
28
|
-
readonly FIND_FILTER?: Conds | null;
|
|
29
|
-
/** Class name for diagnostics (present on every `DBModel` subclass). */
|
|
30
|
-
readonly name?: string;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* A model declaring a `FIND_FILTER` was compiled via the SCP path without its scope
|
|
34
|
-
* predicates present in the authored WHERE — the filter would silently leak. Thrown
|
|
35
|
-
* fail-closed at compile time; never swallowed.
|
|
36
|
-
*/
|
|
37
|
-
export declare class FindFilterLeakError extends Error {
|
|
38
|
-
/** The declaring model's class name (diagnostics). */
|
|
39
|
-
readonly modelName: string;
|
|
40
|
-
/** The FIND_FILTER scope keys that are MISSING from the authored WHERE. */
|
|
41
|
-
readonly missingKeys: readonly string[];
|
|
42
|
-
constructor(
|
|
43
|
-
/** The declaring model's class name (diagnostics). */
|
|
44
|
-
modelName: string,
|
|
45
|
-
/** The FIND_FILTER scope keys that are MISSING from the authored WHERE. */
|
|
46
|
-
missingKeys: readonly string[]);
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Extract the top-level predicate KEYS a `FIND_FILTER` folds into a WHERE. Uses the SAME
|
|
50
|
-
* `condsToRecord` v1 runs when merging (`DBModel._buildSelectSQL`:597) so the key set is
|
|
51
|
-
* exactly what v1 would add to `normalizedCond`. `__or__` (grouped OR) is kept as a key so a
|
|
52
|
-
* scoped OR-group also demands explicit authoring (fail-closed; never silently satisfied).
|
|
53
|
-
*/
|
|
54
|
-
export declare function findFilterKeys(filter: Conds | null | undefined): string[];
|
|
55
|
-
/**
|
|
56
|
-
* Fail-closed guard: assert a model's `FIND_FILTER` scope keys are all present in the
|
|
57
|
-
* authored WHERE key set BEFORE an SCP compile of that model. No FIND_FILTER → no-op. When
|
|
58
|
-
* present, EVERY scope key must appear in `authoredWhereKeys`; any missing key throws
|
|
59
|
-
* {@link FindFilterLeakError}. The caller passes the top-level keys of the object it hands to
|
|
60
|
-
* `L.Select({ where })` (the same shape `condsToRecord` yields), so the check compares
|
|
61
|
-
* like-for-like against v1's merged predicate.
|
|
62
|
-
*
|
|
63
|
-
* @param model a `DBModel`-shaped source that MAY declare `FIND_FILTER`.
|
|
64
|
-
* @param authoredWhereKeys the top-level WHERE keys the SCP author expressed for this model.
|
|
65
|
-
* @throws FindFilterLeakError when a declared scope key is absent from the authored WHERE.
|
|
66
|
-
*/
|
|
67
|
-
export declare function assertFindFilterFolded(model: FindFilterSource, authoredWhereKeys: Iterable<string>): void;
|
|
68
|
-
//# sourceMappingURL=find-filter-guard.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"find-filter-guard.d.ts","sourceRoot":"","sources":["../../src/scp/find-filter-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAiB,KAAK,KAAK,EAAE,MAAM,WAAW,CAAC;AAEtD,gGAAgG;AAChG,MAAM,WAAW,gBAAgB;IAC/B,4FAA4F;IAC5F,QAAQ,CAAC,WAAW,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;IACpC,wEAAwE;IACxE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;GAIG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;IAE1C,sDAAsD;IACtD,QAAQ,CAAC,SAAS,EAAE,MAAM;IAC1B,2EAA2E;IAC3E,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE;;IAHvC,sDAAsD;IAC7C,SAAS,EAAE,MAAM;IAC1B,2EAA2E;IAClE,WAAW,EAAE,SAAS,MAAM,EAAE;CAY1C;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,KAAK,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,EAAE,CAGzE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,gBAAgB,EACvB,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,GAClC,IAAI,CAQN"}
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* litedbmodel v2 SCP — FIND_FILTER fail-closed authoring guard (#47 Finding B / plan R8).
|
|
4
|
-
*
|
|
5
|
-
* `FIND_FILTER` is a v1 PER-MODEL implicit predicate (a soft-delete / tenant scope) that
|
|
6
|
-
* v1 MERGES into the WHERE of every internal `find()`/`count()` before compiling
|
|
7
|
-
* (`DBModel._buildSelectSQL` / `_count`: `normalizedCond.add(condsToRecord(FIND_FILTER))`).
|
|
8
|
-
* It is not a distinct SQL construct — it manifests purely as extra WHERE fragments.
|
|
9
|
-
*
|
|
10
|
-
* The SCP compile path (`L.Select({ where })` → `compileReadGraph` → `renderReadPrimary`)
|
|
11
|
-
* is AUTHORED from an explicit `where`; it has NO `DBModel` class context, so it CANNOT
|
|
12
|
-
* auto-apply a model's `FIND_FILTER` (there is no model reference at compile time, and no
|
|
13
|
-
* production seam routes a `DBModel` into the SCP compile — grep: `FIND_FILTER` appears only
|
|
14
|
-
* in `DBModel`/`decorators`/`types`, never under `src/scp/`). Auto-apply is therefore
|
|
15
|
-
* impossible without model context the SCP compile does not have.
|
|
16
|
-
*
|
|
17
|
-
* Resolution = the plan's variant chosen fail-closed: a model that DECLARES a `FIND_FILTER`
|
|
18
|
-
* MUST have its scope predicates folded into the authored `L.Select({ where })`; if the
|
|
19
|
-
* author routes such a model through SCP WITHOUT the scope keys, this guard throws loudly
|
|
20
|
-
* ({@link FindFilterLeakError}) rather than silently dropping the filter (which would leak
|
|
21
|
-
* soft-deleted / cross-tenant rows — a correctness bug, not a cosmetic one). When the scope
|
|
22
|
-
* keys ARE present the guard is a no-op (byte-identical to v1's merged WHERE — proven in
|
|
23
|
-
* `test/scp/find-filter-noop.test.ts`).
|
|
24
|
-
*/
|
|
25
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.FindFilterLeakError = void 0;
|
|
27
|
-
exports.findFilterKeys = findFilterKeys;
|
|
28
|
-
exports.assertFindFilterFolded = assertFindFilterFolded;
|
|
29
|
-
const Column_1 = require("../Column");
|
|
30
|
-
/**
|
|
31
|
-
* A model declaring a `FIND_FILTER` was compiled via the SCP path without its scope
|
|
32
|
-
* predicates present in the authored WHERE — the filter would silently leak. Thrown
|
|
33
|
-
* fail-closed at compile time; never swallowed.
|
|
34
|
-
*/
|
|
35
|
-
class FindFilterLeakError extends Error {
|
|
36
|
-
modelName;
|
|
37
|
-
missingKeys;
|
|
38
|
-
constructor(
|
|
39
|
-
/** The declaring model's class name (diagnostics). */
|
|
40
|
-
modelName,
|
|
41
|
-
/** The FIND_FILTER scope keys that are MISSING from the authored WHERE. */
|
|
42
|
-
missingKeys) {
|
|
43
|
-
super(`FIND_FILTER leak: model '${modelName}' declares an implicit scope predicate on ` +
|
|
44
|
-
`[${missingKeys.join(', ')}] that is NOT present in the SCP-authored WHERE. The SCP ` +
|
|
45
|
-
`compile cannot auto-apply FIND_FILTER (no model context at compile time), so the ` +
|
|
46
|
-
`scope predicate would be silently dropped (soft-delete / tenant scope leak). Fold ` +
|
|
47
|
-
`the FIND_FILTER predicates into the authored L.Select({ where }) explicitly ` +
|
|
48
|
-
`(e.g. whereEq/whereIsNull on ${missingKeys.join(', ')}).`);
|
|
49
|
-
this.modelName = modelName;
|
|
50
|
-
this.missingKeys = missingKeys;
|
|
51
|
-
this.name = 'FindFilterLeakError';
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
exports.FindFilterLeakError = FindFilterLeakError;
|
|
55
|
-
/**
|
|
56
|
-
* Extract the top-level predicate KEYS a `FIND_FILTER` folds into a WHERE. Uses the SAME
|
|
57
|
-
* `condsToRecord` v1 runs when merging (`DBModel._buildSelectSQL`:597) so the key set is
|
|
58
|
-
* exactly what v1 would add to `normalizedCond`. `__or__` (grouped OR) is kept as a key so a
|
|
59
|
-
* scoped OR-group also demands explicit authoring (fail-closed; never silently satisfied).
|
|
60
|
-
*/
|
|
61
|
-
function findFilterKeys(filter) {
|
|
62
|
-
if (!filter || filter.length === 0)
|
|
63
|
-
return [];
|
|
64
|
-
return Object.keys((0, Column_1.condsToRecord)(filter));
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Fail-closed guard: assert a model's `FIND_FILTER` scope keys are all present in the
|
|
68
|
-
* authored WHERE key set BEFORE an SCP compile of that model. No FIND_FILTER → no-op. When
|
|
69
|
-
* present, EVERY scope key must appear in `authoredWhereKeys`; any missing key throws
|
|
70
|
-
* {@link FindFilterLeakError}. The caller passes the top-level keys of the object it hands to
|
|
71
|
-
* `L.Select({ where })` (the same shape `condsToRecord` yields), so the check compares
|
|
72
|
-
* like-for-like against v1's merged predicate.
|
|
73
|
-
*
|
|
74
|
-
* @param model a `DBModel`-shaped source that MAY declare `FIND_FILTER`.
|
|
75
|
-
* @param authoredWhereKeys the top-level WHERE keys the SCP author expressed for this model.
|
|
76
|
-
* @throws FindFilterLeakError when a declared scope key is absent from the authored WHERE.
|
|
77
|
-
*/
|
|
78
|
-
function assertFindFilterFolded(model, authoredWhereKeys) {
|
|
79
|
-
const required = findFilterKeys(model.FIND_FILTER);
|
|
80
|
-
if (required.length === 0)
|
|
81
|
-
return; // No implicit scope → nothing to fold → no-op.
|
|
82
|
-
const present = new Set(authoredWhereKeys);
|
|
83
|
-
const missing = required.filter((k) => !present.has(k));
|
|
84
|
-
if (missing.length > 0) {
|
|
85
|
-
throw new FindFilterLeakError(model.name ?? '<anonymous model>', missing);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
//# sourceMappingURL=find-filter-guard.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"find-filter-guard.js","sourceRoot":"","sources":["../../src/scp/find-filter-guard.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;;;AA0CH,wCAGC;AAcD,wDAWC;AApED,sCAAsD;AAUtD;;;;GAIG;AACH,MAAa,mBAAoB,SAAQ,KAAK;IAGjC;IAEA;IAJX;IACE,sDAAsD;IAC7C,SAAiB;IAC1B,2EAA2E;IAClE,WAA8B;QAEvC,KAAK,CACH,4BAA4B,SAAS,4CAA4C;YAC/E,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,2DAA2D;YACrF,mFAAmF;YACnF,oFAAoF;YACpF,8EAA8E;YAC9E,gCAAgC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAC7D,CAAC;QAXO,cAAS,GAAT,SAAS,CAAQ;QAEjB,gBAAW,GAAX,WAAW,CAAmB;QAUvC,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAjBD,kDAiBC;AAED;;;;;GAKG;AACH,SAAgB,cAAc,CAAC,MAAgC;IAC7D,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAC9C,OAAO,MAAM,CAAC,IAAI,CAAC,IAAA,sBAAa,EAAC,MAAM,CAAC,CAAC,CAAC;AAC5C,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAgB,sBAAsB,CACpC,KAAuB,EACvB,iBAAmC;IAEnC,MAAM,QAAQ,GAAG,cAAc,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACnD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,+CAA+C;IAClF,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,iBAAiB,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACxD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,mBAAmB,CAAC,KAAK,CAAC,IAAI,IAAI,mBAAmB,EAAE,OAAO,CAAC,CAAC;IAC5E,CAAC;AACH,CAAC"}
|