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,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* litedbmodel v2 SCP — mode-3 codegen (WS7f, #35; spec §9 exec-mode 3 / §10 / §11).
|
|
3
|
+
*
|
|
4
|
+
* The static-codegen execution mode ("Codegen・静的(全言語)— IR → 各言語ソース生成
|
|
5
|
+
* runtime≈0, 入力は可搬IRのみ, bc#13 共有 generator に SQL catalog を供給" — spec §9). It
|
|
6
|
+
* takes a §8 {@link SqlBundle} (already Backend-Compiled TS-side, WS1↔WS3) and, per target
|
|
7
|
+
* language, emits:
|
|
8
|
+
*
|
|
9
|
+
* 1. **Behavior module** — bc's SHARED generator (`generateModule`, bc#13) run over the
|
|
10
|
+
* bundle's SURROGATE component wrapped as a portable {@link ComponentGraphIR}. The generator
|
|
11
|
+
* bakes that IR as a language-native LITERAL (no runtime JSON parse) and emits a `bind(handlers)`
|
|
12
|
+
* accessor that delegates to the EXISTING runtime-core `runBehavior`. litedbmodel writes NO
|
|
13
|
+
* execution logic here — codegen is upstream-owned (bc), we only SUPPLY the input.
|
|
14
|
+
* 2. **SQL catalog companion** — a pure-JSON sidecar carrying the litedbmodel-specific bundle
|
|
15
|
+
* fields that are OUTSIDE bc's portable-IR vocabulary (`operations` / `dialect` /
|
|
16
|
+
* `optionalHeads` / `relations` / `transaction`). This is the "SQL catalog supplied to the
|
|
17
|
+
* shared generator" (§9): a codegen consumer's thin SQL-handler layer reads it to render →
|
|
18
|
+
* execute, exactly as the mode-2 thin-runtime handler does. It is byte-identical to the bundle
|
|
19
|
+
* minus the (now baked-as-literal) `component`/`irVersion`/`exprVersion`.
|
|
20
|
+
*
|
|
21
|
+
* ## Why this is byte-identical to the thin-runtime (mode-2), by construction
|
|
22
|
+
*
|
|
23
|
+
* The mode-2 thin-runtime ({@link executeBundle}) computes
|
|
24
|
+
* `runBehavior({components:[bundle.component]}, buildHandlers(db, operations, dialect),
|
|
25
|
+
* normalizeInput(...), name)`. The generated module bakes `IR === bundle.component` (proven by
|
|
26
|
+
* the FNV-1a fingerprint the generator embeds and re-checks at load) and its `bind(handlers)`
|
|
27
|
+
* calls the SAME `runBehavior(IR, handlers, input, name)`. So when a codegen runtime pairs the
|
|
28
|
+
* generated `bind` with the SAME {@link buildHandlers} + {@link normalizeInput} (from the SQL
|
|
29
|
+
* catalog companion), it drives the identical core over the identical IR and handlers — the SQL
|
|
30
|
+
* text (all dialects) and the results are identical, NOT approximately equal. The TS leg PROVES
|
|
31
|
+
* this by executing the generated module and asserting exact equality vs `executeBundle` AND vs
|
|
32
|
+
* the frozen conformance vector (see `codegenExecuteBundleForTest`).
|
|
33
|
+
*
|
|
34
|
+
* ## Language support (bc#13 capability — the honest scope boundary)
|
|
35
|
+
*
|
|
36
|
+
* bc's shared generator registers emitters for FIVE languages
|
|
37
|
+
* ({@link CODEGEN_LANGUAGES}); Go IS among them (bc#13 SP2 `emit-go.ts`). So litedbmodel mode-3
|
|
38
|
+
* codegen covers all five — TS/Python/Go/Rust/PHP. If a future litedbmodel construct needed an
|
|
39
|
+
* emitter bc does not provide, the honest move is to ESCALATE to bc (bc#22 pattern), never to
|
|
40
|
+
* fork a parallel litedbmodel-local generator (that would defeat the "codegen は上流所有" design).
|
|
41
|
+
*/
|
|
42
|
+
import { type ComponentGraphIR, type GeneratedModule, type Scope, type Value } from 'behavior-contracts';
|
|
43
|
+
import type { SqlBundle, SqliteDb } from './runtime';
|
|
44
|
+
import { type DialectName } from './dialect';
|
|
45
|
+
import type { CompiledOperation } from './ir';
|
|
46
|
+
import type { RelationOp } from './relation';
|
|
47
|
+
import type { TransactionPlan } from './write-plan';
|
|
48
|
+
/**
|
|
49
|
+
* The languages litedbmodel mode-3 codegen supports — exactly the set bc's shared generator
|
|
50
|
+
* registers (bc#13 SP1 typescript/python + SP2 go/rust/php). This is a FIXED capability the
|
|
51
|
+
* generator advertises via `registeredLanguages()`; {@link assertLanguageSupported} verifies the
|
|
52
|
+
* requested language against the LIVE registry so a bc capability change is caught loudly rather
|
|
53
|
+
* than silently drifting from this constant.
|
|
54
|
+
*/
|
|
55
|
+
export declare const CODEGEN_LANGUAGES: readonly ["typescript", "python", "go", "rust", "php"];
|
|
56
|
+
export type CodegenLanguage = (typeof CODEGEN_LANGUAGES)[number];
|
|
57
|
+
/**
|
|
58
|
+
* The SQL catalog companion (spec §9 — the "SQL catalog supplied to the shared generator"): the
|
|
59
|
+
* litedbmodel-specific §8 bundle fields that live OUTSIDE bc's portable-IR vocabulary and so are
|
|
60
|
+
* NOT baked into the generated behavior module. A codegen consumer's thin SQL-handler layer reads
|
|
61
|
+
* this sidecar to render → bind → execute (identically to the mode-2 handler). Pure JSON —
|
|
62
|
+
* round-trips losslessly (proven by the codegen conformance leg).
|
|
63
|
+
*/
|
|
64
|
+
export interface SqlCatalogCompanion {
|
|
65
|
+
/** Backend-Compiled SQL IR per catalog node id (§8) — `sql` + fragment tree + closed-set params. */
|
|
66
|
+
readonly operations: Record<string, CompiledOperation>;
|
|
67
|
+
/** Target SQL dialect (`sqlite`/`postgres`/`mysql`) — compiled once, TS-side (spec §10). */
|
|
68
|
+
readonly dialect: DialectName;
|
|
69
|
+
/** Input heads normalized to present-as-null (absent-key SKIP) — mirrors the bundle. */
|
|
70
|
+
readonly optionalHeads: readonly string[];
|
|
71
|
+
/** Pre-compiled read-relation batch ops (spec §5/§8), keyed by relation name. */
|
|
72
|
+
readonly relations: Record<string, RelationOp>;
|
|
73
|
+
/** Derived gate-first write-time-relations transaction plan (spec §6/§8), for a Command bundle. */
|
|
74
|
+
readonly transaction?: TransactionPlan;
|
|
75
|
+
}
|
|
76
|
+
/** The full codegen artifact for one bundle × one language. */
|
|
77
|
+
export interface CodegenArtifact {
|
|
78
|
+
/** The target language. */
|
|
79
|
+
readonly language: CodegenLanguage;
|
|
80
|
+
/** The generated behavior module (bc's shared generator output — IR baked as a native literal). */
|
|
81
|
+
readonly module: GeneratedModule;
|
|
82
|
+
/** The SQL catalog companion sidecar (the litedbmodel-specific execution catalog). */
|
|
83
|
+
readonly companion: SqlCatalogCompanion;
|
|
84
|
+
/**
|
|
85
|
+
* The portable IR that WAS baked into {@link module} (the surrogate component + envelope). Kept
|
|
86
|
+
* on the artifact so the in-process TS equivalence check drives the IDENTICAL IR the emitted
|
|
87
|
+
* source embeds — the generator's fingerprint (checked at the emitted module's load) proves the
|
|
88
|
+
* baked literal equals this object.
|
|
89
|
+
*/
|
|
90
|
+
readonly ir: ComponentGraphIR;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* The portable {@link ComponentGraphIR} view of a §8 bundle: the surrogate component (wiring /
|
|
94
|
+
* plan / output / `__scope` ports only — every SQL-structural port already collapsed to portable
|
|
95
|
+
* Expression IR TS-side) wrapped with the bundle's IR envelope. This is EXACTLY the IR
|
|
96
|
+
* {@link executeBundle} feeds `runBehavior`, so baking it is what makes codegen equivalent.
|
|
97
|
+
*/
|
|
98
|
+
export declare function bundleToPortableIR(bundle: SqlBundle): ComponentGraphIR;
|
|
99
|
+
/**
|
|
100
|
+
* Assert the requested language is one bc's shared generator can actually emit — checked against
|
|
101
|
+
* the LIVE generator registry, not just the {@link CODEGEN_LANGUAGES} constant, so a bc capability
|
|
102
|
+
* drift (an emitter removed/renamed upstream) fails LOUDLY here instead of surfacing as a broken
|
|
103
|
+
* generated module. `generateModule` itself also fail-closes on an unknown language; this is the
|
|
104
|
+
* earlier, litedbmodel-scoped guard with the honest "bc supports X" message.
|
|
105
|
+
*/
|
|
106
|
+
export declare function assertLanguageSupported(language: string, registered: readonly string[]): asserts language is CodegenLanguage;
|
|
107
|
+
/**
|
|
108
|
+
* Generate the mode-3 codegen artifact for ONE §8 bundle in ONE target language: bc's SHARED
|
|
109
|
+
* generator bakes the surrogate IR literal + emits `bind(handlers)`, and we attach the SQL catalog
|
|
110
|
+
* companion. litedbmodel supplies the input (IR + catalog); bc owns the emitter.
|
|
111
|
+
*
|
|
112
|
+
* @param registeredLanguages the live `registeredLanguages()` from bc (injected so the guard sees
|
|
113
|
+
* the actual generator capability; the caller passes `bc.registeredLanguages()`).
|
|
114
|
+
* @param runtimeImport optional runtime-core import specifier override (test/vendored layouts);
|
|
115
|
+
* forwarded verbatim to the generator so the generated code stays deterministic.
|
|
116
|
+
*/
|
|
117
|
+
export declare function generateCodegenArtifact(bundle: SqlBundle, language: string, registeredLanguages: readonly string[], runtimeImport?: string): CodegenArtifact;
|
|
118
|
+
/**
|
|
119
|
+
* The TS codegen EXECUTION path used to PROVE byte-identity: reconstruct the exact call the
|
|
120
|
+
* generated TS module's `bind(handlers)` makes — `runBehavior(IR, handlers, normalizedInput,
|
|
121
|
+
* name)` — where `IR` is the baked portable IR and `handlers` are the SAME SQL handlers the SQL
|
|
122
|
+
* catalog companion drives ({@link buildHandlers}). Executing this and comparing to
|
|
123
|
+
* {@link executeBundle} is a REAL byte-identity check on the codegen path (the generated TS module
|
|
124
|
+
* is separately IMPORTED and run in the conformance leg to prove the emitted source itself agrees).
|
|
125
|
+
*
|
|
126
|
+
* This mirrors {@link executeBundle} field-for-field, but drives the components/handlers via the
|
|
127
|
+
* codegen ARTIFACT (baked IR + companion) rather than the raw bundle — so a divergence between the
|
|
128
|
+
* codegen artifact and the bundle would surface as a mismatch.
|
|
129
|
+
*/
|
|
130
|
+
export declare function codegenExecuteBundleForTest(artifact: CodegenArtifact, input: Scope, db: SqliteDb): Value;
|
|
131
|
+
//# sourceMappingURL=codegen.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../../src/scp/codegen.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,OAAO,EAAkB,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,KAAK,KAAK,EAAE,KAAK,KAAK,EAAE,MAAM,oBAAoB,CAAC;AACzH,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAGrD,OAAO,EAAc,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AACzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,wDAAyD,CAAC;AACxF,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjE;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,oGAAoG;IACpG,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IACvD,4FAA4F;IAC5F,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAC9B,wFAAwF;IACxF,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C,iFAAiF;IACjF,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,mGAAmG;IACnG,QAAQ,CAAC,WAAW,CAAC,EAAE,eAAe,CAAC;CACxC;AAED,+DAA+D;AAC/D,MAAM,WAAW,eAAe;IAC9B,2BAA2B;IAC3B,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,mGAAmG;IACnG,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IACjC,sFAAsF;IACtF,QAAQ,CAAC,SAAS,EAAE,mBAAmB,CAAC;IACxC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,EAAE,gBAAgB,CAAC;CAC/B;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,gBAAgB,CAMtE;AAaD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,QAAQ,IAAI,eAAe,CAa5H;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,SAAS,EACjB,QAAQ,EAAE,MAAM,EAChB,mBAAmB,EAAE,SAAS,MAAM,EAAE,EACtC,aAAa,CAAC,EAAE,MAAM,GACrB,eAAe,CAKjB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,eAAe,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,GAAG,KAAK,CAOxG"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* litedbmodel v2 SCP — mode-3 codegen (WS7f, #35; spec §9 exec-mode 3 / §10 / §11).
|
|
4
|
+
*
|
|
5
|
+
* The static-codegen execution mode ("Codegen・静的(全言語)— IR → 各言語ソース生成
|
|
6
|
+
* runtime≈0, 入力は可搬IRのみ, bc#13 共有 generator に SQL catalog を供給" — spec §9). It
|
|
7
|
+
* takes a §8 {@link SqlBundle} (already Backend-Compiled TS-side, WS1↔WS3) and, per target
|
|
8
|
+
* language, emits:
|
|
9
|
+
*
|
|
10
|
+
* 1. **Behavior module** — bc's SHARED generator (`generateModule`, bc#13) run over the
|
|
11
|
+
* bundle's SURROGATE component wrapped as a portable {@link ComponentGraphIR}. The generator
|
|
12
|
+
* bakes that IR as a language-native LITERAL (no runtime JSON parse) and emits a `bind(handlers)`
|
|
13
|
+
* accessor that delegates to the EXISTING runtime-core `runBehavior`. litedbmodel writes NO
|
|
14
|
+
* execution logic here — codegen is upstream-owned (bc), we only SUPPLY the input.
|
|
15
|
+
* 2. **SQL catalog companion** — a pure-JSON sidecar carrying the litedbmodel-specific bundle
|
|
16
|
+
* fields that are OUTSIDE bc's portable-IR vocabulary (`operations` / `dialect` /
|
|
17
|
+
* `optionalHeads` / `relations` / `transaction`). This is the "SQL catalog supplied to the
|
|
18
|
+
* shared generator" (§9): a codegen consumer's thin SQL-handler layer reads it to render →
|
|
19
|
+
* execute, exactly as the mode-2 thin-runtime handler does. It is byte-identical to the bundle
|
|
20
|
+
* minus the (now baked-as-literal) `component`/`irVersion`/`exprVersion`.
|
|
21
|
+
*
|
|
22
|
+
* ## Why this is byte-identical to the thin-runtime (mode-2), by construction
|
|
23
|
+
*
|
|
24
|
+
* The mode-2 thin-runtime ({@link executeBundle}) computes
|
|
25
|
+
* `runBehavior({components:[bundle.component]}, buildHandlers(db, operations, dialect),
|
|
26
|
+
* normalizeInput(...), name)`. The generated module bakes `IR === bundle.component` (proven by
|
|
27
|
+
* the FNV-1a fingerprint the generator embeds and re-checks at load) and its `bind(handlers)`
|
|
28
|
+
* calls the SAME `runBehavior(IR, handlers, input, name)`. So when a codegen runtime pairs the
|
|
29
|
+
* generated `bind` with the SAME {@link buildHandlers} + {@link normalizeInput} (from the SQL
|
|
30
|
+
* catalog companion), it drives the identical core over the identical IR and handlers — the SQL
|
|
31
|
+
* text (all dialects) and the results are identical, NOT approximately equal. The TS leg PROVES
|
|
32
|
+
* this by executing the generated module and asserting exact equality vs `executeBundle` AND vs
|
|
33
|
+
* the frozen conformance vector (see `codegenExecuteBundleForTest`).
|
|
34
|
+
*
|
|
35
|
+
* ## Language support (bc#13 capability — the honest scope boundary)
|
|
36
|
+
*
|
|
37
|
+
* bc's shared generator registers emitters for FIVE languages
|
|
38
|
+
* ({@link CODEGEN_LANGUAGES}); Go IS among them (bc#13 SP2 `emit-go.ts`). So litedbmodel mode-3
|
|
39
|
+
* codegen covers all five — TS/Python/Go/Rust/PHP. If a future litedbmodel construct needed an
|
|
40
|
+
* emitter bc does not provide, the honest move is to ESCALATE to bc (bc#22 pattern), never to
|
|
41
|
+
* fork a parallel litedbmodel-local generator (that would defeat the "codegen は上流所有" design).
|
|
42
|
+
*/
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.CODEGEN_LANGUAGES = void 0;
|
|
45
|
+
exports.bundleToPortableIR = bundleToPortableIR;
|
|
46
|
+
exports.assertLanguageSupported = assertLanguageSupported;
|
|
47
|
+
exports.generateCodegenArtifact = generateCodegenArtifact;
|
|
48
|
+
exports.codegenExecuteBundleForTest = codegenExecuteBundleForTest;
|
|
49
|
+
const behavior_contracts_1 = require("behavior-contracts");
|
|
50
|
+
const runtime_1 = require("./runtime");
|
|
51
|
+
const behavior_contracts_2 = require("behavior-contracts");
|
|
52
|
+
const dialect_1 = require("./dialect");
|
|
53
|
+
/**
|
|
54
|
+
* The languages litedbmodel mode-3 codegen supports — exactly the set bc's shared generator
|
|
55
|
+
* registers (bc#13 SP1 typescript/python + SP2 go/rust/php). This is a FIXED capability the
|
|
56
|
+
* generator advertises via `registeredLanguages()`; {@link assertLanguageSupported} verifies the
|
|
57
|
+
* requested language against the LIVE registry so a bc capability change is caught loudly rather
|
|
58
|
+
* than silently drifting from this constant.
|
|
59
|
+
*/
|
|
60
|
+
exports.CODEGEN_LANGUAGES = ['typescript', 'python', 'go', 'rust', 'php'];
|
|
61
|
+
/**
|
|
62
|
+
* The portable {@link ComponentGraphIR} view of a §8 bundle: the surrogate component (wiring /
|
|
63
|
+
* plan / output / `__scope` ports only — every SQL-structural port already collapsed to portable
|
|
64
|
+
* Expression IR TS-side) wrapped with the bundle's IR envelope. This is EXACTLY the IR
|
|
65
|
+
* {@link executeBundle} feeds `runBehavior`, so baking it is what makes codegen equivalent.
|
|
66
|
+
*/
|
|
67
|
+
function bundleToPortableIR(bundle) {
|
|
68
|
+
return {
|
|
69
|
+
irVersion: bundle.irVersion,
|
|
70
|
+
exprVersion: bundle.exprVersion,
|
|
71
|
+
components: [bundle.component],
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/** The litedbmodel-specific execution catalog carried alongside the (baked) portable IR. */
|
|
75
|
+
function companionOf(bundle) {
|
|
76
|
+
const base = {
|
|
77
|
+
operations: bundle.operations,
|
|
78
|
+
dialect: bundle.dialect,
|
|
79
|
+
optionalHeads: bundle.optionalHeads,
|
|
80
|
+
relations: bundle.relations,
|
|
81
|
+
};
|
|
82
|
+
return bundle.transaction === undefined ? base : { ...base, transaction: bundle.transaction };
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Assert the requested language is one bc's shared generator can actually emit — checked against
|
|
86
|
+
* the LIVE generator registry, not just the {@link CODEGEN_LANGUAGES} constant, so a bc capability
|
|
87
|
+
* drift (an emitter removed/renamed upstream) fails LOUDLY here instead of surfacing as a broken
|
|
88
|
+
* generated module. `generateModule` itself also fail-closes on an unknown language; this is the
|
|
89
|
+
* earlier, litedbmodel-scoped guard with the honest "bc supports X" message.
|
|
90
|
+
*/
|
|
91
|
+
function assertLanguageSupported(language, registered) {
|
|
92
|
+
if (!exports.CODEGEN_LANGUAGES.includes(language)) {
|
|
93
|
+
throw new Error(`litedbmodel codegen: language '${language}' is not a supported target (supported: ${exports.CODEGEN_LANGUAGES.join(', ')})`);
|
|
94
|
+
}
|
|
95
|
+
if (!registered.includes(language)) {
|
|
96
|
+
throw new Error(`litedbmodel codegen: bc's shared generator does not register an emitter for '${language}' ` +
|
|
97
|
+
`(bc registered: ${[...registered].sort().join(', ')}). This is a bc#13 capability limit — ESCALATE to bc (bc#22 pattern), ` +
|
|
98
|
+
`never fork a litedbmodel-local generator (codegen は上流所有, spec §9).`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Generate the mode-3 codegen artifact for ONE §8 bundle in ONE target language: bc's SHARED
|
|
103
|
+
* generator bakes the surrogate IR literal + emits `bind(handlers)`, and we attach the SQL catalog
|
|
104
|
+
* companion. litedbmodel supplies the input (IR + catalog); bc owns the emitter.
|
|
105
|
+
*
|
|
106
|
+
* @param registeredLanguages the live `registeredLanguages()` from bc (injected so the guard sees
|
|
107
|
+
* the actual generator capability; the caller passes `bc.registeredLanguages()`).
|
|
108
|
+
* @param runtimeImport optional runtime-core import specifier override (test/vendored layouts);
|
|
109
|
+
* forwarded verbatim to the generator so the generated code stays deterministic.
|
|
110
|
+
*/
|
|
111
|
+
function generateCodegenArtifact(bundle, language, registeredLanguages, runtimeImport) {
|
|
112
|
+
assertLanguageSupported(language, registeredLanguages);
|
|
113
|
+
const ir = bundleToPortableIR(bundle);
|
|
114
|
+
const module = (0, behavior_contracts_1.generateModule)(ir, runtimeImport === undefined ? { language } : { language, runtimeImport });
|
|
115
|
+
return { language, module, companion: companionOf(bundle), ir };
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* The TS codegen EXECUTION path used to PROVE byte-identity: reconstruct the exact call the
|
|
119
|
+
* generated TS module's `bind(handlers)` makes — `runBehavior(IR, handlers, normalizedInput,
|
|
120
|
+
* name)` — where `IR` is the baked portable IR and `handlers` are the SAME SQL handlers the SQL
|
|
121
|
+
* catalog companion drives ({@link buildHandlers}). Executing this and comparing to
|
|
122
|
+
* {@link executeBundle} is a REAL byte-identity check on the codegen path (the generated TS module
|
|
123
|
+
* is separately IMPORTED and run in the conformance leg to prove the emitted source itself agrees).
|
|
124
|
+
*
|
|
125
|
+
* This mirrors {@link executeBundle} field-for-field, but drives the components/handlers via the
|
|
126
|
+
* codegen ARTIFACT (baked IR + companion) rather than the raw bundle — so a divergence between the
|
|
127
|
+
* codegen artifact and the bundle would surface as a mismatch.
|
|
128
|
+
*/
|
|
129
|
+
function codegenExecuteBundleForTest(artifact, input, db) {
|
|
130
|
+
const { ir } = artifact;
|
|
131
|
+
const component = ir.components[0];
|
|
132
|
+
const { operations, dialect, optionalHeads } = artifact.companion;
|
|
133
|
+
const handlers = (0, runtime_1.buildHandlers)(db, operations, (0, dialect_1.dialectFor)(dialect));
|
|
134
|
+
const normalized = (0, runtime_1.normalizeInput)(component, new Set(optionalHeads), input);
|
|
135
|
+
return (0, behavior_contracts_2.runBehavior)(ir, handlers, normalized, component.name);
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=codegen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codegen.js","sourceRoot":"","sources":["../../src/scp/codegen.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* litedbmodel v2 SCP — dialect-parameterized Backend Compile (WS6, #26; spec §4/§5/§8/§10).
|
|
3
|
+
*
|
|
4
|
+
* The SAME Component-graph IR compiles to SQLite, Postgres and MySQL SQL. The IR→structure
|
|
5
|
+
* lowering (SELECT/INSERT/UPDATE/DELETE skeletons, the WHERE fragment tree, `col = ?`, IN-list
|
|
6
|
+
* `(?)` expansion, param slots) is SHARED across dialects; only the genuine dialect divergences
|
|
7
|
+
* (INSERT conflict clause + INSERT verb) are delegated to the {@link Dialect} strategy (the SSoT
|
|
8
|
+
* — no scattered `?:`). Placeholders stay `?` through compilation; the PG `?`→`$N` conversion is
|
|
9
|
+
* a final render-time one-pass ({@link import('./dialect').Dialect.finalizePlaceholders}), NOT a
|
|
10
|
+
* compile-time concern — so the compiled `CompiledOperation.sql` is dialect-tagged but still
|
|
11
|
+
* `?`-placeheld, keeping the bundle uniform.
|
|
12
|
+
*
|
|
13
|
+
* `compile-sqlite.ts` delegates its INSERT compile here with the SQLite dialect, so the pinned
|
|
14
|
+
* SQLite golden (WS1) is preserved byte-for-byte and the PG/MySQL variants diverge ONLY where the
|
|
15
|
+
* v1 SqlBuilders diverge (proven byte-identical in the WS6 dialect-golden test).
|
|
16
|
+
*/
|
|
17
|
+
import type { CompiledOperation, ExprNode } from './ir';
|
|
18
|
+
import type { Dialect } from './dialect';
|
|
19
|
+
/** Column → value Expression IR (insertion order = SQL column order). */
|
|
20
|
+
export interface InsertShape {
|
|
21
|
+
readonly table: string;
|
|
22
|
+
readonly values: Record<string, ExprNode>;
|
|
23
|
+
readonly returning?: readonly string[];
|
|
24
|
+
readonly onConflict?: readonly string[];
|
|
25
|
+
readonly onConflictAction?: 'ignore' | {
|
|
26
|
+
readonly updateColumns: 'all' | readonly string[];
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Compile an INSERT for a given dialect. Byte-identical to the corresponding v1 SqlBuilder's
|
|
31
|
+
* single-record `buildInsert` output (the golden bar):
|
|
32
|
+
* - SQLite: `INSERT [OR IGNORE] INTO t (c) VALUES (?)[ ON CONFLICT (k) DO UPDATE SET c = excluded.c][ RETURNING r]`
|
|
33
|
+
* - Postgres: `INSERT INTO t (c) VALUES (?)[ ON CONFLICT (k) DO NOTHING | DO UPDATE SET c = EXCLUDED.c][ RETURNING r]`
|
|
34
|
+
* - MySQL: `INSERT [IGNORE] INTO t (c) VALUES (?)[ ON DUPLICATE KEY UPDATE c = VALUES(c)]`
|
|
35
|
+
*
|
|
36
|
+
* Placeholders remain `?`; PG's `?`→`$N` is applied at render time.
|
|
37
|
+
*/
|
|
38
|
+
export declare function compileInsertFor(dialect: Dialect, desc: InsertShape): CompiledOperation;
|
|
39
|
+
//# sourceMappingURL=compile-dialect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compile-dialect.d.ts","sourceRoot":"","sources":["../../src/scp/compile-dialect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AACxD,OAAO,KAAK,EAAE,OAAO,EAAkB,MAAM,WAAW,CAAC;AAKzD,yEAAyE;AACzE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC1C,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,QAAQ,GAAG;QAAE,QAAQ,CAAC,aAAa,EAAE,KAAK,GAAG,SAAS,MAAM,EAAE,CAAA;KAAE,CAAC;CAC9F;AAKD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,GAAG,iBAAiB,CAiBvF"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* litedbmodel v2 SCP — dialect-parameterized Backend Compile (WS6, #26; spec §4/§5/§8/§10).
|
|
4
|
+
*
|
|
5
|
+
* The SAME Component-graph IR compiles to SQLite, Postgres and MySQL SQL. The IR→structure
|
|
6
|
+
* lowering (SELECT/INSERT/UPDATE/DELETE skeletons, the WHERE fragment tree, `col = ?`, IN-list
|
|
7
|
+
* `(?)` expansion, param slots) is SHARED across dialects; only the genuine dialect divergences
|
|
8
|
+
* (INSERT conflict clause + INSERT verb) are delegated to the {@link Dialect} strategy (the SSoT
|
|
9
|
+
* — no scattered `?:`). Placeholders stay `?` through compilation; the PG `?`→`$N` conversion is
|
|
10
|
+
* a final render-time one-pass ({@link import('./dialect').Dialect.finalizePlaceholders}), NOT a
|
|
11
|
+
* compile-time concern — so the compiled `CompiledOperation.sql` is dialect-tagged but still
|
|
12
|
+
* `?`-placeheld, keeping the bundle uniform.
|
|
13
|
+
*
|
|
14
|
+
* `compile-sqlite.ts` delegates its INSERT compile here with the SQLite dialect, so the pinned
|
|
15
|
+
* SQLite golden (WS1) is preserved byte-for-byte and the PG/MySQL variants diverge ONLY where the
|
|
16
|
+
* v1 SqlBuilders diverge (proven byte-identical in the WS6 dialect-golden test).
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.compileInsertFor = compileInsertFor;
|
|
20
|
+
/** Row → logical model assembly (shape only). */
|
|
21
|
+
const assembly = (shape) => ({ shape });
|
|
22
|
+
/**
|
|
23
|
+
* Compile an INSERT for a given dialect. Byte-identical to the corresponding v1 SqlBuilder's
|
|
24
|
+
* single-record `buildInsert` output (the golden bar):
|
|
25
|
+
* - SQLite: `INSERT [OR IGNORE] INTO t (c) VALUES (?)[ ON CONFLICT (k) DO UPDATE SET c = excluded.c][ RETURNING r]`
|
|
26
|
+
* - Postgres: `INSERT INTO t (c) VALUES (?)[ ON CONFLICT (k) DO NOTHING | DO UPDATE SET c = EXCLUDED.c][ RETURNING r]`
|
|
27
|
+
* - MySQL: `INSERT [IGNORE] INTO t (c) VALUES (?)[ ON DUPLICATE KEY UPDATE c = VALUES(c)]`
|
|
28
|
+
*
|
|
29
|
+
* Placeholders remain `?`; PG's `?`→`$N` is applied at render time.
|
|
30
|
+
*/
|
|
31
|
+
function compileInsertFor(dialect, desc) {
|
|
32
|
+
const columns = Object.keys(desc.values);
|
|
33
|
+
if (columns.length === 0)
|
|
34
|
+
throw new Error('INSERT requires at least one value column');
|
|
35
|
+
const placeholders = columns.map(() => '?').join(', ');
|
|
36
|
+
const params = columns.map((c) => desc.values[c]);
|
|
37
|
+
const conflictAction = resolveConflictAction(desc, columns);
|
|
38
|
+
const verb = dialect.insertVerb(conflictAction);
|
|
39
|
+
let sql = `${verb} ${desc.table} (${columns.join(', ')}) VALUES (${placeholders})`;
|
|
40
|
+
if (conflictAction !== undefined) {
|
|
41
|
+
sql += dialect.insertConflictClause(desc.onConflict ?? [], conflictAction);
|
|
42
|
+
}
|
|
43
|
+
if (desc.returning !== undefined)
|
|
44
|
+
sql += ` RETURNING ${desc.returning.join(', ')}`;
|
|
45
|
+
return { component: 'Insert', sql, where: null, params, assembly: assembly('items') };
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Resolve the dialect-neutral {@link ConflictAction} from the INSERT description. An `'all'`
|
|
49
|
+
* update-column list is expanded to the concrete inserted columns EXCEPT the conflict keys
|
|
50
|
+
* (matching the v1 SqlBuilders' `onConflictUpdate === 'all' ? columns : …`, which include all
|
|
51
|
+
* columns; the v1 builders use the full `columns` list for `'all'`, so we mirror that exactly).
|
|
52
|
+
* Returns undefined when the INSERT declares no conflict handling.
|
|
53
|
+
*/
|
|
54
|
+
function resolveConflictAction(desc, columns) {
|
|
55
|
+
if (desc.onConflict === undefined || desc.onConflictAction === undefined)
|
|
56
|
+
return undefined;
|
|
57
|
+
if (desc.onConflictAction === 'ignore')
|
|
58
|
+
return 'ignore';
|
|
59
|
+
const cols = desc.onConflictAction.updateColumns === 'all' ? columns : desc.onConflictAction.updateColumns;
|
|
60
|
+
return { updateColumns: cols };
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=compile-dialect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compile-dialect.js","sourceRoot":"","sources":["../../src/scp/compile-dialect.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;AA6BH,4CAiBC;AA7BD,iDAAiD;AACjD,MAAM,QAAQ,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;AAEhD;;;;;;;;GAQG;AACH,SAAgB,gBAAgB,CAAC,OAAgB,EAAE,IAAiB;IAClE,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACzC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IACvF,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvD,MAAM,MAAM,GAAe,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAE9D,MAAM,cAAc,GAAG,qBAAqB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC5D,MAAM,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;IAChD,IAAI,GAAG,GAAG,GAAG,IAAI,IAAI,IAAI,CAAC,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,YAAY,GAAG,CAAC;IAEnF,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;QACjC,GAAG,IAAI,OAAO,CAAC,oBAAoB,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,EAAE,cAAc,CAAC,CAAC;IAC7E,CAAC;IAED,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS;QAAE,GAAG,IAAI,cAAc,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IAEnF,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;AACxF,CAAC;AAED;;;;;;GAMG;AACH,SAAS,qBAAqB,CAAC,IAAiB,EAAE,OAA0B;IAC1E,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,IAAI,IAAI,CAAC,gBAAgB,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC3F,IAAI,IAAI,CAAC,gBAAgB,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IACxD,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC,aAAa,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC;IAC3G,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* litedbmodel v2 SCP — SQLite Backend Compile (WS1, #21).
|
|
3
|
+
*
|
|
4
|
+
* Lowers a structured CRUD operation description (a Component-graph Select/Insert/Update/
|
|
5
|
+
* Delete node with ports) into a {@link CompiledOperation}: SQLite dialect SQL text,
|
|
6
|
+
* a fragment tree (dynamic WHERE/SET with existence rules), and static param slots — the
|
|
7
|
+
* IR shape of spec §8. Placeholders are unified as `?` (the `?`→`$N` pass is PG-only and
|
|
8
|
+
* OUT OF SCOPE for WS1).
|
|
9
|
+
*
|
|
10
|
+
* The generated SQLite SQL is byte-identical to what litedbmodel v1's SqliteSqlBuilder /
|
|
11
|
+
* `DBModel._buildSelectSQL` produce for equivalent queries (the golden bar). In
|
|
12
|
+
* particular:
|
|
13
|
+
* - SELECT: `SELECT <cols> FROM <t>[ WHERE <c>][ GROUP BY <g>][ ORDER BY <o>][ LIMIT ?][ OFFSET ?]`
|
|
14
|
+
* - INSERT: `INSERT INTO <t> (<cols>) VALUES (<vals>)[ RETURNING <r>]`
|
|
15
|
+
* - UPDATE: `UPDATE <t> SET <a = ?, …> WHERE <c>[ RETURNING <r>]`
|
|
16
|
+
* - DELETE: `DELETE FROM <t> WHERE <c>[ RETURNING <r>]`
|
|
17
|
+
* - WHERE parts joined by ` AND ` (or ` OR ` for an OR group), equality `col = ?`,
|
|
18
|
+
* IN-list `col IN (?, …)`, empty array → `1 = 0`, NULL → `col IS NULL`.
|
|
19
|
+
*
|
|
20
|
+
* ## Hard rule: closed Expression IR only
|
|
21
|
+
*
|
|
22
|
+
* Every param slot this compiler emits is an Expression IR node from bc's closed set
|
|
23
|
+
* (`PORTABLE_EXPR_OPERATORS`). NO litedbmodel-local opcode is ever invented. An
|
|
24
|
+
* un-lowerable predicate is the Raw SQL escape hatch's concern (spec §13), not a fake
|
|
25
|
+
* opcode. {@link compileSelect} et al. only construct `ref` / `coalesce` / etc.
|
|
26
|
+
*/
|
|
27
|
+
import type { CompiledOperation, ExprNode } from './ir';
|
|
28
|
+
/** A reference into the input scope or a sibling wire result (Expression IR `ref`). */
|
|
29
|
+
export type Ref = {
|
|
30
|
+
ref: string[];
|
|
31
|
+
};
|
|
32
|
+
/** A single WHERE condition. `skipWhen` (absent → always present) drives SKIP (§8). */
|
|
33
|
+
export type Condition = {
|
|
34
|
+
kind: 'eq';
|
|
35
|
+
column: string;
|
|
36
|
+
value: ExprNode;
|
|
37
|
+
skipWhen?: ExprNode;
|
|
38
|
+
} | {
|
|
39
|
+
kind: 'cmp';
|
|
40
|
+
column: string;
|
|
41
|
+
op: '<' | '<=' | '>' | '>=' | '<>';
|
|
42
|
+
value: ExprNode;
|
|
43
|
+
skipWhen?: ExprNode;
|
|
44
|
+
} | {
|
|
45
|
+
kind: 'isNull';
|
|
46
|
+
column: string;
|
|
47
|
+
skipWhen?: ExprNode;
|
|
48
|
+
} | {
|
|
49
|
+
kind: 'in';
|
|
50
|
+
column: string;
|
|
51
|
+
value: ExprNode;
|
|
52
|
+
skipWhen?: ExprNode;
|
|
53
|
+
}
|
|
54
|
+
/** A nested AND/OR group (parenthesized, dynamic-expansion spec §4). */
|
|
55
|
+
| {
|
|
56
|
+
kind: 'group';
|
|
57
|
+
connector: 'AND' | 'OR';
|
|
58
|
+
conditions: Condition[];
|
|
59
|
+
skipWhen?: ExprNode;
|
|
60
|
+
};
|
|
61
|
+
export interface SelectDesc {
|
|
62
|
+
table: string;
|
|
63
|
+
/** Projection columns; `['*']` renders `*`. */
|
|
64
|
+
select: string[];
|
|
65
|
+
where?: Condition[];
|
|
66
|
+
/** Raw ORDER BY body (dialect-neutral text, e.g. `"created_at DESC"`). */
|
|
67
|
+
order?: string;
|
|
68
|
+
/** GROUP BY body. */
|
|
69
|
+
group?: string;
|
|
70
|
+
/** LIMIT value as an Expression IR node (e.g. a `coalesce` default). */
|
|
71
|
+
limit?: ExprNode;
|
|
72
|
+
/** OFFSET value as an Expression IR node. */
|
|
73
|
+
offset?: ExprNode;
|
|
74
|
+
}
|
|
75
|
+
export interface InsertDesc {
|
|
76
|
+
table: string;
|
|
77
|
+
/** Column → value Expression IR (insertion order = SQL column order). */
|
|
78
|
+
values: Record<string, ExprNode>;
|
|
79
|
+
returning?: string[];
|
|
80
|
+
onConflict?: string[];
|
|
81
|
+
onConflictAction?: 'ignore' | {
|
|
82
|
+
updateColumns: 'all' | string[];
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
export interface UpdateDesc {
|
|
86
|
+
table: string;
|
|
87
|
+
/** Column → value Expression IR (insertion order = SET clause order). */
|
|
88
|
+
set: Record<string, ExprNode>;
|
|
89
|
+
where: Condition[];
|
|
90
|
+
returning?: string[];
|
|
91
|
+
}
|
|
92
|
+
export interface DeleteDesc {
|
|
93
|
+
table: string;
|
|
94
|
+
where: Condition[];
|
|
95
|
+
returning?: string[];
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Compile a SELECT. Static params (LIMIT / OFFSET) sit AFTER the `{where}` splice, so
|
|
99
|
+
* they are emitted after the fragment params (dynamic-expansion spec §6).
|
|
100
|
+
*/
|
|
101
|
+
export declare function compileSelect(desc: SelectDesc): CompiledOperation;
|
|
102
|
+
/**
|
|
103
|
+
* Compile an INSERT (SQLite). All params are static (no WHERE); order = column order. The
|
|
104
|
+
* dialect-specific conflict/verb rendering is delegated to the SQLite {@link SQLITE} strategy
|
|
105
|
+
* ({@link compileInsertFor}) — the SAME dialect-parameterized compile the PG/MySQL Backend
|
|
106
|
+
* Compile uses (WS6), so SQLite is byte-for-byte unchanged and the other dialects diverge only
|
|
107
|
+
* where the v1 SqlBuilders diverge.
|
|
108
|
+
*/
|
|
109
|
+
export declare function compileInsert(desc: InsertDesc): CompiledOperation;
|
|
110
|
+
/** Compile an UPDATE. SET params (static) precede the `{where}` splice (spec §6). */
|
|
111
|
+
export declare function compileUpdate(desc: UpdateDesc): CompiledOperation;
|
|
112
|
+
/** Compile a DELETE. No static params before the WHERE (all params are conditions). */
|
|
113
|
+
export declare function compileDelete(desc: DeleteDesc): CompiledOperation;
|
|
114
|
+
//# sourceMappingURL=compile-sqlite.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compile-sqlite.d.ts","sourceRoot":"","sources":["../../src/scp/compile-sqlite.ts"],"names":[],"mappings":"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"}
|