litedbmodel 2.0.0 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/scp/authoring-sql.d.ts +78 -0
- package/dist/scp/authoring-sql.d.ts.map +1 -1
- package/dist/scp/authoring-sql.js +110 -2
- package/dist/scp/authoring-sql.js.map +1 -1
- package/dist/scp/catalog.d.ts +5 -2
- package/dist/scp/catalog.d.ts.map +1 -1
- package/dist/scp/catalog.js +32 -1
- package/dist/scp/catalog.js.map +1 -1
- package/dist/scp/codegen.d.ts +143 -85
- package/dist/scp/codegen.d.ts.map +1 -1
- package/dist/scp/codegen.js +374 -90
- package/dist/scp/codegen.js.map +1 -1
- package/dist/scp/coltype.d.ts +41 -0
- package/dist/scp/coltype.d.ts.map +1 -0
- package/dist/scp/coltype.js +188 -0
- package/dist/scp/coltype.js.map +1 -0
- package/dist/scp/dialect.d.ts +12 -3
- package/dist/scp/dialect.d.ts.map +1 -1
- package/dist/scp/dialect.js +12 -3
- package/dist/scp/dialect.js.map +1 -1
- package/dist/scp/find-filter-guard.d.ts +68 -0
- package/dist/scp/find-filter-guard.d.ts.map +1 -0
- package/dist/scp/find-filter-guard.js +88 -0
- package/dist/scp/find-filter-guard.js.map +1 -0
- package/dist/scp/fragment/assemble.d.ts +61 -0
- package/dist/scp/fragment/assemble.d.ts.map +1 -0
- package/dist/scp/fragment/assemble.js +156 -0
- package/dist/scp/fragment/assemble.js.map +1 -0
- package/dist/scp/fragment/compile-pg.d.ts +107 -0
- package/dist/scp/fragment/compile-pg.d.ts.map +1 -0
- package/dist/scp/fragment/compile-pg.js +142 -0
- package/dist/scp/fragment/compile-pg.js.map +1 -0
- package/dist/scp/fragment/index.d.ts +16 -0
- package/dist/scp/fragment/index.d.ts.map +1 -0
- package/dist/scp/fragment/index.js +34 -0
- package/dist/scp/fragment/index.js.map +1 -0
- package/dist/scp/fragment/model.d.ts +119 -0
- package/dist/scp/fragment/model.d.ts.map +1 -0
- package/dist/scp/fragment/model.js +66 -0
- package/dist/scp/fragment/model.js.map +1 -0
- package/dist/scp/fragment/pg-array-type.d.ts +13 -0
- package/dist/scp/fragment/pg-array-type.d.ts.map +1 -0
- package/dist/scp/fragment/pg-array-type.js +34 -0
- package/dist/scp/fragment/pg-array-type.js.map +1 -0
- package/dist/scp/guard.d.ts +2 -6
- package/dist/scp/guard.d.ts.map +1 -1
- package/dist/scp/guard.js +19 -22
- package/dist/scp/guard.js.map +1 -1
- package/dist/scp/index.cjs +18695 -3921
- package/dist/scp/index.d.ts +41 -24
- package/dist/scp/index.d.ts.map +1 -1
- package/dist/scp/index.js +134 -49
- package/dist/scp/index.js.map +1 -1
- package/dist/scp/index.mjs +4830 -1432
- package/dist/scp/makesql/authoring-compile.d.ts +90 -0
- package/dist/scp/makesql/authoring-compile.d.ts.map +1 -0
- package/dist/scp/makesql/authoring-compile.js +494 -0
- package/dist/scp/makesql/authoring-compile.js.map +1 -0
- package/dist/scp/makesql/compile-crud.d.ts +133 -0
- package/dist/scp/makesql/compile-crud.d.ts.map +1 -0
- package/dist/scp/makesql/compile-crud.js +288 -0
- package/dist/scp/makesql/compile-crud.js.map +1 -0
- package/dist/scp/makesql/compile-relation.d.ts +157 -0
- package/dist/scp/makesql/compile-relation.d.ts.map +1 -0
- package/dist/scp/makesql/compile-relation.js +425 -0
- package/dist/scp/makesql/compile-relation.js.map +1 -0
- package/dist/scp/makesql/compile-select.d.ts +52 -0
- package/dist/scp/makesql/compile-select.d.ts.map +1 -0
- package/dist/scp/makesql/compile-select.js +58 -0
- package/dist/scp/makesql/compile-select.js.map +1 -0
- package/dist/scp/makesql/compile.d.ts +63 -0
- package/dist/scp/makesql/compile.d.ts.map +1 -0
- package/dist/scp/makesql/compile.js +99 -0
- package/dist/scp/makesql/compile.js.map +1 -0
- package/dist/scp/makesql/handler.d.ts +58 -0
- package/dist/scp/makesql/handler.d.ts.map +1 -0
- package/dist/scp/makesql/handler.js +113 -0
- package/dist/scp/makesql/handler.js.map +1 -0
- package/dist/scp/makesql/index.d.ts +33 -0
- package/dist/scp/makesql/index.d.ts.map +1 -0
- package/dist/scp/makesql/index.js +114 -0
- package/dist/scp/makesql/index.js.map +1 -0
- package/dist/scp/makesql/ir.d.ts +42 -0
- package/dist/scp/makesql/ir.d.ts.map +1 -0
- package/dist/scp/makesql/ir.js +66 -0
- package/dist/scp/makesql/ir.js.map +1 -0
- package/dist/scp/makesql/json-array.d.ts +84 -0
- package/dist/scp/makesql/json-array.d.ts.map +1 -0
- package/dist/scp/makesql/json-array.js +118 -0
- package/dist/scp/makesql/json-array.js.map +1 -0
- package/dist/scp/makesql/json-batch.d.ts +102 -0
- package/dist/scp/makesql/json-batch.d.ts.map +1 -0
- package/dist/scp/makesql/json-batch.js +269 -0
- package/dist/scp/makesql/json-batch.js.map +1 -0
- package/dist/scp/makesql/makesql.d.ts +99 -0
- package/dist/scp/makesql/makesql.d.ts.map +1 -0
- package/dist/scp/makesql/makesql.js +122 -0
- package/dist/scp/makesql/makesql.js.map +1 -0
- package/dist/scp/makesql/outtype.d.ts +44 -0
- package/dist/scp/makesql/outtype.d.ts.map +1 -0
- package/dist/scp/makesql/outtype.js +197 -0
- package/dist/scp/makesql/outtype.js.map +1 -0
- package/dist/scp/makesql/pool-executor.d.ts +47 -0
- package/dist/scp/makesql/pool-executor.d.ts.map +1 -0
- package/dist/scp/makesql/pool-executor.js +50 -0
- package/dist/scp/makesql/pool-executor.js.map +1 -0
- package/dist/scp/makesql/static-bundle.d.ts +187 -0
- package/dist/scp/makesql/static-bundle.d.ts.map +1 -0
- package/dist/scp/makesql/static-bundle.js +1113 -0
- package/dist/scp/makesql/static-bundle.js.map +1 -0
- package/dist/scp/makesql/tx.d.ts +216 -0
- package/dist/scp/makesql/tx.d.ts.map +1 -0
- package/dist/scp/makesql/tx.js +788 -0
- package/dist/scp/makesql/tx.js.map +1 -0
- package/dist/scp/makesql/writeouttype.d.ts +66 -0
- package/dist/scp/makesql/writeouttype.d.ts.map +1 -0
- package/dist/scp/makesql/writeouttype.js +195 -0
- package/dist/scp/makesql/writeouttype.js.map +1 -0
- package/dist/scp/relation.d.ts +86 -74
- package/dist/scp/relation.d.ts.map +1 -1
- package/dist/scp/relation.js +186 -120
- package/dist/scp/relation.js.map +1 -1
- package/dist/scp/runtime.d.ts +158 -211
- package/dist/scp/runtime.d.ts.map +1 -1
- package/dist/scp/runtime.js +250 -515
- package/dist/scp/runtime.js.map +1 -1
- package/dist/scp/typed-object.d.ts +12 -1
- package/dist/scp/typed-object.d.ts.map +1 -1
- package/dist/scp/typed-object.js +25 -4
- package/dist/scp/typed-object.js.map +1 -1
- package/docs/proposal/litedbmodel-v2-scp-architecture.md +51 -0
- package/docs/proposal/v0-coverage-matrix.md +157 -0
- package/docs/proposal/v2-completeness-plan.md +90 -0
- package/docs/proposal/v2-sql-parity-checklist.md +162 -0
- package/package.json +3 -3
- package/dist/scp/bridge.d.ts +0 -64
- package/dist/scp/bridge.d.ts.map +0 -1
- package/dist/scp/bridge.js +0 -329
- package/dist/scp/bridge.js.map +0 -1
- package/dist/scp/compile-dialect.d.ts +0 -39
- package/dist/scp/compile-dialect.d.ts.map +0 -1
- package/dist/scp/compile-dialect.js +0 -62
- package/dist/scp/compile-dialect.js.map +0 -1
- package/dist/scp/compile-sqlite.d.ts +0 -114
- package/dist/scp/compile-sqlite.d.ts.map +0 -1
- package/dist/scp/compile-sqlite.js +0 -149
- package/dist/scp/compile-sqlite.js.map +0 -1
- package/dist/scp/ir.d.ts +0 -92
- package/dist/scp/ir.d.ts.map +0 -1
- package/dist/scp/ir.js +0 -28
- package/dist/scp/ir.js.map +0 -1
- package/dist/scp/render.d.ts +0 -40
- package/dist/scp/render.d.ts.map +0 -1
- package/dist/scp/render.js +0 -170
- package/dist/scp/render.js.map +0 -1
- package/dist/scp/write-plan.d.ts +0 -161
- package/dist/scp/write-plan.d.ts.map +0 -1
- package/dist/scp/write-plan.js +0 -528
- package/dist/scp/write-plan.js.map +0 -1
- package/dist/scp/write-runtime.d.ts +0 -80
- package/dist/scp/write-runtime.d.ts.map +0 -1
- package/dist/scp/write-runtime.js +0 -167
- package/dist/scp/write-runtime.js.map +0 -1
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* litedbmodel v2 SCP — fragment RUNTIME (assemble + bind).
|
|
4
|
+
*
|
|
5
|
+
* This is the thin runtime a bundle drives. It does exactly three things:
|
|
6
|
+
*
|
|
7
|
+
* 1. ASSEMBLE — walk the ordered fragment list; drop any fragment whose `skip`
|
|
8
|
+
* is satisfied; concatenate the present fragments' `sql`, and their `params`
|
|
9
|
+
* in order. Nested-fragment params splice their own `sql` at the `?` and
|
|
10
|
+
* contribute their own params in order.
|
|
11
|
+
* 2. EVALUATE — turn each value-spec param into a concrete bound value using the
|
|
12
|
+
* runtime `input` (and upstream `wire` results).
|
|
13
|
+
* 3. RENDER — the produced `{ sql, params }` uses `?`; a dialect step turns `?`
|
|
14
|
+
* into `$N` for PostgreSQL (identical to the original driver's naive replace).
|
|
15
|
+
*
|
|
16
|
+
* NO SQL structure is generated here. The `sql` text is already complete; the
|
|
17
|
+
* runtime only splices nested-fragment text and fills `?`.
|
|
18
|
+
*/
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.isSkipped = isSkipped;
|
|
21
|
+
exports.evalValueSpec = evalValueSpec;
|
|
22
|
+
exports.assembleFragment = assembleFragment;
|
|
23
|
+
exports.assembleWhereGroup = assembleWhereGroup;
|
|
24
|
+
exports.assemble = assemble;
|
|
25
|
+
exports.toPostgres = toPostgres;
|
|
26
|
+
const model_1 = require("./model");
|
|
27
|
+
function readPath(root, path) {
|
|
28
|
+
let cur = root;
|
|
29
|
+
for (const seg of path) {
|
|
30
|
+
if (cur == null)
|
|
31
|
+
return undefined;
|
|
32
|
+
cur = cur[seg];
|
|
33
|
+
}
|
|
34
|
+
return cur;
|
|
35
|
+
}
|
|
36
|
+
/** Is a fragment's `skip` satisfied (⇒ omit the fragment)? */
|
|
37
|
+
function isSkipped(cond, scope) {
|
|
38
|
+
if (!cond)
|
|
39
|
+
return false;
|
|
40
|
+
const v = readPath(scope.input, cond.absent);
|
|
41
|
+
return v == null;
|
|
42
|
+
}
|
|
43
|
+
/** Evaluate a value-spec to its bound value against the runtime scope. */
|
|
44
|
+
function evalValueSpec(spec, scope) {
|
|
45
|
+
if ((0, model_1.isInputRef)(spec))
|
|
46
|
+
return readPath(scope.input, spec.input);
|
|
47
|
+
if ((0, model_1.isWireRef)(spec)) {
|
|
48
|
+
const [node, ...rest] = spec.wire;
|
|
49
|
+
// A wire-ref reads a value an UPSTREAM node produced (WireRef doc). Fragments carrying a
|
|
50
|
+
// wire-ref are dropped by `isSkipped` when their upstream is skipped, so by evaluation time the
|
|
51
|
+
// node MUST be present. An absent node is a wiring/ordering bug — fail loudly, NEVER a silent
|
|
52
|
+
// `?? {}` → null (an unspec'd fallback that would swallow the bug).
|
|
53
|
+
if (scope.wire === undefined || !(node in scope.wire)) {
|
|
54
|
+
throw new Error(`scp assemble: wire-ref to node '${node}' has no produced result in scope ` +
|
|
55
|
+
`(wire keys: ${scope.wire === undefined ? '<no wire scope>' : Object.keys(scope.wire).join(', ')}). ` +
|
|
56
|
+
`A wire-ref must reference an upstream node that produced — this is a wiring/ordering bug, not a silent null.`);
|
|
57
|
+
}
|
|
58
|
+
return readPath(scope.wire[node], rest);
|
|
59
|
+
}
|
|
60
|
+
if ((0, model_1.isLiteral)(spec))
|
|
61
|
+
return spec.literal;
|
|
62
|
+
if ((0, model_1.isValueExpr)(spec)) {
|
|
63
|
+
if (spec.op === 'coalesce') {
|
|
64
|
+
for (const a of spec.args) {
|
|
65
|
+
const v = evalValueSpec(a, scope);
|
|
66
|
+
if (v != null)
|
|
67
|
+
return v;
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
if (spec.op === 'add') {
|
|
72
|
+
return spec.args.reduce((acc, a) => acc + evalValueSpec(a, scope), 0);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
throw new Error(`unknown value-spec: ${JSON.stringify(spec)}`);
|
|
76
|
+
}
|
|
77
|
+
/** Flatten one param (value-spec OR nested fragment) into sql text + bound params. */
|
|
78
|
+
function assembleParam(param, scope) {
|
|
79
|
+
if ((0, model_1.isFragment)(param)) {
|
|
80
|
+
// Nested fragment: splice its own sql at the `?`, contribute its own params.
|
|
81
|
+
return assembleFragment(param, scope);
|
|
82
|
+
}
|
|
83
|
+
// Value-spec: this `?` is filled by a single bound value.
|
|
84
|
+
return { sql: '?', params: [evalValueSpec(param, scope)] };
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Assemble a single fragment: interleave its literal `sql` (split on `?`) with the
|
|
88
|
+
* rendered text of each param, concatenating params in order.
|
|
89
|
+
*/
|
|
90
|
+
function assembleFragment(frag, scope) {
|
|
91
|
+
const chunks = frag.sql.split('?');
|
|
92
|
+
if (chunks.length - 1 !== frag.params.length) {
|
|
93
|
+
throw new Error(`fragment placeholder/param mismatch: ${chunks.length - 1} '?' vs ${frag.params.length} params in ${JSON.stringify(frag.sql)}`);
|
|
94
|
+
}
|
|
95
|
+
let sql = chunks[0];
|
|
96
|
+
const params = [];
|
|
97
|
+
for (let i = 0; i < frag.params.length; i++) {
|
|
98
|
+
const rendered = assembleParam(frag.params[i], scope);
|
|
99
|
+
sql += rendered.sql + chunks[i + 1];
|
|
100
|
+
params.push(...rendered.params);
|
|
101
|
+
}
|
|
102
|
+
return { sql, params };
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Assemble a WHERE group: join present members with `" AND "`, prefix `" WHERE "`.
|
|
106
|
+
* If no member is present, produce the empty string (identical to the ORIGINAL
|
|
107
|
+
* `DBConditions.compile` → `parts.length === 0 ? '' : parts.join(' AND ')`, with the
|
|
108
|
+
* `" WHERE "` prefix owned by the caller/select in the original — here folded in).
|
|
109
|
+
*/
|
|
110
|
+
function assembleWhereGroup(group, scope) {
|
|
111
|
+
const parts = [];
|
|
112
|
+
const params = [];
|
|
113
|
+
for (const member of group.where) {
|
|
114
|
+
if (isSkipped(member.skip, scope))
|
|
115
|
+
continue;
|
|
116
|
+
const r = assembleFragment(member, scope);
|
|
117
|
+
parts.push(r.sql);
|
|
118
|
+
params.push(...r.params);
|
|
119
|
+
}
|
|
120
|
+
if (parts.length === 0)
|
|
121
|
+
return { sql: '', params: [] };
|
|
122
|
+
return { sql: ` WHERE ${parts.join(' AND ')}`, params };
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Assemble an ordered fragment/WHERE-group list into a single `{ sql, params }`
|
|
126
|
+
* (with `?`). Fragments whose `skip` is satisfied are omitted entirely (sql AND
|
|
127
|
+
* params). A WHERE group joins its present members with the original's text glue.
|
|
128
|
+
*/
|
|
129
|
+
function assemble(nodes, scope) {
|
|
130
|
+
let sql = '';
|
|
131
|
+
const params = [];
|
|
132
|
+
for (const node of nodes) {
|
|
133
|
+
if ((0, model_1.isWhereGroup)(node)) {
|
|
134
|
+
const r = assembleWhereGroup(node, scope);
|
|
135
|
+
sql += r.sql;
|
|
136
|
+
params.push(...r.params);
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
if (isSkipped(node.skip, scope))
|
|
140
|
+
continue;
|
|
141
|
+
const r = assembleFragment(node, scope);
|
|
142
|
+
sql += r.sql;
|
|
143
|
+
params.push(...r.params);
|
|
144
|
+
}
|
|
145
|
+
return { sql, params };
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* PostgreSQL dialect render: `?` → `$1, $2, …`. Byte-identical to the original
|
|
149
|
+
* driver's `convertPlaceholders` (naive left-to-right replace; see
|
|
150
|
+
* `src/drivers/postgres.ts`).
|
|
151
|
+
*/
|
|
152
|
+
function toPostgres(sql) {
|
|
153
|
+
let index = 0;
|
|
154
|
+
return sql.replace(/\?/g, () => `$${++index}`);
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=assemble.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assemble.js","sourceRoot":"","sources":["../../../src/scp/fragment/assemble.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* litedbmodel v2 SCP — PostgreSQL compile (build time, TS).
|
|
3
|
+
*
|
|
4
|
+
* Produces the fragment list for a query. Every fragment's `sql` text is emitted by
|
|
5
|
+
* REUSING the ORIGINAL tuned builders (`DBConditions`, `buildSelectSQL`,
|
|
6
|
+
* `LazyRelation`) so that ANY SKIP combination reassembles to exactly what the
|
|
7
|
+
* original builder would produce for that combination. The compiler runs at build
|
|
8
|
+
* time (TS); its OUTPUT (the fragment list) is the pure-JSON portable bundle.
|
|
9
|
+
*
|
|
10
|
+
* NO abstract IR is produced. Only `{ sql, params, skip }` fragments (+ nested
|
|
11
|
+
* fragment params where a subquery/sub-expression is needed).
|
|
12
|
+
*/
|
|
13
|
+
import type { Fragment, Node, ValueSpec } from './model';
|
|
14
|
+
/**
|
|
15
|
+
* An authored optional WHERE equality: `<column> = <value from input.path>`,
|
|
16
|
+
* present only when `input.path` is non-null (else the fragment is skipped).
|
|
17
|
+
*/
|
|
18
|
+
export interface OptionalEq {
|
|
19
|
+
column: string;
|
|
20
|
+
inputPath: string[];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Compile one optional equality to a fragment carrying a `skip`.
|
|
24
|
+
*
|
|
25
|
+
* The condition core text (`<col> = ?`) is emitted by the ORIGINAL `DBConditions`,
|
|
26
|
+
* so it is byte-identical to the tuned builder. The leading `" AND "` is the exact
|
|
27
|
+
* connector the original uses when joining a present condition after an earlier
|
|
28
|
+
* (mandatory) part — see the byte-match invariant in {@link compileSelect}.
|
|
29
|
+
*/
|
|
30
|
+
export declare function compileOptionalEq(cond: OptionalEq): Fragment;
|
|
31
|
+
/**
|
|
32
|
+
* belongsTo / single-key batch (PG): `SELECT … FROM t WHERE t.key = ANY(?::type[])`.
|
|
33
|
+
*
|
|
34
|
+
* This is byte-identical to `LazyRelation.batchLoadWithAnyArray`. The array of keys
|
|
35
|
+
* binds as ONE param (`keys` value-spec) — the `?::type[]` cast text is static,
|
|
36
|
+
* chosen at compile time by the ORIGINAL `inferPgArrayType`. Optional relation
|
|
37
|
+
* `where`-filters (config.conditions) are appended as `compileOptionalEq` fragments.
|
|
38
|
+
*/
|
|
39
|
+
export declare function compileBelongsTo(opts: {
|
|
40
|
+
tableName: string;
|
|
41
|
+
selectColumn?: string;
|
|
42
|
+
targetKey: string;
|
|
43
|
+
/** compile-time sample values used ONLY for cast-type inference. */
|
|
44
|
+
sampleKeys: unknown[];
|
|
45
|
+
/** value-spec producing the runtime key array (bound as one param). */
|
|
46
|
+
keys: ValueSpec;
|
|
47
|
+
sqlCast?: string;
|
|
48
|
+
filters?: OptionalEq[];
|
|
49
|
+
}): Fragment[];
|
|
50
|
+
/**
|
|
51
|
+
* hasMany + per-parent limit (PG): `CROSS JOIN LATERAL`.
|
|
52
|
+
*
|
|
53
|
+
* Byte-identical to `LazyRelation.batchLoadWithLateral`. The inner SELECT is emitted
|
|
54
|
+
* by the ORIGINAL `buildSelectSQL` (reproduced here as the same template it yields:
|
|
55
|
+
* `SELECT <sel> FROM t WHERE t.key = _keys.key[ AND <filters>] ORDER BY <order> LIMIT n`).
|
|
56
|
+
* The outer wraps it in `unnest(?::type[]) AS _keys(key) CROSS JOIN LATERAL (…)`.
|
|
57
|
+
*
|
|
58
|
+
* `limit` is inlined into the text (the original inlines it: `LIMIT ${limit}`), so it
|
|
59
|
+
* is NOT a param. The key array binds as ONE param.
|
|
60
|
+
*/
|
|
61
|
+
export declare function compileHasManyLimited(opts: {
|
|
62
|
+
tableName: string;
|
|
63
|
+
selectColumn?: string;
|
|
64
|
+
targetKey: string;
|
|
65
|
+
sampleKeys: unknown[];
|
|
66
|
+
keys: ValueSpec;
|
|
67
|
+
order: string;
|
|
68
|
+
limit: number;
|
|
69
|
+
sqlCast?: string;
|
|
70
|
+
filters?: OptionalEq[];
|
|
71
|
+
}): Fragment[];
|
|
72
|
+
/**
|
|
73
|
+
* hasMany / single-key batch WITHOUT limit (PG): `= ANY(?::type[])` + ORDER BY.
|
|
74
|
+
* Byte-identical to `batchLoadWithAnyArray` (used for hasMany when no limit) —
|
|
75
|
+
* same shape as {@link compileBelongsTo} plus a trailing ORDER BY carried on the
|
|
76
|
+
* base fragment (so optional filters slot BEFORE the ORDER BY, matching the
|
|
77
|
+
* original which appends conditions before the order clause).
|
|
78
|
+
*/
|
|
79
|
+
export declare function compileHasManyAny(opts: {
|
|
80
|
+
tableName: string;
|
|
81
|
+
selectColumn?: string;
|
|
82
|
+
targetKey: string;
|
|
83
|
+
sampleKeys: unknown[];
|
|
84
|
+
keys: ValueSpec;
|
|
85
|
+
order?: string;
|
|
86
|
+
sqlCast?: string;
|
|
87
|
+
filters?: OptionalEq[];
|
|
88
|
+
}): Fragment[];
|
|
89
|
+
/**
|
|
90
|
+
* A plain `SELECT <sel> FROM t` with a WHERE built only from optional conditions.
|
|
91
|
+
*
|
|
92
|
+
* The WHERE is a {@link WhereGroup}: each member fragment carries the BARE condition
|
|
93
|
+
* core (`"status = ?"`, NO leading connector), emitted by the ORIGINAL
|
|
94
|
+
* `DBConditions`, and its own `skip`. At assemble time the group joins the SURVIVORS
|
|
95
|
+
* with `" AND "` and prefixes `" WHERE "` — byte-identical to the original
|
|
96
|
+
* `DBConditions.compile` → `parts.join(' AND ')` for EVERY present/absent subset,
|
|
97
|
+
* including when the first condition is skipped (the group's join, not a static
|
|
98
|
+
* connector, decides the leading text). No new SQL-structure vocabulary: the join is
|
|
99
|
+
* pure text glue, exactly the original's algorithm.
|
|
100
|
+
*/
|
|
101
|
+
export declare function compileBaseSelect(opts: {
|
|
102
|
+
tableName: string;
|
|
103
|
+
selectColumn?: string;
|
|
104
|
+
/** ordered optional equality conditions */
|
|
105
|
+
conditions: OptionalEq[];
|
|
106
|
+
}): Node[];
|
|
107
|
+
//# sourceMappingURL=compile-pg.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compile-pg.d.ts","sourceRoot":"","sources":["../../../src/scp/fragment/compile-pg.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAqB,SAAS,EAAE,MAAM,SAAS,CAAC;AAM5E;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,GAAG,QAAQ,CAU5D;AAMD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,UAAU,EAAE,OAAO,EAAE,CAAC;IACtB,uEAAuE;IACvE,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC;CACxB,GAAG,QAAQ,EAAE,CAQb;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,OAAO,EAAE,CAAC;IACtB,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC;CACxB,GAAG,QAAQ,EAAE,CAsBb;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,OAAO,EAAE,CAAC;IACtB,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC;CACxB,GAAG,QAAQ,EAAE,CAUb;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,2CAA2C;IAC3C,UAAU,EAAE,UAAU,EAAE,CAAC;CAC1B,GAAG,IAAI,EAAE,CAeT"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* litedbmodel v2 SCP — PostgreSQL compile (build time, TS).
|
|
4
|
+
*
|
|
5
|
+
* Produces the fragment list for a query. Every fragment's `sql` text is emitted by
|
|
6
|
+
* REUSING the ORIGINAL tuned builders (`DBConditions`, `buildSelectSQL`,
|
|
7
|
+
* `LazyRelation`) so that ANY SKIP combination reassembles to exactly what the
|
|
8
|
+
* original builder would produce for that combination. The compiler runs at build
|
|
9
|
+
* time (TS); its OUTPUT (the fragment list) is the pure-JSON portable bundle.
|
|
10
|
+
*
|
|
11
|
+
* NO abstract IR is produced. Only `{ sql, params, skip }` fragments (+ nested
|
|
12
|
+
* fragment params where a subquery/sub-expression is needed).
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.compileOptionalEq = compileOptionalEq;
|
|
16
|
+
exports.compileBelongsTo = compileBelongsTo;
|
|
17
|
+
exports.compileHasManyLimited = compileHasManyLimited;
|
|
18
|
+
exports.compileHasManyAny = compileHasManyAny;
|
|
19
|
+
exports.compileBaseSelect = compileBaseSelect;
|
|
20
|
+
const DBConditions_1 = require("../../DBConditions");
|
|
21
|
+
const pg_array_type_1 = require("./pg-array-type");
|
|
22
|
+
/**
|
|
23
|
+
* Compile one optional equality to a fragment carrying a `skip`.
|
|
24
|
+
*
|
|
25
|
+
* The condition core text (`<col> = ?`) is emitted by the ORIGINAL `DBConditions`,
|
|
26
|
+
* so it is byte-identical to the tuned builder. The leading `" AND "` is the exact
|
|
27
|
+
* connector the original uses when joining a present condition after an earlier
|
|
28
|
+
* (mandatory) part — see the byte-match invariant in {@link compileSelect}.
|
|
29
|
+
*/
|
|
30
|
+
function compileOptionalEq(cond) {
|
|
31
|
+
const probe = [];
|
|
32
|
+
const core = new DBConditions_1.DBConditions({ [cond.column]: '__probe__' }).compile(probe);
|
|
33
|
+
// core === `<col> = ?` (source of the text is the original builder)
|
|
34
|
+
const param = { input: cond.inputPath };
|
|
35
|
+
return {
|
|
36
|
+
sql: ` AND ${core}`,
|
|
37
|
+
params: [param],
|
|
38
|
+
skip: { absent: cond.inputPath },
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
// ============================================================================
|
|
42
|
+
// Relation batch-load fragments — text emitted by the ORIGINAL LazyRelation paths.
|
|
43
|
+
// ============================================================================
|
|
44
|
+
/**
|
|
45
|
+
* belongsTo / single-key batch (PG): `SELECT … FROM t WHERE t.key = ANY(?::type[])`.
|
|
46
|
+
*
|
|
47
|
+
* This is byte-identical to `LazyRelation.batchLoadWithAnyArray`. The array of keys
|
|
48
|
+
* binds as ONE param (`keys` value-spec) — the `?::type[]` cast text is static,
|
|
49
|
+
* chosen at compile time by the ORIGINAL `inferPgArrayType`. Optional relation
|
|
50
|
+
* `where`-filters (config.conditions) are appended as `compileOptionalEq` fragments.
|
|
51
|
+
*/
|
|
52
|
+
function compileBelongsTo(opts) {
|
|
53
|
+
const select = opts.selectColumn || '*';
|
|
54
|
+
const pgType = (0, pg_array_type_1.inferPgArrayTypeForCompile)(opts.sampleKeys, opts.sqlCast);
|
|
55
|
+
const base = {
|
|
56
|
+
sql: `SELECT ${select} FROM ${opts.tableName} WHERE ${opts.tableName}.${opts.targetKey} = ANY(?::${pgType})`,
|
|
57
|
+
params: [opts.keys],
|
|
58
|
+
};
|
|
59
|
+
return [base, ...(opts.filters ?? []).map(compileOptionalEq)];
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* hasMany + per-parent limit (PG): `CROSS JOIN LATERAL`.
|
|
63
|
+
*
|
|
64
|
+
* Byte-identical to `LazyRelation.batchLoadWithLateral`. The inner SELECT is emitted
|
|
65
|
+
* by the ORIGINAL `buildSelectSQL` (reproduced here as the same template it yields:
|
|
66
|
+
* `SELECT <sel> FROM t WHERE t.key = _keys.key[ AND <filters>] ORDER BY <order> LIMIT n`).
|
|
67
|
+
* The outer wraps it in `unnest(?::type[]) AS _keys(key) CROSS JOIN LATERAL (…)`.
|
|
68
|
+
*
|
|
69
|
+
* `limit` is inlined into the text (the original inlines it: `LIMIT ${limit}`), so it
|
|
70
|
+
* is NOT a param. The key array binds as ONE param.
|
|
71
|
+
*/
|
|
72
|
+
function compileHasManyLimited(opts) {
|
|
73
|
+
const select = opts.selectColumn || '*';
|
|
74
|
+
const pgType = (0, pg_array_type_1.inferPgArrayTypeForCompile)(opts.sampleKeys, opts.sqlCast);
|
|
75
|
+
const filterFrags = (opts.filters ?? []).map(compileOptionalEq);
|
|
76
|
+
// The full inner+outer text (byte-identical to batchLoadWithLateral) is split into
|
|
77
|
+
// three fragments so optional filters slot in AFTER the mandatory `t.key=_keys.key`
|
|
78
|
+
// predicate and BEFORE the ORDER BY, exactly where the original appends them:
|
|
79
|
+
// head: ... CROSS JOIN LATERAL (SELECT * FROM t WHERE t.key = _keys.key
|
|
80
|
+
// [filters] each `" AND <core>"` (skip-guarded)
|
|
81
|
+
// tail: ORDER BY <order> LIMIT <n>) t
|
|
82
|
+
const head = {
|
|
83
|
+
sql: `SELECT ${opts.tableName}.* FROM unnest(?::${pgType}) AS _keys(key) CROSS JOIN LATERAL (` +
|
|
84
|
+
`SELECT ${select} FROM ${opts.tableName} WHERE ${opts.tableName}.${opts.targetKey} = _keys.key`,
|
|
85
|
+
params: [opts.keys],
|
|
86
|
+
};
|
|
87
|
+
const tail = {
|
|
88
|
+
sql: ` ORDER BY ${opts.order} LIMIT ${opts.limit}) ${opts.tableName}`,
|
|
89
|
+
params: [],
|
|
90
|
+
};
|
|
91
|
+
return [head, ...filterFrags, tail];
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* hasMany / single-key batch WITHOUT limit (PG): `= ANY(?::type[])` + ORDER BY.
|
|
95
|
+
* Byte-identical to `batchLoadWithAnyArray` (used for hasMany when no limit) —
|
|
96
|
+
* same shape as {@link compileBelongsTo} plus a trailing ORDER BY carried on the
|
|
97
|
+
* base fragment (so optional filters slot BEFORE the ORDER BY, matching the
|
|
98
|
+
* original which appends conditions before the order clause).
|
|
99
|
+
*/
|
|
100
|
+
function compileHasManyAny(opts) {
|
|
101
|
+
const select = opts.selectColumn || '*';
|
|
102
|
+
const pgType = (0, pg_array_type_1.inferPgArrayTypeForCompile)(opts.sampleKeys, opts.sqlCast);
|
|
103
|
+
const head = {
|
|
104
|
+
sql: `SELECT ${select} FROM ${opts.tableName} WHERE ${opts.tableName}.${opts.targetKey} = ANY(?::${pgType})`,
|
|
105
|
+
params: [opts.keys],
|
|
106
|
+
};
|
|
107
|
+
const filterFrags = (opts.filters ?? []).map(compileOptionalEq);
|
|
108
|
+
const tail = opts.order ? [{ sql: ` ORDER BY ${opts.order}`, params: [] }] : [];
|
|
109
|
+
return [head, ...filterFrags, ...tail];
|
|
110
|
+
}
|
|
111
|
+
// ============================================================================
|
|
112
|
+
// Base SELECT + WHERE (all-optional conditions, no mandatory predicate).
|
|
113
|
+
// ============================================================================
|
|
114
|
+
/**
|
|
115
|
+
* A plain `SELECT <sel> FROM t` with a WHERE built only from optional conditions.
|
|
116
|
+
*
|
|
117
|
+
* The WHERE is a {@link WhereGroup}: each member fragment carries the BARE condition
|
|
118
|
+
* core (`"status = ?"`, NO leading connector), emitted by the ORIGINAL
|
|
119
|
+
* `DBConditions`, and its own `skip`. At assemble time the group joins the SURVIVORS
|
|
120
|
+
* with `" AND "` and prefixes `" WHERE "` — byte-identical to the original
|
|
121
|
+
* `DBConditions.compile` → `parts.join(' AND ')` for EVERY present/absent subset,
|
|
122
|
+
* including when the first condition is skipped (the group's join, not a static
|
|
123
|
+
* connector, decides the leading text). No new SQL-structure vocabulary: the join is
|
|
124
|
+
* pure text glue, exactly the original's algorithm.
|
|
125
|
+
*/
|
|
126
|
+
function compileBaseSelect(opts) {
|
|
127
|
+
const select = opts.selectColumn || '*';
|
|
128
|
+
const base = { sql: `SELECT ${select} FROM ${opts.tableName}`, params: [] };
|
|
129
|
+
const group = {
|
|
130
|
+
where: opts.conditions.map((c) => {
|
|
131
|
+
const probe = [];
|
|
132
|
+
const core = new DBConditions_1.DBConditions({ [c.column]: '__probe__' }).compile(probe);
|
|
133
|
+
return {
|
|
134
|
+
sql: core, // bare core, e.g. `status = ?` — connector belongs to the join
|
|
135
|
+
params: [{ input: c.inputPath }],
|
|
136
|
+
skip: { absent: c.inputPath },
|
|
137
|
+
};
|
|
138
|
+
}),
|
|
139
|
+
};
|
|
140
|
+
return [base, group];
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=compile-pg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compile-pg.js","sourceRoot":"","sources":["../../../src/scp/fragment/compile-pg.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* litedbmodel v2 SCP — the MINIMAL fragment model (epic #43 reset).
|
|
3
|
+
*
|
|
4
|
+
* Public surface: the fragment types, the compile helpers (build-time TS, reuse the
|
|
5
|
+
* original tuned builders), and the runtime assembler (thin, language-portable).
|
|
6
|
+
*
|
|
7
|
+
* There is NO abstract IR here. The portable artifact is ONLY a combination of
|
|
8
|
+
* `{ sql, params, skip }` fragments, with params being either value-specs or nested
|
|
9
|
+
* fragments. SQL structure (`= ANY`, `CROSS JOIN LATERAL`, `UNNEST`, subquery, cast)
|
|
10
|
+
* is TEXT inside `sql`, never a modeled construct.
|
|
11
|
+
*/
|
|
12
|
+
export * from './model';
|
|
13
|
+
export * from './assemble';
|
|
14
|
+
export * from './compile-pg';
|
|
15
|
+
export { inferPgArrayTypeForCompile } from './pg-array-type';
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/scp/fragment/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,OAAO,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* litedbmodel v2 SCP — the MINIMAL fragment model (epic #43 reset).
|
|
4
|
+
*
|
|
5
|
+
* Public surface: the fragment types, the compile helpers (build-time TS, reuse the
|
|
6
|
+
* original tuned builders), and the runtime assembler (thin, language-portable).
|
|
7
|
+
*
|
|
8
|
+
* There is NO abstract IR here. The portable artifact is ONLY a combination of
|
|
9
|
+
* `{ sql, params, skip }` fragments, with params being either value-specs or nested
|
|
10
|
+
* fragments. SQL structure (`= ANY`, `CROSS JOIN LATERAL`, `UNNEST`, subquery, cast)
|
|
11
|
+
* is TEXT inside `sql`, never a modeled construct.
|
|
12
|
+
*/
|
|
13
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
16
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
17
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
18
|
+
}
|
|
19
|
+
Object.defineProperty(o, k2, desc);
|
|
20
|
+
}) : (function(o, m, k, k2) {
|
|
21
|
+
if (k2 === undefined) k2 = k;
|
|
22
|
+
o[k2] = m[k];
|
|
23
|
+
}));
|
|
24
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
25
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
26
|
+
};
|
|
27
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
|
+
exports.inferPgArrayTypeForCompile = void 0;
|
|
29
|
+
__exportStar(require("./model"), exports);
|
|
30
|
+
__exportStar(require("./assemble"), exports);
|
|
31
|
+
__exportStar(require("./compile-pg"), exports);
|
|
32
|
+
var pg_array_type_1 = require("./pg-array-type");
|
|
33
|
+
Object.defineProperty(exports, "inferPgArrayTypeForCompile", { enumerable: true, get: function () { return pg_array_type_1.inferPgArrayTypeForCompile; } });
|
|
34
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/scp/fragment/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;;;;;;;;;;;;;;;AAEH,0CAAwB;AACxB,6CAA2B;AAC3B,+CAA6B;AAC7B,iDAA6D;AAApD,2HAAA,0BAA0B,OAAA"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* litedbmodel v2 SCP — the MINIMAL fragment model (epic #43 reset).
|
|
3
|
+
*
|
|
4
|
+
* ## The locked vocabulary (owner-specified — nothing else exists here)
|
|
5
|
+
*
|
|
6
|
+
* The portable artifact is ONLY a combination of **fragments**. There is NO
|
|
7
|
+
* abstract "Expression IR", NO relation-op / operator kinds for SQL structure,
|
|
8
|
+
* NO `FragmentTree` connector algebra, NO `{where}` splice marker. SQL structure
|
|
9
|
+
* (`= ANY`, `CROSS JOIN LATERAL`, `UNNEST`, subquery, cast, batch shapes) lives
|
|
10
|
+
* ENTIRELY as TEXT inside `sql`.
|
|
11
|
+
*
|
|
12
|
+
* fragment = { sql: string, params: Param[], skip?: PresenceCondition }
|
|
13
|
+
*
|
|
14
|
+
* - A query is an ordered list of fragments.
|
|
15
|
+
* - Assembling = concatenate the `sql` of every PRESENT fragment, and concatenate
|
|
16
|
+
* their `params` in order. If a fragment's `skip` is satisfied, BOTH its `sql`
|
|
17
|
+
* and its `params` are omitted.
|
|
18
|
+
*
|
|
19
|
+
* Param = EITHER
|
|
20
|
+
* (a) a **value-spec** — how to compute the bound value from input at runtime:
|
|
21
|
+
* an input-ref / wire-ref / a small closed value-expression
|
|
22
|
+
* (e.g. `coalesce(input.limit, 20)`). This computes the VALUE only.
|
|
23
|
+
* OR
|
|
24
|
+
* (b) a **nested fragment** — a raw SQL sub-piece with its own params. This is
|
|
25
|
+
* how subqueries / sub-expressions are represented: NOT as IR constructs,
|
|
26
|
+
* just a nested { sql, params }.
|
|
27
|
+
*
|
|
28
|
+
* Array-parameter placeholder expansion is DRIVER-side, not modeled here. On
|
|
29
|
+
* PostgreSQL an array param binds directly (`= ANY(?::int[])`), so the text is
|
|
30
|
+
* static and the array is ONE param. On MySQL/SQLite (no array binding) the DRIVER
|
|
31
|
+
* expands an array param into `(?, ?, …)` at bind time. The bundle stays
|
|
32
|
+
* "string + params" regardless.
|
|
33
|
+
*
|
|
34
|
+
* The whole model is plain JSON / serializable so a thin runtime in any language
|
|
35
|
+
* reads it identically.
|
|
36
|
+
*/
|
|
37
|
+
/** Read a value from runtime input by path, e.g. `{ input: ["authorId"] }`. */
|
|
38
|
+
export interface InputRef {
|
|
39
|
+
input: string[];
|
|
40
|
+
}
|
|
41
|
+
/** Read a value produced by an upstream node/wire, e.g. `{ wire: ["node1", "id"] }`. */
|
|
42
|
+
export interface WireRef {
|
|
43
|
+
wire: string[];
|
|
44
|
+
}
|
|
45
|
+
/** A literal constant value baked into the bundle (e.g. an array of keys, or 20). */
|
|
46
|
+
export interface LiteralValue {
|
|
47
|
+
literal: unknown;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* A small CLOSED value-expression. It computes a value from other value-specs.
|
|
51
|
+
* This is deliberately tiny: `coalesce` and `add` are enough for the LIMIT / key
|
|
52
|
+
* shapes in this slice. It is NOT an SQL-structure IR — it never emits SQL.
|
|
53
|
+
*/
|
|
54
|
+
export interface ValueExpr {
|
|
55
|
+
op: 'coalesce' | 'add';
|
|
56
|
+
args: ValueSpec[];
|
|
57
|
+
}
|
|
58
|
+
/** Param variant (a): a value-spec. */
|
|
59
|
+
export type ValueSpec = InputRef | WireRef | LiteralValue | ValueExpr;
|
|
60
|
+
/**
|
|
61
|
+
* Param variant (b): a nested fragment. A subquery / sub-expression is just a
|
|
62
|
+
* `{ sql, params }` embedded as a param — its `sql` is spliced into the parent's
|
|
63
|
+
* `?` position, its params flow into the parent's param stream in order. This is
|
|
64
|
+
* how subqueries are represented WITHOUT any IR construct.
|
|
65
|
+
*/
|
|
66
|
+
export type Param = ValueSpec | Fragment;
|
|
67
|
+
/**
|
|
68
|
+
* A presence condition for `skip`. When SATISFIED, the fragment (sql + params)
|
|
69
|
+
* is OMITTED. Deliberately closed and tiny: "the input at this path is absent /
|
|
70
|
+
* null / undefined". SKIP is not an operator — it is the ABSENCE of the fragment.
|
|
71
|
+
*/
|
|
72
|
+
export interface PresenceCondition {
|
|
73
|
+
/** Skip the fragment when the input at this path is null/undefined. */
|
|
74
|
+
absent: string[];
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The one and only structural type: `{ sql, params, skip? }`.
|
|
78
|
+
*
|
|
79
|
+
* `sql` is literal SQL text (leading connector included where relevant, e.g.
|
|
80
|
+
* `" AND status = ?"`) with `?` placeholders. `params` are 1:1 with the `?`
|
|
81
|
+
* (a value-spec fills one `?`; a nested-fragment param splices its own `sql`,
|
|
82
|
+
* which itself may contain further `?`). `skip`, when present and satisfied,
|
|
83
|
+
* omits the whole fragment.
|
|
84
|
+
*/
|
|
85
|
+
export interface Fragment {
|
|
86
|
+
sql: string;
|
|
87
|
+
params: Param[];
|
|
88
|
+
skip?: PresenceCondition;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* A WHERE clause is an ordered list of condition fragments joined by the SAME text
|
|
92
|
+
* glue the ORIGINAL `DBConditions.compile` uses: present members are joined with
|
|
93
|
+
* `" AND "` and the whole is prefixed with `" WHERE "` — and if NO member is
|
|
94
|
+
* present, the clause degenerates to the empty string (exactly the original's
|
|
95
|
+
* `parts.length === 0 → ''`).
|
|
96
|
+
*
|
|
97
|
+
* This is the "tree" form of the fragment model (a query is an ordered list/tree of
|
|
98
|
+
* fragments). It carries NO SQL-structure vocabulary — the join is pure text glue,
|
|
99
|
+
* identical to the original builder's `parts.join(' AND ')`. Each member fragment's
|
|
100
|
+
* `sql` is the bare condition core (`"status = ?"`, NO leading connector); the
|
|
101
|
+
* connector belongs to the join, so it is SKIP-stable regardless of which members
|
|
102
|
+
* survive.
|
|
103
|
+
*
|
|
104
|
+
* Members carry their own `skip`; a skipped member contributes neither text nor
|
|
105
|
+
* params, and the join simply closes over the survivors (so the first survivor never
|
|
106
|
+
* emits a stray leading `" AND "`).
|
|
107
|
+
*/
|
|
108
|
+
export interface WhereGroup {
|
|
109
|
+
where: Fragment[];
|
|
110
|
+
}
|
|
111
|
+
/** A member of an assembled query: a plain fragment or a WHERE group. */
|
|
112
|
+
export type Node = Fragment | WhereGroup;
|
|
113
|
+
export declare function isFragment(p: Param | Node): p is Fragment;
|
|
114
|
+
export declare function isWhereGroup(n: Node): n is WhereGroup;
|
|
115
|
+
export declare function isInputRef(v: ValueSpec): v is InputRef;
|
|
116
|
+
export declare function isWireRef(v: ValueSpec): v is WireRef;
|
|
117
|
+
export declare function isLiteral(v: ValueSpec): v is LiteralValue;
|
|
118
|
+
export declare function isValueExpr(v: ValueSpec): v is ValueExpr;
|
|
119
|
+
//# sourceMappingURL=model.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../../src/scp/fragment/model.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAOH,+EAA+E;AAC/E,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,wFAAwF;AACxF,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,qFAAqF;AACrF,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,UAAU,GAAG,KAAK,CAAC;IACvB,IAAI,EAAE,SAAS,EAAE,CAAC;CACnB;AAED,uCAAuC;AACvC,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,YAAY,GAAG,SAAS,CAAC;AAMtE;;;;;GAKG;AACH,MAAM,MAAM,KAAK,GAAG,SAAS,GAAG,QAAQ,CAAC;AAMzC;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,uEAAuE;IACvE,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,IAAI,CAAC,EAAE,iBAAiB,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB;AAED,yEAAyE;AACzE,MAAM,MAAM,IAAI,GAAG,QAAQ,GAAG,UAAU,CAAC;AAMzC,wBAAgB,UAAU,CAAC,CAAC,EAAE,KAAK,GAAG,IAAI,GAAG,CAAC,IAAI,QAAQ,CAEzD;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,IAAI,GAAG,CAAC,IAAI,UAAU,CAErD;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,IAAI,QAAQ,CAEtD;AACD,wBAAgB,SAAS,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,IAAI,OAAO,CAEpD;AACD,wBAAgB,SAAS,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,IAAI,YAAY,CAEzD;AACD,wBAAgB,WAAW,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,IAAI,SAAS,CAExD"}
|