@memberjunction/codegen-lib 6.1.0-edge.1 → 6.1.0-edge.3
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/LICENSE +180 -4
- package/README.md +39 -22
- package/dist/Angular/angular-codegen.d.ts +0 -8
- package/dist/Angular/angular-codegen.d.ts.map +1 -1
- package/dist/Angular/angular-codegen.js +32 -22
- package/dist/Angular/angular-codegen.js.map +1 -1
- package/dist/Angular/entity-data-grid-related-entity-component.js +2 -2
- package/dist/Angular/entity-data-grid-related-entity-component.js.map +1 -1
- package/dist/Angular/related-entity-components.d.ts +1 -1
- package/dist/Angular/related-entity-components.js +1 -1
- package/dist/Database/codeGenDatabaseProvider.d.ts +107 -1
- package/dist/Database/codeGenDatabaseProvider.d.ts.map +1 -1
- package/dist/Database/codeGenDatabaseProvider.js +77 -10
- package/dist/Database/codeGenDatabaseProvider.js.map +1 -1
- package/dist/Database/manage-metadata.d.ts +354 -14
- package/dist/Database/manage-metadata.d.ts.map +1 -1
- package/dist/Database/manage-metadata.js +1308 -65
- package/dist/Database/manage-metadata.js.map +1 -1
- package/dist/Database/materializationAnalysis.d.ts +241 -0
- package/dist/Database/materializationAnalysis.d.ts.map +1 -0
- package/dist/Database/materializationAnalysis.js +415 -0
- package/dist/Database/materializationAnalysis.js.map +1 -0
- package/dist/Database/materializationBroadRender.d.ts +67 -0
- package/dist/Database/materializationBroadRender.d.ts.map +1 -0
- package/dist/Database/materializationBroadRender.js +104 -0
- package/dist/Database/materializationBroadRender.js.map +1 -0
- package/dist/Database/materializationDrift.d.ts +59 -0
- package/dist/Database/materializationDrift.d.ts.map +1 -0
- package/dist/Database/materializationDrift.js +85 -0
- package/dist/Database/materializationDrift.js.map +1 -0
- package/dist/Database/materializationParamClassifier.d.ts +92 -0
- package/dist/Database/materializationParamClassifier.d.ts.map +1 -0
- package/dist/Database/materializationParamClassifier.js +224 -0
- package/dist/Database/materializationParamClassifier.js.map +1 -0
- package/dist/Database/materializationParamVerifier.d.ts +71 -0
- package/dist/Database/materializationParamVerifier.d.ts.map +1 -0
- package/dist/Database/materializationParamVerifier.js +302 -0
- package/dist/Database/materializationParamVerifier.js.map +1 -0
- package/dist/Database/materializationSqlAst.d.ts +78 -0
- package/dist/Database/materializationSqlAst.d.ts.map +1 -0
- package/dist/Database/materializationSqlAst.js +142 -0
- package/dist/Database/materializationSqlAst.js.map +1 -0
- package/dist/Database/providers/postgresql/PostgreSQLCodeGenProvider.d.ts +69 -30
- package/dist/Database/providers/postgresql/PostgreSQLCodeGenProvider.d.ts.map +1 -1
- package/dist/Database/providers/postgresql/PostgreSQLCodeGenProvider.js +325 -216
- package/dist/Database/providers/postgresql/PostgreSQLCodeGenProvider.js.map +1 -1
- package/dist/Database/providers/postgresql/__tests__/PostgreSQLCodeGenProvider.materialization.test.d.ts +2 -0
- package/dist/Database/providers/postgresql/__tests__/PostgreSQLCodeGenProvider.materialization.test.d.ts.map +1 -0
- package/dist/Database/providers/postgresql/__tests__/PostgreSQLCodeGenProvider.materialization.test.js +119 -0
- package/dist/Database/providers/postgresql/__tests__/PostgreSQLCodeGenProvider.materialization.test.js.map +1 -0
- package/dist/Database/providers/postgresql/__tests__/PostgreSQLHierarchyFunctions.test.d.ts +2 -0
- package/dist/Database/providers/postgresql/__tests__/PostgreSQLHierarchyFunctions.test.d.ts.map +1 -0
- package/dist/Database/providers/postgresql/__tests__/PostgreSQLHierarchyFunctions.test.js +155 -0
- package/dist/Database/providers/postgresql/__tests__/PostgreSQLHierarchyFunctions.test.js.map +1 -0
- package/dist/Database/providers/sqlserver/SQLServerCodeGenProvider.d.ts +61 -2
- package/dist/Database/providers/sqlserver/SQLServerCodeGenProvider.d.ts.map +1 -1
- package/dist/Database/providers/sqlserver/SQLServerCodeGenProvider.js +306 -3
- package/dist/Database/providers/sqlserver/SQLServerCodeGenProvider.js.map +1 -1
- package/dist/Database/providers/sqlserver/__tests__/BaseViewEmissionGoldenMaster.test.d.ts +2 -0
- package/dist/Database/providers/sqlserver/__tests__/BaseViewEmissionGoldenMaster.test.d.ts.map +1 -0
- package/dist/Database/providers/sqlserver/__tests__/BaseViewEmissionGoldenMaster.test.js +547 -0
- package/dist/Database/providers/sqlserver/__tests__/BaseViewEmissionGoldenMaster.test.js.map +1 -0
- package/dist/Database/providers/sqlserver/__tests__/BaseViewRegenDecision.test.d.ts +2 -0
- package/dist/Database/providers/sqlserver/__tests__/BaseViewRegenDecision.test.d.ts.map +1 -0
- package/dist/Database/providers/sqlserver/__tests__/BaseViewRegenDecision.test.js +721 -0
- package/dist/Database/providers/sqlserver/__tests__/BaseViewRegenDecision.test.js.map +1 -0
- package/dist/Database/providers/sqlserver/__tests__/SQLServerCodeGenProvider.materialization.test.d.ts +2 -0
- package/dist/Database/providers/sqlserver/__tests__/SQLServerCodeGenProvider.materialization.test.d.ts.map +1 -0
- package/dist/Database/providers/sqlserver/__tests__/SQLServerCodeGenProvider.materialization.test.js +78 -0
- package/dist/Database/providers/sqlserver/__tests__/SQLServerCodeGenProvider.materialization.test.js.map +1 -0
- package/dist/Database/providers/sqlserver/__tests__/SQLServerHierarchyTVF.test.d.ts +2 -0
- package/dist/Database/providers/sqlserver/__tests__/SQLServerHierarchyTVF.test.d.ts.map +1 -0
- package/dist/Database/providers/sqlserver/__tests__/SQLServerHierarchyTVF.test.js +155 -0
- package/dist/Database/providers/sqlserver/__tests__/SQLServerHierarchyTVF.test.js.map +1 -0
- package/dist/Database/sql_codegen.d.ts +21 -5
- package/dist/Database/sql_codegen.d.ts.map +1 -1
- package/dist/Database/sql_codegen.js +85 -27
- package/dist/Database/sql_codegen.js.map +1 -1
- package/dist/Misc/action_subclasses_codegen.d.ts.map +1 -1
- package/dist/Misc/action_subclasses_codegen.js +4 -4
- package/dist/Misc/action_subclasses_codegen.js.map +1 -1
- package/dist/Misc/createNewUser.js +1 -1
- package/dist/Misc/createNewUser.js.map +1 -1
- package/dist/Misc/entity_subclasses_codegen.d.ts +44 -0
- package/dist/Misc/entity_subclasses_codegen.d.ts.map +1 -1
- package/dist/Misc/entity_subclasses_codegen.js +369 -156
- package/dist/Misc/entity_subclasses_codegen.js.map +1 -1
- package/dist/Misc/graphql_server_codegen.d.ts +4 -58
- package/dist/Misc/graphql_server_codegen.d.ts.map +1 -1
- package/dist/Misc/graphql_server_codegen.js +22 -236
- package/dist/Misc/graphql_server_codegen.js.map +1 -1
- package/dist/Misc/sql_logging.d.ts +25 -0
- package/dist/Misc/sql_logging.d.ts.map +1 -1
- package/dist/Misc/sql_logging.js +51 -8
- package/dist/Misc/sql_logging.js.map +1 -1
- package/package.json +30 -30
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import { SQLParser } from '@memberjunction/sql-parser';
|
|
2
|
+
import { COMPARISON_OPS, isObject, nodeType, isLiteralNode, columnName, isAllLiteralBag, } from './materializationSqlAst.js';
|
|
3
|
+
/** Flips a scalar comparison operator so a `value <op> column` predicate reads canonically as `column <flip> value`. */
|
|
4
|
+
function flipOperator(op) {
|
|
5
|
+
switch (op) {
|
|
6
|
+
case '<': return '>';
|
|
7
|
+
case '>': return '<';
|
|
8
|
+
case '<=': return '>=';
|
|
9
|
+
case '>=': return '<=';
|
|
10
|
+
// =, !=, <> are symmetric so need no flip. IN/BETWEEN/IS never appear as `value <op> column`.
|
|
11
|
+
// NOTE: LIKE is NOT symmetric (`value LIKE column` ≠ `column LIKE value`), so this default would
|
|
12
|
+
// MIS-normalize a column-on-right LIKE — safe only because LIKE is excluded from
|
|
13
|
+
// SAFE_READ_FILTER_OPERATORS (refused → live-only) and never reaches read-time injection. If LIKE
|
|
14
|
+
// (or any non-symmetric op) is ever whitelisted, handle its column-on-right form explicitly here.
|
|
15
|
+
default: return op;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** The column attributed to a varying site, given the context it was found in. */
|
|
19
|
+
function siteColumn(ctx) {
|
|
20
|
+
return ctx.topWhere && ctx.conjClean ? ctx.predColumn : null;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Builds a varying site from the walk context. A site is *clean* (read-time-filterable) only inside the
|
|
24
|
+
* top-level conjunctive WHERE as the value operand of a `column <op> value` predicate; otherwise its
|
|
25
|
+
* column/operator are null (tainted → the parameter becomes Unbounded). `kind` records scalar vs list bag.
|
|
26
|
+
*/
|
|
27
|
+
function makeSite(ctx, kind) {
|
|
28
|
+
const clean = ctx.topWhere && ctx.conjClean;
|
|
29
|
+
return {
|
|
30
|
+
column: clean ? ctx.predColumn : null,
|
|
31
|
+
operator: clean ? ctx.predOperator : null,
|
|
32
|
+
kind,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** Whether a bag's literal contents differ (length or any element value) between two variants. */
|
|
36
|
+
function bagVaries(a, b) {
|
|
37
|
+
const av = a.value;
|
|
38
|
+
const bv = b.value;
|
|
39
|
+
if (av.length !== bv.length) {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
for (let i = 0; i < av.length; i++) {
|
|
43
|
+
const ai = av[i];
|
|
44
|
+
const bi = bv[i];
|
|
45
|
+
if (isObject(ai) && isObject(bi) && ai.value !== bi.value) {
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
/** Recursively diffs two AST nodes in lockstep, collecting varying-literal sites. Returns structural equality. */
|
|
52
|
+
function walk(a, b, ctx, sites) {
|
|
53
|
+
// Both absent.
|
|
54
|
+
if (a == null && b == null) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
if (a == null || b == null) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
// Scalars (operator names, aliases, flags). A mismatch here is a structural difference.
|
|
61
|
+
if (!isObject(a) && !Array.isArray(a)) {
|
|
62
|
+
return a === b;
|
|
63
|
+
}
|
|
64
|
+
if (Array.isArray(a) || Array.isArray(b)) {
|
|
65
|
+
return walkArray(a, b, ctx, sites);
|
|
66
|
+
}
|
|
67
|
+
// Both objects from here on.
|
|
68
|
+
if (isLiteralNode(a) && isLiteralNode(b)) {
|
|
69
|
+
return walkLiteral(a, b, ctx, sites);
|
|
70
|
+
}
|
|
71
|
+
if (isAllLiteralBag(a) && isAllLiteralBag(b)) {
|
|
72
|
+
return walkBag(a, b, ctx, sites);
|
|
73
|
+
}
|
|
74
|
+
const ta = nodeType(a);
|
|
75
|
+
const tb = nodeType(b);
|
|
76
|
+
if (ta !== tb) {
|
|
77
|
+
return false; // shape change (e.g., column_ref → number, select → binary_expr)
|
|
78
|
+
}
|
|
79
|
+
if (ta === 'binary_expr') {
|
|
80
|
+
return walkBinaryExpr(a, b, ctx, sites);
|
|
81
|
+
}
|
|
82
|
+
if (ta === 'select') {
|
|
83
|
+
// A nested SELECT (subquery / derived table) — its insides are never the top-level WHERE.
|
|
84
|
+
return walkObjectKeys(a, b, plainSubtreeCtx(), sites);
|
|
85
|
+
}
|
|
86
|
+
return walkObjectKeys(a, b, plainSubtreeCtx(), sites);
|
|
87
|
+
}
|
|
88
|
+
/** A context for any subtree that cannot host a clean read-time filter (resets all flags). */
|
|
89
|
+
function plainSubtreeCtx() {
|
|
90
|
+
return { topWhere: false, conjClean: false, predColumn: null, predOperator: null };
|
|
91
|
+
}
|
|
92
|
+
function walkArray(a, b, ctx, sites) {
|
|
93
|
+
if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
let ok = true;
|
|
97
|
+
for (let i = 0; i < a.length; i++) {
|
|
98
|
+
ok = walk(a[i], b[i], ctx, sites) && ok;
|
|
99
|
+
}
|
|
100
|
+
return ok;
|
|
101
|
+
}
|
|
102
|
+
function walkLiteral(a, b, ctx, sites) {
|
|
103
|
+
if (a.type !== b.type) {
|
|
104
|
+
return false; // literal category changed (string ↔ number) — treat as structural
|
|
105
|
+
}
|
|
106
|
+
if (a.value !== b.value) {
|
|
107
|
+
sites.push(makeSite(ctx, 'scalar'));
|
|
108
|
+
}
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
function walkBag(a, b, ctx, sites) {
|
|
112
|
+
// Collapse the bag: a differing length/content is allowed *literal* variation, not a shape change.
|
|
113
|
+
if (bagVaries(a, b)) {
|
|
114
|
+
sites.push(makeSite(ctx, 'list'));
|
|
115
|
+
}
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
/** Context for the value operand of a clean comparison: keep AND/where flags, attach the column + normalized operator. */
|
|
119
|
+
function valueOperandCtx(ctx, column, operator) {
|
|
120
|
+
return { topWhere: ctx.topWhere, conjClean: ctx.conjClean, predColumn: column, predOperator: operator };
|
|
121
|
+
}
|
|
122
|
+
/** Context for the column operand (and any non-value child): keep flags, no predicate column/operator. */
|
|
123
|
+
function plainOperandCtx(ctx) {
|
|
124
|
+
return { topWhere: ctx.topWhere, conjClean: ctx.conjClean, predColumn: null, predOperator: null };
|
|
125
|
+
}
|
|
126
|
+
/** Context below a non-AND combinator (`OR`, etc.): still in where, but no longer conjunctive-clean. */
|
|
127
|
+
function disjunctiveCtx(ctx) {
|
|
128
|
+
return { topWhere: ctx.topWhere, conjClean: false, predColumn: null, predOperator: null };
|
|
129
|
+
}
|
|
130
|
+
function walkBinaryExpr(a, b, ctx, sites) {
|
|
131
|
+
const op = a.operator;
|
|
132
|
+
if (op !== b.operator || typeof op !== 'string') {
|
|
133
|
+
return false; // operator change is structural
|
|
134
|
+
}
|
|
135
|
+
if (op === 'AND') {
|
|
136
|
+
// Conjunction preserves clean context down both sides.
|
|
137
|
+
const left = walk(a.left, b.left, ctx, sites);
|
|
138
|
+
const right = walk(a.right, b.right, ctx, sites);
|
|
139
|
+
return left && right;
|
|
140
|
+
}
|
|
141
|
+
if (COMPARISON_OPS.has(op)) {
|
|
142
|
+
return walkComparison(a, b, ctx, sites);
|
|
143
|
+
}
|
|
144
|
+
// OR / XOR / any other combinator → descendants are not conjunctive-clean.
|
|
145
|
+
const c = disjunctiveCtx(ctx);
|
|
146
|
+
const left = walk(a.left, b.left, c, sites);
|
|
147
|
+
const right = walk(a.right, b.right, c, sites);
|
|
148
|
+
return left && right;
|
|
149
|
+
}
|
|
150
|
+
function walkComparison(a, b, ctx, sites) {
|
|
151
|
+
const op = typeof a.operator === 'string' ? a.operator : null;
|
|
152
|
+
const leftCol = columnName(a.left);
|
|
153
|
+
const rightCol = columnName(a.right);
|
|
154
|
+
let leftCtx = plainOperandCtx(ctx);
|
|
155
|
+
let rightCtx = plainOperandCtx(ctx);
|
|
156
|
+
// Attach the predicate column + operator to the *value* side only when exactly one side is a plain
|
|
157
|
+
// column_ref. Normalize the operator to the `column <op> value` reading: when the column is on the
|
|
158
|
+
// RIGHT (`value < column`), flip it so read-time injection emits `column > value` — an un-flipped
|
|
159
|
+
// operator here would invert the predicate and silently over/under-scope the materialized read.
|
|
160
|
+
if (leftCol && !rightCol) {
|
|
161
|
+
rightCtx = valueOperandCtx(ctx, leftCol, op); // column on left → operator as written
|
|
162
|
+
}
|
|
163
|
+
else if (rightCol && !leftCol) {
|
|
164
|
+
leftCtx = valueOperandCtx(ctx, rightCol, op == null ? null : flipOperator(op));
|
|
165
|
+
}
|
|
166
|
+
const left = walk(a.left, b.left, leftCtx, sites);
|
|
167
|
+
const right = walk(a.right, b.right, rightCtx, sites);
|
|
168
|
+
return left && right;
|
|
169
|
+
}
|
|
170
|
+
/** Generic structural recursion over an object's keys (ignoring source-location noise). */
|
|
171
|
+
function walkObjectKeys(a, b, childCtx, sites) {
|
|
172
|
+
const keys = new Set([...Object.keys(a), ...Object.keys(b)]);
|
|
173
|
+
keys.delete('loc');
|
|
174
|
+
let ok = true;
|
|
175
|
+
for (const k of keys) {
|
|
176
|
+
ok = walk(a[k], b[k], childCtx, sites) && ok;
|
|
177
|
+
}
|
|
178
|
+
return ok;
|
|
179
|
+
}
|
|
180
|
+
/** True for a single plain SELECT that can host a clean top-level WHERE (not a set-op / SELECT INTO). */
|
|
181
|
+
function isSimpleSelect(node) {
|
|
182
|
+
if (nodeType(node) !== 'select' || !isObject(node)) {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
if (node.set_op != null || node._next != null) {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
// node-sql-parser always emits `into: { position: null }` on a plain SELECT; only a real
|
|
189
|
+
// SELECT ... INTO sets `into.position`. Treat only the latter as disqualifying.
|
|
190
|
+
const into = node.into;
|
|
191
|
+
if (isObject(into) && into.position != null) {
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
/** Diffs the two statement roots, applying top-WHERE context only to a simple SELECT's `where`. */
|
|
197
|
+
function walkRoot(a, b, sites) {
|
|
198
|
+
if (nodeType(a) !== nodeType(b)) {
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
if (isSimpleSelect(a) && isSimpleSelect(b) && isObject(a) && isObject(b)) {
|
|
202
|
+
const keys = new Set([...Object.keys(a), ...Object.keys(b)]);
|
|
203
|
+
keys.delete('loc');
|
|
204
|
+
let ok = true;
|
|
205
|
+
for (const k of keys) {
|
|
206
|
+
const ctx = k === 'where'
|
|
207
|
+
? { topWhere: true, conjClean: true, predColumn: null, predOperator: null }
|
|
208
|
+
: plainSubtreeCtx();
|
|
209
|
+
ok = walk(a[k], b[k], ctx, sites) && ok;
|
|
210
|
+
}
|
|
211
|
+
return ok;
|
|
212
|
+
}
|
|
213
|
+
// Non-simple root (set-op, mutation, etc.) — no position can be a clean read-time filter.
|
|
214
|
+
return walk(a, b, plainSubtreeCtx(), sites);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Returns the sole statement of an AST, or null if it is not exactly one statement.
|
|
218
|
+
* A multi-statement render (e.g. `SELECT …; SELECT …`) cannot be analyzed from one statement —
|
|
219
|
+
* the parameter might act anywhere in the rest — so we refuse rather than inspect only the first.
|
|
220
|
+
*/
|
|
221
|
+
function soleStatement(ast) {
|
|
222
|
+
if (Array.isArray(ast)) {
|
|
223
|
+
return ast.length === 1 ? ast[0] : null;
|
|
224
|
+
}
|
|
225
|
+
return ast;
|
|
226
|
+
}
|
|
227
|
+
/** Parses and diffs one pair of rendered variants. */
|
|
228
|
+
function diffVariantPair(sqlA, sqlB, dialect) {
|
|
229
|
+
const ra = SQLParser.Astify(sqlA, dialect);
|
|
230
|
+
const rb = SQLParser.Astify(sqlB, dialect);
|
|
231
|
+
if (!ra.astParsed || !rb.astParsed || ra.ast == null || rb.ast == null) {
|
|
232
|
+
return { structurallyEqual: false, varyingSites: [], hardRefuse: 'a rendered variant failed to parse — cannot verify; refusing under uncertainty' };
|
|
233
|
+
}
|
|
234
|
+
const aStmt = soleStatement(ra.ast);
|
|
235
|
+
const bStmt = soleStatement(rb.ast);
|
|
236
|
+
if (aStmt == null || bStmt == null) {
|
|
237
|
+
return { structurallyEqual: false, varyingSites: [], hardRefuse: 'a rendered variant is multi-statement — cannot verify a single row-filter; refusing under uncertainty' };
|
|
238
|
+
}
|
|
239
|
+
const sites = [];
|
|
240
|
+
const structurallyEqual = walkRoot(aStmt, bStmt, sites);
|
|
241
|
+
return { structurallyEqual, varyingSites: sites };
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Verifies a single parameter's {@link ParamRole} from ≥2 full-query SQL variants — the same query
|
|
245
|
+
* template rendered with the same values for every parameter *except* this one, which is varied
|
|
246
|
+
* across distinct values. Pure; the Phase 2c adapter supplies the rendered strings.
|
|
247
|
+
*
|
|
248
|
+
* Decision (refuse-under-uncertainty, §10):
|
|
249
|
+
* - <2 variants, or any variant fails to parse → `Unbounded`.
|
|
250
|
+
* - any pair differs structurally → `Structural` (shape depends on the value; possibly Bucket 2).
|
|
251
|
+
* - all pairs structurally equal but no literal varied → `Unbounded` (no observable effect to prove).
|
|
252
|
+
* - a varying literal is tainted (projection / `OR` / subquery / function / non-top-WHERE) → `Unbounded`.
|
|
253
|
+
* - varying literals touch >1 column → `Unbounded` (multi-column not modeled in v1).
|
|
254
|
+
* - else → `RowFilter` on the single bound column.
|
|
255
|
+
*/
|
|
256
|
+
export function verifyParamRole(variants, dialect) {
|
|
257
|
+
if (!variants || variants.length < 2) {
|
|
258
|
+
return { role: 'Unbounded', reason: 'need at least 2 distinct rendered variants to verify a parameter' };
|
|
259
|
+
}
|
|
260
|
+
const pairs = [];
|
|
261
|
+
for (let i = 1; i < variants.length; i++) {
|
|
262
|
+
pairs.push(diffVariantPair(variants[0], variants[i], dialect));
|
|
263
|
+
}
|
|
264
|
+
const refused = pairs.find((p) => p.hardRefuse);
|
|
265
|
+
if (refused) {
|
|
266
|
+
return { role: 'Unbounded', reason: refused.hardRefuse };
|
|
267
|
+
}
|
|
268
|
+
if (pairs.some((p) => !p.structurallyEqual)) {
|
|
269
|
+
return { role: 'Structural', reason: 'varying the value changes the SQL shape (different branch/columns/joins) — structural, not a row filter' };
|
|
270
|
+
}
|
|
271
|
+
const allSites = pairs.flatMap((p) => p.varyingSites);
|
|
272
|
+
if (allSites.length === 0) {
|
|
273
|
+
return { role: 'Unbounded', reason: 'varying the value produced no observable SQL change — cannot prove a pure row filter; refusing under uncertainty' };
|
|
274
|
+
}
|
|
275
|
+
if (allSites.some((s) => s.column == null)) {
|
|
276
|
+
return { role: 'Unbounded', reason: 'value varies outside a clean top-level conjunctive WHERE predicate (projection, OR/NOT, subquery, function, or JOIN ON) — not a safe read-time row filter' };
|
|
277
|
+
}
|
|
278
|
+
const distinct = new Map(); // lowercased → original casing
|
|
279
|
+
for (const s of allSites) {
|
|
280
|
+
const col = s.column;
|
|
281
|
+
const key = col.trim().toLowerCase();
|
|
282
|
+
if (!distinct.has(key)) {
|
|
283
|
+
distinct.set(key, col);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
if (distinct.size > 1) {
|
|
287
|
+
return { role: 'Unbounded', reason: `value affects multiple columns (${[...distinct.values()].join(', ')}) — not modeled in v1; refusing under uncertainty` };
|
|
288
|
+
}
|
|
289
|
+
const filterColumn = [...distinct.values()][0];
|
|
290
|
+
// Derive the single operator + kind for read-time reconstruction (Phase 2). All clean sites for one
|
|
291
|
+
// parameter must agree — a single parameter can only occupy one predicate position, so >1 distinct
|
|
292
|
+
// operator/kind means our AST reading is ambiguous → refuse under uncertainty (§10) rather than guess.
|
|
293
|
+
const distinctOps = new Set(allSites.map((s) => s.operator).filter((o) => o != null));
|
|
294
|
+
const distinctKinds = new Set(allSites.map((s) => s.kind));
|
|
295
|
+
if (distinctOps.size !== 1 || distinctKinds.size !== 1) {
|
|
296
|
+
return { role: 'Unbounded', reason: `value varies on "${filterColumn}" but the predicate operator/shape is ambiguous (ops: [${[...distinctOps].join(', ')}], kinds: [${[...distinctKinds].join(', ')}]) — refusing under uncertainty` };
|
|
297
|
+
}
|
|
298
|
+
const filterOperator = [...distinctOps][0];
|
|
299
|
+
const filterKind = [...distinctKinds][0];
|
|
300
|
+
return { role: 'RowFilter', filterColumn, filterOperator, filterKind, reason: `value varies only a literal at a clean top-level WHERE predicate "${filterColumn} ${filterOperator} <value>" (${filterKind})` };
|
|
301
|
+
}
|
|
302
|
+
//# sourceMappingURL=materializationParamVerifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"materializationParamVerifier.js","sourceRoot":"","sources":["../../src/Database/materializationParamVerifier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAGvD,OAAO,EACH,cAAc,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,UAAU,EAAE,eAAe,GAEjF,MAAM,yBAAyB,CAAC;AA4DjC,wHAAwH;AACxH,SAAS,YAAY,CAAC,EAAU;IAC5B,QAAQ,EAAE,EAAE,CAAC;QACT,KAAK,GAAG,CAAC,CAAC,OAAO,GAAG,CAAC;QACrB,KAAK,GAAG,CAAC,CAAC,OAAO,GAAG,CAAC;QACrB,KAAK,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC;QACvB,KAAK,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC;QACvB,8FAA8F;QAC9F,iGAAiG;QACjG,iFAAiF;QACjF,kGAAkG;QAClG,kGAAkG;QAClG,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC;IACvB,CAAC;AACL,CAAC;AAsCD,kFAAkF;AAClF,SAAS,UAAU,CAAC,GAAY;IAC5B,OAAO,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AACjE,CAAC;AAED;;;;GAIG;AACH,SAAS,QAAQ,CAAC,GAAY,EAAE,IAAgB;IAC5C,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,SAAS,CAAC;IAC5C,OAAO;QACH,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI;QACrC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI;QACzC,IAAI;KACP,CAAC;AACN,CAAC;AAED,kGAAkG;AAClG,SAAS,SAAS,CAAC,CAAY,EAAE,CAAY;IACzC,MAAM,EAAE,GAAG,CAAC,CAAC,KAAkB,CAAC;IAChC,MAAM,EAAE,GAAG,CAAC,CAAC,KAAkB,CAAC;IAChC,IAAI,EAAE,CAAC,MAAM,KAAK,EAAE,CAAC,MAAM,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACjC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;QACjB,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;QACjB,IAAI,QAAQ,CAAC,EAAE,CAAC,IAAI,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,KAAK,EAAE,CAAC,KAAK,EAAE,CAAC;YACxD,OAAO,IAAI,CAAC;QAChB,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC;AACjB,CAAC;AAED,kHAAkH;AAClH,SAAS,IAAI,CAAC,CAAU,EAAE,CAAU,EAAE,GAAY,EAAE,KAAoB;IACpE,eAAe;IACf,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,wFAAwF;IACxF,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACpC,OAAO,CAAC,KAAK,CAAC,CAAC;IACnB,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACvC,OAAO,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IACvC,CAAC;IACD,6BAA6B;IAC7B,IAAI,aAAa,CAAC,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;QACvC,OAAO,WAAW,CAAC,CAAc,EAAE,CAAc,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IACnE,CAAC;IACD,IAAI,eAAe,CAAC,CAAC,CAAC,IAAI,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3C,OAAO,OAAO,CAAC,CAAc,EAAE,CAAc,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IAC/D,CAAC;IACD,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACvB,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACvB,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACZ,OAAO,KAAK,CAAC,CAAC,iEAAiE;IACnF,CAAC;IACD,IAAI,EAAE,KAAK,aAAa,EAAE,CAAC;QACvB,OAAO,cAAc,CAAC,CAAc,EAAE,CAAc,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IACtE,CAAC;IACD,IAAI,EAAE,KAAK,QAAQ,EAAE,CAAC;QAClB,0FAA0F;QAC1F,OAAO,cAAc,CAAC,CAAc,EAAE,CAAc,EAAE,eAAe,EAAE,EAAE,KAAK,CAAC,CAAC;IACpF,CAAC;IACD,OAAO,cAAc,CAAC,CAAc,EAAE,CAAc,EAAE,eAAe,EAAE,EAAE,KAAK,CAAC,CAAC;AACpF,CAAC;AAED,8FAA8F;AAC9F,SAAS,eAAe;IACpB,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;AACvF,CAAC;AAED,SAAS,SAAS,CAAC,CAAU,EAAE,CAAU,EAAE,GAAY,EAAE,KAAoB;IACzE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC;QAClE,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,IAAI,EAAE,GAAG,IAAI,CAAC;IACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAChC,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;IAC5C,CAAC;IACD,OAAO,EAAE,CAAC;AACd,CAAC;AAED,SAAS,WAAW,CAAC,CAAY,EAAE,CAAY,EAAE,GAAY,EAAE,KAAoB;IAC/E,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;QACpB,OAAO,KAAK,CAAC,CAAC,mEAAmE;IACrF,CAAC;IACD,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC;QACtB,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,SAAS,OAAO,CAAC,CAAY,EAAE,CAAY,EAAE,GAAY,EAAE,KAAoB;IAC3E,mGAAmG;IACnG,IAAI,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QAClB,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,0HAA0H;AAC1H,SAAS,eAAe,CAAC,GAAY,EAAE,MAAc,EAAE,QAAuB;IAC1E,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC;AAC5G,CAAC;AAED,0GAA0G;AAC1G,SAAS,eAAe,CAAC,GAAY;IACjC,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;AACtG,CAAC;AAED,wGAAwG;AACxG,SAAS,cAAc,CAAC,GAAY;IAChC,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;AAC9F,CAAC;AAED,SAAS,cAAc,CAAC,CAAY,EAAE,CAAY,EAAE,GAAY,EAAE,KAAoB;IAClF,MAAM,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC;IACtB,IAAI,EAAE,KAAK,CAAC,CAAC,QAAQ,IAAI,OAAO,EAAE,KAAK,QAAQ,EAAE,CAAC;QAC9C,OAAO,KAAK,CAAC,CAAC,gCAAgC;IAClD,CAAC;IACD,IAAI,EAAE,KAAK,KAAK,EAAE,CAAC;QACf,uDAAuD;QACvD,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;QAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;QACjD,OAAO,IAAI,IAAI,KAAK,CAAC;IACzB,CAAC;IACD,IAAI,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;QACzB,OAAO,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IAC5C,CAAC;IACD,2EAA2E;IAC3E,MAAM,CAAC,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;IAC9B,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;IAC/C,OAAO,IAAI,IAAI,KAAK,CAAC;AACzB,CAAC;AAED,SAAS,cAAc,CAAC,CAAY,EAAE,CAAY,EAAE,GAAY,EAAE,KAAoB;IAClF,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9D,MAAM,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,QAAQ,GAAG,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACrC,IAAI,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IACpC,mGAAmG;IACnG,mGAAmG;IACnG,kGAAkG;IAClG,gGAAgG;IAChG,IAAI,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC;QACvB,QAAQ,GAAG,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,uCAAuC;IACzF,CAAC;SAAM,IAAI,QAAQ,IAAI,CAAC,OAAO,EAAE,CAAC;QAC9B,OAAO,GAAG,eAAe,CAAC,GAAG,EAAE,QAAQ,EAAE,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC;IACnF,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IAClD,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;IACtD,OAAO,IAAI,IAAI,KAAK,CAAC;AACzB,CAAC;AAED,2FAA2F;AAC3F,SAAS,cAAc,CAAC,CAAY,EAAE,CAAY,EAAE,QAAiB,EAAE,KAAoB;IACvF,MAAM,IAAI,GAAG,IAAI,GAAG,CAAS,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACnB,IAAI,EAAE,GAAG,IAAI,CAAC;IACd,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACnB,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;IACjD,CAAC;IACD,OAAO,EAAE,CAAC;AACd,CAAC;AAED,yGAAyG;AACzG,SAAS,cAAc,CAAC,IAAa;IACjC,IAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,QAAQ,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACjD,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,EAAE,CAAC;QAC5C,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,yFAAyF;IACzF,gFAAgF;IAChF,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;IACvB,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,EAAE,CAAC;QAC1C,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,mGAAmG;AACnG,SAAS,QAAQ,CAAC,CAAU,EAAE,CAAU,EAAE,KAAoB;IAC1D,IAAI,QAAQ,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,IAAI,cAAc,CAAC,CAAC,CAAC,IAAI,cAAc,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QACvE,MAAM,IAAI,GAAG,IAAI,GAAG,CAAS,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACrE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACnB,IAAI,EAAE,GAAG,IAAI,CAAC;QACd,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACnB,MAAM,GAAG,GACL,CAAC,KAAK,OAAO;gBACT,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE;gBAC3E,CAAC,CAAC,eAAe,EAAE,CAAC;YAC5B,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;QAC5C,CAAC;QACD,OAAO,EAAE,CAAC;IACd,CAAC;IACD,0FAA0F;IAC1F,OAAO,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,eAAe,EAAE,EAAE,KAAK,CAAC,CAAC;AAChD,CAAC;AAED;;;;GAIG;AACH,SAAS,aAAa,CAAC,GAAY;IAC/B,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,OAAO,GAAG,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC5C,CAAC;IACD,OAAO,GAAG,CAAC;AACf,CAAC;AAED,sDAAsD;AACtD,SAAS,eAAe,CAAC,IAAY,EAAE,IAAY,EAAE,OAAyB;IAC1E,MAAM,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC3C,MAAM,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC3C,IAAI,CAAC,EAAE,CAAC,SAAS,IAAI,CAAC,EAAE,CAAC,SAAS,IAAI,EAAE,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC,GAAG,IAAI,IAAI,EAAE,CAAC;QACrE,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,EAAE,UAAU,EAAE,gFAAgF,EAAE,CAAC;IACxJ,CAAC;IACD,MAAM,KAAK,GAAG,aAAa,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IACpC,MAAM,KAAK,GAAG,aAAa,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;QACjC,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,EAAE,UAAU,EAAE,uGAAuG,EAAE,CAAC;IAC/K,CAAC;IACD,MAAM,KAAK,GAAkB,EAAE,CAAC;IAChC,MAAM,iBAAiB,GAAG,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IACxD,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;AACtD,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,eAAe,CAAC,QAAkB,EAAE,OAAyB;IACzE,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnC,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,kEAAkE,EAAE,CAAC;IAC7G,CAAC;IAED,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;IACnE,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;IAChD,IAAI,OAAO,EAAE,CAAC;QACV,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,UAAoB,EAAE,CAAC;IACvE,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAC1C,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,yGAAyG,EAAE,CAAC;IACrJ,CAAC;IAED,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;IACtD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,kHAAkH,EAAE,CAAC;IAC7J,CAAC;IACD,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC,EAAE,CAAC;QACzC,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,2JAA2J,EAAE,CAAC;IACtM,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAC,CAAC,+BAA+B;IAC3E,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,CAAC,CAAC,MAAgB,CAAC;QAC/B,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAC3B,CAAC;IACL,CAAC;IACD,IAAI,QAAQ,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;QACpB,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,mCAAmC,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,mDAAmD,EAAE,CAAC;IAClK,CAAC;IAED,MAAM,YAAY,GAAG,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAE/C,oGAAoG;IACpG,mGAAmG;IACnG,uGAAuG;IACvG,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;IACnG,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3D,IAAI,WAAW,CAAC,IAAI,KAAK,CAAC,IAAI,aAAa,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACrD,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,oBAAoB,YAAY,0DAA0D,CAAC,GAAG,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,aAAa,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,iCAAiC,EAAE,CAAC;IAC5O,CAAC;IACD,MAAM,cAAc,GAAG,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAmB,CAAC;IAC7D,MAAM,UAAU,GAAG,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;IACzC,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,EAAE,qEAAqE,YAAY,IAAI,cAAc,cAAc,UAAU,GAAG,EAAE,CAAC;AACnN,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared, dialect-tolerant primitives for walking node-sql-parser's loosely-typed JSON AST, used by the
|
|
3
|
+
* materialization CodeGen analyzers: the parameter verifier (materializationParamVerifier.ts), the broad-render
|
|
4
|
+
* predicate stripper (materializationBroadRender.ts), and the GROUP BY key detector (materializationAnalysis.ts).
|
|
5
|
+
*
|
|
6
|
+
* These MUST be a single source of truth. The verifier classifies a parameter as a clean RowFilter using
|
|
7
|
+
* LITERAL_NODE_TYPES / COMPARISON_OPS, and broad-render strips exactly those predicates; if divergent hand-kept
|
|
8
|
+
* copies drifted (e.g. a node-sql-parser upgrade adds a literal node type to one set but not the other), the
|
|
9
|
+
* verifier could accept a predicate broad-render then fails to isolate — a wrongly-filtered materialization.
|
|
10
|
+
* Centralizing them here removes that hazard.
|
|
11
|
+
*
|
|
12
|
+
* node-sql-parser emits a discriminated-ish union of dozens of node shapes; walking it generically is the
|
|
13
|
+
* correct use of `unknown` + type guards (every access is narrowed), not a lazy escape. A node is a scalar,
|
|
14
|
+
* an array, or a keyed object with an optional `type` discriminant.
|
|
15
|
+
*/
|
|
16
|
+
export type AstNode = unknown;
|
|
17
|
+
export type AstObject = Record<string, unknown>;
|
|
18
|
+
/** Literal-leaf node types whose `value` is the substituted literal (the value side of a filter predicate). */
|
|
19
|
+
export declare const LITERAL_NODE_TYPES: Set<string>;
|
|
20
|
+
/** Comparison operators whose `column <op> value` form is a re-applicable read-time row filter. */
|
|
21
|
+
export declare const COMPARISON_OPS: Set<string>;
|
|
22
|
+
export declare function isObject(v: AstNode): v is AstObject;
|
|
23
|
+
export declare function nodeType(v: AstNode): string | undefined;
|
|
24
|
+
export declare function isLiteralNode(v: AstNode): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Resolves a `column_ref` node's bare column name across dialects. SQL Server emits `column` as a string;
|
|
27
|
+
* PostgreSQL emits `column: { expr: { type: 'default', value: 'X' } }`. Returns null for computed/expression
|
|
28
|
+
* columns (which are not clean filter/grouping columns).
|
|
29
|
+
*
|
|
30
|
+
* **This deliberately DISCARDS the table qualifier** — `o.Status` and `c.Status` both return `'Status'`.
|
|
31
|
+
* That is correct for callers that only need a name, but a caller that MATCHES a column reference against
|
|
32
|
+
* another column reference (a SELECT-list output, another predicate) MUST also compare
|
|
33
|
+
* {@link columnQualifier} — see {@link qualifiedColumn}. Matching on the bare name alone silently conflates
|
|
34
|
+
* same-named columns from different tables in a join.
|
|
35
|
+
*/
|
|
36
|
+
export declare function columnName(v: AstNode): string | null;
|
|
37
|
+
/**
|
|
38
|
+
* Resolves a `column_ref` node's TABLE QUALIFIER — the `o` in `o.Status` (a table alias, or the table name
|
|
39
|
+
* when no alias is declared). Returns null when the reference is unqualified (`Status`) or when the node is
|
|
40
|
+
* not a `column_ref`. Dialect-tolerant in the same way as {@link columnName}.
|
|
41
|
+
*/
|
|
42
|
+
export declare function columnQualifier(v: AstNode): string | null;
|
|
43
|
+
/** A `column_ref` split into its optional table qualifier and its bare column name. */
|
|
44
|
+
export interface QualifiedColumn {
|
|
45
|
+
/** Table alias / table name qualifying the reference (`o` in `o.Status`); null when unqualified. */
|
|
46
|
+
qualifier: string | null;
|
|
47
|
+
/** Bare column name (`Status` in `o.Status`). */
|
|
48
|
+
column: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Resolves a `column_ref` into its qualifier + column pair, or null when the node is not a plain column
|
|
52
|
+
* reference. Prefer this over {@link columnName} whenever the resolved column is compared to ANOTHER
|
|
53
|
+
* column reference — the qualifier is what distinguishes `o.Status` from `c.Status`.
|
|
54
|
+
*/
|
|
55
|
+
export declare function qualifiedColumn(v: AstNode): QualifiedColumn | null;
|
|
56
|
+
/** Case- and whitespace-insensitive SQL identifier equality. Null/undefined never matches anything. */
|
|
57
|
+
export declare function identifiersEqual(a: string | null | undefined, b: string | null | undefined): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* True when a parsed statement root is a SET OPERATION (`UNION` / `UNION ALL` / `EXCEPT` / `INTERSECT`).
|
|
60
|
+
*
|
|
61
|
+
* **Why every analyzer needs this guard:** node-sql-parser does NOT emit a distinct `union` node type. It
|
|
62
|
+
* emits a SINGLE `type: 'select'` root for the FIRST branch, carrying `set_op: 'union all'` and `_next`
|
|
63
|
+
* (the remaining branch, itself a select node). So a naive `ast[0]` reader sees a plain SELECT whose
|
|
64
|
+
* `columns`, `where`, and `groupby` describe **only the first branch** — every other branch is invisible.
|
|
65
|
+
* Any analyzer that draws a conclusion about the whole result set (its key, its predicates, its shape)
|
|
66
|
+
* from that root is silently reasoning about a fraction of the query. All such analyzers MUST refuse a
|
|
67
|
+
* set-op root outright (§10 refuse-under-uncertainty).
|
|
68
|
+
*/
|
|
69
|
+
export declare function isSetOperationRoot(node: AstNode): boolean;
|
|
70
|
+
/**
|
|
71
|
+
* Returns the sole statement of a parsed AST, or null when it is not exactly one statement.
|
|
72
|
+
* A multi-statement script cannot be analyzed from its first statement alone, so callers refuse
|
|
73
|
+
* rather than inspect only `ast[0]`.
|
|
74
|
+
*/
|
|
75
|
+
export declare function soleStatement(ast: AstNode): AstNode | null;
|
|
76
|
+
/** True when every element of an `expr_list` value array is a literal leaf (an all-literal bag). */
|
|
77
|
+
export declare function isAllLiteralBag(v: AstNode): boolean;
|
|
78
|
+
//# sourceMappingURL=materializationSqlAst.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"materializationSqlAst.d.ts","sourceRoot":"","sources":["../../src/Database/materializationSqlAst.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,MAAM,OAAO,GAAG,OAAO,CAAC;AAC9B,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEhD,+GAA+G;AAC/G,eAAO,MAAM,kBAAkB,aAe7B,CAAC;AAEH,mGAAmG;AACnG,eAAO,MAAM,cAAc,aAGzB,CAAC;AAEH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,SAAS,CAEnD;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAEvD;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAGjD;AAkBD;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAKpD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAKzD;AAED,uFAAuF;AACvF,MAAM,WAAW,eAAe;IAC5B,oGAAoG;IACpG,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,GAAG,eAAe,GAAG,IAAI,CAMlE;AAED,uGAAuG;AACvG,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAKpG;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAEzD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,GAAG,IAAI,CAK1D;AAED,oGAAoG;AACpG,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAKnD"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared, dialect-tolerant primitives for walking node-sql-parser's loosely-typed JSON AST, used by the
|
|
3
|
+
* materialization CodeGen analyzers: the parameter verifier (materializationParamVerifier.ts), the broad-render
|
|
4
|
+
* predicate stripper (materializationBroadRender.ts), and the GROUP BY key detector (materializationAnalysis.ts).
|
|
5
|
+
*
|
|
6
|
+
* These MUST be a single source of truth. The verifier classifies a parameter as a clean RowFilter using
|
|
7
|
+
* LITERAL_NODE_TYPES / COMPARISON_OPS, and broad-render strips exactly those predicates; if divergent hand-kept
|
|
8
|
+
* copies drifted (e.g. a node-sql-parser upgrade adds a literal node type to one set but not the other), the
|
|
9
|
+
* verifier could accept a predicate broad-render then fails to isolate — a wrongly-filtered materialization.
|
|
10
|
+
* Centralizing them here removes that hazard.
|
|
11
|
+
*
|
|
12
|
+
* node-sql-parser emits a discriminated-ish union of dozens of node shapes; walking it generically is the
|
|
13
|
+
* correct use of `unknown` + type guards (every access is narrowed), not a lazy escape. A node is a scalar,
|
|
14
|
+
* an array, or a keyed object with an optional `type` discriminant.
|
|
15
|
+
*/
|
|
16
|
+
/** Literal-leaf node types whose `value` is the substituted literal (the value side of a filter predicate). */
|
|
17
|
+
export const LITERAL_NODE_TYPES = new Set([
|
|
18
|
+
'single_quote_string',
|
|
19
|
+
'double_quote_string',
|
|
20
|
+
'backticks_quote_string',
|
|
21
|
+
'string',
|
|
22
|
+
'number',
|
|
23
|
+
'bool',
|
|
24
|
+
'boolean',
|
|
25
|
+
'null',
|
|
26
|
+
'date',
|
|
27
|
+
'datetime',
|
|
28
|
+
'time',
|
|
29
|
+
'timestamp',
|
|
30
|
+
'hex_string',
|
|
31
|
+
'bit_string',
|
|
32
|
+
]);
|
|
33
|
+
/** Comparison operators whose `column <op> value` form is a re-applicable read-time row filter. */
|
|
34
|
+
export const COMPARISON_OPS = new Set([
|
|
35
|
+
'=', '!=', '<>', '<', '>', '<=', '>=',
|
|
36
|
+
'IN', 'NOT IN', 'LIKE', 'NOT LIKE', 'IS', 'IS NOT', 'BETWEEN', 'NOT BETWEEN',
|
|
37
|
+
]);
|
|
38
|
+
export function isObject(v) {
|
|
39
|
+
return typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
40
|
+
}
|
|
41
|
+
export function nodeType(v) {
|
|
42
|
+
return isObject(v) && typeof v.type === 'string' ? v.type : undefined;
|
|
43
|
+
}
|
|
44
|
+
export function isLiteralNode(v) {
|
|
45
|
+
const t = nodeType(v);
|
|
46
|
+
return t !== undefined && LITERAL_NODE_TYPES.has(t);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Unwraps a node-sql-parser identifier slot (`column`, `table`) to plain text across dialects.
|
|
50
|
+
* SQL Server emits a bare string; PostgreSQL wraps a quoted identifier as
|
|
51
|
+
* `{ expr: { type: 'double_quote_string' | 'default', value: 'X' } }`. Returns null for anything else
|
|
52
|
+
* (an absent qualifier, or a computed/expression node that is not a plain identifier).
|
|
53
|
+
*/
|
|
54
|
+
function identifierText(v) {
|
|
55
|
+
if (typeof v === 'string') {
|
|
56
|
+
return v;
|
|
57
|
+
}
|
|
58
|
+
if (isObject(v) && isObject(v.expr) && typeof v.expr.value === 'string') {
|
|
59
|
+
return v.expr.value;
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Resolves a `column_ref` node's bare column name across dialects. SQL Server emits `column` as a string;
|
|
65
|
+
* PostgreSQL emits `column: { expr: { type: 'default', value: 'X' } }`. Returns null for computed/expression
|
|
66
|
+
* columns (which are not clean filter/grouping columns).
|
|
67
|
+
*
|
|
68
|
+
* **This deliberately DISCARDS the table qualifier** — `o.Status` and `c.Status` both return `'Status'`.
|
|
69
|
+
* That is correct for callers that only need a name, but a caller that MATCHES a column reference against
|
|
70
|
+
* another column reference (a SELECT-list output, another predicate) MUST also compare
|
|
71
|
+
* {@link columnQualifier} — see {@link qualifiedColumn}. Matching on the bare name alone silently conflates
|
|
72
|
+
* same-named columns from different tables in a join.
|
|
73
|
+
*/
|
|
74
|
+
export function columnName(v) {
|
|
75
|
+
if (nodeType(v) !== 'column_ref' || !isObject(v)) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
return identifierText(v.column);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Resolves a `column_ref` node's TABLE QUALIFIER — the `o` in `o.Status` (a table alias, or the table name
|
|
82
|
+
* when no alias is declared). Returns null when the reference is unqualified (`Status`) or when the node is
|
|
83
|
+
* not a `column_ref`. Dialect-tolerant in the same way as {@link columnName}.
|
|
84
|
+
*/
|
|
85
|
+
export function columnQualifier(v) {
|
|
86
|
+
if (nodeType(v) !== 'column_ref' || !isObject(v)) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
return identifierText(v.table);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Resolves a `column_ref` into its qualifier + column pair, or null when the node is not a plain column
|
|
93
|
+
* reference. Prefer this over {@link columnName} whenever the resolved column is compared to ANOTHER
|
|
94
|
+
* column reference — the qualifier is what distinguishes `o.Status` from `c.Status`.
|
|
95
|
+
*/
|
|
96
|
+
export function qualifiedColumn(v) {
|
|
97
|
+
const column = columnName(v);
|
|
98
|
+
if (column == null) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
return { qualifier: columnQualifier(v), column };
|
|
102
|
+
}
|
|
103
|
+
/** Case- and whitespace-insensitive SQL identifier equality. Null/undefined never matches anything. */
|
|
104
|
+
export function identifiersEqual(a, b) {
|
|
105
|
+
if (a == null || b == null) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
return a.trim().toLowerCase() === b.trim().toLowerCase();
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* True when a parsed statement root is a SET OPERATION (`UNION` / `UNION ALL` / `EXCEPT` / `INTERSECT`).
|
|
112
|
+
*
|
|
113
|
+
* **Why every analyzer needs this guard:** node-sql-parser does NOT emit a distinct `union` node type. It
|
|
114
|
+
* emits a SINGLE `type: 'select'` root for the FIRST branch, carrying `set_op: 'union all'` and `_next`
|
|
115
|
+
* (the remaining branch, itself a select node). So a naive `ast[0]` reader sees a plain SELECT whose
|
|
116
|
+
* `columns`, `where`, and `groupby` describe **only the first branch** — every other branch is invisible.
|
|
117
|
+
* Any analyzer that draws a conclusion about the whole result set (its key, its predicates, its shape)
|
|
118
|
+
* from that root is silently reasoning about a fraction of the query. All such analyzers MUST refuse a
|
|
119
|
+
* set-op root outright (§10 refuse-under-uncertainty).
|
|
120
|
+
*/
|
|
121
|
+
export function isSetOperationRoot(node) {
|
|
122
|
+
return isObject(node) && (node.set_op != null || node._next != null);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Returns the sole statement of a parsed AST, or null when it is not exactly one statement.
|
|
126
|
+
* A multi-statement script cannot be analyzed from its first statement alone, so callers refuse
|
|
127
|
+
* rather than inspect only `ast[0]`.
|
|
128
|
+
*/
|
|
129
|
+
export function soleStatement(ast) {
|
|
130
|
+
if (Array.isArray(ast)) {
|
|
131
|
+
return ast.length === 1 ? ast[0] : null;
|
|
132
|
+
}
|
|
133
|
+
return ast;
|
|
134
|
+
}
|
|
135
|
+
/** True when every element of an `expr_list` value array is a literal leaf (an all-literal bag). */
|
|
136
|
+
export function isAllLiteralBag(v) {
|
|
137
|
+
if (nodeType(v) !== 'expr_list' || !isObject(v) || !Array.isArray(v.value)) {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
return v.value.length > 0 && v.value.every(isLiteralNode);
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=materializationSqlAst.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"materializationSqlAst.js","sourceRoot":"","sources":["../../src/Database/materializationSqlAst.ts"],"names":[],"mappings":"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"}
|