sof-mssql 2.2.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -0
- package/dist/fhirpath/jsonSafeEmptiness.test.d.ts +19 -0
- package/dist/fhirpath/jsonSafeEmptiness.test.d.ts.map +1 -0
- package/dist/fhirpath/jsonSafeEmptiness.test.js +80 -0
- package/dist/fhirpath/jsonSafeEmptiness.test.js.map +1 -0
- package/dist/fhirpath/visitor.d.ts +78 -0
- package/dist/fhirpath/visitor.d.ts.map +1 -1
- package/dist/fhirpath/visitor.js +228 -23
- package/dist/fhirpath/visitor.js.map +1 -1
- package/dist/load.d.ts +9 -0
- package/dist/load.d.ts.map +1 -1
- package/dist/load.js +4 -0
- package/dist/load.js.map +1 -1
- package/dist/loader/feedback.integration.test.d.ts +14 -0
- package/dist/loader/feedback.integration.test.d.ts.map +1 -0
- package/dist/loader/feedback.integration.test.js +76 -0
- package/dist/loader/feedback.integration.test.js.map +1 -0
- package/dist/loader/index.d.ts.map +1 -1
- package/dist/loader/index.js +19 -6
- package/dist/loader/index.js.map +1 -1
- package/dist/loader/jsonColumn.integration.test.d.ts +13 -0
- package/dist/loader/jsonColumn.integration.test.d.ts.map +1 -0
- package/dist/loader/jsonColumn.integration.test.js +86 -0
- package/dist/loader/jsonColumn.integration.test.js.map +1 -0
- package/dist/loader/tables.d.ts +96 -3
- package/dist/loader/tables.d.ts.map +1 -1
- package/dist/loader/tables.js +182 -16
- package/dist/loader/tables.js.map +1 -1
- package/dist/loader/tables.test.d.ts +12 -0
- package/dist/loader/tables.test.d.ts.map +1 -0
- package/dist/loader/tables.test.js +130 -0
- package/dist/loader/tables.test.js.map +1 -0
- package/dist/loader/types.d.ts +9 -0
- package/dist/loader/types.d.ts.map +1 -1
- package/dist/parser.d.ts +1 -1
- package/dist/parser.js +1 -1
- package/dist/queryGenerator/treeWalker/compile.js +0 -1
- package/dist/queryGenerator/treeWalker/compile.js.map +1 -1
- package/dist/queryGenerator/treeWalker/cteTemplates.d.ts +9 -1
- package/dist/queryGenerator/treeWalker/cteTemplates.d.ts.map +1 -1
- package/dist/queryGenerator/treeWalker/cteTemplates.js +39 -3
- package/dist/queryGenerator/treeWalker/cteTemplates.js.map +1 -1
- package/dist/queryGenerator/treeWalker/operators/forEach.d.ts +4 -2
- package/dist/queryGenerator/treeWalker/operators/forEach.d.ts.map +1 -1
- package/dist/queryGenerator/treeWalker/operators/forEach.js +11 -5
- package/dist/queryGenerator/treeWalker/operators/forEach.js.map +1 -1
- package/dist/queryGenerator/treeWalker/operators/repeat.d.ts +2 -0
- package/dist/queryGenerator/treeWalker/operators/repeat.d.ts.map +1 -1
- package/dist/queryGenerator/treeWalker/operators/repeat.js +12 -0
- package/dist/queryGenerator/treeWalker/operators/repeat.js.map +1 -1
- package/dist/queryGenerator/treeWalker/types.d.ts +0 -2
- package/dist/queryGenerator/treeWalker/types.d.ts.map +1 -1
- package/dist/tests/load.test.d.ts +11 -0
- package/dist/tests/load.test.d.ts.map +1 -0
- package/dist/tests/load.test.js +37 -0
- package/dist/tests/load.test.js.map +1 -0
- package/dist/tests/utils/database.d.ts +2 -0
- package/dist/tests/utils/database.d.ts.map +1 -1
- package/dist/tests/utils/database.js +61 -4
- package/dist/tests/utils/database.js.map +1 -1
- package/dist/tests/utils/generator.d.ts +2 -0
- package/dist/tests/utils/generator.d.ts.map +1 -1
- package/dist/tests/utils/generator.js +24 -0
- package/dist/tests/utils/generator.js.map +1 -1
- package/dist/tests/utils/loaderIntegration.d.ts +59 -0
- package/dist/tests/utils/loaderIntegration.d.ts.map +1 -0
- package/dist/tests/utils/loaderIntegration.js +137 -0
- package/dist/tests/utils/loaderIntegration.js.map +1 -0
- package/dist/tests/utils/reporter.d.ts +1 -1
- package/dist/tests/utils/reporter.d.ts.map +1 -1
- package/dist/tests/utils/reporter.js +5 -4
- package/dist/tests/utils/reporter.js.map +1 -1
- package/dist/tests/utils/serverCapabilities.d.ts +23 -0
- package/dist/tests/utils/serverCapabilities.d.ts.map +1 -0
- package/dist/tests/utils/serverCapabilities.js +35 -0
- package/dist/tests/utils/serverCapabilities.js.map +1 -0
- package/dist/tests/utils/types.d.ts +1 -1
- package/dist/tests/utils/types.js +1 -1
- package/dist/tests/validation.test.d.ts +13 -0
- package/dist/tests/validation.test.d.ts.map +1 -0
- package/dist/tests/validation.test.js +81 -0
- package/dist/tests/validation.test.js.map +1 -0
- package/dist/types.d.ts +1 -1
- package/dist/validation.d.ts +40 -0
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +56 -0
- package/dist/validation.js.map +1 -1
- package/package.json +2 -1
package/dist/loader/tables.js
CHANGED
|
@@ -9,12 +9,119 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
9
9
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.buildCreateTableStatements = buildCreateTableStatements;
|
|
13
|
+
exports.resolveColumnJsonDataType = resolveColumnJsonDataType;
|
|
14
|
+
exports.buildJsonTypeMismatchWarning = buildJsonTypeMismatchWarning;
|
|
12
15
|
exports.tableExists = tableExists;
|
|
16
|
+
exports.getExistingJsonColumnType = getExistingJsonColumnType;
|
|
17
|
+
exports.warnIfJsonTypeMismatch = warnIfJsonTypeMismatch;
|
|
13
18
|
exports.createTable = createTable;
|
|
14
19
|
exports.truncateTable = truncateTable;
|
|
15
20
|
exports.ensureTable = ensureTable;
|
|
16
21
|
const mssql_1 = __importDefault(require("mssql"));
|
|
17
22
|
const validation_js_1 = require("../validation.js");
|
|
23
|
+
/**
|
|
24
|
+
* Build the DDL statements for the resources table and its index.
|
|
25
|
+
*
|
|
26
|
+
* This is a pure function so the generated SQL can be unit-tested without a
|
|
27
|
+
* database. The `json` column is typed with the resolved {@link
|
|
28
|
+
* ResourceJsonDataType}; with the default `NVARCHAR(MAX)` the output is
|
|
29
|
+
* byte-for-byte identical to earlier releases (SC-001). Identifiers are assumed
|
|
30
|
+
* to have been validated by the caller (see {@link createTable}).
|
|
31
|
+
*
|
|
32
|
+
* @param schemaName - Schema name (already validated).
|
|
33
|
+
* @param tableName - Table name (already validated).
|
|
34
|
+
* @param jsonType - Resolved canonical storage type for the `json` column.
|
|
35
|
+
* @returns The `CREATE TABLE` and `CREATE INDEX` statements.
|
|
36
|
+
*/
|
|
37
|
+
function buildCreateTableStatements(schemaName, tableName, jsonType) {
|
|
38
|
+
// Only the json column's type varies; every other part of the DDL is held
|
|
39
|
+
// constant so the default path is unchanged from earlier releases.
|
|
40
|
+
const createTable = `
|
|
41
|
+
CREATE TABLE [${schemaName}].[${tableName}] (
|
|
42
|
+
[id] INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
|
|
43
|
+
[resource_type] NVARCHAR(64) NOT NULL,
|
|
44
|
+
[json] ${jsonType} NOT NULL
|
|
45
|
+
)
|
|
46
|
+
`;
|
|
47
|
+
const createIndex = `
|
|
48
|
+
CREATE INDEX [IX_${tableName}_resource_type]
|
|
49
|
+
ON [${schemaName}].[${tableName}] ([resource_type])
|
|
50
|
+
`;
|
|
51
|
+
return { createTable, createIndex };
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Render an INFORMATION_SCHEMA column type for a diagnostic message.
|
|
55
|
+
*
|
|
56
|
+
* Length-bearing types are shown with their declared length, with the `-1`
|
|
57
|
+
* sentinel rendered as `MAX`; types reported without a length (such as the
|
|
58
|
+
* native `JSON` type) are shown as the bare type name.
|
|
59
|
+
*
|
|
60
|
+
* @param dataType - The INFORMATION_SCHEMA DATA_TYPE.
|
|
61
|
+
* @param characterMaximumLength - The INFORMATION_SCHEMA CHARACTER_MAXIMUM_LENGTH.
|
|
62
|
+
* @returns A readable type such as `VARCHAR(100)`, `NVARCHAR(MAX)` or `JSON`.
|
|
63
|
+
*/
|
|
64
|
+
function formatColumnType(dataType, characterMaximumLength) {
|
|
65
|
+
const baseType = dataType.trim().toUpperCase();
|
|
66
|
+
if (characterMaximumLength === null) {
|
|
67
|
+
return baseType;
|
|
68
|
+
}
|
|
69
|
+
const length = characterMaximumLength === -1 ? "MAX" : String(characterMaximumLength);
|
|
70
|
+
return `${baseType}(${length})`;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Resolve an INFORMATION_SCHEMA column description to a canonical json type.
|
|
74
|
+
*
|
|
75
|
+
* Only two column shapes can faithfully hold a serialised FHIR resource: the
|
|
76
|
+
* native type (`data_type = 'json'`) and `NVARCHAR(MAX)` (`data_type =
|
|
77
|
+
* 'nvarchar'` with `character_maximum_length = -1`). Any other shape - a bounded
|
|
78
|
+
* `NVARCHAR(64)`, a non-Unicode `VARCHAR`, `TEXT`, and so on - is rejected here
|
|
79
|
+
* rather than silently coerced to `NVARCHAR(MAX)`. Coercion would let the
|
|
80
|
+
* mismatch check pass and the loader write into a column that cannot hold the
|
|
81
|
+
* data, surfacing later as a `String or binary data would be truncated` error
|
|
82
|
+
* or, under non-Unicode `VARCHAR`, silent character corruption. Failing fast
|
|
83
|
+
* turns that late, data-dependent failure into an early, actionable
|
|
84
|
+
* configuration error (Constitution Principle IV).
|
|
85
|
+
*
|
|
86
|
+
* @param dataType - The INFORMATION_SCHEMA DATA_TYPE.
|
|
87
|
+
* @param characterMaximumLength - The INFORMATION_SCHEMA CHARACTER_MAXIMUM_LENGTH.
|
|
88
|
+
* @returns The canonical resource json data type (`JSON` or `NVARCHAR(MAX)`).
|
|
89
|
+
* @throws Error if the column is neither native `JSON` nor `NVARCHAR(MAX)`. The
|
|
90
|
+
* message names the offending type and the two acceptable types.
|
|
91
|
+
*/
|
|
92
|
+
function resolveColumnJsonDataType(dataType, characterMaximumLength) {
|
|
93
|
+
const normalised = dataType.trim().toLowerCase();
|
|
94
|
+
if (normalised === "json") {
|
|
95
|
+
return "JSON";
|
|
96
|
+
}
|
|
97
|
+
// NVARCHAR(MAX) is the only nvarchar form that can hold an arbitrarily long
|
|
98
|
+
// resource; bounded lengths would truncate, so the length is required here.
|
|
99
|
+
if (normalised === "nvarchar" && characterMaximumLength === -1) {
|
|
100
|
+
return "NVARCHAR(MAX)";
|
|
101
|
+
}
|
|
102
|
+
throw new Error(`Existing [json] column is ` +
|
|
103
|
+
`${formatColumnType(dataType, characterMaximumLength)}, which cannot ` +
|
|
104
|
+
`safely hold serialised FHIR resources. Expected NVARCHAR(MAX) or JSON. ` +
|
|
105
|
+
`Alter or drop the column before loading.`);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Build a warning for an existing table whose json column type differs from the
|
|
109
|
+
* requested type.
|
|
110
|
+
*
|
|
111
|
+
* @param schemaName - Schema name.
|
|
112
|
+
* @param tableName - Table name.
|
|
113
|
+
* @param existingType - The table's current json column type.
|
|
114
|
+
* @param requestedType - The requested json column type.
|
|
115
|
+
* @returns A warning message naming both types, or null when they match.
|
|
116
|
+
*/
|
|
117
|
+
function buildJsonTypeMismatchWarning(schemaName, tableName, existingType, requestedType) {
|
|
118
|
+
if (existingType === requestedType) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
return (`Warning: table [${schemaName}].[${tableName}] already exists with a json ` +
|
|
122
|
+
`column of type ${existingType}, but ${requestedType} was requested. The ` +
|
|
123
|
+
`existing table is left unaltered and loading continues into it.`);
|
|
124
|
+
}
|
|
18
125
|
/**
|
|
19
126
|
* Check if a table exists in the database.
|
|
20
127
|
*
|
|
@@ -34,31 +141,82 @@ async function tableExists(pool, schemaName, tableName) {
|
|
|
34
141
|
`);
|
|
35
142
|
return result.recordset[0].count > 0;
|
|
36
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* Read the effective json column type for an existing table.
|
|
146
|
+
*
|
|
147
|
+
* @param pool - Database connection pool.
|
|
148
|
+
* @param schemaName - Schema name.
|
|
149
|
+
* @param tableName - Name of the table.
|
|
150
|
+
* @returns The canonical json column type, or null if the table or its `json`
|
|
151
|
+
* column does not exist.
|
|
152
|
+
* @throws Error if the column exists but is neither native `JSON` nor
|
|
153
|
+
* `NVARCHAR(MAX)` (see {@link resolveColumnJsonDataType}).
|
|
154
|
+
*/
|
|
155
|
+
async function getExistingJsonColumnType(pool, schemaName, tableName) {
|
|
156
|
+
const result = await pool
|
|
157
|
+
.request()
|
|
158
|
+
.input("schemaName", mssql_1.default.NVarChar, schemaName)
|
|
159
|
+
.input("tableName", mssql_1.default.NVarChar, tableName).query(`
|
|
160
|
+
SELECT DATA_TYPE, CHARACTER_MAXIMUM_LENGTH
|
|
161
|
+
FROM INFORMATION_SCHEMA.COLUMNS
|
|
162
|
+
WHERE TABLE_SCHEMA = @schemaName
|
|
163
|
+
AND TABLE_NAME = @tableName
|
|
164
|
+
AND COLUMN_NAME = 'json'
|
|
165
|
+
`);
|
|
166
|
+
const row = result.recordset[0];
|
|
167
|
+
if (!row) {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
return resolveColumnJsonDataType(row.DATA_TYPE, row.CHARACTER_MAXIMUM_LENGTH);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Emit a warning if an existing table's json column type differs from the
|
|
174
|
+
* requested type. The table is never altered; this only surfaces the mismatch
|
|
175
|
+
* so it is visible rather than silently ignored (FR-008, SC-005).
|
|
176
|
+
*
|
|
177
|
+
* An existing column that is neither native `JSON` nor `NVARCHAR(MAX)` cannot
|
|
178
|
+
* hold a serialised FHIR resource, so it is rejected outright rather than
|
|
179
|
+
* warned about: the error is raised here before any rows are loaded.
|
|
180
|
+
*
|
|
181
|
+
* @param pool - Database connection pool.
|
|
182
|
+
* @param schemaName - Schema name.
|
|
183
|
+
* @param tableName - Name of the table.
|
|
184
|
+
* @param requestedType - The requested json column type.
|
|
185
|
+
* @throws Error if the existing `json` column is neither native `JSON` nor
|
|
186
|
+
* `NVARCHAR(MAX)` (see {@link resolveColumnJsonDataType}).
|
|
187
|
+
*/
|
|
188
|
+
async function warnIfJsonTypeMismatch(pool, schemaName, tableName, requestedType) {
|
|
189
|
+
const existingType = await getExistingJsonColumnType(pool, schemaName, tableName);
|
|
190
|
+
if (existingType === null) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
const warning = buildJsonTypeMismatchWarning(schemaName, tableName, existingType, requestedType);
|
|
194
|
+
if (warning !== null) {
|
|
195
|
+
// The warning is emitted regardless of quiet mode so the misconfiguration
|
|
196
|
+
// is always visible (SC-005).
|
|
197
|
+
console.warn(warning);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
37
200
|
/**
|
|
38
201
|
* Create the fhir_resources table with an index on resource_type.
|
|
39
|
-
* Table schema: id (INT IDENTITY PRIMARY KEY), resource_type (NVARCHAR(64)),
|
|
202
|
+
* Table schema: id (INT IDENTITY PRIMARY KEY), resource_type (NVARCHAR(64)),
|
|
203
|
+
* json (the configured storage type, NVARCHAR(MAX) by default).
|
|
40
204
|
*
|
|
41
205
|
* @param pool - Database connection pool.
|
|
42
206
|
* @param schemaName - Schema name.
|
|
43
207
|
* @param tableName - Name of the table to create.
|
|
208
|
+
* @param jsonType - Storage type for the `json` column (default `NVARCHAR(MAX)`).
|
|
44
209
|
*/
|
|
45
|
-
async function createTable(pool, schemaName, tableName) {
|
|
46
|
-
// Validate identifiers to prevent SQL injection
|
|
210
|
+
async function createTable(pool, schemaName, tableName, jsonType = "NVARCHAR(MAX)") {
|
|
211
|
+
// Validate identifiers to prevent SQL injection. The json type is already a
|
|
212
|
+
// canonical, allowlisted value, so it carries no injection risk.
|
|
47
213
|
(0, validation_js_1.validateSqlServerIdentifier)(schemaName, "Schema name");
|
|
48
214
|
(0, validation_js_1.validateSqlServerIdentifier)(tableName, "Table name");
|
|
215
|
+
const { createTable: createTableSql, createIndex: createIndexSql } = buildCreateTableStatements(schemaName, tableName, jsonType);
|
|
49
216
|
// Create the table.
|
|
50
|
-
await pool.request().query(
|
|
51
|
-
CREATE TABLE [${schemaName}].[${tableName}] (
|
|
52
|
-
[id] INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
|
|
53
|
-
[resource_type] NVARCHAR(64) NOT NULL,
|
|
54
|
-
[json] NVARCHAR(MAX) NOT NULL
|
|
55
|
-
)
|
|
56
|
-
`);
|
|
217
|
+
await pool.request().query(createTableSql);
|
|
57
218
|
// Create an index on resource_type for efficient filtering by resource type.
|
|
58
|
-
await pool.request().query(
|
|
59
|
-
CREATE INDEX [IX_${tableName}_resource_type]
|
|
60
|
-
ON [${schemaName}].[${tableName}] ([resource_type])
|
|
61
|
-
`);
|
|
219
|
+
await pool.request().query(createIndexSql);
|
|
62
220
|
}
|
|
63
221
|
/**
|
|
64
222
|
* Truncate a table (remove all rows).
|
|
@@ -76,20 +234,28 @@ async function truncateTable(pool, schemaName, tableName) {
|
|
|
76
234
|
/**
|
|
77
235
|
* Ensure the fhir_resources table exists, creating it if necessary.
|
|
78
236
|
*
|
|
237
|
+
* When the table already exists it is never altered; the requested `json`
|
|
238
|
+
* column type only governs creation of a new table.
|
|
239
|
+
*
|
|
79
240
|
* @param pool - Database connection pool.
|
|
80
241
|
* @param schemaName - Schema name.
|
|
81
242
|
* @param tableName - Name of the table.
|
|
82
243
|
* @param truncate - Whether to truncate the table if it exists.
|
|
244
|
+
* @param jsonType - Storage type for the `json` column when creating the table
|
|
245
|
+
* (default `NVARCHAR(MAX)`).
|
|
83
246
|
*/
|
|
84
|
-
async function ensureTable(pool, schemaName, tableName, truncate = false) {
|
|
247
|
+
async function ensureTable(pool, schemaName, tableName, truncate = false, jsonType = "NVARCHAR(MAX)") {
|
|
85
248
|
const exists = await tableExists(pool, schemaName, tableName);
|
|
86
249
|
if (exists) {
|
|
250
|
+
// The table already exists, so the requested type cannot take effect. Warn
|
|
251
|
+
// if it differs from the existing column type, then leave the table as is.
|
|
252
|
+
await warnIfJsonTypeMismatch(pool, schemaName, tableName, jsonType);
|
|
87
253
|
if (truncate) {
|
|
88
254
|
await truncateTable(pool, schemaName, tableName);
|
|
89
255
|
}
|
|
90
256
|
}
|
|
91
257
|
else {
|
|
92
|
-
await createTable(pool, schemaName, tableName);
|
|
258
|
+
await createTable(pool, schemaName, tableName, jsonType);
|
|
93
259
|
}
|
|
94
260
|
}
|
|
95
261
|
//# sourceMappingURL=tables.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tables.js","sourceRoot":"","sources":["../../src/loader/tables.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;;;
|
|
1
|
+
{"version":3,"file":"tables.js","sourceRoot":"","sources":["../../src/loader/tables.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for pure table DDL generation and existing-column-type resolution.
|
|
3
|
+
*
|
|
4
|
+
* These exercise the string-building and comparison logic without a database,
|
|
5
|
+
* so the byte-for-byte DDL contract (SC-001), the native JSON column type
|
|
6
|
+
* (FR-005) and the type-mismatch decision (FR-008) can be verified in
|
|
7
|
+
* isolation.
|
|
8
|
+
*
|
|
9
|
+
* @author John Grimes
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=tables.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tables.test.d.ts","sourceRoot":"","sources":["../../src/loader/tables.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Unit tests for pure table DDL generation and existing-column-type resolution.
|
|
4
|
+
*
|
|
5
|
+
* These exercise the string-building and comparison logic without a database,
|
|
6
|
+
* so the byte-for-byte DDL contract (SC-001), the native JSON column type
|
|
7
|
+
* (FR-005) and the type-mismatch decision (FR-008) can be verified in
|
|
8
|
+
* isolation.
|
|
9
|
+
*
|
|
10
|
+
* @author John Grimes
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
const vitest_1 = require("vitest");
|
|
14
|
+
const tables_1 = require("./tables");
|
|
15
|
+
(0, vitest_1.describe)("buildCreateTableStatements", () => {
|
|
16
|
+
(0, vitest_1.describe)("default NVARCHAR(MAX) json column", () => {
|
|
17
|
+
const statements = (0, tables_1.buildCreateTableStatements)("dbo", "fhir_resources", "NVARCHAR(MAX)");
|
|
18
|
+
(0, vitest_1.it)("types the json column as NVARCHAR(MAX) NOT NULL", () => {
|
|
19
|
+
(0, vitest_1.expect)(statements.createTable).toContain("[json] NVARCHAR(MAX) NOT NULL");
|
|
20
|
+
});
|
|
21
|
+
(0, vitest_1.it)("keeps the id column unchanged", () => {
|
|
22
|
+
(0, vitest_1.expect)(statements.createTable).toContain("[id] INT IDENTITY(1,1) NOT NULL PRIMARY KEY");
|
|
23
|
+
});
|
|
24
|
+
(0, vitest_1.it)("keeps the resource_type column unchanged", () => {
|
|
25
|
+
(0, vitest_1.expect)(statements.createTable).toContain("[resource_type] NVARCHAR(64) NOT NULL");
|
|
26
|
+
});
|
|
27
|
+
(0, vitest_1.it)("brackets the schema and table identifiers", () => {
|
|
28
|
+
(0, vitest_1.expect)(statements.createTable).toContain("[dbo].[fhir_resources]");
|
|
29
|
+
});
|
|
30
|
+
(0, vitest_1.it)("builds the resource_type index", () => {
|
|
31
|
+
(0, vitest_1.expect)(statements.createIndex).toContain("[IX_fhir_resources_resource_type]");
|
|
32
|
+
(0, vitest_1.expect)(statements.createIndex).toContain("[dbo].[fhir_resources] ([resource_type])");
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
(0, vitest_1.describe)("native JSON json column", () => {
|
|
36
|
+
const statements = (0, tables_1.buildCreateTableStatements)("dbo", "fhir_resources", "JSON");
|
|
37
|
+
(0, vitest_1.it)("types the json column as JSON NOT NULL", () => {
|
|
38
|
+
(0, vitest_1.expect)(statements.createTable).toContain("[json] JSON NOT NULL");
|
|
39
|
+
});
|
|
40
|
+
(0, vitest_1.it)("does not emit NVARCHAR(MAX) for the json column", () => {
|
|
41
|
+
(0, vitest_1.expect)(statements.createTable).not.toContain("[json] NVARCHAR(MAX)");
|
|
42
|
+
});
|
|
43
|
+
(0, vitest_1.it)("keeps the resource_type column unchanged", () => {
|
|
44
|
+
(0, vitest_1.expect)(statements.createTable).toContain("[resource_type] NVARCHAR(64) NOT NULL");
|
|
45
|
+
});
|
|
46
|
+
(0, vitest_1.it)("leaves the index statement identical to the default", () => {
|
|
47
|
+
const defaultStatements = (0, tables_1.buildCreateTableStatements)("dbo", "fhir_resources", "NVARCHAR(MAX)");
|
|
48
|
+
(0, vitest_1.expect)(statements.createIndex).toBe(defaultStatements.createIndex);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
(0, vitest_1.describe)("identifier bracketing", () => {
|
|
52
|
+
(0, vitest_1.it)("brackets custom schema and table names", () => {
|
|
53
|
+
const statements = (0, tables_1.buildCreateTableStatements)("analytics", "resources", "JSON");
|
|
54
|
+
(0, vitest_1.expect)(statements.createTable).toContain("[analytics].[resources]");
|
|
55
|
+
(0, vitest_1.expect)(statements.createIndex).toContain("[IX_resources_resource_type]");
|
|
56
|
+
(0, vitest_1.expect)(statements.createIndex).toContain("[analytics].[resources] ([resource_type])");
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
(0, vitest_1.describe)("resolveColumnJsonDataType", () => {
|
|
61
|
+
(0, vitest_1.it)("resolves nvarchar with MAX length to NVARCHAR(MAX)", () => {
|
|
62
|
+
// NVARCHAR(MAX) appears in INFORMATION_SCHEMA as data_type 'nvarchar' with a
|
|
63
|
+
// character_maximum_length of -1.
|
|
64
|
+
(0, vitest_1.expect)((0, tables_1.resolveColumnJsonDataType)("nvarchar", -1)).toBe("NVARCHAR(MAX)");
|
|
65
|
+
});
|
|
66
|
+
(0, vitest_1.it)("resolves json to JSON", () => {
|
|
67
|
+
// The native type appears as data_type 'json' with a null maximum length.
|
|
68
|
+
(0, vitest_1.expect)((0, tables_1.resolveColumnJsonDataType)("json", null)).toBe("JSON");
|
|
69
|
+
});
|
|
70
|
+
(0, vitest_1.it)("is case-insensitive on the data type name", () => {
|
|
71
|
+
(0, vitest_1.expect)((0, tables_1.resolveColumnJsonDataType)("JSON", null)).toBe("JSON");
|
|
72
|
+
(0, vitest_1.expect)((0, tables_1.resolveColumnJsonDataType)("NVARCHAR", -1)).toBe("NVARCHAR(MAX)");
|
|
73
|
+
});
|
|
74
|
+
(0, vitest_1.it)("tolerates surrounding whitespace on the data type name", () => {
|
|
75
|
+
(0, vitest_1.expect)((0, tables_1.resolveColumnJsonDataType)(" json ", null)).toBe("JSON");
|
|
76
|
+
(0, vitest_1.expect)((0, tables_1.resolveColumnJsonDataType)(" nvarchar ", -1)).toBe("NVARCHAR(MAX)");
|
|
77
|
+
});
|
|
78
|
+
// An existing column that is neither native JSON nor NVARCHAR(MAX) cannot
|
|
79
|
+
// faithfully hold a serialised FHIR resource. Such a column must be rejected
|
|
80
|
+
// at the boundary, naming the offending type, rather than silently coerced to
|
|
81
|
+
// NVARCHAR(MAX) - coercion would let the loader write into it and lose data
|
|
82
|
+
// through truncation or, under non-Unicode VARCHAR, character corruption
|
|
83
|
+
// (Constitution Principle IV).
|
|
84
|
+
(0, vitest_1.describe)("rejects column types that cannot hold a FHIR resource", () => {
|
|
85
|
+
(0, vitest_1.it)("throws for a bounded nvarchar, naming the offending type", () => {
|
|
86
|
+
(0, vitest_1.expect)(() => (0, tables_1.resolveColumnJsonDataType)("nvarchar", 64)).toThrow(/NVARCHAR\(64\)/);
|
|
87
|
+
});
|
|
88
|
+
(0, vitest_1.it)("throws for varchar, naming the offending type", () => {
|
|
89
|
+
(0, vitest_1.expect)(() => (0, tables_1.resolveColumnJsonDataType)("varchar", 100)).toThrow(/VARCHAR\(100\)/);
|
|
90
|
+
});
|
|
91
|
+
(0, vitest_1.it)("throws for a max-length varchar, which is still not Unicode-safe", () => {
|
|
92
|
+
// VARCHAR(MAX) reports a length of -1 but is non-Unicode, so it can
|
|
93
|
+
// silently corrupt multi-byte characters and must still be rejected.
|
|
94
|
+
(0, vitest_1.expect)(() => (0, tables_1.resolveColumnJsonDataType)("varchar", -1)).toThrow(/VARCHAR\(MAX\)/);
|
|
95
|
+
});
|
|
96
|
+
(0, vitest_1.it)("throws for text, naming the offending type", () => {
|
|
97
|
+
(0, vitest_1.expect)(() => (0, tables_1.resolveColumnJsonDataType)("text", 2147483647)).toThrow(/TEXT/);
|
|
98
|
+
});
|
|
99
|
+
(0, vitest_1.it)("names both acceptable types in the error message", () => {
|
|
100
|
+
let message = "";
|
|
101
|
+
try {
|
|
102
|
+
(0, tables_1.resolveColumnJsonDataType)("varchar", 100);
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
message = error.message;
|
|
106
|
+
}
|
|
107
|
+
(0, vitest_1.expect)(message).toContain("NVARCHAR(MAX)");
|
|
108
|
+
(0, vitest_1.expect)(message).toContain("JSON");
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
(0, vitest_1.describe)("buildJsonTypeMismatchWarning", () => {
|
|
113
|
+
(0, vitest_1.it)("returns null when the existing and requested types are equal", () => {
|
|
114
|
+
(0, vitest_1.expect)((0, tables_1.buildJsonTypeMismatchWarning)("dbo", "t", "NVARCHAR(MAX)", "NVARCHAR(MAX)")).toBeNull();
|
|
115
|
+
(0, vitest_1.expect)((0, tables_1.buildJsonTypeMismatchWarning)("dbo", "t", "JSON", "JSON")).toBeNull();
|
|
116
|
+
});
|
|
117
|
+
(0, vitest_1.it)("returns a warning naming both types and the table when they differ", () => {
|
|
118
|
+
const warning = (0, tables_1.buildJsonTypeMismatchWarning)("dbo", "fhir_resources", "NVARCHAR(MAX)", "JSON");
|
|
119
|
+
(0, vitest_1.expect)(warning).not.toBeNull();
|
|
120
|
+
(0, vitest_1.expect)(warning).toContain("NVARCHAR(MAX)");
|
|
121
|
+
(0, vitest_1.expect)(warning).toContain("JSON");
|
|
122
|
+
(0, vitest_1.expect)(warning).toContain("fhir_resources");
|
|
123
|
+
});
|
|
124
|
+
(0, vitest_1.it)("names both the existing and the requested type in either direction", () => {
|
|
125
|
+
const warning = (0, tables_1.buildJsonTypeMismatchWarning)("dbo", "t", "JSON", "NVARCHAR(MAX)");
|
|
126
|
+
(0, vitest_1.expect)(warning).toMatch(/JSON/);
|
|
127
|
+
(0, vitest_1.expect)(warning).toMatch(/NVARCHAR\(MAX\)/);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
//# sourceMappingURL=tables.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tables.test.js","sourceRoot":"","sources":["../../src/loader/tables.test.ts"],"names":[],"mappings":"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"}
|
package/dist/loader/types.d.ts
CHANGED
|
@@ -49,6 +49,15 @@ export interface LoaderOptions {
|
|
|
49
49
|
tableName?: string;
|
|
50
50
|
/** Schema name (default: dbo). */
|
|
51
51
|
schemaName?: string;
|
|
52
|
+
/**
|
|
53
|
+
* Storage type for the resources table `json` column. One of `NVARCHAR(MAX)`
|
|
54
|
+
* (default) or `JSON`. Matching is case-insensitive and tolerant of
|
|
55
|
+
* surrounding whitespace. `JSON` selects SQL Server 2025's native JSON type
|
|
56
|
+
* and requires SQL Server 2025 or later; when omitted the column is created as
|
|
57
|
+
* `NVARCHAR(MAX)`, exactly as in earlier releases. The value is validated
|
|
58
|
+
* against the allowlist before any database connection is opened.
|
|
59
|
+
*/
|
|
60
|
+
resourceJsonDataType?: string;
|
|
52
61
|
/** Create table if it doesn't exist. */
|
|
53
62
|
createTable?: boolean;
|
|
54
63
|
/** Truncate table before loading. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/loader/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/loader/types.ts"],"names":[],"mappings":"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"}
|
package/dist/parser.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export declare class ViewDefinitionParser {
|
|
|
8
8
|
*/
|
|
9
9
|
static parseViewDefinition(json: string | object): ViewDefinition;
|
|
10
10
|
/**
|
|
11
|
-
* Parse a test suite from the
|
|
11
|
+
* Parse a test suite from the SQL on FHIR test format.
|
|
12
12
|
*/
|
|
13
13
|
static parseTestSuite(json: string | object): TestSuite;
|
|
14
14
|
/**
|
package/dist/parser.js
CHANGED
|
@@ -16,7 +16,7 @@ class ViewDefinitionParser {
|
|
|
16
16
|
throw new Error("Invalid ViewDefinition structure.");
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
|
-
* Parse a test suite from the
|
|
19
|
+
* Parse a test suite from the SQL on FHIR test format.
|
|
20
20
|
*/
|
|
21
21
|
static parseTestSuite(json) {
|
|
22
22
|
const data = typeof json === "string" ? JSON.parse(json) : json;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compile.js","sourceRoot":"","sources":["../../../src/queryGenerator/treeWalker/compile.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;AAwCH,sDA0BC;AAhED,gEAA6E;AAO7E,kFAA4E;AAC5E,oDAA8C;AAC9C,oEAA8D;AAC9D,2CAAyC;AACzC,yCAAsE;AACtE,2CAAyC;AAEzC,MAAM,eAAe,GAAG,IAAI,wDAAyB,EAAE,CAAC;AACxD,MAAM,UAAU,GAAG,IAAI,0BAAU,EAAE,CAAC;AACpC,MAAM,kBAAkB,GAAG,IAAI,0CAAkB,EAAE,CAAC;AASpD;;;;;;;;;;;;GAYG;AACH,SAAgB,qBAAqB,CACnC,OAAuB,EACvB,OAAuB;IAEvB,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,aAAa,CAAC;IAC1D,MAAM,GAAG,GAAG,gBAAgB,CAAC,aAAa,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IAEnE,MAAM,QAAQ,GAAyB,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;IAClE,MAAM,IAAI,GAAG,IAAA,sBAAU,EAAC;QACtB,eAAe;QACf,UAAU;QACV,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,SAAS,EAAE,OAAO,CAAC,SAAS;KAC7B,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAErC,MAAM,GAAG,GAAG,IAAA,sBAAU,EAAC,QAAQ,EAAE,OAAO,EAAE;QACxC,aAAa;QACb,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,kBAAkB;QAClB,aAAa,EAAE,OAAO,CAAC,aAAa;KACrC,CAAC,CAAC;IAEH,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,qBAAqB,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;AACjE,CAAC;AAED,SAAS,gBAAgB,CACvB,aAAqB,EACrB,aAAgC;IAEhC,MAAM,KAAK,GAAiB;QAC1B,IAAI,EAAE,IAAI;QACV,OAAO,EAAE,IAAI,aAAa,QAAQ;QAClC,OAAO,EAAE,kBAAO;KACjB,CAAC;IACF,OAAO;QACL,aAAa;QACb,qEAAqE;QACrE,wEAAwE;QACxE,yCAAyC;QACzC,MAAM,EAAE,GAAG,aAAa,OAAO;QAC/B,aAAa,EAAE,CAAC,KAAK,CAAC;QACtB,eAAe,EAAE,EAAE;QACnB,
|
|
1
|
+
{"version":3,"file":"compile.js","sourceRoot":"","sources":["../../../src/queryGenerator/treeWalker/compile.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,8 +9,10 @@
|
|
|
9
9
|
* If a JSON object key contains a literal `.`, two distinct nodes could
|
|
10
10
|
* theoretically produce equal `__path` strings. FHIR JSON keys do not
|
|
11
11
|
* contain dots in practice; not a blocker.
|
|
12
|
+
*
|
|
13
|
+
* @author John Grimes
|
|
12
14
|
*/
|
|
13
|
-
import type
|
|
15
|
+
import { type CteDefinition, type PartitionKey } from "./types.js";
|
|
14
16
|
export interface BuildRepeatCteArgs {
|
|
15
17
|
cteAlias: string;
|
|
16
18
|
/** FHIRPath strings — first is the anchor path; all are recursive paths. */
|
|
@@ -47,4 +49,10 @@ export interface BuildRepeatCteArgs {
|
|
|
47
49
|
* `alias AS (...)` wrapper, which `renderRoot` adds).
|
|
48
50
|
*/
|
|
49
51
|
export declare function buildRepeatCte(args: BuildRepeatCteArgs): CteDefinition;
|
|
52
|
+
/**
|
|
53
|
+
* Renders the partition keys as a comma-separated list of bracket-quoted
|
|
54
|
+
* columns qualified by `alias` (e.g. `cte.[id], cte.[fe_0_key]`). Shared by the
|
|
55
|
+
* recursive-member projection and the repeat `%rowIndex` window's PARTITION BY.
|
|
56
|
+
*/
|
|
57
|
+
export declare function qualifiedKeyCols(alias: string, keys: PartitionKey[]): string;
|
|
50
58
|
//# sourceMappingURL=cteTemplates.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cteTemplates.d.ts","sourceRoot":"","sources":["../../../src/queryGenerator/treeWalker/cteTemplates.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"cteTemplates.d.ts","sourceRoot":"","sources":["../../../src/queryGenerator/treeWalker/cteTemplates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,YAAY,EAGlB,MAAM,YAAY,CAAC;AAOpB,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,gFAAgF;IAChF,MAAM,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,UAAU,EAAE,MAAM,CAAC;IACnB,gFAAgF;IAChF,eAAe,EAAE,MAAM,CAAC;IACxB,sEAAsE;IACtE,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,oEAAoE;IACpE,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,kBAAkB,GAAG,aAAa,CAOtE;AAqED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,MAAM,CAE5E"}
|
|
@@ -10,9 +10,13 @@
|
|
|
10
10
|
* If a JSON object key contains a literal `.`, two distinct nodes could
|
|
11
11
|
* theoretically produce equal `__path` strings. FHIR JSON keys do not
|
|
12
12
|
* contain dots in practice; not a blocker.
|
|
13
|
+
*
|
|
14
|
+
* @author John Grimes
|
|
13
15
|
*/
|
|
14
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
17
|
exports.buildRepeatCte = buildRepeatCte;
|
|
18
|
+
exports.qualifiedKeyCols = qualifiedKeyCols;
|
|
19
|
+
const types_js_1 = require("./types.js");
|
|
16
20
|
/**
|
|
17
21
|
* Builds the SQL body of the recursive CTE used by the Repeat operator.
|
|
18
22
|
*
|
|
@@ -50,7 +54,8 @@ function buildAnchorMember(args) {
|
|
|
50
54
|
const wherePart = resourcePredicate ? `\n ${resourcePredicate}` : "";
|
|
51
55
|
return ` SELECT
|
|
52
56
|
${projLines},
|
|
53
|
-
CAST(${chain.lastAlias}.[key] AS
|
|
57
|
+
CAST(${chain.lastAlias}.[key] AS ${types_js_1.SQL_NVARCHAR_MAX}) AS __path,
|
|
58
|
+
CAST(${orderSegment(chain.lastAlias)} AS ${types_js_1.SQL_NVARCHAR_MAX}) AS __order,
|
|
54
59
|
${chain.lastAlias}.value AS item_json,
|
|
55
60
|
0 AS depth
|
|
56
61
|
${fromClause}${ancestorApplies}
|
|
@@ -58,16 +63,47 @@ function buildAnchorMember(args) {
|
|
|
58
63
|
}
|
|
59
64
|
function buildRecursiveMember(args, path, index) {
|
|
60
65
|
const { cteAlias, partitionKeys } = args;
|
|
61
|
-
const head =
|
|
66
|
+
const head = qualifiedKeyCols("cte", partitionKeys);
|
|
62
67
|
const chain = buildOpenJsonChain("cte.item_json", path, `child_${index}`);
|
|
63
68
|
return ` SELECT
|
|
64
69
|
${head},
|
|
65
|
-
cte.__path + '.' + CAST(${chain.lastAlias}.[key] AS
|
|
70
|
+
cte.__path + '.' + CAST(${chain.lastAlias}.[key] AS ${types_js_1.SQL_NVARCHAR_4000}) AS __path,
|
|
71
|
+
cte.__order + '.' + ${orderSegment(chain.lastAlias)} AS __order,
|
|
66
72
|
${chain.lastAlias}.value AS item_json,
|
|
67
73
|
cte.depth + 1
|
|
68
74
|
FROM ${cteAlias} AS cte
|
|
69
75
|
${chain.applyClauses}`;
|
|
70
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Width, in characters, that each `__order` segment is zero-padded to. A level
|
|
79
|
+
* with up to 10^ORDER_SEGMENT_WIDTH elements still sorts correctly; ten digits
|
|
80
|
+
* assume no single level exceeds 10^10 elements.
|
|
81
|
+
*/
|
|
82
|
+
const ORDER_SEGMENT_WIDTH = 10;
|
|
83
|
+
/**
|
|
84
|
+
* Builds one segment of the `__order` accumulator: the element's `[key]`
|
|
85
|
+
* zero-padded to a fixed width so that lexical ordering of the `.`-joined
|
|
86
|
+
* order string is equivalent to numeric depth-first (pre-order) traversal.
|
|
87
|
+
* Without padding, lexical order would break once a level has ten or more
|
|
88
|
+
* elements (e.g. `"10" < "2"`). This is what `%rowIndex` orders by inside a
|
|
89
|
+
* `repeat`.
|
|
90
|
+
*
|
|
91
|
+
* `__order` is emitted by every repeat CTE unconditionally: the walker builds
|
|
92
|
+
* the CTE before descending into the inner subtree, so whether `%rowIndex` is
|
|
93
|
+
* actually referenced is not yet known when the column list is generated.
|
|
94
|
+
*/
|
|
95
|
+
function orderSegment(alias) {
|
|
96
|
+
const pad = "0".repeat(ORDER_SEGMENT_WIDTH);
|
|
97
|
+
return `RIGHT('${pad}' + CAST(${alias}.[key] AS NVARCHAR(${ORDER_SEGMENT_WIDTH})), ${ORDER_SEGMENT_WIDTH})`;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Renders the partition keys as a comma-separated list of bracket-quoted
|
|
101
|
+
* columns qualified by `alias` (e.g. `cte.[id], cte.[fe_0_key]`). Shared by the
|
|
102
|
+
* recursive-member projection and the repeat `%rowIndex` window's PARTITION BY.
|
|
103
|
+
*/
|
|
104
|
+
function qualifiedKeyCols(alias, keys) {
|
|
105
|
+
return keys.map((k) => `${alias}.[${k.name}]`).join(", ");
|
|
106
|
+
}
|
|
71
107
|
/**
|
|
72
108
|
* Builds the CROSS APPLY OPENJSON chain for a (possibly multi-segment) path.
|
|
73
109
|
* For "a.b.c" produces three chained APPLYs; the last alias is `finalAlias`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cteTemplates.js","sourceRoot":"","sources":["../../../src/queryGenerator/treeWalker/cteTemplates.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"cteTemplates.js","sourceRoot":"","sources":["../../../src/queryGenerator/treeWalker/cteTemplates.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Path-handling parity is delegated to PathParser (`.where()`, `.first()`,
|
|
10
10
|
* array indexing, multi-segment array flattening).
|
|
11
|
+
*
|
|
12
|
+
* @author John Grimes
|
|
11
13
|
*/
|
|
12
14
|
import type { ViewDefinitionSelect } from "../../../types.js";
|
|
13
15
|
import type { PathParser } from "../../PathParser.js";
|
|
@@ -32,8 +34,8 @@ interface ForEachDeps {
|
|
|
32
34
|
* @param node - The ForEach or ForEachOrNull select node. `node.forEach` or
|
|
33
35
|
* `node.forEachOrNull` supplies the FHIRPath expression to iterate.
|
|
34
36
|
* @param ctx - The current walker context; the inner context is derived from
|
|
35
|
-
* it by updating `source`, `partitionKeys`, `ancestorApplies`,
|
|
36
|
-
*
|
|
37
|
+
* it by updating `source`, `partitionKeys`, `ancestorApplies`, and
|
|
38
|
+
* `transpilerCtx`.
|
|
37
39
|
* @param walk - The recursive walk function used to visit the inner sub-tree.
|
|
38
40
|
* @param deps - Dependencies containing the `PathParser` used to parse and
|
|
39
41
|
* decompose the FHIRPath expression.
|