sof-mssql 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/load.d.ts.map +1 -1
- package/dist/load.js +3 -0
- package/dist/load.js.map +1 -1
- package/dist/loader/connection.d.ts.map +1 -1
- package/dist/loader/connection.js +6 -0
- package/dist/loader/connection.js.map +1 -1
- package/dist/loader/types.d.ts +2 -0
- package/dist/loader/types.d.ts.map +1 -1
- package/dist/parser.d.ts +10 -1
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +35 -1
- package/dist/parser.js.map +1 -1
- package/dist/queryGenerator/index.d.ts +0 -3
- package/dist/queryGenerator/index.d.ts.map +1 -1
- package/dist/queryGenerator/index.js +1 -7
- package/dist/queryGenerator/index.js.map +1 -1
- package/dist/queryGenerator/treeWalker/aliasGenerator.d.ts +26 -0
- package/dist/queryGenerator/treeWalker/aliasGenerator.d.ts.map +1 -0
- package/dist/queryGenerator/treeWalker/aliasGenerator.js +31 -0
- package/dist/queryGenerator/treeWalker/aliasGenerator.js.map +1 -0
- package/dist/queryGenerator/treeWalker/classify.d.ts +19 -0
- package/dist/queryGenerator/treeWalker/classify.d.ts.map +1 -0
- package/dist/queryGenerator/treeWalker/classify.js +36 -0
- package/dist/queryGenerator/treeWalker/classify.js.map +1 -0
- package/dist/queryGenerator/treeWalker/compile.d.ts +29 -0
- package/dist/queryGenerator/treeWalker/compile.d.ts.map +1 -0
- package/dist/queryGenerator/treeWalker/compile.js +98 -0
- package/dist/queryGenerator/treeWalker/compile.js.map +1 -0
- package/dist/queryGenerator/treeWalker/cteTemplates.d.ts +50 -0
- package/dist/queryGenerator/treeWalker/cteTemplates.d.ts.map +1 -0
- package/dist/queryGenerator/treeWalker/cteTemplates.js +95 -0
- package/dist/queryGenerator/treeWalker/cteTemplates.js.map +1 -0
- package/dist/queryGenerator/treeWalker/index.d.ts +6 -0
- package/dist/queryGenerator/treeWalker/index.d.ts.map +1 -0
- package/dist/queryGenerator/treeWalker/index.js +9 -0
- package/dist/queryGenerator/treeWalker/index.js.map +1 -0
- package/dist/queryGenerator/treeWalker/mergeSiblings.d.ts +28 -0
- package/dist/queryGenerator/treeWalker/mergeSiblings.d.ts.map +1 -0
- package/dist/queryGenerator/treeWalker/mergeSiblings.js +54 -0
- package/dist/queryGenerator/treeWalker/mergeSiblings.js.map +1 -0
- package/dist/queryGenerator/treeWalker/operators/columnsOnly.d.ts +40 -0
- package/dist/queryGenerator/treeWalker/operators/columnsOnly.d.ts.map +1 -0
- package/dist/queryGenerator/treeWalker/operators/columnsOnly.js +56 -0
- package/dist/queryGenerator/treeWalker/operators/columnsOnly.js.map +1 -0
- package/dist/queryGenerator/treeWalker/operators/forEach.d.ts +45 -0
- package/dist/queryGenerator/treeWalker/operators/forEach.d.ts.map +1 -0
- package/dist/queryGenerator/treeWalker/operators/forEach.js +144 -0
- package/dist/queryGenerator/treeWalker/operators/forEach.js.map +1 -0
- package/dist/queryGenerator/treeWalker/operators/group.d.ts +35 -0
- package/dist/queryGenerator/treeWalker/operators/group.d.ts.map +1 -0
- package/dist/queryGenerator/treeWalker/operators/group.js +56 -0
- package/dist/queryGenerator/treeWalker/operators/group.js.map +1 -0
- package/dist/queryGenerator/treeWalker/operators/repeat.d.ts +45 -0
- package/dist/queryGenerator/treeWalker/operators/repeat.d.ts.map +1 -0
- package/dist/queryGenerator/treeWalker/operators/repeat.js +110 -0
- package/dist/queryGenerator/treeWalker/operators/repeat.js.map +1 -0
- package/dist/queryGenerator/treeWalker/operators/unionAll.d.ts +54 -0
- package/dist/queryGenerator/treeWalker/operators/unionAll.d.ts.map +1 -0
- package/dist/queryGenerator/treeWalker/operators/unionAll.js +121 -0
- package/dist/queryGenerator/treeWalker/operators/unionAll.js.map +1 -0
- package/dist/queryGenerator/treeWalker/render.d.ts +34 -0
- package/dist/queryGenerator/treeWalker/render.d.ts.map +1 -0
- package/dist/queryGenerator/treeWalker/render.js +41 -0
- package/dist/queryGenerator/treeWalker/render.js.map +1 -0
- package/dist/queryGenerator/treeWalker/types.d.ts +66 -0
- package/dist/queryGenerator/treeWalker/types.d.ts.map +1 -0
- package/dist/queryGenerator/treeWalker/types.js +14 -0
- package/dist/queryGenerator/treeWalker/types.js.map +1 -0
- package/dist/queryGenerator/treeWalker/walker.d.ts +36 -0
- package/dist/queryGenerator/treeWalker/walker.d.ts.map +1 -0
- package/dist/queryGenerator/treeWalker/walker.js +58 -0
- package/dist/queryGenerator/treeWalker/walker.js.map +1 -0
- package/dist/queryGenerator.d.ts +8 -34
- package/dist/queryGenerator.d.ts.map +1 -1
- package/dist/queryGenerator.js +16 -110
- package/dist/queryGenerator.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/queryGenerator/ForEachProcessor.d.ts +0 -127
- package/dist/queryGenerator/ForEachProcessor.d.ts.map +0 -1
- package/dist/queryGenerator/ForEachProcessor.js +0 -351
- package/dist/queryGenerator/ForEachProcessor.js.map +0 -1
- package/dist/queryGenerator/SelectClauseBuilder.d.ts +0 -63
- package/dist/queryGenerator/SelectClauseBuilder.d.ts.map +0 -1
- package/dist/queryGenerator/SelectClauseBuilder.js +0 -196
- package/dist/queryGenerator/SelectClauseBuilder.js.map +0 -1
- package/dist/queryGenerator/SelectCombinationExpander.d.ts +0 -42
- package/dist/queryGenerator/SelectCombinationExpander.d.ts.map +0 -1
- package/dist/queryGenerator/SelectCombinationExpander.js +0 -95
- package/dist/queryGenerator/SelectCombinationExpander.js.map +0 -1
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Walker for Repeat nodes — emits a recursive CTE and returns a set Fragment.
|
|
3
|
+
*
|
|
4
|
+
* The CTE projects the current partition keys and any baked scalar columns
|
|
5
|
+
* plus a content-derived `__path` for stable identity across re-evaluations.
|
|
6
|
+
* The Fragment's `fromExtensions` is an INNER JOIN to the CTE on the partition key
|
|
7
|
+
* `[id]`; sibling-level composite-key joins are added by `mergeSiblings`.
|
|
8
|
+
*/
|
|
9
|
+
import type { ViewDefinitionSelect } from "../../../types.js";
|
|
10
|
+
import { type Context, type Fragment } from "../types.js";
|
|
11
|
+
export interface RepeatDeps {
|
|
12
|
+
schemaName: string;
|
|
13
|
+
tableName: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Walker for Repeat nodes — emits a recursive CTE and returns a set Fragment.
|
|
17
|
+
*
|
|
18
|
+
* Generates a `WITH RECURSIVE`-style CTE (via `buildRepeatCte`) whose anchor
|
|
19
|
+
* member starts at the resource root and whose recursive members re-expand
|
|
20
|
+
* each element's `item_json` using the same path list. The CTE accumulates a
|
|
21
|
+
* `__path` string for stable per-element identity across recursion levels.
|
|
22
|
+
*
|
|
23
|
+
* The returned Fragment contains the CTE plus an `INNER JOIN` to it in
|
|
24
|
+
* `fromExtensions`; the join is keyed on all current partition keys so that
|
|
25
|
+
* only rows belonging to the enclosing resource (and any ancestor forEach)
|
|
26
|
+
* are included. The inner context updates `source` to `<cteAlias>.item_json`
|
|
27
|
+
* and appends a new `<cteAlias>_path` partition key so that nested operators
|
|
28
|
+
* can further partition the result set.
|
|
29
|
+
*
|
|
30
|
+
* @param node - The Repeat select node; `node.repeat` supplies the ordered
|
|
31
|
+
* list of FHIRPath strings used as the anchor and recursive paths.
|
|
32
|
+
* @param ctx - The current walker context; the inner context is derived from
|
|
33
|
+
* it by updating `source`, `partitionKeys`, `ancestorApplies`, and
|
|
34
|
+
* `transpilerCtx`.
|
|
35
|
+
* @param walk - The recursive walk function used to visit the inner sub-tree
|
|
36
|
+
* (`column`, `select`, `unionAll`) in the repeat-item context.
|
|
37
|
+
* @param deps - Schema and table name needed to construct the resource FROM
|
|
38
|
+
* clause inside the CTE anchor.
|
|
39
|
+
* @returns A Fragment whose `ctes` list begins with the recursive CTE,
|
|
40
|
+
* `fromExtensions` begins with the INNER JOIN to that CTE, and `columns`
|
|
41
|
+
* are those produced by the inner walk.
|
|
42
|
+
* @throws {Error} When `node.repeat` is absent or empty.
|
|
43
|
+
*/
|
|
44
|
+
export declare function walkRepeat(node: ViewDefinitionSelect, ctx: Context, walk: (n: ViewDefinitionSelect, c: Context) => Fragment, deps: RepeatDeps): Fragment;
|
|
45
|
+
//# sourceMappingURL=repeat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repeat.d.ts","sourceRoot":"","sources":["../../../../src/queryGenerator/treeWalker/operators/repeat.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAG9D,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,QAAQ,EAGd,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,oBAAoB,EAC1B,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE,CAAC,CAAC,EAAE,oBAAoB,EAAE,CAAC,EAAE,OAAO,KAAK,QAAQ,EACvD,IAAI,EAAE,UAAU,GACf,QAAQ,CAmCV"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Walker for Repeat nodes — emits a recursive CTE and returns a set Fragment.
|
|
4
|
+
*
|
|
5
|
+
* The CTE projects the current partition keys and any baked scalar columns
|
|
6
|
+
* plus a content-derived `__path` for stable identity across re-evaluations.
|
|
7
|
+
* The Fragment's `fromExtensions` is an INNER JOIN to the CTE on the partition key
|
|
8
|
+
* `[id]`; sibling-level composite-key joins are added by `mergeSiblings`.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.walkRepeat = walkRepeat;
|
|
12
|
+
const aliasGenerator_js_1 = require("../aliasGenerator.js");
|
|
13
|
+
const cteTemplates_js_1 = require("../cteTemplates.js");
|
|
14
|
+
const types_js_1 = require("../types.js");
|
|
15
|
+
/**
|
|
16
|
+
* Walker for Repeat nodes — emits a recursive CTE and returns a set Fragment.
|
|
17
|
+
*
|
|
18
|
+
* Generates a `WITH RECURSIVE`-style CTE (via `buildRepeatCte`) whose anchor
|
|
19
|
+
* member starts at the resource root and whose recursive members re-expand
|
|
20
|
+
* each element's `item_json` using the same path list. The CTE accumulates a
|
|
21
|
+
* `__path` string for stable per-element identity across recursion levels.
|
|
22
|
+
*
|
|
23
|
+
* The returned Fragment contains the CTE plus an `INNER JOIN` to it in
|
|
24
|
+
* `fromExtensions`; the join is keyed on all current partition keys so that
|
|
25
|
+
* only rows belonging to the enclosing resource (and any ancestor forEach)
|
|
26
|
+
* are included. The inner context updates `source` to `<cteAlias>.item_json`
|
|
27
|
+
* and appends a new `<cteAlias>_path` partition key so that nested operators
|
|
28
|
+
* can further partition the result set.
|
|
29
|
+
*
|
|
30
|
+
* @param node - The Repeat select node; `node.repeat` supplies the ordered
|
|
31
|
+
* list of FHIRPath strings used as the anchor and recursive paths.
|
|
32
|
+
* @param ctx - The current walker context; the inner context is derived from
|
|
33
|
+
* it by updating `source`, `partitionKeys`, `ancestorApplies`, and
|
|
34
|
+
* `transpilerCtx`.
|
|
35
|
+
* @param walk - The recursive walk function used to visit the inner sub-tree
|
|
36
|
+
* (`column`, `select`, `unionAll`) in the repeat-item context.
|
|
37
|
+
* @param deps - Schema and table name needed to construct the resource FROM
|
|
38
|
+
* clause inside the CTE anchor.
|
|
39
|
+
* @returns A Fragment whose `ctes` list begins with the recursive CTE,
|
|
40
|
+
* `fromExtensions` begins with the INNER JOIN to that CTE, and `columns`
|
|
41
|
+
* are those produced by the inner walk.
|
|
42
|
+
* @throws {Error} When `node.repeat` is absent or empty.
|
|
43
|
+
*/
|
|
44
|
+
function walkRepeat(node, ctx, walk, deps) {
|
|
45
|
+
const cteAlias = (0, aliasGenerator_js_1.freshAlias)(ctx, "repeat");
|
|
46
|
+
const paths = node.repeat ?? [];
|
|
47
|
+
if (paths.length === 0) {
|
|
48
|
+
throw new Error("walkRepeat: repeat node has empty paths array");
|
|
49
|
+
}
|
|
50
|
+
const tableRef = `[${deps.schemaName}].[${deps.tableName}]`;
|
|
51
|
+
const cte = (0, cteTemplates_js_1.buildRepeatCte)({
|
|
52
|
+
cteAlias,
|
|
53
|
+
paths,
|
|
54
|
+
source: ctx.source,
|
|
55
|
+
fromClause: `FROM ${tableRef} AS [${ctx.resourceAlias}]`,
|
|
56
|
+
ancestorApplies: ctx.ancestorApplies,
|
|
57
|
+
partitionKeys: ctx.partitionKeys,
|
|
58
|
+
resourcePredicate: null, // Resource-level WHERE goes in the outer SELECT.
|
|
59
|
+
});
|
|
60
|
+
const joinClause = buildJoinClause(cteAlias, ctx);
|
|
61
|
+
const innerCtx = buildRepeatInnerCtx(ctx, cteAlias, paths, joinClause);
|
|
62
|
+
const innerNode = {
|
|
63
|
+
column: node.column,
|
|
64
|
+
select: node.select,
|
|
65
|
+
unionAll: node.unionAll,
|
|
66
|
+
};
|
|
67
|
+
const inner = walk(innerNode, innerCtx);
|
|
68
|
+
return {
|
|
69
|
+
ctes: [cte, ...inner.ctes],
|
|
70
|
+
// Join the CTE FIRST so subsequent applies/joins inside the repeat
|
|
71
|
+
// (which reference `<cteAlias>.item_json`) have the alias in scope.
|
|
72
|
+
fromExtensions: joinClause + inner.fromExtensions,
|
|
73
|
+
columns: inner.columns,
|
|
74
|
+
partitionKeys: innerCtx.partitionKeys,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Outer-SELECT join condition aligning this CTE's rows with the enclosing
|
|
79
|
+
* partition (resource id plus any forEach/repeat keys above this scope).
|
|
80
|
+
*/
|
|
81
|
+
function buildJoinClause(cteAlias, ctx) {
|
|
82
|
+
const joinConditions = ctx.partitionKeys
|
|
83
|
+
.map((k) => `${cteAlias}.[${k.name}] = ${k.sqlExpr}`)
|
|
84
|
+
.join(" AND ");
|
|
85
|
+
return `\nINNER JOIN ${cteAlias} ON ${joinConditions}`;
|
|
86
|
+
}
|
|
87
|
+
function buildRepeatInnerCtx(ctx, cteAlias, paths, joinClause) {
|
|
88
|
+
const newKey = {
|
|
89
|
+
name: `${cteAlias}_path`,
|
|
90
|
+
sqlExpr: `${cteAlias}.__path`,
|
|
91
|
+
sqlType: types_js_1.SQL_NVARCHAR_MAX,
|
|
92
|
+
};
|
|
93
|
+
const innerTranspilerCtx = {
|
|
94
|
+
...ctx.transpilerCtx,
|
|
95
|
+
iterationContext: `${cteAlias}.item_json`,
|
|
96
|
+
currentForEachAlias: cteAlias,
|
|
97
|
+
forEachSource: ctx.source,
|
|
98
|
+
forEachPath: paths.map((p) => `$.${p}`).join(", "),
|
|
99
|
+
};
|
|
100
|
+
// Propagate the join into ancestorApplies so any *nested* Repeat builds
|
|
101
|
+
// its CTE anchor with this CTE in scope.
|
|
102
|
+
return {
|
|
103
|
+
...ctx,
|
|
104
|
+
source: `${cteAlias}.item_json`,
|
|
105
|
+
partitionKeys: [...ctx.partitionKeys, newKey],
|
|
106
|
+
ancestorApplies: ctx.ancestorApplies + joinClause,
|
|
107
|
+
transpilerCtx: innerTranspilerCtx,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=repeat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repeat.js","sourceRoot":"","sources":["../../../../src/queryGenerator/treeWalker/operators/repeat.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Walker for UnionAll nodes.
|
|
3
|
+
*
|
|
4
|
+
* Emits a local derived table with one SELECT per branch, joined by
|
|
5
|
+
* `UNION ALL`, wrapped as `CROSS APPLY (...) AS ua_<n>`. CTEs from any
|
|
6
|
+
* branch (e.g. enclosed Repeats) bubble up to the top-level WITH clause.
|
|
7
|
+
*
|
|
8
|
+
* Branches must produce the same column names and types (SoF spec
|
|
9
|
+
* requirement). The walker aligns them positionally — branch[0]'s names
|
|
10
|
+
* become the outer projection.
|
|
11
|
+
*
|
|
12
|
+
* If the same node also has `column[]` or `select[]` alongside `unionAll`,
|
|
13
|
+
* those are emitted as outer siblings (they live in the SELECT list at the
|
|
14
|
+
* same level as the ua_<n> projection, evaluated in the parent scope).
|
|
15
|
+
*/
|
|
16
|
+
import type { ViewDefinitionSelect } from "../../../types.js";
|
|
17
|
+
import type { ColumnExpressionGenerator } from "../../ColumnExpressionGenerator.js";
|
|
18
|
+
import type { Context, Fragment } from "../types.js";
|
|
19
|
+
export interface UnionAllDeps {
|
|
20
|
+
columnGenerator: ColumnExpressionGenerator;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Walker for UnionAll nodes.
|
|
24
|
+
*
|
|
25
|
+
* Walks each branch of `node.unionAll` in the current context and assembles
|
|
26
|
+
* them into a `CROSS APPLY (...) AS ua_<n>` derived table where each branch
|
|
27
|
+
* contributes a `SELECT … FROM (SELECT 1 AS _) AS _seed …` statement joined
|
|
28
|
+
* by `UNION ALL`. Branch columns are aligned positionally to branch[0]'s
|
|
29
|
+
* names, satisfying the SoF spec requirement that all branches produce the
|
|
30
|
+
* same column names and types.
|
|
31
|
+
*
|
|
32
|
+
* CTEs from any branch (e.g. produced by enclosed Repeat nodes) bubble up
|
|
33
|
+
* into the returned Fragment's `ctes` list so they appear in the top-level
|
|
34
|
+
* `WITH` clause.
|
|
35
|
+
*
|
|
36
|
+
* If the same node also carries `column[]` or `select[]` alongside
|
|
37
|
+
* `unionAll`, those are emitted as outer siblings in the enclosing SELECT
|
|
38
|
+
* scope and merged with the union fragment via `mergeSiblings`.
|
|
39
|
+
*
|
|
40
|
+
* @param node - The UnionAll select node; `node.unionAll` must be a non-empty
|
|
41
|
+
* array of branch select nodes.
|
|
42
|
+
* @param ctx - The current walker context, passed unchanged to every branch
|
|
43
|
+
* and to any sibling column/select processing.
|
|
44
|
+
* @param walk - The recursive walk function used to visit each branch and any
|
|
45
|
+
* outer sibling select nodes.
|
|
46
|
+
* @param deps - Dependencies containing the `ColumnExpressionGenerator` used
|
|
47
|
+
* to project any outer sibling `column[]` entries.
|
|
48
|
+
* @returns A Fragment whose `fromExtensions` contains the `CROSS APPLY`
|
|
49
|
+
* derived-table clause, `ctes` aggregates all branch CTEs, and `columns`
|
|
50
|
+
* contains the outer projection (plus any sibling columns).
|
|
51
|
+
* @throws {Error} When `node.unionAll` is empty.
|
|
52
|
+
*/
|
|
53
|
+
export declare function walkUnionAll(node: ViewDefinitionSelect, ctx: Context, walk: (n: ViewDefinitionSelect, c: Context) => Fragment, deps: UnionAllDeps): Fragment;
|
|
54
|
+
//# sourceMappingURL=unionAll.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unionAll.d.ts","sourceRoot":"","sources":["../../../../src/queryGenerator/treeWalker/operators/unionAll.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AAGpF,OAAO,KAAK,EACV,OAAO,EAEP,QAAQ,EAET,MAAM,aAAa,CAAC;AAGrB,MAAM,WAAW,YAAY;IAC3B,eAAe,EAAE,yBAAyB,CAAC;CAC5C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,oBAAoB,EAC1B,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE,CAAC,CAAC,EAAE,oBAAoB,EAAE,CAAC,EAAE,OAAO,KAAK,QAAQ,EACvD,IAAI,EAAE,YAAY,GACjB,QAAQ,CAWV"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Walker for UnionAll nodes.
|
|
4
|
+
*
|
|
5
|
+
* Emits a local derived table with one SELECT per branch, joined by
|
|
6
|
+
* `UNION ALL`, wrapped as `CROSS APPLY (...) AS ua_<n>`. CTEs from any
|
|
7
|
+
* branch (e.g. enclosed Repeats) bubble up to the top-level WITH clause.
|
|
8
|
+
*
|
|
9
|
+
* Branches must produce the same column names and types (SoF spec
|
|
10
|
+
* requirement). The walker aligns them positionally — branch[0]'s names
|
|
11
|
+
* become the outer projection.
|
|
12
|
+
*
|
|
13
|
+
* If the same node also has `column[]` or `select[]` alongside `unionAll`,
|
|
14
|
+
* those are emitted as outer siblings (they live in the SELECT list at the
|
|
15
|
+
* same level as the ua_<n> projection, evaluated in the parent scope).
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.walkUnionAll = walkUnionAll;
|
|
19
|
+
const aliasGenerator_js_1 = require("../aliasGenerator.js");
|
|
20
|
+
const mergeSiblings_js_1 = require("../mergeSiblings.js");
|
|
21
|
+
const columnsOnly_js_1 = require("./columnsOnly.js");
|
|
22
|
+
/**
|
|
23
|
+
* Walker for UnionAll nodes.
|
|
24
|
+
*
|
|
25
|
+
* Walks each branch of `node.unionAll` in the current context and assembles
|
|
26
|
+
* them into a `CROSS APPLY (...) AS ua_<n>` derived table where each branch
|
|
27
|
+
* contributes a `SELECT … FROM (SELECT 1 AS _) AS _seed …` statement joined
|
|
28
|
+
* by `UNION ALL`. Branch columns are aligned positionally to branch[0]'s
|
|
29
|
+
* names, satisfying the SoF spec requirement that all branches produce the
|
|
30
|
+
* same column names and types.
|
|
31
|
+
*
|
|
32
|
+
* CTEs from any branch (e.g. produced by enclosed Repeat nodes) bubble up
|
|
33
|
+
* into the returned Fragment's `ctes` list so they appear in the top-level
|
|
34
|
+
* `WITH` clause.
|
|
35
|
+
*
|
|
36
|
+
* If the same node also carries `column[]` or `select[]` alongside
|
|
37
|
+
* `unionAll`, those are emitted as outer siblings in the enclosing SELECT
|
|
38
|
+
* scope and merged with the union fragment via `mergeSiblings`.
|
|
39
|
+
*
|
|
40
|
+
* @param node - The UnionAll select node; `node.unionAll` must be a non-empty
|
|
41
|
+
* array of branch select nodes.
|
|
42
|
+
* @param ctx - The current walker context, passed unchanged to every branch
|
|
43
|
+
* and to any sibling column/select processing.
|
|
44
|
+
* @param walk - The recursive walk function used to visit each branch and any
|
|
45
|
+
* outer sibling select nodes.
|
|
46
|
+
* @param deps - Dependencies containing the `ColumnExpressionGenerator` used
|
|
47
|
+
* to project any outer sibling `column[]` entries.
|
|
48
|
+
* @returns A Fragment whose `fromExtensions` contains the `CROSS APPLY`
|
|
49
|
+
* derived-table clause, `ctes` aggregates all branch CTEs, and `columns`
|
|
50
|
+
* contains the outer projection (plus any sibling columns).
|
|
51
|
+
* @throws {Error} When `node.unionAll` is empty.
|
|
52
|
+
*/
|
|
53
|
+
function walkUnionAll(node, ctx, walk, deps) {
|
|
54
|
+
const branches = node.unionAll ?? [];
|
|
55
|
+
if (branches.length === 0)
|
|
56
|
+
throw new Error("walkUnionAll: empty unionAll");
|
|
57
|
+
const branchFragments = branches.map((b) => walk(b, ctx));
|
|
58
|
+
const uaFragment = buildUnionAllFragment(branchFragments, ctx);
|
|
59
|
+
const outerSiblings = collectOuterSiblings(node, ctx, walk, deps);
|
|
60
|
+
return outerSiblings.length === 0
|
|
61
|
+
? uaFragment
|
|
62
|
+
: (0, mergeSiblings_js_1.mergeSiblings)([...outerSiblings, uaFragment], ctx);
|
|
63
|
+
}
|
|
64
|
+
function buildUnionAllFragment(branchFragments, ctx) {
|
|
65
|
+
const uaAlias = (0, aliasGenerator_js_1.freshAlias)(ctx, "ua");
|
|
66
|
+
const allCtes = branchFragments.flatMap((f) => f.ctes);
|
|
67
|
+
const referenceColumns = branchFragments[0].columns;
|
|
68
|
+
const branchSqls = branchFragments.map((f) => renderBranchSelect(f, referenceColumns));
|
|
69
|
+
const unionDerivedTable = `(\n ${branchSqls.join("\n UNION ALL\n ")}\n) AS ${uaAlias}`;
|
|
70
|
+
const uaColumns = referenceColumns.map((c) => ({
|
|
71
|
+
name: c.name,
|
|
72
|
+
sqlExpr: `${uaAlias}.[${c.name}]`,
|
|
73
|
+
}));
|
|
74
|
+
return {
|
|
75
|
+
ctes: allCtes,
|
|
76
|
+
fromExtensions: `\nCROSS APPLY ${unionDerivedTable}`,
|
|
77
|
+
columns: uaColumns,
|
|
78
|
+
partitionKeys: ctx.partitionKeys,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function collectOuterSiblings(node, ctx, walk, deps) {
|
|
82
|
+
const out = [];
|
|
83
|
+
if (node.column && node.column.length > 0) {
|
|
84
|
+
out.push({
|
|
85
|
+
ctes: [],
|
|
86
|
+
fromExtensions: "",
|
|
87
|
+
columns: (0, columnsOnly_js_1.projectColumns)(node.column, ctx, deps.columnGenerator),
|
|
88
|
+
partitionKeys: ctx.partitionKeys,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
if (node.select) {
|
|
92
|
+
for (const child of node.select)
|
|
93
|
+
out.push(walk(child, ctx));
|
|
94
|
+
}
|
|
95
|
+
return out;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Renders one branch's SELECT inside the unionAll derived table.
|
|
99
|
+
*
|
|
100
|
+
* The seed `(SELECT 1 AS _) AS _seed` ensures the branch always has a
|
|
101
|
+
* FROM clause to attach its CROSS/OUTER APPLY chain to, and keeps the SQL
|
|
102
|
+
* uniform whether the branch has operators or not. No unique suffix is
|
|
103
|
+
* needed because each SELECT in a UNION ALL has its own independent FROM
|
|
104
|
+
* scope — `_seed` in one branch cannot collide with `_seed` in another.
|
|
105
|
+
*
|
|
106
|
+
* Columns are re-aliased to branch[0]'s names so the outer projection by
|
|
107
|
+
* name works for every branch row.
|
|
108
|
+
*/
|
|
109
|
+
function renderBranchSelect(fragment, referenceColumns) {
|
|
110
|
+
const projection = referenceColumns
|
|
111
|
+
.map((ref, i) => {
|
|
112
|
+
const branchCol = fragment.columns[i];
|
|
113
|
+
if (!branchCol) {
|
|
114
|
+
throw new Error(`unionAll branch is missing column at index ${i} (expected '${ref.name}')`);
|
|
115
|
+
}
|
|
116
|
+
return `${branchCol.sqlExpr} AS [${ref.name}]`;
|
|
117
|
+
})
|
|
118
|
+
.join(", ");
|
|
119
|
+
return `SELECT ${projection} FROM (SELECT 1 AS _) AS _seed${fragment.fromExtensions}`;
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=unionAll.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unionAll.js","sourceRoot":"","sources":["../../../../src/queryGenerator/treeWalker/operators/unionAll.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renders a root Fragment into the final T-SQL statement:
|
|
3
|
+
*
|
|
4
|
+
* WITH <ctes> SELECT <cols> FROM <root> <fromExtensions> WHERE <pred>
|
|
5
|
+
*/
|
|
6
|
+
import type { TranspilerContext } from "../../fhirpath/transpiler.js";
|
|
7
|
+
import type { ViewDefinition } from "../../types.js";
|
|
8
|
+
import type { WhereClauseBuilder } from "../WhereClauseBuilder.js";
|
|
9
|
+
import type { Fragment } from "./types.js";
|
|
10
|
+
export interface RenderOptions {
|
|
11
|
+
resourceAlias: string;
|
|
12
|
+
schemaName: string;
|
|
13
|
+
tableName: string;
|
|
14
|
+
testId?: string;
|
|
15
|
+
whereClauseBuilder: WhereClauseBuilder;
|
|
16
|
+
transpilerCtx: TranspilerContext;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Renders a root Fragment into the final T-SQL statement.
|
|
20
|
+
*
|
|
21
|
+
* Assembles the optional `WITH <ctes>` preamble, the `SELECT <cols>` list,
|
|
22
|
+
* the `FROM <table>` clause, any `fromExtensions` (APPLY / JOIN chains), and
|
|
23
|
+
* the optional `WHERE` predicate built by `WhereClauseBuilder`.
|
|
24
|
+
*
|
|
25
|
+
* @param fragment - The root Fragment produced by walking the select tree.
|
|
26
|
+
* @param viewDef - The ViewDefinition supplying the resource type, WHERE
|
|
27
|
+
* predicates, and other metadata needed to construct the WHERE clause.
|
|
28
|
+
* @param options - Render options including table/schema names, resource alias,
|
|
29
|
+
* optional test-isolation ID, the where-clause builder, and the transpiler
|
|
30
|
+
* context.
|
|
31
|
+
* @returns The complete T-SQL query string ready for execution.
|
|
32
|
+
*/
|
|
33
|
+
export declare function renderRoot(fragment: Fragment, viewDef: ViewDefinition, options: RenderOptions): string;
|
|
34
|
+
//# sourceMappingURL=render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/queryGenerator/treeWalker/render.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,WAAW,aAAa;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,aAAa,EAAE,iBAAiB,CAAC;CAClC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,UAAU,CACxB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,aAAa,GACrB,MAAM,CA6BR"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Renders a root Fragment into the final T-SQL statement:
|
|
4
|
+
*
|
|
5
|
+
* WITH <ctes> SELECT <cols> FROM <root> <fromExtensions> WHERE <pred>
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.renderRoot = renderRoot;
|
|
9
|
+
/**
|
|
10
|
+
* Renders a root Fragment into the final T-SQL statement.
|
|
11
|
+
*
|
|
12
|
+
* Assembles the optional `WITH <ctes>` preamble, the `SELECT <cols>` list,
|
|
13
|
+
* the `FROM <table>` clause, any `fromExtensions` (APPLY / JOIN chains), and
|
|
14
|
+
* the optional `WHERE` predicate built by `WhereClauseBuilder`.
|
|
15
|
+
*
|
|
16
|
+
* @param fragment - The root Fragment produced by walking the select tree.
|
|
17
|
+
* @param viewDef - The ViewDefinition supplying the resource type, WHERE
|
|
18
|
+
* predicates, and other metadata needed to construct the WHERE clause.
|
|
19
|
+
* @param options - Render options including table/schema names, resource alias,
|
|
20
|
+
* optional test-isolation ID, the where-clause builder, and the transpiler
|
|
21
|
+
* context.
|
|
22
|
+
* @returns The complete T-SQL query string ready for execution.
|
|
23
|
+
*/
|
|
24
|
+
function renderRoot(fragment, viewDef, options) {
|
|
25
|
+
const { resourceAlias, schemaName, tableName } = options;
|
|
26
|
+
const tableRef = `[${schemaName}].[${tableName}]`;
|
|
27
|
+
const cteSection = fragment.ctes.length > 0
|
|
28
|
+
? `WITH\n${fragment.ctes.map((c) => `${c.alias} AS (\n${c.body}\n)`).join(",\n")}\n`
|
|
29
|
+
: "";
|
|
30
|
+
const selectList = fragment.columns
|
|
31
|
+
.map((c) => `${c.sqlExpr} AS [${c.name}]`)
|
|
32
|
+
.join(",\n ");
|
|
33
|
+
const fromClause = `FROM ${tableRef} AS [${resourceAlias}]`;
|
|
34
|
+
const whereClause = options.whereClauseBuilder.buildWhereClause(viewDef.resource, resourceAlias, options.testId, viewDef.where, options.transpilerCtx);
|
|
35
|
+
let body = `SELECT\n ${selectList}\n${fromClause}${fragment.fromExtensions}`;
|
|
36
|
+
if (whereClause !== null) {
|
|
37
|
+
body += `\n${whereClause}`;
|
|
38
|
+
}
|
|
39
|
+
return `${cteSection}${body}`;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../../src/queryGenerator/treeWalker/render.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;AA+BH,gCAiCC;AAhDD;;;;;;;;;;;;;;GAcG;AACH,SAAgB,UAAU,CACxB,QAAkB,EAClB,OAAuB,EACvB,OAAsB;IAEtB,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;IACzD,MAAM,QAAQ,GAAG,IAAI,UAAU,MAAM,SAAS,GAAG,CAAC;IAElD,MAAM,UAAU,GACd,QAAQ,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC;QACtB,CAAC,CAAC,SAAS,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI;QACpF,CAAC,CAAC,EAAE,CAAC;IAET,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO;SAChC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,OAAO,QAAQ,CAAC,CAAC,IAAI,GAAG,CAAC;SACzC,IAAI,CAAC,OAAO,CAAC,CAAC;IAEjB,MAAM,UAAU,GAAG,QAAQ,QAAQ,QAAQ,aAAa,GAAG,CAAC;IAE5D,MAAM,WAAW,GAAG,OAAO,CAAC,kBAAkB,CAAC,gBAAgB,CAC7D,OAAO,CAAC,QAAQ,EAChB,aAAa,EACb,OAAO,CAAC,MAAM,EACd,OAAO,CAAC,KAAK,EACb,OAAO,CAAC,aAAa,CACtB,CAAC;IAEF,IAAI,IAAI,GAAG,aAAa,UAAU,KAAK,UAAU,GAAG,QAAQ,CAAC,cAAc,EAAE,CAAC;IAC9E,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;QACzB,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;IAC7B,CAAC;IAED,OAAO,GAAG,UAAU,GAAG,IAAI,EAAE,CAAC;AAChC,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core types for the tree-walker query generator.
|
|
3
|
+
*
|
|
4
|
+
* Each select-tree node produces a Fragment; sibling fragments are merged
|
|
5
|
+
* via partition-key joins. Context threads through descent, accumulating
|
|
6
|
+
* the current JSON source, partition keys, and APPLY chain.
|
|
7
|
+
*/
|
|
8
|
+
import type { TranspilerContext } from "../../fhirpath/transpiler.js";
|
|
9
|
+
export declare const SQL_INT = "INT";
|
|
10
|
+
export declare const SQL_NVARCHAR_4000 = "NVARCHAR(4000)";
|
|
11
|
+
export declare const SQL_NVARCHAR_MAX = "NVARCHAR(MAX)";
|
|
12
|
+
export type NodeKind = "ColumnsOnly" | "Group" | "ForEach" | "ForEachOrNull" | "Repeat" | "UnionAll";
|
|
13
|
+
export interface PartitionKey {
|
|
14
|
+
/** Logical name, e.g. "id", "fe_0_key", "repeat_2_path". */
|
|
15
|
+
name: string;
|
|
16
|
+
/** SQL expression that yields it in the *defining* scope. */
|
|
17
|
+
sqlExpr: string;
|
|
18
|
+
/** Type used when projecting it through a CTE column list. */
|
|
19
|
+
sqlType: string;
|
|
20
|
+
}
|
|
21
|
+
export interface ProjectedColumn {
|
|
22
|
+
/** Bracketed identifier as it appears in the final SELECT list. */
|
|
23
|
+
name: string;
|
|
24
|
+
sqlExpr: string;
|
|
25
|
+
}
|
|
26
|
+
export interface CteDefinition {
|
|
27
|
+
alias: string;
|
|
28
|
+
/** Full SQL body without the "alias AS (...)" wrapper. */
|
|
29
|
+
body: string;
|
|
30
|
+
}
|
|
31
|
+
export interface Context {
|
|
32
|
+
resourceAlias: string;
|
|
33
|
+
/** Current JSON source expression, e.g. "r.json", "forEach_0.value". */
|
|
34
|
+
source: string;
|
|
35
|
+
/** Ordered, monotonically appended as the walker descends. */
|
|
36
|
+
partitionKeys: PartitionKey[];
|
|
37
|
+
/**
|
|
38
|
+
* CROSS/OUTER APPLY chain accumulated above this point, needed so any
|
|
39
|
+
* enclosed Repeat CTE anchor can reach `ctx.source`. Each element starts
|
|
40
|
+
* with "\n".
|
|
41
|
+
*/
|
|
42
|
+
ancestorApplies: string;
|
|
43
|
+
/** True if any forEachOrNull ancestor is in scope. */
|
|
44
|
+
nullable: boolean;
|
|
45
|
+
/** Shared mutable counter for unique CTE/alias names across the whole compile. */
|
|
46
|
+
cteCounter: {
|
|
47
|
+
value: number;
|
|
48
|
+
};
|
|
49
|
+
/** Pass-through context for the FHIRPath transpiler. */
|
|
50
|
+
transpilerCtx: TranspilerContext;
|
|
51
|
+
}
|
|
52
|
+
export interface Fragment {
|
|
53
|
+
ctes: CteDefinition[];
|
|
54
|
+
/**
|
|
55
|
+
* Ordered sequence of FROM-clause extensions: a mix of CROSS/OUTER APPLY
|
|
56
|
+
* and INNER/LEFT/FULL OUTER JOIN clauses, each prefixed by "\n". Order is
|
|
57
|
+
* preserved so that aliases are always introduced before they are
|
|
58
|
+
* referenced (e.g. an INNER JOIN to a Repeat CTE precedes any CROSS APPLY
|
|
59
|
+
* that reads from the CTE's `item_json`).
|
|
60
|
+
*/
|
|
61
|
+
fromExtensions: string;
|
|
62
|
+
columns: ProjectedColumn[];
|
|
63
|
+
/** Keys exposed by this fragment for use by sibling joins. */
|
|
64
|
+
partitionKeys: PartitionKey[];
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/queryGenerator/treeWalker/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEtE,eAAO,MAAM,OAAO,QAAQ,CAAC;AAC7B,eAAO,MAAM,iBAAiB,mBAAmB,CAAC;AAClD,eAAO,MAAM,gBAAgB,kBAAkB,CAAC;AAEhD,MAAM,MAAM,QAAQ,GAChB,aAAa,GACb,OAAO,GACP,SAAS,GACT,eAAe,GACf,QAAQ,GACR,UAAU,CAAC;AAEf,MAAM,WAAW,YAAY;IAC3B,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,OAAO,EAAE,MAAM,CAAC;IAChB,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,mEAAmE;IACnE,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,OAAO;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,wEAAwE;IACxE,MAAM,EAAE,MAAM,CAAC;IACf,8DAA8D;IAC9D,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B;;;;OAIG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB,sDAAsD;IACtD,QAAQ,EAAE,OAAO,CAAC;IAClB,kFAAkF;IAClF,UAAU,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9B,wDAAwD;IACxD,aAAa,EAAE,iBAAiB,CAAC;CAClC;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,aAAa,EAAE,CAAC;IACtB;;;;;;OAMG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,8DAA8D;IAC9D,aAAa,EAAE,YAAY,EAAE,CAAC;CAC/B"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Core types for the tree-walker query generator.
|
|
4
|
+
*
|
|
5
|
+
* Each select-tree node produces a Fragment; sibling fragments are merged
|
|
6
|
+
* via partition-key joins. Context threads through descent, accumulating
|
|
7
|
+
* the current JSON source, partition keys, and APPLY chain.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.SQL_NVARCHAR_MAX = exports.SQL_NVARCHAR_4000 = exports.SQL_INT = void 0;
|
|
11
|
+
exports.SQL_INT = "INT";
|
|
12
|
+
exports.SQL_NVARCHAR_4000 = "NVARCHAR(4000)";
|
|
13
|
+
exports.SQL_NVARCHAR_MAX = "NVARCHAR(MAX)";
|
|
14
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/queryGenerator/treeWalker/types.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAIU,QAAA,OAAO,GAAG,KAAK,CAAC;AAChB,QAAA,iBAAiB,GAAG,gBAAgB,CAAC;AACrC,QAAA,gBAAgB,GAAG,eAAe,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recursive dispatch — visits a select-tree node and produces a Fragment.
|
|
3
|
+
*
|
|
4
|
+
* Each node kind has its own walker; this module just dispatches via
|
|
5
|
+
* classifyNode. Operators not yet implemented throw a clear error.
|
|
6
|
+
*/
|
|
7
|
+
import type { ViewDefinitionSelect } from "../../types.js";
|
|
8
|
+
import type { ColumnExpressionGenerator } from "../ColumnExpressionGenerator.js";
|
|
9
|
+
import type { PathParser } from "../PathParser.js";
|
|
10
|
+
import type { Context, Fragment } from "./types.js";
|
|
11
|
+
export interface WalkerDeps {
|
|
12
|
+
columnGenerator: ColumnExpressionGenerator;
|
|
13
|
+
pathParser: PathParser;
|
|
14
|
+
schemaName: string;
|
|
15
|
+
tableName: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Creates the recursive walk function used to traverse the select tree.
|
|
19
|
+
*
|
|
20
|
+
* The returned `walk` function classifies each `ViewDefinitionSelect` node via
|
|
21
|
+
* `classifyNode` and dispatches to the appropriate operator walker
|
|
22
|
+
* (`walkColumnsOnly`, `walkGroup`, `walkForEach`, `walkRepeat`, or
|
|
23
|
+
* `walkUnionAll`). The same `walk` reference is threaded into every operator
|
|
24
|
+
* so they can recurse into child nodes without circular imports.
|
|
25
|
+
*
|
|
26
|
+
* @param deps - External service dependencies shared across all operator
|
|
27
|
+
* walkers: a `ColumnExpressionGenerator`, a `PathParser`, and the target
|
|
28
|
+
* schema/table names used by the Repeat CTE builder.
|
|
29
|
+
* @returns A `walk` function that accepts a node and a `Context` and returns
|
|
30
|
+
* the corresponding `Fragment`.
|
|
31
|
+
* @throws {Error} When a node's kind is not handled (should not occur given
|
|
32
|
+
* the exhaustive `classifyNode` discriminants, but TypeScript exhaustiveness
|
|
33
|
+
* checking requires the switch to be complete).
|
|
34
|
+
*/
|
|
35
|
+
export declare function makeWalker(deps: WalkerDeps): (node: ViewDefinitionSelect, ctx: Context) => Fragment;
|
|
36
|
+
//# sourceMappingURL=walker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"walker.d.ts","sourceRoot":"","sources":["../../../src/queryGenerator/treeWalker/walker.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAC;AACjF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAOnD,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEpD,MAAM,WAAW,UAAU;IACzB,eAAe,EAAE,yBAAyB,CAAC;IAC3C,UAAU,EAAE,UAAU,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,UAAU,GACf,CAAC,IAAI,EAAE,oBAAoB,EAAE,GAAG,EAAE,OAAO,KAAK,QAAQ,CAuBxD"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Recursive dispatch — visits a select-tree node and produces a Fragment.
|
|
4
|
+
*
|
|
5
|
+
* Each node kind has its own walker; this module just dispatches via
|
|
6
|
+
* classifyNode. Operators not yet implemented throw a clear error.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.makeWalker = makeWalker;
|
|
10
|
+
const classify_js_1 = require("./classify.js");
|
|
11
|
+
const columnsOnly_js_1 = require("./operators/columnsOnly.js");
|
|
12
|
+
const forEach_js_1 = require("./operators/forEach.js");
|
|
13
|
+
const group_js_1 = require("./operators/group.js");
|
|
14
|
+
const repeat_js_1 = require("./operators/repeat.js");
|
|
15
|
+
const unionAll_js_1 = require("./operators/unionAll.js");
|
|
16
|
+
/**
|
|
17
|
+
* Creates the recursive walk function used to traverse the select tree.
|
|
18
|
+
*
|
|
19
|
+
* The returned `walk` function classifies each `ViewDefinitionSelect` node via
|
|
20
|
+
* `classifyNode` and dispatches to the appropriate operator walker
|
|
21
|
+
* (`walkColumnsOnly`, `walkGroup`, `walkForEach`, `walkRepeat`, or
|
|
22
|
+
* `walkUnionAll`). The same `walk` reference is threaded into every operator
|
|
23
|
+
* so they can recurse into child nodes without circular imports.
|
|
24
|
+
*
|
|
25
|
+
* @param deps - External service dependencies shared across all operator
|
|
26
|
+
* walkers: a `ColumnExpressionGenerator`, a `PathParser`, and the target
|
|
27
|
+
* schema/table names used by the Repeat CTE builder.
|
|
28
|
+
* @returns A `walk` function that accepts a node and a `Context` and returns
|
|
29
|
+
* the corresponding `Fragment`.
|
|
30
|
+
* @throws {Error} When a node's kind is not handled (should not occur given
|
|
31
|
+
* the exhaustive `classifyNode` discriminants, but TypeScript exhaustiveness
|
|
32
|
+
* checking requires the switch to be complete).
|
|
33
|
+
*/
|
|
34
|
+
function makeWalker(deps) {
|
|
35
|
+
function walk(node, ctx) {
|
|
36
|
+
const kind = (0, classify_js_1.classifyNode)(node);
|
|
37
|
+
switch (kind) {
|
|
38
|
+
case "ColumnsOnly":
|
|
39
|
+
return (0, columnsOnly_js_1.walkColumnsOnly)(node, ctx, deps.columnGenerator);
|
|
40
|
+
case "Group":
|
|
41
|
+
return (0, group_js_1.walkGroup)(node, ctx, walk, deps.columnGenerator);
|
|
42
|
+
case "ForEach":
|
|
43
|
+
case "ForEachOrNull":
|
|
44
|
+
return (0, forEach_js_1.walkForEach)(node, ctx, walk, { pathParser: deps.pathParser });
|
|
45
|
+
case "Repeat":
|
|
46
|
+
return (0, repeat_js_1.walkRepeat)(node, ctx, walk, {
|
|
47
|
+
schemaName: deps.schemaName,
|
|
48
|
+
tableName: deps.tableName,
|
|
49
|
+
});
|
|
50
|
+
case "UnionAll":
|
|
51
|
+
return (0, unionAll_js_1.walkUnionAll)(node, ctx, walk, {
|
|
52
|
+
columnGenerator: deps.columnGenerator,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return walk;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=walker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"walker.js","sourceRoot":"","sources":["../../../src/queryGenerator/treeWalker/walker.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;AAsCH,gCAyBC;AA1DD,+CAA6C;AAC7C,+DAA6D;AAC7D,uDAAqD;AACrD,mDAAiD;AACjD,qDAAmD;AACnD,yDAAuD;AAUvD;;;;;;;;;;;;;;;;;GAiBG;AACH,SAAgB,UAAU,CACxB,IAAgB;IAEhB,SAAS,IAAI,CAAC,IAA0B,EAAE,GAAY;QACpD,MAAM,IAAI,GAAG,IAAA,0BAAY,EAAC,IAAI,CAAC,CAAC;QAChC,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,aAAa;gBAChB,OAAO,IAAA,gCAAe,EAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;YAC1D,KAAK,OAAO;gBACV,OAAO,IAAA,oBAAS,EAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;YAC1D,KAAK,SAAS,CAAC;YACf,KAAK,eAAe;gBAClB,OAAO,IAAA,wBAAW,EAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;YACvE,KAAK,QAAQ;gBACX,OAAO,IAAA,sBAAU,EAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE;oBACjC,UAAU,EAAE,IAAI,CAAC,UAAU;oBAC3B,SAAS,EAAE,IAAI,CAAC,SAAS;iBAC1B,CAAC,CAAC;YACL,KAAK,UAAU;gBACb,OAAO,IAAA,0BAAY,EAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE;oBACnC,eAAe,EAAE,IAAI,CAAC,eAAe;iBACtC,CAAC,CAAC;QACP,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|