rawsql-ts 0.11.13-beta → 0.11.15-beta
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/esm/index.js +3 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/index.min.js +19 -17
- package/dist/esm/index.min.js.map +4 -4
- package/dist/esm/src/index.d.ts +3 -0
- package/dist/esm/src/index.js +3 -0
- package/dist/esm/src/index.js.map +1 -1
- package/dist/esm/src/transformers/CTEComposer.d.ts +136 -0
- package/dist/esm/src/transformers/CTEComposer.js +298 -0
- package/dist/esm/src/transformers/CTEComposer.js.map +1 -0
- package/dist/esm/src/transformers/CTEQueryDecomposer.d.ts +213 -0
- package/dist/esm/src/transformers/CTEQueryDecomposer.js +360 -0
- package/dist/esm/src/transformers/CTEQueryDecomposer.js.map +1 -0
- package/dist/esm/src/transformers/SqlFormatter.d.ts +39 -21
- package/dist/esm/src/transformers/SqlFormatter.js.map +1 -1
- package/dist/esm/tsconfig.browser.tsbuildinfo +1 -1
- package/dist/index.min.js +19 -17
- package/dist/index.min.js.map +4 -4
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.js +3 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/transformers/CTEComposer.d.ts +136 -0
- package/dist/src/transformers/CTEComposer.js +302 -0
- package/dist/src/transformers/CTEComposer.js.map +1 -0
- package/dist/src/transformers/CTEQueryDecomposer.d.ts +213 -0
- package/dist/src/transformers/CTEQueryDecomposer.js +369 -0
- package/dist/src/transformers/CTEQueryDecomposer.js.map +1 -0
- package/dist/src/transformers/SqlFormatter.d.ts +39 -21
- package/dist/src/transformers/SqlFormatter.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
package/dist/src/index.d.ts
CHANGED
|
@@ -8,7 +8,10 @@ export * from './models/CTEError';
|
|
|
8
8
|
export * from './models/Lexeme';
|
|
9
9
|
export * from './transformers/CTECollector';
|
|
10
10
|
export * from './transformers/CTENormalizer';
|
|
11
|
+
export * from './transformers/CTEDisabler';
|
|
11
12
|
export * from './transformers/CTEDependencyAnalyzer';
|
|
13
|
+
export * from './transformers/CTEQueryDecomposer';
|
|
14
|
+
export * from './transformers/CTEComposer';
|
|
12
15
|
export * from './transformers/Formatter';
|
|
13
16
|
export * from './transformers/SqlFormatter';
|
|
14
17
|
export * from './transformers/PostgresJsonQueryBuilder';
|
package/dist/src/index.js
CHANGED
|
@@ -26,7 +26,10 @@ __exportStar(require("./models/CTEError"), exports);
|
|
|
26
26
|
__exportStar(require("./models/Lexeme"), exports);
|
|
27
27
|
__exportStar(require("./transformers/CTECollector"), exports);
|
|
28
28
|
__exportStar(require("./transformers/CTENormalizer"), exports);
|
|
29
|
+
__exportStar(require("./transformers/CTEDisabler"), exports);
|
|
29
30
|
__exportStar(require("./transformers/CTEDependencyAnalyzer"), exports);
|
|
31
|
+
__exportStar(require("./transformers/CTEQueryDecomposer"), exports);
|
|
32
|
+
__exportStar(require("./transformers/CTEComposer"), exports);
|
|
30
33
|
__exportStar(require("./transformers/Formatter"), exports);
|
|
31
34
|
__exportStar(require("./transformers/SqlFormatter"), exports);
|
|
32
35
|
__exportStar(require("./transformers/PostgresJsonQueryBuilder"), exports);
|
package/dist/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,oCAAoC;AACpC,8DAA4C;AAC5C,8DAA4C;AAE5C,6DAA2C;AAC3C,uDAAqC;AACrC,0DAAwC;AACxC,uDAAqC;AACrC,oDAAkC;AAClC,kDAAgC;AAEhC,8DAA4C;AAC5C,+DAA6C;AAC7C,uEAAqD;AACrD,2DAAyC;AACzC,8DAA4C;AAC5C,0EAAwD;AACxD,8DAA4C,CAAC,0BAA0B;AACvE,sEAAoD;AACpD,2EAAyD;AACzD,qEAAmD;AACnD,sEAAoD;AACpD,sEAAoD;AACpD,qEAAmD;AACnD,gFAQ+C;AAN3C,mIAAA,yBAAyB,OAAA;AACzB,oIAAA,0BAA0B,OAAA;AAM9B,wEAM2C;AALvC,6DAA6D;AAC7D,wHAAA,kBAAkB,OAAA;AAClB,yHAAA,mBAAmB,OAAA;AACnB,qHAAA,eAAe,OAAA;AACf,oHAAA,cAAc,OAAA;AAGlB,qEAAqE;AACrE,wEAAqE;AAA5D,sHAAA,gBAAgB,OAAA;AACzB,2EAAyD;AACzD,iFAA+D;AAE/D,iEAA+C;AAC/C,2EAAyD;AACzD,kEAAgD;AAChD,iEAA+C;AAC/C,uEAAqD;AACrD,qEAAmD;AAEnD,6DAA2C;AAC3C,8DAA4C;AAC5C,wDAAsC;AACtC,wDAAsC;AACtC,uDAAqC;AAGrC,oEAAoE"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,oCAAoC;AACpC,8DAA4C;AAC5C,8DAA4C;AAE5C,6DAA2C;AAC3C,uDAAqC;AACrC,0DAAwC;AACxC,uDAAqC;AACrC,oDAAkC;AAClC,kDAAgC;AAEhC,8DAA4C;AAC5C,+DAA6C;AAC7C,6DAA2C;AAC3C,uEAAqD;AACrD,oEAAkD;AAClD,6DAA2C;AAC3C,2DAAyC;AACzC,8DAA4C;AAC5C,0EAAwD;AACxD,8DAA4C,CAAC,0BAA0B;AACvE,sEAAoD;AACpD,2EAAyD;AACzD,qEAAmD;AACnD,sEAAoD;AACpD,sEAAoD;AACpD,qEAAmD;AACnD,gFAQ+C;AAN3C,mIAAA,yBAAyB,OAAA;AACzB,oIAAA,0BAA0B,OAAA;AAM9B,wEAM2C;AALvC,6DAA6D;AAC7D,wHAAA,kBAAkB,OAAA;AAClB,yHAAA,mBAAmB,OAAA;AACnB,qHAAA,eAAe,OAAA;AACf,oHAAA,cAAc,OAAA;AAGlB,qEAAqE;AACrE,wEAAqE;AAA5D,sHAAA,gBAAgB,OAAA;AACzB,2EAAyD;AACzD,iFAA+D;AAE/D,iEAA+C;AAC/C,2EAAyD;AACzD,kEAAgD;AAChD,iEAA+C;AAC/C,uEAAqD;AACrD,qEAAmD;AAEnD,6DAA2C;AAC3C,8DAA4C;AAC5C,wDAAsC;AACtC,wDAAsC;AACtC,uDAAqC;AAGrC,oEAAoE"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { SqlFormatterOptions } from "./SqlFormatter";
|
|
2
|
+
/**
|
|
3
|
+
* Interface representing an edited CTE with simplified structure
|
|
4
|
+
* @public
|
|
5
|
+
*/
|
|
6
|
+
export interface EditedCTE {
|
|
7
|
+
/** Name of the CTE */
|
|
8
|
+
name: string;
|
|
9
|
+
/** SQL query for this CTE, may contain WITH clause from editing */
|
|
10
|
+
query: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Options for CTEComposer extending SqlFormatterOptions
|
|
14
|
+
* @public
|
|
15
|
+
*/
|
|
16
|
+
export interface CTEComposerOptions extends SqlFormatterOptions {
|
|
17
|
+
/** Whether to validate the composed query against a schema */
|
|
18
|
+
validateSchema?: boolean;
|
|
19
|
+
/** Table to columns mapping for schema validation (required if validateSchema is true) */
|
|
20
|
+
schema?: Record<string, string[]>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Composes edited CTEs back into a unified SQL query
|
|
24
|
+
*
|
|
25
|
+
* Takes CTEs that were individually edited after decomposition and reconstructs them
|
|
26
|
+
* into a proper WITH clause structure. This completes the CTE debugging workflow:
|
|
27
|
+
* 1. Use CTEQueryDecomposer to break down complex CTEs
|
|
28
|
+
* 2. Edit individual CTEs to fix issues
|
|
29
|
+
* 3. Use CTEComposer to reconstruct the unified query
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* // After decomposing and editing CTEs
|
|
34
|
+
* const composer = new CTEComposer({
|
|
35
|
+
* preset: 'postgres',
|
|
36
|
+
* validateSchema: true,
|
|
37
|
+
* schema: { users: ['id', 'name', 'active'] }
|
|
38
|
+
* });
|
|
39
|
+
*
|
|
40
|
+
* const editedCTEs = [
|
|
41
|
+
* { name: 'base_data', query: 'select * from users where active = true' },
|
|
42
|
+
* { name: 'filtered_data', query: 'select * from base_data where region = "US"' }
|
|
43
|
+
* ];
|
|
44
|
+
*
|
|
45
|
+
* const composedSQL = composer.compose(editedCTEs, 'select * from filtered_data');
|
|
46
|
+
* // Dependencies are automatically analyzed and sorted
|
|
47
|
+
* // Result: "with base_data as (...), filtered_data as (...) select * from filtered_data"
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* @public
|
|
51
|
+
*/
|
|
52
|
+
export declare class CTEComposer {
|
|
53
|
+
private readonly formatter;
|
|
54
|
+
private readonly options;
|
|
55
|
+
private readonly dependencyAnalyzer;
|
|
56
|
+
private knownCTENames;
|
|
57
|
+
/**
|
|
58
|
+
* Creates a new CTEComposer instance
|
|
59
|
+
* @param options - Configuration options extending SqlFormatterOptions
|
|
60
|
+
*/
|
|
61
|
+
constructor(options?: CTEComposerOptions);
|
|
62
|
+
/**
|
|
63
|
+
* Compose edited CTEs and root query into a unified SQL query
|
|
64
|
+
*
|
|
65
|
+
* This method:
|
|
66
|
+
* 1. Extracts pure SELECT queries from edited CTEs (removes any WITH clauses)
|
|
67
|
+
* 2. Builds a temporary query to analyze dependencies automatically
|
|
68
|
+
* 3. Sorts CTEs by dependency order using topological sort
|
|
69
|
+
* 4. Validates schema if options.validateSchema is enabled
|
|
70
|
+
* 5. Applies formatter options for consistent output
|
|
71
|
+
* 6. Constructs the final WITH clause with proper recursive handling
|
|
72
|
+
*
|
|
73
|
+
* @param editedCTEs - Array of edited CTEs with name and query only
|
|
74
|
+
* @param rootQuery - The main query that uses the CTEs (without WITH clause)
|
|
75
|
+
* @returns Composed SQL query with properly structured WITH clause
|
|
76
|
+
* @throws Error if schema validation fails or circular dependencies are detected
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```typescript
|
|
80
|
+
* const editedCTEs = [
|
|
81
|
+
* { name: 'base_data', query: 'select * from users where active = true' },
|
|
82
|
+
* { name: 'filtered_data', query: 'select * from base_data where region = "US"' }
|
|
83
|
+
* ];
|
|
84
|
+
*
|
|
85
|
+
* const result = composer.compose(editedCTEs, 'select count(*) from filtered_data');
|
|
86
|
+
* // Dependencies automatically analyzed and sorted
|
|
87
|
+
* // Result: "with base_data as (...), filtered_data as (...) select count(*) from filtered_data"
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
compose(editedCTEs: EditedCTE[], rootQuery: string): string;
|
|
91
|
+
/**
|
|
92
|
+
* Extract pure SELECT query from a query that may contain WITH clause
|
|
93
|
+
* If query contains WITH with known CTEs, extract main SELECT and ignore old definitions
|
|
94
|
+
* If query contains WITH with unknown CTEs, preserve entire query
|
|
95
|
+
* @param query The query that may contain WITH clause
|
|
96
|
+
* @param cteName The name of the CTE to extract (if query contains WITH)
|
|
97
|
+
* @returns Pure SELECT query without WITH clause, or entire query if it contains new sub-CTEs
|
|
98
|
+
*/
|
|
99
|
+
private extractPureQuery;
|
|
100
|
+
/**
|
|
101
|
+
* Get list of known CTE names from current composition context
|
|
102
|
+
*/
|
|
103
|
+
private getKnownCTENames;
|
|
104
|
+
/**
|
|
105
|
+
* Extract CTE name from CommonTable
|
|
106
|
+
*/
|
|
107
|
+
private getCTEName;
|
|
108
|
+
/**
|
|
109
|
+
* Extract CTE definition using regex as fallback
|
|
110
|
+
*/
|
|
111
|
+
private extractCTEWithRegex;
|
|
112
|
+
/**
|
|
113
|
+
* Build a temporary query for dependency analysis
|
|
114
|
+
*/
|
|
115
|
+
private buildTempQueryForAnalysis;
|
|
116
|
+
/**
|
|
117
|
+
* Sort CTEs by dependencies using dependency graph
|
|
118
|
+
*/
|
|
119
|
+
private sortCTEsByDependencies;
|
|
120
|
+
/**
|
|
121
|
+
* Detect if any CTEs are recursive by analyzing original queries
|
|
122
|
+
*/
|
|
123
|
+
private detectRecursiveFromOriginalQueries;
|
|
124
|
+
/**
|
|
125
|
+
* Detect if any CTEs are recursive
|
|
126
|
+
*/
|
|
127
|
+
private detectRecursiveCTEs;
|
|
128
|
+
/**
|
|
129
|
+
* Validate the composed query against schema
|
|
130
|
+
*/
|
|
131
|
+
private validateComposedQuery;
|
|
132
|
+
/**
|
|
133
|
+
* Apply formatting to the final query
|
|
134
|
+
*/
|
|
135
|
+
private formatFinalQuery;
|
|
136
|
+
}
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CTEComposer = void 0;
|
|
4
|
+
const SimpleSelectQuery_1 = require("../models/SimpleSelectQuery");
|
|
5
|
+
const SelectQueryParser_1 = require("../parsers/SelectQueryParser");
|
|
6
|
+
const SqlFormatter_1 = require("./SqlFormatter");
|
|
7
|
+
const SqlSchemaValidator_1 = require("../utils/SqlSchemaValidator");
|
|
8
|
+
const CTEDependencyAnalyzer_1 = require("./CTEDependencyAnalyzer");
|
|
9
|
+
/**
|
|
10
|
+
* Composes edited CTEs back into a unified SQL query
|
|
11
|
+
*
|
|
12
|
+
* Takes CTEs that were individually edited after decomposition and reconstructs them
|
|
13
|
+
* into a proper WITH clause structure. This completes the CTE debugging workflow:
|
|
14
|
+
* 1. Use CTEQueryDecomposer to break down complex CTEs
|
|
15
|
+
* 2. Edit individual CTEs to fix issues
|
|
16
|
+
* 3. Use CTEComposer to reconstruct the unified query
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* // After decomposing and editing CTEs
|
|
21
|
+
* const composer = new CTEComposer({
|
|
22
|
+
* preset: 'postgres',
|
|
23
|
+
* validateSchema: true,
|
|
24
|
+
* schema: { users: ['id', 'name', 'active'] }
|
|
25
|
+
* });
|
|
26
|
+
*
|
|
27
|
+
* const editedCTEs = [
|
|
28
|
+
* { name: 'base_data', query: 'select * from users where active = true' },
|
|
29
|
+
* { name: 'filtered_data', query: 'select * from base_data where region = "US"' }
|
|
30
|
+
* ];
|
|
31
|
+
*
|
|
32
|
+
* const composedSQL = composer.compose(editedCTEs, 'select * from filtered_data');
|
|
33
|
+
* // Dependencies are automatically analyzed and sorted
|
|
34
|
+
* // Result: "with base_data as (...), filtered_data as (...) select * from filtered_data"
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @public
|
|
38
|
+
*/
|
|
39
|
+
class CTEComposer {
|
|
40
|
+
/**
|
|
41
|
+
* Creates a new CTEComposer instance
|
|
42
|
+
* @param options - Configuration options extending SqlFormatterOptions
|
|
43
|
+
*/
|
|
44
|
+
constructor(options = {}) {
|
|
45
|
+
this.knownCTENames = [];
|
|
46
|
+
this.options = options;
|
|
47
|
+
this.formatter = new SqlFormatter_1.SqlFormatter(options);
|
|
48
|
+
this.dependencyAnalyzer = new CTEDependencyAnalyzer_1.CTEDependencyAnalyzer();
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Compose edited CTEs and root query into a unified SQL query
|
|
52
|
+
*
|
|
53
|
+
* This method:
|
|
54
|
+
* 1. Extracts pure SELECT queries from edited CTEs (removes any WITH clauses)
|
|
55
|
+
* 2. Builds a temporary query to analyze dependencies automatically
|
|
56
|
+
* 3. Sorts CTEs by dependency order using topological sort
|
|
57
|
+
* 4. Validates schema if options.validateSchema is enabled
|
|
58
|
+
* 5. Applies formatter options for consistent output
|
|
59
|
+
* 6. Constructs the final WITH clause with proper recursive handling
|
|
60
|
+
*
|
|
61
|
+
* @param editedCTEs - Array of edited CTEs with name and query only
|
|
62
|
+
* @param rootQuery - The main query that uses the CTEs (without WITH clause)
|
|
63
|
+
* @returns Composed SQL query with properly structured WITH clause
|
|
64
|
+
* @throws Error if schema validation fails or circular dependencies are detected
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```typescript
|
|
68
|
+
* const editedCTEs = [
|
|
69
|
+
* { name: 'base_data', query: 'select * from users where active = true' },
|
|
70
|
+
* { name: 'filtered_data', query: 'select * from base_data where region = "US"' }
|
|
71
|
+
* ];
|
|
72
|
+
*
|
|
73
|
+
* const result = composer.compose(editedCTEs, 'select count(*) from filtered_data');
|
|
74
|
+
* // Dependencies automatically analyzed and sorted
|
|
75
|
+
* // Result: "with base_data as (...), filtered_data as (...) select count(*) from filtered_data"
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
compose(editedCTEs, rootQuery) {
|
|
79
|
+
if (editedCTEs.length === 0) {
|
|
80
|
+
return rootQuery;
|
|
81
|
+
}
|
|
82
|
+
// Set known CTE names for WITH clause filtering
|
|
83
|
+
this.knownCTENames = editedCTEs.map(cte => cte.name);
|
|
84
|
+
// Extract pure queries and detect recursion
|
|
85
|
+
const pureQueries = editedCTEs.map(cte => ({
|
|
86
|
+
name: cte.name,
|
|
87
|
+
query: this.extractPureQuery(cte.query, cte.name)
|
|
88
|
+
}));
|
|
89
|
+
// Build temporary query to analyze dependencies
|
|
90
|
+
const tempQuery = this.buildTempQueryForAnalysis(pureQueries, rootQuery);
|
|
91
|
+
// Analyze dependencies
|
|
92
|
+
const dependencyGraph = this.dependencyAnalyzer.analyzeDependencies(tempQuery);
|
|
93
|
+
// Sort CTEs by dependencies
|
|
94
|
+
const sortedCTEs = this.sortCTEsByDependencies(pureQueries, dependencyGraph);
|
|
95
|
+
// Check for recursive CTEs by analyzing original queries
|
|
96
|
+
const isRecursive = this.detectRecursiveFromOriginalQueries(editedCTEs);
|
|
97
|
+
// Special handling for recursive CTEs: Current implementation preserves recursive CTEs as-is
|
|
98
|
+
// This is expected behavior for now as recursive CTEs require complex handling
|
|
99
|
+
// Build WITH clause with sorted CTEs
|
|
100
|
+
const cteDefinitions = sortedCTEs.map(cte => {
|
|
101
|
+
return `${cte.name} as (${cte.query})`;
|
|
102
|
+
});
|
|
103
|
+
const withKeyword = isRecursive ? "with recursive" : "with";
|
|
104
|
+
const composedQuery = `${withKeyword} ${cteDefinitions.join(", ")} ${rootQuery}`;
|
|
105
|
+
// Validate schema if requested
|
|
106
|
+
if (this.options.validateSchema && this.options.schema) {
|
|
107
|
+
this.validateComposedQuery(composedQuery);
|
|
108
|
+
}
|
|
109
|
+
// Apply formatting if options specify it
|
|
110
|
+
return this.formatFinalQuery(composedQuery);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Extract pure SELECT query from a query that may contain WITH clause
|
|
114
|
+
* If query contains WITH with known CTEs, extract main SELECT and ignore old definitions
|
|
115
|
+
* If query contains WITH with unknown CTEs, preserve entire query
|
|
116
|
+
* @param query The query that may contain WITH clause
|
|
117
|
+
* @param cteName The name of the CTE to extract (if query contains WITH)
|
|
118
|
+
* @returns Pure SELECT query without WITH clause, or entire query if it contains new sub-CTEs
|
|
119
|
+
*/
|
|
120
|
+
extractPureQuery(query, cteName) {
|
|
121
|
+
// Simple regex to check if query starts with WITH
|
|
122
|
+
const withPattern = /^\s*with\s+/i;
|
|
123
|
+
if (!withPattern.test(query)) {
|
|
124
|
+
return query;
|
|
125
|
+
}
|
|
126
|
+
// Check if this is a recursive CTE by looking for "WITH RECURSIVE"
|
|
127
|
+
const recursivePattern = /^\s*with\s+recursive\s+/i;
|
|
128
|
+
if (recursivePattern.test(query)) {
|
|
129
|
+
// For recursive CTEs, preserve the entire query as-is
|
|
130
|
+
return query;
|
|
131
|
+
}
|
|
132
|
+
// Parse the query to check what CTEs are defined in the WITH clause
|
|
133
|
+
try {
|
|
134
|
+
const parsed = SelectQueryParser_1.SelectQueryParser.parse(query);
|
|
135
|
+
if (parsed.withClause && parsed.withClause.tables) {
|
|
136
|
+
// Check if WITH clause contains only known CTEs from our composition
|
|
137
|
+
const knownCTENames = this.getKnownCTENames();
|
|
138
|
+
const withCTENames = parsed.withClause.tables.map(cte => this.getCTEName(cte));
|
|
139
|
+
// If all CTEs in WITH clause are known (old definitions), extract main SELECT
|
|
140
|
+
const hasOnlyKnownCTEs = withCTENames.every(name => knownCTENames.includes(name));
|
|
141
|
+
if (hasOnlyKnownCTEs) {
|
|
142
|
+
// Remove WITH clause and format just the main query
|
|
143
|
+
const queryWithoutWith = new SimpleSelectQuery_1.SimpleSelectQuery({
|
|
144
|
+
selectClause: parsed.selectClause,
|
|
145
|
+
fromClause: parsed.fromClause,
|
|
146
|
+
whereClause: parsed.whereClause,
|
|
147
|
+
groupByClause: parsed.groupByClause,
|
|
148
|
+
havingClause: parsed.havingClause,
|
|
149
|
+
orderByClause: parsed.orderByClause,
|
|
150
|
+
windowClause: parsed.windowClause,
|
|
151
|
+
limitClause: parsed.limitClause,
|
|
152
|
+
offsetClause: parsed.offsetClause,
|
|
153
|
+
fetchClause: parsed.fetchClause,
|
|
154
|
+
forClause: parsed.forClause,
|
|
155
|
+
withClause: undefined // withClause removed
|
|
156
|
+
});
|
|
157
|
+
// Use a formatter without quotes for extraction to preserve original format
|
|
158
|
+
const extractFormatter = new SqlFormatter_1.SqlFormatter({
|
|
159
|
+
identifierEscape: { start: "", end: "" }
|
|
160
|
+
});
|
|
161
|
+
return extractFormatter.format(queryWithoutWith).formattedSql;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
// If parsing fails, fall through to preserve entire query
|
|
167
|
+
}
|
|
168
|
+
// If query contains WITH clause with unknown CTEs, preserve it like a recursive CTE
|
|
169
|
+
// This handles the case where user edited a CTE and added new sub-CTEs
|
|
170
|
+
return query;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Get list of known CTE names from current composition context
|
|
174
|
+
*/
|
|
175
|
+
getKnownCTENames() {
|
|
176
|
+
// This will be set during composition to track known CTE names
|
|
177
|
+
return this.knownCTENames || [];
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Extract CTE name from CommonTable
|
|
181
|
+
*/
|
|
182
|
+
getCTEName(cte) {
|
|
183
|
+
return cte.aliasExpression.table.name;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Extract CTE definition using regex as fallback
|
|
187
|
+
*/
|
|
188
|
+
extractCTEWithRegex(query, cteName) {
|
|
189
|
+
// More robust regex to extract CTE definition
|
|
190
|
+
// Pattern: cteName as (...) accounting for nested parentheses
|
|
191
|
+
const ctePattern = new RegExp(`${cteName}\\s+as\\s*\\(`, 'i');
|
|
192
|
+
const match = query.match(ctePattern);
|
|
193
|
+
if (!match) {
|
|
194
|
+
return query;
|
|
195
|
+
}
|
|
196
|
+
// Find the start of the CTE definition (after "as (")
|
|
197
|
+
const startIndex = match.index + match[0].length;
|
|
198
|
+
// Use parentheses counting to find the end of the CTE definition
|
|
199
|
+
let parenCount = 1;
|
|
200
|
+
let endIndex = startIndex;
|
|
201
|
+
while (endIndex < query.length && parenCount > 0) {
|
|
202
|
+
const char = query[endIndex];
|
|
203
|
+
if (char === '(') {
|
|
204
|
+
parenCount++;
|
|
205
|
+
}
|
|
206
|
+
else if (char === ')') {
|
|
207
|
+
parenCount--;
|
|
208
|
+
}
|
|
209
|
+
endIndex++;
|
|
210
|
+
}
|
|
211
|
+
if (parenCount === 0) {
|
|
212
|
+
// Extract the content between parentheses
|
|
213
|
+
const cteDefinition = query.substring(startIndex, endIndex - 1).trim();
|
|
214
|
+
return cteDefinition;
|
|
215
|
+
}
|
|
216
|
+
return query;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Build a temporary query for dependency analysis
|
|
220
|
+
*/
|
|
221
|
+
buildTempQueryForAnalysis(pureQueries, rootQuery) {
|
|
222
|
+
const cteDefinitions = pureQueries.map(cte => `${cte.name} as (${cte.query})`);
|
|
223
|
+
const tempSql = `with ${cteDefinitions.join(", ")} ${rootQuery}`;
|
|
224
|
+
try {
|
|
225
|
+
return SelectQueryParser_1.SelectQueryParser.parse(tempSql);
|
|
226
|
+
}
|
|
227
|
+
catch (error) {
|
|
228
|
+
throw new Error(`Failed to parse temporary query for dependency analysis: ${error}`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Sort CTEs by dependencies using dependency graph
|
|
233
|
+
*/
|
|
234
|
+
sortCTEsByDependencies(pureQueries, dependencyGraph) {
|
|
235
|
+
// Create a map for quick lookup
|
|
236
|
+
const queryMap = new Map();
|
|
237
|
+
pureQueries.forEach(cte => queryMap.set(cte.name, cte.query));
|
|
238
|
+
// Return CTEs in dependency order
|
|
239
|
+
return dependencyGraph.nodes.map(node => ({
|
|
240
|
+
name: node.name,
|
|
241
|
+
query: queryMap.get(node.name) || ""
|
|
242
|
+
})).filter(cte => cte.query !== "");
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Detect if any CTEs are recursive by analyzing original queries
|
|
246
|
+
*/
|
|
247
|
+
detectRecursiveFromOriginalQueries(editedCTEs) {
|
|
248
|
+
// Check if any of the original queries contain "with recursive"
|
|
249
|
+
return editedCTEs.some(cte => {
|
|
250
|
+
const queryLower = cte.query.toLowerCase();
|
|
251
|
+
return queryLower.includes('with recursive');
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Detect if any CTEs are recursive
|
|
256
|
+
*/
|
|
257
|
+
detectRecursiveCTEs(query) {
|
|
258
|
+
if (!query.withClause)
|
|
259
|
+
return false;
|
|
260
|
+
// Check if the query text contains "recursive"
|
|
261
|
+
const queryText = this.formatter.format(query).formattedSql.toLowerCase();
|
|
262
|
+
return queryText.includes('with recursive');
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Validate the composed query against schema
|
|
266
|
+
*/
|
|
267
|
+
validateComposedQuery(composedQuery) {
|
|
268
|
+
try {
|
|
269
|
+
const parsed = SelectQueryParser_1.SelectQueryParser.parse(composedQuery);
|
|
270
|
+
// Convert schema to TableSchema format
|
|
271
|
+
const tableSchemas = Object.entries(this.options.schema).map(([name, columns]) => ({
|
|
272
|
+
name,
|
|
273
|
+
columns
|
|
274
|
+
}));
|
|
275
|
+
SqlSchemaValidator_1.SqlSchemaValidator.validate(parsed, tableSchemas);
|
|
276
|
+
}
|
|
277
|
+
catch (error) {
|
|
278
|
+
if (error instanceof Error) {
|
|
279
|
+
throw new Error(`Schema validation failed: ${error.message}`);
|
|
280
|
+
}
|
|
281
|
+
throw error;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Apply formatting to the final query
|
|
286
|
+
*/
|
|
287
|
+
formatFinalQuery(composedQuery) {
|
|
288
|
+
if (this.options.preset || this.options.keywordCase) {
|
|
289
|
+
try {
|
|
290
|
+
const parsed = SelectQueryParser_1.SelectQueryParser.parse(composedQuery);
|
|
291
|
+
return this.formatter.format(parsed).formattedSql;
|
|
292
|
+
}
|
|
293
|
+
catch (error) {
|
|
294
|
+
// If parsing fails, return unformatted query
|
|
295
|
+
return composedQuery;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return composedQuery;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
exports.CTEComposer = CTEComposer;
|
|
302
|
+
//# sourceMappingURL=CTEComposer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CTEComposer.js","sourceRoot":"","sources":["../../../src/transformers/CTEComposer.ts"],"names":[],"mappings":"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"}
|