@memberjunction/generic-database-provider 5.14.0 → 5.16.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.
@@ -0,0 +1,87 @@
1
+ import { DatabasePlatform } from '@memberjunction/core';
2
+ /**
3
+ * Result of wrapping SQL with paging directives.
4
+ */
5
+ export interface PagingWrappedSQL {
6
+ /** SQL that returns the paged data rows */
7
+ DataSQL: string;
8
+ /** SQL that returns the total row count (without paging) */
9
+ CountSQL: string;
10
+ /** The computed offset (same as startRow input) */
11
+ Offset: number;
12
+ /** The page size (same as maxRows input) */
13
+ PageSize: number;
14
+ }
15
+ /**
16
+ * Handles server-side pagination for query SQL by wrapping resolved SQL in CTEs
17
+ * and applying platform-specific OFFSET/FETCH or LIMIT/OFFSET clauses.
18
+ *
19
+ * Uses a two-tier strategy:
20
+ * 1. **AST path** — parse SQL via node-sql-parser, extract ORDER BY and TOP from
21
+ * the AST, reconstruct clean SQL via sqlify. Handles CTEs, subqueries, UNION,
22
+ * and complex expressions correctly without string heuristics.
23
+ * 2. **Regex fallback** — for SQL that node-sql-parser cannot handle (e.g.,
24
+ * STRING_AGG WITHIN GROUP, certain FOR XML patterns), falls back to the
25
+ * original string-based approach with paren-depth tracking.
26
+ */
27
+ export declare class QueryPagingEngine {
28
+ /**
29
+ * Wraps resolved SQL with CTE-based paging for server-side pagination.
30
+ *
31
+ * @param resolvedSQL The fully-resolved SQL (after composition + Nunjucks)
32
+ * @param startRow 0-based row offset
33
+ * @param maxRows Maximum rows to return (page size)
34
+ * @param platform Target database platform
35
+ * @returns DataSQL for paged results and CountSQL for total row count
36
+ */
37
+ static WrapWithPaging(resolvedSQL: string, startRow: number, maxRows: number, platform: DatabasePlatform): PagingWrappedSQL;
38
+ /**
39
+ * Determines whether the given params indicate paging should be applied.
40
+ */
41
+ static ShouldPage(startRow: number | undefined, maxRows: number | undefined): boolean;
42
+ private static wrapViaAST;
43
+ /**
44
+ * Remaps ORDER BY terms to projected column names using AST comparison.
45
+ *
46
+ * For each ORDER BY expression, checks the SELECT column list for a match:
47
+ * 1. If the SELECT column has an AS alias, use the alias
48
+ * 2. If the SELECT column is a bare column_ref, use the column name
49
+ * 3. If the ORDER BY is a simple column_ref, strip the table qualifier
50
+ *
51
+ * This is more robust than string-based remapping because it works directly
52
+ * with the parsed AST structure — no regex needed for quoting or prefix stripping.
53
+ */
54
+ private static remapOrderByViaAST;
55
+ /**
56
+ * Resolves an ORDER BY expression to its projected column name by matching
57
+ * against the SELECT column list at the AST level.
58
+ */
59
+ private static resolveOrderByExpr;
60
+ /**
61
+ * Compares two AST expression nodes for structural equality.
62
+ * Handles column_ref (with table qualifier matching), aggregates, and functions.
63
+ */
64
+ private static astExprsMatch;
65
+ private static extractCTEsFromAST;
66
+ private static findOrderByStatement;
67
+ private static wrapViaRegex;
68
+ static splitCTEAndSelect(sql: string): {
69
+ ctePrefix: string;
70
+ mainSelect: string;
71
+ };
72
+ static extractOrderBy(sql: string): {
73
+ sqlWithoutOrder: string;
74
+ orderByClause: string | null;
75
+ };
76
+ static stripTopClause(sql: string): {
77
+ sql: string;
78
+ topRemoved: boolean;
79
+ };
80
+ private static quoteIdentifier;
81
+ private static buildPagingClause;
82
+ static remapOrderByToProjectedNames(orderByClause: string, selectSQL: string): string;
83
+ private static buildSelectAliasMap;
84
+ private static splitAtTopLevelCommas;
85
+ private static defaultOrderBy;
86
+ }
87
+ //# sourceMappingURL=queryPagingEngine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queryPagingEngine.d.ts","sourceRoot":"","sources":["../src/queryPagingEngine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAGxD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC7B,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,iBAAiB;IAE1B;;;;;;;;OAQG;IACH,MAAM,CAAC,cAAc,CACjB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,gBAAgB,GAC3B,gBAAgB;IAYnB;;OAEG;IACH,MAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO;IAQrF,OAAO,CAAC,MAAM,CAAC,UAAU;IAuDzB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,MAAM,CAAC,kBAAkB;IA6BjC;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,kBAAkB;IA2BjC;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,aAAa;IA2B5B,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAcjC,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAUnC,OAAO,CAAC,MAAM,CAAC,YAAY;IA8B3B,MAAM,CAAC,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE;IAgDhF,MAAM,CAAC,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,eAAe,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE;IA4B7F,MAAM,CAAC,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAE;IAWxE,OAAO,CAAC,MAAM,CAAC,eAAe;IAI9B,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAMhC,MAAM,CAAC,4BAA4B,CAAC,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IAoCrF,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAsClC,OAAO,CAAC,MAAM,CAAC,qBAAqB;IAcpC,OAAO,CAAC,MAAM,CAAC,cAAc;CAGhC"}
@@ -0,0 +1,399 @@
1
+ import { SQLParser } from '@memberjunction/sql-parser';
2
+ /**
3
+ * Handles server-side pagination for query SQL by wrapping resolved SQL in CTEs
4
+ * and applying platform-specific OFFSET/FETCH or LIMIT/OFFSET clauses.
5
+ *
6
+ * Uses a two-tier strategy:
7
+ * 1. **AST path** — parse SQL via node-sql-parser, extract ORDER BY and TOP from
8
+ * the AST, reconstruct clean SQL via sqlify. Handles CTEs, subqueries, UNION,
9
+ * and complex expressions correctly without string heuristics.
10
+ * 2. **Regex fallback** — for SQL that node-sql-parser cannot handle (e.g.,
11
+ * STRING_AGG WITHIN GROUP, certain FOR XML patterns), falls back to the
12
+ * original string-based approach with paren-depth tracking.
13
+ */
14
+ export class QueryPagingEngine {
15
+ /**
16
+ * Wraps resolved SQL with CTE-based paging for server-side pagination.
17
+ *
18
+ * @param resolvedSQL The fully-resolved SQL (after composition + Nunjucks)
19
+ * @param startRow 0-based row offset
20
+ * @param maxRows Maximum rows to return (page size)
21
+ * @param platform Target database platform
22
+ * @returns DataSQL for paged results and CountSQL for total row count
23
+ */
24
+ static WrapWithPaging(resolvedSQL, startRow, maxRows, platform) {
25
+ // Strip trailing semicolons — they break CTE wrapping and OFFSET/FETCH clauses
26
+ const cleanedSQL = resolvedSQL.trimEnd().replace(/;\s*$/, '');
27
+ // Tier 1: AST-based paging (robust, handles CTEs/subqueries/UNION correctly)
28
+ const astResult = QueryPagingEngine.wrapViaAST(cleanedSQL, startRow, maxRows, platform);
29
+ if (astResult)
30
+ return astResult;
31
+ // Tier 2: Regex-based fallback for SQL the parser can't handle
32
+ return QueryPagingEngine.wrapViaRegex(cleanedSQL, startRow, maxRows, platform);
33
+ }
34
+ /**
35
+ * Determines whether the given params indicate paging should be applied.
36
+ */
37
+ static ShouldPage(startRow, maxRows) {
38
+ return maxRows != null && maxRows > 0 && startRow != null && startRow >= 0;
39
+ }
40
+ // ════════════════════════════════════════════════════════════════════
41
+ // AST-based paging (primary path)
42
+ // ════════════════════════════════════════════════════════════════════
43
+ static wrapViaAST(sql, startRow, maxRows, platform) {
44
+ const parserDialect = platform === 'postgresql' ? 'PostgresQL' : 'TransactSQL';
45
+ try {
46
+ const ast = SQLParser.ParseSQL(sql, parserDialect);
47
+ if (!ast)
48
+ return null;
49
+ const stmt = (Array.isArray(ast) ? ast[0] : ast);
50
+ if (!stmt)
51
+ return null;
52
+ // Extract CTEs via AST
53
+ const cteDefs = QueryPagingEngine.extractCTEsFromAST(stmt, parserDialect, platform);
54
+ // Extract ORDER BY and remap to projected column names via AST.
55
+ // The outer query is SELECT * FROM [__paged], so table aliases from the
56
+ // inner query don't exist. We match ORDER BY expressions against SELECT
57
+ // columns to find the projected name (AS alias or bare column name).
58
+ const orderByStmt = QueryPagingEngine.findOrderByStatement(stmt);
59
+ const selectColumns = (stmt.columns && Array.isArray(stmt.columns))
60
+ ? stmt.columns
61
+ : [];
62
+ const remappedOrderBy = QueryPagingEngine.remapOrderByViaAST(orderByStmt, selectColumns, parserDialect);
63
+ if (orderByStmt?.orderby) {
64
+ orderByStmt.orderby = null;
65
+ }
66
+ // Strip TOP
67
+ if (stmt.top)
68
+ stmt.top = null;
69
+ // Get main SELECT without CTEs or ORDER BY
70
+ stmt.with = null;
71
+ const mainSelectSQL = SQLParser.SqlifyAST(stmt, parserDialect);
72
+ // Assemble paged query (skip string-based remapping — already done via AST)
73
+ const pagingCTEName = QueryPagingEngine.quoteIdentifier('__paged', platform);
74
+ const allCTEs = [...cteDefs, `${pagingCTEName} AS (\n${mainSelectSQL}\n)`];
75
+ const cteChain = `WITH ${allCTEs.join(',\n')}`;
76
+ const outerOrderBy = remappedOrderBy || QueryPagingEngine.defaultOrderBy(platform);
77
+ const pagingClause = QueryPagingEngine.buildPagingClause(startRow, maxRows, platform);
78
+ const dataSQL = `${cteChain}\nSELECT * FROM ${pagingCTEName}\nORDER BY ${outerOrderBy}\n${pagingClause}`;
79
+ const countSQL = `${cteChain}\nSELECT COUNT(*) AS TotalRowCount FROM ${pagingCTEName}`;
80
+ return { DataSQL: dataSQL, CountSQL: countSQL, Offset: startRow, PageSize: maxRows };
81
+ }
82
+ catch {
83
+ return null;
84
+ }
85
+ }
86
+ /**
87
+ * Remaps ORDER BY terms to projected column names using AST comparison.
88
+ *
89
+ * For each ORDER BY expression, checks the SELECT column list for a match:
90
+ * 1. If the SELECT column has an AS alias, use the alias
91
+ * 2. If the SELECT column is a bare column_ref, use the column name
92
+ * 3. If the ORDER BY is a simple column_ref, strip the table qualifier
93
+ *
94
+ * This is more robust than string-based remapping because it works directly
95
+ * with the parsed AST structure — no regex needed for quoting or prefix stripping.
96
+ */
97
+ static remapOrderByViaAST(orderByStmt, selectColumns, parserDialect) {
98
+ if (!orderByStmt?.orderby || !Array.isArray(orderByStmt.orderby))
99
+ return null;
100
+ const orderByTerms = orderByStmt.orderby;
101
+ const remappedTerms = orderByTerms.map(orderTerm => {
102
+ const direction = orderTerm.type === 'DESC' ? ' DESC' : '';
103
+ const projectedName = QueryPagingEngine.resolveOrderByExpr(orderTerm.expr, selectColumns);
104
+ if (projectedName) {
105
+ return projectedName + direction;
106
+ }
107
+ // Fallback: if it's a simple column_ref, strip the table qualifier
108
+ if (orderTerm.expr.type === 'column_ref') {
109
+ return orderTerm.expr.column + direction;
110
+ }
111
+ // Last resort: convert via ExprToSQL (will have correct quoting at least)
112
+ return SQLParser.ExprToSQL(orderTerm.expr, parserDialect) + direction;
113
+ });
114
+ return remappedTerms.join(', ');
115
+ }
116
+ /**
117
+ * Resolves an ORDER BY expression to its projected column name by matching
118
+ * against the SELECT column list at the AST level.
119
+ */
120
+ static resolveOrderByExpr(orderExpr, selectColumns) {
121
+ for (const col of selectColumns) {
122
+ if (!col.expr)
123
+ continue;
124
+ // Check if the ORDER BY expression matches this SELECT column's expression
125
+ if (QueryPagingEngine.astExprsMatch(orderExpr, col.expr)) {
126
+ // If the column has an AS alias, use it
127
+ if (col.as)
128
+ return col.as;
129
+ // If it's a bare column_ref, use the column name
130
+ if (col.expr.type === 'column_ref')
131
+ return col.expr.column;
132
+ }
133
+ // Also check: ORDER BY references a column by name that matches an AS alias
134
+ if (orderExpr.type === 'column_ref' && col.as) {
135
+ const orderCol = orderExpr.column;
136
+ if (orderCol.toLowerCase() === col.as.toLowerCase()) {
137
+ return col.as;
138
+ }
139
+ }
140
+ }
141
+ return null;
142
+ }
143
+ /**
144
+ * Compares two AST expression nodes for structural equality.
145
+ * Handles column_ref (with table qualifier matching), aggregates, and functions.
146
+ */
147
+ static astExprsMatch(a, b) {
148
+ if (!a || !b)
149
+ return false;
150
+ if (a.type !== b.type)
151
+ return false;
152
+ // column_ref: match by column name (ignore table qualifier — the whole point
153
+ // of remapping is that table qualifiers don't exist in the outer query)
154
+ if (a.type === 'column_ref') {
155
+ return a.column?.toLowerCase() === b.column?.toLowerCase() &&
156
+ a.table?.toLowerCase() === b.table?.toLowerCase();
157
+ }
158
+ // For aggregate functions (COUNT, SUM, etc.), compare name and args
159
+ if (a.type === 'aggr_func') {
160
+ if (a.name !== b.name)
161
+ return false;
162
+ return JSON.stringify(a.args) === JSON.stringify(b.args);
163
+ }
164
+ // For regular functions, compare name and args
165
+ if (a.type === 'function') {
166
+ return JSON.stringify(a.name) === JSON.stringify(b.name) &&
167
+ JSON.stringify(a.args) === JSON.stringify(b.args);
168
+ }
169
+ // Generic fallback: JSON deep equality (works for simple expressions)
170
+ return JSON.stringify(a) === JSON.stringify(b);
171
+ }
172
+ static extractCTEsFromAST(stmt, parserDialect, platform) {
173
+ const ctes = stmt.with || [];
174
+ return ctes.map(cte => {
175
+ const cteRecord = cte;
176
+ const quotedName = QueryPagingEngine.quoteIdentifier(cteRecord.name.value, platform);
177
+ const bodySQL = SQLParser.SqlifyAST(cteRecord.stmt.ast, parserDialect);
178
+ return `${quotedName} AS (\n${bodySQL}\n)`;
179
+ });
180
+ }
181
+ static findOrderByStatement(stmt) {
182
+ if (stmt.orderby)
183
+ return stmt;
184
+ if (stmt._next)
185
+ return QueryPagingEngine.findOrderByStatement(stmt._next);
186
+ return null;
187
+ }
188
+ // ════════════════════════════════════════════════════════════════════
189
+ // Regex-based paging (fallback)
190
+ // ════════════════════════════════════════════════════════════════════
191
+ static wrapViaRegex(sql, startRow, maxRows, platform) {
192
+ const { ctePrefix, mainSelect } = QueryPagingEngine.splitCTEAndSelect(sql);
193
+ const { sqlWithoutOrder, orderByClause } = QueryPagingEngine.extractOrderBy(mainSelect);
194
+ const { sql: cleanSelect } = QueryPagingEngine.stripTopClause(sqlWithoutOrder);
195
+ const pagingCTEName = QueryPagingEngine.quoteIdentifier('__paged', platform);
196
+ const existingCTEs = ctePrefix ? ctePrefix + ',\n' : 'WITH ';
197
+ const cteChain = `${existingCTEs}${pagingCTEName} AS (\n${cleanSelect}\n)`;
198
+ const rawOrderBy = orderByClause || QueryPagingEngine.defaultOrderBy(platform);
199
+ const outerOrderBy = orderByClause
200
+ ? QueryPagingEngine.remapOrderByToProjectedNames(rawOrderBy, cleanSelect)
201
+ : rawOrderBy;
202
+ const pagingClause = QueryPagingEngine.buildPagingClause(startRow, maxRows, platform);
203
+ const dataSQL = `${cteChain}\nSELECT * FROM ${pagingCTEName}\nORDER BY ${outerOrderBy}\n${pagingClause}`;
204
+ const countSQL = `${cteChain}\nSELECT COUNT(*) AS TotalRowCount FROM ${pagingCTEName}`;
205
+ return { DataSQL: dataSQL, CountSQL: countSQL, Offset: startRow, PageSize: maxRows };
206
+ }
207
+ // ════════════════════════════════════════════════════════════════════
208
+ // Regex helpers (used by fallback path)
209
+ // ════════════════════════════════════════════════════════════════════
210
+ static splitCTEAndSelect(sql) {
211
+ const trimmed = sql.trim();
212
+ if (!/^WITH\s/i.test(trimmed)) {
213
+ return { ctePrefix: '', mainSelect: trimmed };
214
+ }
215
+ let depth = 0;
216
+ let lastCTEEnd = -1;
217
+ let i = 0;
218
+ const withMatch = trimmed.match(/^WITH\s+/i);
219
+ if (!withMatch)
220
+ return { ctePrefix: '', mainSelect: trimmed };
221
+ i = withMatch[0].length;
222
+ while (i < trimmed.length) {
223
+ const ch = trimmed[i];
224
+ if (ch === '(') {
225
+ depth++;
226
+ }
227
+ else if (ch === ')') {
228
+ depth--;
229
+ if (depth === 0) {
230
+ lastCTEEnd = i;
231
+ const rest = trimmed.substring(i + 1).trimStart();
232
+ if (rest.startsWith(',')) {
233
+ i = trimmed.indexOf(',', i + 1) + 1;
234
+ continue;
235
+ }
236
+ break;
237
+ }
238
+ }
239
+ else if (ch === "'" && depth > 0) {
240
+ i++;
241
+ while (i < trimmed.length && trimmed[i] !== "'") {
242
+ if (trimmed[i] === "'" && i + 1 < trimmed.length && trimmed[i + 1] === "'") {
243
+ i += 2;
244
+ }
245
+ else {
246
+ i++;
247
+ }
248
+ }
249
+ }
250
+ i++;
251
+ }
252
+ if (lastCTEEnd === -1)
253
+ return { ctePrefix: '', mainSelect: trimmed };
254
+ return {
255
+ ctePrefix: trimmed.substring(0, lastCTEEnd + 1).trim(),
256
+ mainSelect: trimmed.substring(lastCTEEnd + 1).trim(),
257
+ };
258
+ }
259
+ static extractOrderBy(sql) {
260
+ const upperSQL = sql.toUpperCase();
261
+ let depth = 0;
262
+ let lastOrderByPos = -1;
263
+ for (let i = 0; i < sql.length; i++) {
264
+ const ch = sql[i];
265
+ if (ch === '(')
266
+ depth++;
267
+ else if (ch === ')')
268
+ depth--;
269
+ else if (depth === 0 && i + 8 <= sql.length) {
270
+ if (upperSQL.substring(i, i + 8) === 'ORDER BY') {
271
+ if (i === 0 || /\s/.test(sql[i - 1])) {
272
+ lastOrderByPos = i;
273
+ }
274
+ }
275
+ }
276
+ }
277
+ if (lastOrderByPos === -1) {
278
+ return { sqlWithoutOrder: sql, orderByClause: null };
279
+ }
280
+ return {
281
+ orderByClause: sql.substring(lastOrderByPos + 9).trim(),
282
+ sqlWithoutOrder: sql.substring(0, lastOrderByPos).trim(),
283
+ };
284
+ }
285
+ static stripTopClause(sql) {
286
+ const topRegex = /^(SELECT\s+(?:DISTINCT\s+)?)TOP\s+(?:\(\s*\d+\s*\)|\d+)\s+/i;
287
+ const match = sql.match(topRegex);
288
+ if (!match)
289
+ return { sql, topRemoved: false };
290
+ return { sql: match[1] + sql.substring(match[0].length), topRemoved: true };
291
+ }
292
+ // ════════════════════════════════════════════════════════════════════
293
+ // Shared helpers
294
+ // ════════════════════════════════════════════════════════════════════
295
+ static quoteIdentifier(name, platform) {
296
+ return platform === 'postgresql' ? `"${name}"` : `[${name}]`;
297
+ }
298
+ static buildPagingClause(startRow, maxRows, platform) {
299
+ return platform === 'postgresql'
300
+ ? `LIMIT ${maxRows} OFFSET ${startRow}`
301
+ : `OFFSET ${startRow} ROWS FETCH NEXT ${maxRows} ROWS ONLY`;
302
+ }
303
+ static remapOrderByToProjectedNames(orderByClause, selectSQL) {
304
+ const aliasMap = QueryPagingEngine.buildSelectAliasMap(selectSQL);
305
+ const terms = QueryPagingEngine.splitAtTopLevelCommas(orderByClause);
306
+ const remapped = terms.map(term => {
307
+ const trimmed = term.trim();
308
+ const dirMatch = trimmed.match(/\s+(ASC|DESC)(\s+NULLS\s+(FIRST|LAST))?\s*$/i);
309
+ const expr = dirMatch ? trimmed.substring(0, dirMatch.index).trim() : trimmed;
310
+ const direction = dirMatch ? dirMatch[0] : '';
311
+ // Strip bracket/backtick/double-quote quoting for normalized matching.
312
+ // The AST path produces [bracket]-quoted identifiers, while the alias map
313
+ // may use either quoted or unquoted forms.
314
+ const unquoted = expr.replace(/\[([^\]]+)\]/g, '$1').replace(/`([^`]+)`/g, '$1').replace(/"([^"]+)"/g, '$1');
315
+ const normalizedExpr = unquoted.replace(/\s+/g, ' ').trim();
316
+ // 1. Try exact match against SELECT expressions
317
+ const exactMatch = aliasMap.get(normalizedExpr.toUpperCase());
318
+ if (exactMatch)
319
+ return exactMatch + direction;
320
+ // 2. Strip table alias prefixes (handles both quoted and unquoted)
321
+ const stripped = normalizedExpr.replace(/\b[a-zA-Z_]\w*\./g, '');
322
+ const strippedMatch = aliasMap.get(stripped.toUpperCase());
323
+ if (strippedMatch)
324
+ return strippedMatch + direction;
325
+ // 3. Simple table.column — return just the column name
326
+ const dotMatch = normalizedExpr.match(/^[a-zA-Z_]\w*\.([a-zA-Z_]\w*)$/);
327
+ if (dotMatch)
328
+ return dotMatch[1] + direction;
329
+ // 4. Fallback: return stripped expression
330
+ return stripped + direction;
331
+ });
332
+ return remapped.join(', ');
333
+ }
334
+ static buildSelectAliasMap(selectSQL) {
335
+ const map = new Map();
336
+ const stripped = selectSQL.replace(/^(\s*(--[^\n]*\n|\/\*[\s\S]*?\*\/))*\s*/i, '');
337
+ const selectMatch = stripped.match(/^SELECT\s+(?:DISTINCT\s+)?/i);
338
+ if (!selectMatch)
339
+ return map;
340
+ const afterSelect = stripped.substring(selectMatch[0].length);
341
+ const upperAfter = afterSelect.toUpperCase();
342
+ let depth = 0;
343
+ let fromPos = -1;
344
+ for (let i = 0; i < afterSelect.length; i++) {
345
+ const ch = afterSelect[i];
346
+ if (ch === '(')
347
+ depth++;
348
+ else if (ch === ')')
349
+ depth--;
350
+ else if (depth === 0 && i + 5 <= afterSelect.length) {
351
+ if (upperAfter.substring(i, i + 5) === 'FROM ' || upperAfter.substring(i, i + 5) === 'FROM\n' || upperAfter.substring(i, i + 5) === 'FROM\t') {
352
+ if (i === 0 || /\s/.test(afterSelect[i - 1])) {
353
+ fromPos = i;
354
+ break;
355
+ }
356
+ }
357
+ }
358
+ }
359
+ const columnList = fromPos === -1 ? afterSelect : afterSelect.substring(0, fromPos);
360
+ for (const item of QueryPagingEngine.splitAtTopLevelCommas(columnList)) {
361
+ const trimmedItem = item.trim();
362
+ if (!trimmedItem)
363
+ continue;
364
+ const asMatch = trimmedItem.match(/\s+AS\s+(\[?\w+\]?)\s*$/i);
365
+ if (asMatch) {
366
+ const exprPart = trimmedItem.substring(0, asMatch.index).trim();
367
+ const alias = asMatch[1].replace(/[[\]]/g, '');
368
+ const normalizedExpr = exprPart.replace(/\s+/g, ' ').toUpperCase();
369
+ map.set(normalizedExpr, alias);
370
+ const strippedExpr = normalizedExpr.replace(/\b[A-Z_]\w*\./g, '');
371
+ if (strippedExpr !== normalizedExpr)
372
+ map.set(strippedExpr, alias);
373
+ }
374
+ }
375
+ return map;
376
+ }
377
+ static splitAtTopLevelCommas(sql) {
378
+ const parts = [];
379
+ let depth = 0;
380
+ let start = 0;
381
+ for (let i = 0; i < sql.length; i++) {
382
+ const ch = sql[i];
383
+ if (ch === '(')
384
+ depth++;
385
+ else if (ch === ')')
386
+ depth--;
387
+ else if (ch === ',' && depth === 0) {
388
+ parts.push(sql.substring(start, i));
389
+ start = i + 1;
390
+ }
391
+ }
392
+ parts.push(sql.substring(start));
393
+ return parts;
394
+ }
395
+ static defaultOrderBy(platform) {
396
+ return platform === 'postgresql' ? '1' : '(SELECT NULL)';
397
+ }
398
+ }
399
+ //# sourceMappingURL=queryPagingEngine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queryPagingEngine.js","sourceRoot":"","sources":["../src/queryPagingEngine.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -35,6 +35,19 @@ export interface SqlLoggingOptions {
35
35
  sessionName?: string;
36
36
  /** Whether to output verbose debug information to console (default: false) */
37
37
  verboseOutput?: boolean;
38
+ /**
39
+ * When set, enables variable-count-based batch separation instead of emitting the batch separator
40
+ * after every statement. The logger tracks how many SQL variable declarations (DECLARE @...) have
41
+ * accumulated in the current batch. When the running count reaches this threshold, a batch separator
42
+ * is emitted before the next statement and the counter resets.
43
+ *
44
+ * This prevents SQL Server's 10,000-variable-per-batch limit from being hit on large migration files
45
+ * while avoiding the verbosity of one GO per statement.
46
+ *
47
+ * Requires `batchSeparator` to also be set. Recommended value: 200.
48
+ * Set to 0 or leave undefined to use the legacy per-statement behavior.
49
+ */
50
+ variableBatchThreshold?: number;
38
51
  /**
39
52
  * Array of patterns to filter SQL statements.
40
53
  * Supports both regex (RegExp objects) and simple wildcard patterns (strings).
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,mFAAmF;IACnF,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B,2EAA2E;IAC3E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2GAA2G;IAC3G,cAAc,CAAC,EAAE,SAAS,GAAG,WAAW,GAAG,MAAM,CAAC;IAClD,wFAAwF;IACxF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oEAAoE;IACpE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,4IAA4I;IAC5I,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,oJAAoJ;IACpJ,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,kFAAkF;IAClF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uEAAuE;IACvE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;;;;;;;;;;OAaG;IACH,cAAc,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IACrC;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,wBAAwB;IACxB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,0CAA0C;IAC1C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,yBAAyB;IACzB,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,yCAAyC;IACzC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,6CAA6C;IAC7C,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC,4DAA4D;IAC5D,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,mFAAmF;IACnF,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B,2EAA2E;IAC3E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2GAA2G;IAC3G,cAAc,CAAC,EAAE,SAAS,GAAG,WAAW,GAAG,MAAM,CAAC;IAClD,wFAAwF;IACxF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oEAAoE;IACpE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,4IAA4I;IAC5I,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,oJAAoJ;IACpJ,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,kFAAkF;IAClF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uEAAuE;IACvE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;;;;;;;;OAWG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC;;;;;;;;;;;;;OAaG;IACH,cAAc,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IACrC;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,wBAAwB;IACxB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,0CAA0C;IAC1C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,yBAAyB;IACzB,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,yCAAyC;IACzC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,6CAA6C;IAC7C,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC,4DAA4D;IAC5D,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@memberjunction/generic-database-provider",
3
3
  "type": "module",
4
- "version": "5.14.0",
4
+ "version": "5.16.0",
5
5
  "description": "Shared database provider logic for MemberJunction — intermediate base class between DatabaseProviderBase and platform-specific providers",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -22,17 +22,17 @@
22
22
  "vitest": "^3.1.1"
23
23
  },
24
24
  "dependencies": {
25
- "@memberjunction/actions": "5.14.0",
26
- "@memberjunction/actions-base": "5.14.0",
27
- "@memberjunction/aiengine": "5.14.0",
28
- "@memberjunction/core": "5.14.0",
29
- "@memberjunction/core-entities": "5.14.0",
30
- "@memberjunction/encryption": "5.14.0",
31
- "@memberjunction/global": "5.14.0",
32
- "@memberjunction/query-processor": "5.14.0",
33
- "@memberjunction/sql-dialect": "5.14.0",
34
- "node-sql-parser": "^5.4.0",
35
- "@memberjunction/queue": "5.14.0",
25
+ "@memberjunction/actions": "5.16.0",
26
+ "@memberjunction/actions-base": "5.16.0",
27
+ "@memberjunction/aiengine": "5.16.0",
28
+ "@memberjunction/core": "5.16.0",
29
+ "@memberjunction/core-entities": "5.16.0",
30
+ "@memberjunction/encryption": "5.16.0",
31
+ "@memberjunction/global": "5.16.0",
32
+ "@memberjunction/query-processor": "5.16.0",
33
+ "@memberjunction/sql-dialect": "5.16.0",
34
+ "@memberjunction/sql-parser": "5.16.0",
35
+ "@memberjunction/queue": "5.16.0",
36
36
  "sql-formatter": "^15.7.0",
37
37
  "uuid": "^13.0.0"
38
38
  },