@memberjunction/core 5.12.0 → 5.14.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/generic/QueryCacheManager.d.ts +12 -2
- package/dist/generic/QueryCacheManager.d.ts.map +1 -1
- package/dist/generic/QueryCacheManager.js +17 -3
- package/dist/generic/QueryCacheManager.js.map +1 -1
- package/dist/generic/baseEntity.js +2 -2
- package/dist/generic/baseEntity.js.map +1 -1
- package/dist/generic/dataHooks.d.ts +56 -0
- package/dist/generic/dataHooks.d.ts.map +1 -0
- package/dist/generic/dataHooks.js +56 -0
- package/dist/generic/dataHooks.js.map +1 -0
- package/dist/generic/databaseProviderBase.d.ts +7 -1
- package/dist/generic/databaseProviderBase.d.ts.map +1 -1
- package/dist/generic/databaseProviderBase.js.map +1 -1
- package/dist/generic/interfaces.d.ts +10 -0
- package/dist/generic/interfaces.d.ts.map +1 -1
- package/dist/generic/interfaces.js.map +1 -1
- package/dist/generic/providerBase.d.ts +15 -18
- package/dist/generic/providerBase.d.ts.map +1 -1
- package/dist/generic/providerBase.js +19 -33
- package/dist/generic/providerBase.js.map +1 -1
- package/dist/generic/queryExecutionSpec.d.ts +68 -0
- package/dist/generic/queryExecutionSpec.d.ts.map +1 -0
- package/dist/generic/queryExecutionSpec.js +45 -0
- package/dist/generic/queryExecutionSpec.js.map +1 -0
- package/dist/generic/runQuery.d.ts +10 -0
- package/dist/generic/runQuery.d.ts.map +1 -1
- package/dist/generic/runQuery.js +11 -0
- package/dist/generic/runQuery.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/generic/hookRegistry.d.ts +0 -83
- package/dist/generic/hookRegistry.d.ts.map +0 -1
- package/dist/generic/hookRegistry.js +0 -87
- package/dist/generic/hookRegistry.js.map +0 -1
- package/dist/generic/queryCompositionEngine.d.ts +0 -165
- package/dist/generic/queryCompositionEngine.d.ts.map +0 -1
- package/dist/generic/queryCompositionEngine.js +0 -464
- package/dist/generic/queryCompositionEngine.js.map +0 -1
|
@@ -1,464 +0,0 @@
|
|
|
1
|
-
import { UUIDsEqual } from "@memberjunction/global";
|
|
2
|
-
import { Metadata } from "./metadata.js";
|
|
3
|
-
/**
|
|
4
|
-
* Maximum depth for recursive query composition resolution.
|
|
5
|
-
* Prevents runaway recursion from deeply nested compositions.
|
|
6
|
-
*/
|
|
7
|
-
const MAX_COMPOSITION_DEPTH = 10;
|
|
8
|
-
/**
|
|
9
|
-
* Regex for matching {{query:"CategoryPath/QueryName(params)"}} tokens.
|
|
10
|
-
* Captures the full content inside the quotes including optional parameters.
|
|
11
|
-
*/
|
|
12
|
-
const COMPOSITION_TOKEN_REGEX = /\{\{query:"([^"]+)"\}\}/g;
|
|
13
|
-
/**
|
|
14
|
-
* Regex for parsing the inner reference: path/QueryName(param1=value1, param2=value2)
|
|
15
|
-
* Group 1: full path including query name (everything before optional parentheses)
|
|
16
|
-
* Group 2: parameters string (inside parentheses, optional)
|
|
17
|
-
*/
|
|
18
|
-
const REFERENCE_PARSE_REGEX = /^(.+?)(?:\((.+)\))?$/;
|
|
19
|
-
/**
|
|
20
|
-
* Regex for parsing individual parameter assignments: key=value or key='literal'
|
|
21
|
-
*/
|
|
22
|
-
const PARAM_PARSE_REGEX = /^\s*(\w+)\s*=\s*(?:'([^']*)'|(\w+))\s*$/;
|
|
23
|
-
/**
|
|
24
|
-
* QueryCompositionEngine resolves {{query:"CategoryPath/QueryName(params)"}} tokens
|
|
25
|
-
* in query SQL into Common Table Expressions (CTEs). It handles:
|
|
26
|
-
*
|
|
27
|
-
* - Recursive resolution of nested compositions
|
|
28
|
-
* - Cycle detection via an in-progress set
|
|
29
|
-
* - Parameter modes: static literals and pass-through from outer query
|
|
30
|
-
* - Deduplication of identical query+params references
|
|
31
|
-
* - Platform-aware SQL resolution via QueryInfo.GetPlatformSQL()
|
|
32
|
-
*
|
|
33
|
-
* This engine runs BEFORE Nunjucks template processing, so regular {{param}}
|
|
34
|
-
* tokens are preserved for later substitution.
|
|
35
|
-
*/
|
|
36
|
-
export class QueryCompositionEngine {
|
|
37
|
-
/**
|
|
38
|
-
* Checks whether SQL contains any {{query:"..."}} composition tokens.
|
|
39
|
-
* Use this as a fast guard before calling ResolveComposition().
|
|
40
|
-
* Only considers tokens outside of SQL comments.
|
|
41
|
-
*/
|
|
42
|
-
HasCompositionTokens(sql) {
|
|
43
|
-
if (!sql)
|
|
44
|
-
return false;
|
|
45
|
-
const stripped = this.stripSQLComments(sql);
|
|
46
|
-
return stripped.includes('{{query:"');
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Parses all {{query:"..."}} tokens from SQL without resolving them.
|
|
50
|
-
* Useful for dependency extraction during the save pipeline.
|
|
51
|
-
* Only considers tokens outside of SQL comments.
|
|
52
|
-
*
|
|
53
|
-
* @param sql - The SQL text to parse
|
|
54
|
-
* @returns Array of parsed token metadata
|
|
55
|
-
*/
|
|
56
|
-
ParseCompositionTokens(sql) {
|
|
57
|
-
if (!sql)
|
|
58
|
-
return [];
|
|
59
|
-
const stripped = this.stripSQLComments(sql);
|
|
60
|
-
const tokens = [];
|
|
61
|
-
let match;
|
|
62
|
-
const regex = new RegExp(COMPOSITION_TOKEN_REGEX.source, 'g');
|
|
63
|
-
while ((match = regex.exec(stripped)) !== null) {
|
|
64
|
-
const parsed = this.parseTokenContent(match[0], match[1]);
|
|
65
|
-
if (parsed) {
|
|
66
|
-
tokens.push(parsed);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
return tokens;
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Resolves all {{query:"..."}} composition tokens in the given SQL into CTEs.
|
|
73
|
-
*
|
|
74
|
-
* @param sql - The SQL containing composition tokens
|
|
75
|
-
* @param platform - Target database platform for SQL resolution
|
|
76
|
-
* @param contextUser - User context for permission checks on referenced queries
|
|
77
|
-
* @param outerParams - Parameter values from the outer/parent query (for pass-through resolution)
|
|
78
|
-
* @returns CompositionResult with fully resolved SQL and provenance metadata
|
|
79
|
-
* @throws Error if a referenced query is not found, not composable, or creates a cycle
|
|
80
|
-
*/
|
|
81
|
-
ResolveComposition(sql, platform, contextUser, outerParams) {
|
|
82
|
-
const cteEntries = [];
|
|
83
|
-
const dependencyGraph = new Map();
|
|
84
|
-
const inProgressSet = new Set();
|
|
85
|
-
const resolvedSQL = this.resolveTokensRecursive(sql, platform, contextUser, outerParams || {}, cteEntries, dependencyGraph, inProgressSet, 0);
|
|
86
|
-
const hasCompositions = cteEntries.length > 0;
|
|
87
|
-
let finalSQL = resolvedSQL;
|
|
88
|
-
if (hasCompositions) {
|
|
89
|
-
finalSQL = this.assembleCTEs(cteEntries, resolvedSQL);
|
|
90
|
-
}
|
|
91
|
-
return {
|
|
92
|
-
ResolvedSQL: finalSQL,
|
|
93
|
-
CTEs: cteEntries.map(e => e.Info),
|
|
94
|
-
DependencyGraph: dependencyGraph,
|
|
95
|
-
HasCompositions: hasCompositions
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Recursively resolves composition tokens in SQL, building up CTE entries.
|
|
100
|
-
*/
|
|
101
|
-
resolveTokensRecursive(sql, platform, contextUser, outerParams, cteEntries, dependencyGraph, inProgressSet, depth) {
|
|
102
|
-
if (depth > MAX_COMPOSITION_DEPTH) {
|
|
103
|
-
throw new Error(`Query composition depth exceeds maximum of ${MAX_COMPOSITION_DEPTH}. ` +
|
|
104
|
-
`This likely indicates an overly deep nesting chain.`);
|
|
105
|
-
}
|
|
106
|
-
const tokens = this.ParseCompositionTokens(sql);
|
|
107
|
-
if (tokens.length === 0)
|
|
108
|
-
return sql;
|
|
109
|
-
let resolvedSQL = sql;
|
|
110
|
-
for (const token of tokens) {
|
|
111
|
-
const referencedQuery = this.lookupQuery(token);
|
|
112
|
-
this.validateQueryComposable(referencedQuery, token, contextUser);
|
|
113
|
-
// Cycle detection
|
|
114
|
-
if (inProgressSet.has(referencedQuery.ID)) {
|
|
115
|
-
const cyclePath = [...inProgressSet, referencedQuery.ID].join(' → ');
|
|
116
|
-
throw new Error(`Circular query dependency detected: ${cyclePath}. ` +
|
|
117
|
-
`Query "${referencedQuery.Name}" is already being resolved.`);
|
|
118
|
-
}
|
|
119
|
-
// Resolve parameter values
|
|
120
|
-
const resolvedParams = this.resolveParameters(token.Parameters, outerParams);
|
|
121
|
-
// Build deduplication key
|
|
122
|
-
const dedupeKey = this.buildDeduplicationKey(referencedQuery.ID, resolvedParams);
|
|
123
|
-
// Check if we already have this exact CTE
|
|
124
|
-
const existingCTE = cteEntries.find(e => e.DeduplicationKey === dedupeKey);
|
|
125
|
-
if (existingCTE) {
|
|
126
|
-
resolvedSQL = resolvedSQL.replace(token.FullToken, existingCTE.CTEName);
|
|
127
|
-
continue;
|
|
128
|
-
}
|
|
129
|
-
// Get platform-specific SQL for the referenced query
|
|
130
|
-
const refSQL = referencedQuery.GetPlatformSQL(platform);
|
|
131
|
-
// Substitute static parameter values directly into the referenced query's SQL
|
|
132
|
-
const paramSubstitutedSQL = this.substituteStaticParams(refSQL, resolvedParams);
|
|
133
|
-
// Track in-progress for cycle detection
|
|
134
|
-
inProgressSet.add(referencedQuery.ID);
|
|
135
|
-
// Recursively resolve any nested composition tokens in the referenced query
|
|
136
|
-
const nestedResolvedSQL = this.resolveTokensRecursive(paramSubstitutedSQL, platform, contextUser, resolvedParams, cteEntries, dependencyGraph, inProgressSet, depth + 1);
|
|
137
|
-
inProgressSet.delete(referencedQuery.ID);
|
|
138
|
-
// Track dependency
|
|
139
|
-
const parentDeps = dependencyGraph.get('__current__') || [];
|
|
140
|
-
if (!parentDeps.some(id => UUIDsEqual(id, referencedQuery.ID))) {
|
|
141
|
-
parentDeps.push(referencedQuery.ID);
|
|
142
|
-
dependencyGraph.set('__current__', parentDeps);
|
|
143
|
-
}
|
|
144
|
-
// Generate CTE name (platform-aware: brackets for SQL Server, double quotes for PG)
|
|
145
|
-
const cteName = this.generateCTEName(referencedQuery, resolvedParams, platform);
|
|
146
|
-
const cteEntry = {
|
|
147
|
-
DeduplicationKey: dedupeKey,
|
|
148
|
-
CTEName: cteName,
|
|
149
|
-
SQL: nestedResolvedSQL,
|
|
150
|
-
Info: {
|
|
151
|
-
QueryID: referencedQuery.ID,
|
|
152
|
-
QueryName: referencedQuery.Name,
|
|
153
|
-
CategoryPath: token.FullPath,
|
|
154
|
-
CTEName: cteName,
|
|
155
|
-
OriginalSQL: refSQL,
|
|
156
|
-
ResolvedSQL: nestedResolvedSQL,
|
|
157
|
-
Parameters: resolvedParams
|
|
158
|
-
}
|
|
159
|
-
};
|
|
160
|
-
cteEntries.push(cteEntry);
|
|
161
|
-
resolvedSQL = resolvedSQL.replace(token.FullToken, cteName);
|
|
162
|
-
}
|
|
163
|
-
return resolvedSQL;
|
|
164
|
-
}
|
|
165
|
-
/**
|
|
166
|
-
* Parses the content inside a {{query:"..."}} token.
|
|
167
|
-
*/
|
|
168
|
-
parseTokenContent(fullToken, content) {
|
|
169
|
-
const refMatch = REFERENCE_PARSE_REGEX.exec(content.trim());
|
|
170
|
-
if (!refMatch)
|
|
171
|
-
return null;
|
|
172
|
-
const fullPath = refMatch[1].trim();
|
|
173
|
-
const paramsString = refMatch[2] || '';
|
|
174
|
-
// Split path into segments; last segment is the query name
|
|
175
|
-
const segments = fullPath.split('/').map(s => s.trim()).filter(s => s.length > 0);
|
|
176
|
-
if (segments.length === 0)
|
|
177
|
-
return null;
|
|
178
|
-
const queryName = segments[segments.length - 1];
|
|
179
|
-
const categorySegments = segments.slice(0, -1);
|
|
180
|
-
// Parse parameters
|
|
181
|
-
const parameters = [];
|
|
182
|
-
if (paramsString.trim().length > 0) {
|
|
183
|
-
const paramParts = this.splitParams(paramsString);
|
|
184
|
-
for (const part of paramParts) {
|
|
185
|
-
const paramMatch = PARAM_PARSE_REGEX.exec(part);
|
|
186
|
-
if (paramMatch) {
|
|
187
|
-
parameters.push({
|
|
188
|
-
Name: paramMatch[1],
|
|
189
|
-
StaticValue: paramMatch[2] !== undefined ? paramMatch[2] : null,
|
|
190
|
-
PassThroughName: paramMatch[3] !== undefined ? paramMatch[3] : null
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
return {
|
|
196
|
-
FullToken: fullToken,
|
|
197
|
-
CategorySegments: categorySegments,
|
|
198
|
-
QueryName: queryName,
|
|
199
|
-
FullPath: fullPath,
|
|
200
|
-
Parameters: parameters
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
/**
|
|
204
|
-
* Splits parameter string by commas, respecting quoted values.
|
|
205
|
-
*/
|
|
206
|
-
splitParams(paramsString) {
|
|
207
|
-
const parts = [];
|
|
208
|
-
let current = '';
|
|
209
|
-
let inQuote = false;
|
|
210
|
-
for (const ch of paramsString) {
|
|
211
|
-
if (ch === "'" && !inQuote) {
|
|
212
|
-
inQuote = true;
|
|
213
|
-
current += ch;
|
|
214
|
-
}
|
|
215
|
-
else if (ch === "'" && inQuote) {
|
|
216
|
-
inQuote = false;
|
|
217
|
-
current += ch;
|
|
218
|
-
}
|
|
219
|
-
else if (ch === ',' && !inQuote) {
|
|
220
|
-
parts.push(current.trim());
|
|
221
|
-
current = '';
|
|
222
|
-
}
|
|
223
|
-
else {
|
|
224
|
-
current += ch;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
if (current.trim().length > 0) {
|
|
228
|
-
parts.push(current.trim());
|
|
229
|
-
}
|
|
230
|
-
return parts;
|
|
231
|
-
}
|
|
232
|
-
/**
|
|
233
|
-
* Looks up a query by category path + name in the metadata provider.
|
|
234
|
-
*/
|
|
235
|
-
lookupQuery(token) {
|
|
236
|
-
const allQueries = Metadata.Provider.Queries;
|
|
237
|
-
const queryName = token.QueryName.toLowerCase();
|
|
238
|
-
// If category segments provided, build expected category path
|
|
239
|
-
if (token.CategorySegments.length > 0) {
|
|
240
|
-
const expectedPath = `/${token.CategorySegments.join('/')}/`;
|
|
241
|
-
const match = allQueries.find(q => q.Name.toLowerCase() === queryName &&
|
|
242
|
-
q.CategoryPath.toLowerCase() === expectedPath.toLowerCase());
|
|
243
|
-
if (match)
|
|
244
|
-
return match;
|
|
245
|
-
}
|
|
246
|
-
// Fall back to name-only match
|
|
247
|
-
const matches = allQueries.filter(q => q.Name.toLowerCase() === queryName);
|
|
248
|
-
if (matches.length === 0) {
|
|
249
|
-
throw new Error(`Referenced query not found: "${token.FullPath}". ` +
|
|
250
|
-
`Ensure the query exists and the category path is correct.`);
|
|
251
|
-
}
|
|
252
|
-
if (matches.length > 1) {
|
|
253
|
-
throw new Error(`Ambiguous query reference: "${token.FullPath}" matches ${matches.length} queries. ` +
|
|
254
|
-
`Use the full category path to disambiguate.`);
|
|
255
|
-
}
|
|
256
|
-
return matches[0];
|
|
257
|
-
}
|
|
258
|
-
/**
|
|
259
|
-
* Validates that a referenced query is eligible for composition.
|
|
260
|
-
*/
|
|
261
|
-
validateQueryComposable(query, token, contextUser) {
|
|
262
|
-
if (!query.Reusable) {
|
|
263
|
-
throw new Error(`Query "${token.FullPath}" (${query.Name}) is not marked as Reusable. ` +
|
|
264
|
-
`Set Reusable=true on the query to allow composition.`);
|
|
265
|
-
}
|
|
266
|
-
if (!query.IsApproved) {
|
|
267
|
-
throw new Error(`Query "${token.FullPath}" (${query.Name}) is not Approved (status: ${query.Status}). ` +
|
|
268
|
-
`Only Approved queries can be composed.`);
|
|
269
|
-
}
|
|
270
|
-
if (!query.UserCanRun(contextUser)) {
|
|
271
|
-
throw new Error(`User does not have permission to run referenced query "${token.FullPath}" (${query.Name}).`);
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
/**
|
|
275
|
-
* Resolves parameter values for a composition reference.
|
|
276
|
-
* Static values are used directly; pass-through values are looked up from outer params.
|
|
277
|
-
*/
|
|
278
|
-
resolveParameters(params, outerParams) {
|
|
279
|
-
const resolved = {};
|
|
280
|
-
for (const param of params) {
|
|
281
|
-
if (param.StaticValue !== null) {
|
|
282
|
-
resolved[param.Name] = param.StaticValue;
|
|
283
|
-
}
|
|
284
|
-
else if (param.PassThroughName !== null) {
|
|
285
|
-
// Pass-through: the value comes from the outer query's parameters
|
|
286
|
-
// At composition time, we create a Nunjucks placeholder so that
|
|
287
|
-
// the downstream Nunjucks processor can substitute the actual value
|
|
288
|
-
resolved[param.Name] = `{{${param.PassThroughName}}}`;
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
return resolved;
|
|
292
|
-
}
|
|
293
|
-
/**
|
|
294
|
-
* Substitutes resolved parameter values into a query's SQL.
|
|
295
|
-
* - Static values: replaces {{paramName}} with 'value'
|
|
296
|
-
* - Pass-through values: renames {{paramName}} to {{outerParamName}} so
|
|
297
|
-
* the downstream Nunjucks processor can resolve it from the outer query's parameters.
|
|
298
|
-
*/
|
|
299
|
-
substituteStaticParams(sql, params) {
|
|
300
|
-
let result = sql;
|
|
301
|
-
for (const [name, value] of Object.entries(params)) {
|
|
302
|
-
const paramRegex = new RegExp(`\\{\\{\\s*${name}\\s*\\}\\}`, 'g');
|
|
303
|
-
if (value.startsWith('{{') && value.endsWith('}}')) {
|
|
304
|
-
// Pass-through: rename the inner param token to the outer param name
|
|
305
|
-
// e.g., {{region}} → {{userRegion}} when the mapping is region=userRegion
|
|
306
|
-
result = result.replace(paramRegex, value);
|
|
307
|
-
}
|
|
308
|
-
else if (/^-?\d+(\.\d+)?$/.test(value)) {
|
|
309
|
-
// Numeric value: substitute as bare literal (no quotes)
|
|
310
|
-
// so expressions like DATEADD(DAY, -{{lookbackDays}}, ...) work correctly
|
|
311
|
-
result = result.replace(paramRegex, value);
|
|
312
|
-
}
|
|
313
|
-
else {
|
|
314
|
-
// String value: substitute as a quoted literal
|
|
315
|
-
result = result.replace(paramRegex, `'${value.replace(/'/g, "''")}'`);
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
return result;
|
|
319
|
-
}
|
|
320
|
-
/**
|
|
321
|
-
* Builds a deduplication key for a CTE based on query ID and sorted parameter values.
|
|
322
|
-
*/
|
|
323
|
-
buildDeduplicationKey(queryID, params) {
|
|
324
|
-
const sortedParams = Object.entries(params)
|
|
325
|
-
.sort(([a], [b]) => a.localeCompare(b))
|
|
326
|
-
.map(([k, v]) => `${k}=${v}`)
|
|
327
|
-
.join('&');
|
|
328
|
-
return `${queryID}|${sortedParams}`;
|
|
329
|
-
}
|
|
330
|
-
/**
|
|
331
|
-
* Generates a SQL-safe CTE name from the query name + short hash for uniqueness.
|
|
332
|
-
*/
|
|
333
|
-
generateCTEName(query, params, platform) {
|
|
334
|
-
// Sanitize query name: remove non-alphanumeric chars, replace spaces with underscores
|
|
335
|
-
const sanitized = query.Name
|
|
336
|
-
.replace(/[^a-zA-Z0-9_ ]/g, '')
|
|
337
|
-
.replace(/\s+/g, '_')
|
|
338
|
-
.substring(0, 50);
|
|
339
|
-
// Create a short hash suffix from query ID + params for uniqueness
|
|
340
|
-
const hashInput = query.ID + JSON.stringify(params);
|
|
341
|
-
const hash = this.simpleHash(hashInput);
|
|
342
|
-
const identifier = `__cte_${sanitized}_${hash}`;
|
|
343
|
-
return platform === 'postgresql' ? `"${identifier}"` : `[${identifier}]`;
|
|
344
|
-
}
|
|
345
|
-
/**
|
|
346
|
-
* Simple string hash for generating short, deterministic suffixes.
|
|
347
|
-
*/
|
|
348
|
-
simpleHash(input) {
|
|
349
|
-
let hash = 0;
|
|
350
|
-
for (let i = 0; i < input.length; i++) {
|
|
351
|
-
const char = input.charCodeAt(i);
|
|
352
|
-
hash = ((hash << 5) - hash) + char;
|
|
353
|
-
hash = hash & hash; // Convert to 32bit integer
|
|
354
|
-
}
|
|
355
|
-
return Math.abs(hash).toString(36).substring(0, 6);
|
|
356
|
-
}
|
|
357
|
-
/**
|
|
358
|
-
* Assembles CTE entries into a WITH clause prepended to the main SQL.
|
|
359
|
-
*/
|
|
360
|
-
assembleCTEs(cteEntries, mainSQL) {
|
|
361
|
-
if (cteEntries.length === 0)
|
|
362
|
-
return mainSQL;
|
|
363
|
-
// Check if the main SQL already starts with a WITH clause
|
|
364
|
-
const trimmedMain = mainSQL.trimStart();
|
|
365
|
-
const startsWithWith = /^WITH\s/i.test(trimmedMain);
|
|
366
|
-
const cteDefinitions = cteEntries.map(entry => `${entry.CTEName} AS (\n${this.stripTrailingOrderBy(entry.SQL)}\n)`);
|
|
367
|
-
if (startsWithWith) {
|
|
368
|
-
// Main SQL has its own WITH — merge by removing the leading WITH
|
|
369
|
-
// and prepending our CTEs before it
|
|
370
|
-
const mainWithoutWith = trimmedMain.replace(/^WITH\s+/i, '');
|
|
371
|
-
return `WITH ${cteDefinitions.join(',\n')},\n${mainWithoutWith}`;
|
|
372
|
-
}
|
|
373
|
-
return `WITH ${cteDefinitions.join(',\n')}\n${mainSQL}`;
|
|
374
|
-
}
|
|
375
|
-
/**
|
|
376
|
-
* Strips a trailing ORDER BY clause from SQL that will be wrapped in a CTE.
|
|
377
|
-
* SQL Server (and the SQL standard) disallows ORDER BY inside CTEs unless
|
|
378
|
-
* TOP, OFFSET, or FOR XML is also present. Since reusable queries often
|
|
379
|
-
* include ORDER BY for standalone use, we must remove it when composing.
|
|
380
|
-
*/
|
|
381
|
-
stripTrailingOrderBy(sql) {
|
|
382
|
-
// Match a trailing ORDER BY clause (possibly with ASC/DESC, multiple columns)
|
|
383
|
-
// that is NOT accompanied by TOP, OFFSET, or FOR XML.
|
|
384
|
-
// We only strip if there's no TOP in the SELECT and no OFFSET after ORDER BY.
|
|
385
|
-
const trimmed = sql.trimEnd();
|
|
386
|
-
// Check if the query uses TOP or OFFSET — if so, ORDER BY is valid in CTEs
|
|
387
|
-
if (/\bTOP\s+\d/i.test(trimmed) || /\bOFFSET\s+\d/i.test(trimmed) || /\bFOR\s+XML\b/i.test(trimmed)) {
|
|
388
|
-
return sql;
|
|
389
|
-
}
|
|
390
|
-
// Strip the trailing ORDER BY clause
|
|
391
|
-
// Match ORDER BY followed by column references, ASC/DESC, NULLS FIRST/LAST, commas
|
|
392
|
-
const orderByMatch = trimmed.match(/\bORDER\s+BY\s+[\s\S]+$/i);
|
|
393
|
-
if (!orderByMatch)
|
|
394
|
-
return sql;
|
|
395
|
-
// Make sure we're not stripping ORDER BY from a subquery — check that this ORDER BY
|
|
396
|
-
// is at the outermost level by counting unmatched parentheses before it
|
|
397
|
-
const beforeOrderBy = trimmed.substring(0, orderByMatch.index);
|
|
398
|
-
let parenDepth = 0;
|
|
399
|
-
for (const ch of beforeOrderBy) {
|
|
400
|
-
if (ch === '(')
|
|
401
|
-
parenDepth++;
|
|
402
|
-
else if (ch === ')')
|
|
403
|
-
parenDepth--;
|
|
404
|
-
}
|
|
405
|
-
// Only strip if we're at the top level (not inside a subquery)
|
|
406
|
-
if (parenDepth !== 0)
|
|
407
|
-
return sql;
|
|
408
|
-
return trimmed.substring(0, orderByMatch.index).trimEnd();
|
|
409
|
-
}
|
|
410
|
-
/**
|
|
411
|
-
* Strips SQL comments from the input string so that composition tokens
|
|
412
|
-
* inside comments are not treated as real references.
|
|
413
|
-
* Handles both single-line (-- ...) and multi-line block comments.
|
|
414
|
-
* Preserves string literals (single-quoted) to avoid stripping inside them.
|
|
415
|
-
*/
|
|
416
|
-
stripSQLComments(sql) {
|
|
417
|
-
let result = '';
|
|
418
|
-
let i = 0;
|
|
419
|
-
while (i < sql.length) {
|
|
420
|
-
// Single-quoted string literal — preserve as-is
|
|
421
|
-
if (sql[i] === "'") {
|
|
422
|
-
result += sql[i++];
|
|
423
|
-
while (i < sql.length) {
|
|
424
|
-
if (sql[i] === "'" && i + 1 < sql.length && sql[i + 1] === "'") {
|
|
425
|
-
// Escaped quote inside string
|
|
426
|
-
result += "''";
|
|
427
|
-
i += 2;
|
|
428
|
-
}
|
|
429
|
-
else if (sql[i] === "'") {
|
|
430
|
-
result += sql[i++];
|
|
431
|
-
break;
|
|
432
|
-
}
|
|
433
|
-
else {
|
|
434
|
-
result += sql[i++];
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
// Single-line comment: -- to end of line
|
|
439
|
-
else if (sql[i] === '-' && i + 1 < sql.length && sql[i + 1] === '-') {
|
|
440
|
-
// Skip to end of line
|
|
441
|
-
while (i < sql.length && sql[i] !== '\n') {
|
|
442
|
-
i++;
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
// Block comment: /* ... */
|
|
446
|
-
else if (sql[i] === '/' && i + 1 < sql.length && sql[i + 1] === '*') {
|
|
447
|
-
i += 2; // skip /*
|
|
448
|
-
while (i < sql.length) {
|
|
449
|
-
if (sql[i] === '*' && i + 1 < sql.length && sql[i + 1] === '/') {
|
|
450
|
-
i += 2; // skip */
|
|
451
|
-
break;
|
|
452
|
-
}
|
|
453
|
-
i++;
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
// Normal character
|
|
457
|
-
else {
|
|
458
|
-
result += sql[i++];
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
return result;
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
//# sourceMappingURL=queryCompositionEngine.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"queryCompositionEngine.js","sourceRoot":"","sources":["../../src/generic/queryCompositionEngine.ts"],"names":[],"mappings":"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"}
|