rawsql-ts 0.1.0-beta.11 → 0.1.0-beta.12
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 +22 -0
- package/dist/esm/index.js +17 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/models/BinarySelectQuery.js +137 -0
- package/dist/esm/models/BinarySelectQuery.js.map +1 -0
- package/dist/esm/models/Clause.js +289 -0
- package/dist/esm/models/Clause.js.map +1 -0
- package/dist/esm/models/KeywordTrie.js +48 -0
- package/dist/esm/models/KeywordTrie.js.map +1 -0
- package/dist/esm/models/Lexeme.js +18 -0
- package/dist/esm/models/Lexeme.js.map +1 -0
- package/dist/esm/models/SelectQuery.js +5 -0
- package/dist/esm/models/SelectQuery.js.map +1 -0
- package/dist/esm/models/SimpleSelectQuery.js +288 -0
- package/dist/esm/models/SimpleSelectQuery.js.map +1 -0
- package/dist/esm/models/SqlComponent.js +22 -0
- package/dist/esm/models/SqlComponent.js.map +1 -0
- package/dist/esm/models/ValueComponent.js +223 -0
- package/dist/esm/models/ValueComponent.js.map +1 -0
- package/dist/esm/models/ValuesQuery.js +12 -0
- package/dist/esm/models/ValuesQuery.js.map +1 -0
- package/dist/esm/parsers/CommandExpressionParser.js +120 -0
- package/dist/esm/parsers/CommandExpressionParser.js.map +1 -0
- package/dist/esm/parsers/CommonTableParser.js +58 -0
- package/dist/esm/parsers/CommonTableParser.js.map +1 -0
- package/dist/esm/parsers/ForClauseParser.js +54 -0
- package/dist/esm/parsers/ForClauseParser.js.map +1 -0
- package/dist/esm/parsers/FromClauseParser.js +43 -0
- package/dist/esm/parsers/FromClauseParser.js.map +1 -0
- package/dist/esm/parsers/FunctionExpressionParser.js +174 -0
- package/dist/esm/parsers/FunctionExpressionParser.js.map +1 -0
- package/dist/esm/parsers/GroupByParser.js +54 -0
- package/dist/esm/parsers/GroupByParser.js.map +1 -0
- package/dist/esm/parsers/HavingParser.js +32 -0
- package/dist/esm/parsers/HavingParser.js.map +1 -0
- package/dist/esm/parsers/IdentifierParser.js +35 -0
- package/dist/esm/parsers/IdentifierParser.js.map +1 -0
- package/dist/esm/parsers/JoinClauseParser.js +101 -0
- package/dist/esm/parsers/JoinClauseParser.js.map +1 -0
- package/dist/esm/parsers/KeywordParser.js +87 -0
- package/dist/esm/parsers/KeywordParser.js.map +1 -0
- package/dist/esm/parsers/LimitClauseParser.js +46 -0
- package/dist/esm/parsers/LimitClauseParser.js.map +1 -0
- package/dist/esm/parsers/LiteralParser.js +34 -0
- package/dist/esm/parsers/LiteralParser.js.map +1 -0
- package/dist/esm/parsers/OrderByClauseParser.js +73 -0
- package/dist/esm/parsers/OrderByClauseParser.js.map +1 -0
- package/dist/esm/parsers/OverExpressionParser.js +40 -0
- package/dist/esm/parsers/OverExpressionParser.js.map +1 -0
- package/dist/esm/parsers/ParameterExpressionParser.js +11 -0
- package/dist/esm/parsers/ParameterExpressionParser.js.map +1 -0
- package/dist/esm/parsers/ParenExpressionParser.js +29 -0
- package/dist/esm/parsers/ParenExpressionParser.js.map +1 -0
- package/dist/esm/parsers/PartitionByParser.js +49 -0
- package/dist/esm/parsers/PartitionByParser.js.map +1 -0
- package/dist/esm/parsers/SelectClauseParser.js +80 -0
- package/dist/esm/parsers/SelectClauseParser.js.map +1 -0
- package/dist/esm/parsers/SelectQueryParser.js +149 -0
- package/dist/esm/parsers/SelectQueryParser.js.map +1 -0
- package/dist/esm/parsers/SourceAliasExpressionParser.js +45 -0
- package/dist/esm/parsers/SourceAliasExpressionParser.js.map +1 -0
- package/dist/esm/parsers/SourceExpressionParser.js +31 -0
- package/dist/esm/parsers/SourceExpressionParser.js.map +1 -0
- package/dist/esm/parsers/SourceParser.js +115 -0
- package/dist/esm/parsers/SourceParser.js.map +1 -0
- package/dist/esm/parsers/SqlTokenizer.js +170 -0
- package/dist/esm/parsers/SqlTokenizer.js.map +1 -0
- package/dist/esm/parsers/StringSpecifierExpressionParser.js +18 -0
- package/dist/esm/parsers/StringSpecifierExpressionParser.js.map +1 -0
- package/dist/esm/parsers/UnaryExpressionParser.js +26 -0
- package/dist/esm/parsers/UnaryExpressionParser.js.map +1 -0
- package/dist/esm/parsers/ValueParser.js +132 -0
- package/dist/esm/parsers/ValueParser.js.map +1 -0
- package/dist/esm/parsers/ValuesQueryParser.js +82 -0
- package/dist/esm/parsers/ValuesQueryParser.js.map +1 -0
- package/dist/esm/parsers/WhereClauseParser.js +32 -0
- package/dist/esm/parsers/WhereClauseParser.js.map +1 -0
- package/dist/esm/parsers/WindowClauseParser.js +41 -0
- package/dist/esm/parsers/WindowClauseParser.js.map +1 -0
- package/dist/esm/parsers/WindowExpressionParser.js +159 -0
- package/dist/esm/parsers/WindowExpressionParser.js.map +1 -0
- package/dist/esm/parsers/WithClauseParser.js +53 -0
- package/dist/esm/parsers/WithClauseParser.js.map +1 -0
- package/dist/esm/tokenReaders/BaseTokenReader.js +78 -0
- package/dist/esm/tokenReaders/BaseTokenReader.js.map +1 -0
- package/dist/esm/tokenReaders/CommandTokenReader.js +141 -0
- package/dist/esm/tokenReaders/CommandTokenReader.js.map +1 -0
- package/dist/esm/tokenReaders/FunctionTokenReader.js +41 -0
- package/dist/esm/tokenReaders/FunctionTokenReader.js.map +1 -0
- package/dist/esm/tokenReaders/IdentifierTokenReader.js +66 -0
- package/dist/esm/tokenReaders/IdentifierTokenReader.js.map +1 -0
- package/dist/esm/tokenReaders/LiteralTokenReader.js +185 -0
- package/dist/esm/tokenReaders/LiteralTokenReader.js.map +1 -0
- package/dist/esm/tokenReaders/OperatorTokenReader.js +94 -0
- package/dist/esm/tokenReaders/OperatorTokenReader.js.map +1 -0
- package/dist/esm/tokenReaders/ParameterTokenReader.js +40 -0
- package/dist/esm/tokenReaders/ParameterTokenReader.js.map +1 -0
- package/dist/esm/tokenReaders/StringSpecifierTokenReader.js +27 -0
- package/dist/esm/tokenReaders/StringSpecifierTokenReader.js.map +1 -0
- package/dist/esm/tokenReaders/SymbolTokenReader.js +31 -0
- package/dist/esm/tokenReaders/SymbolTokenReader.js.map +1 -0
- package/dist/esm/tokenReaders/TokenReaderManager.js +106 -0
- package/dist/esm/tokenReaders/TokenReaderManager.js.map +1 -0
- package/dist/esm/tokenReaders/TypeTokenReader.js +55 -0
- package/dist/esm/tokenReaders/TypeTokenReader.js.map +1 -0
- package/dist/esm/transformers/CTEBuilder.js +184 -0
- package/dist/esm/transformers/CTEBuilder.js.map +1 -0
- package/dist/esm/transformers/CTECollector.js +380 -0
- package/dist/esm/transformers/CTECollector.js.map +1 -0
- package/dist/esm/transformers/CTEDisabler.js +321 -0
- package/dist/esm/transformers/CTEDisabler.js.map +1 -0
- package/dist/esm/transformers/CTEInjector.js +79 -0
- package/dist/esm/transformers/CTEInjector.js.map +1 -0
- package/dist/esm/transformers/CTENormalizer.js +42 -0
- package/dist/esm/transformers/CTENormalizer.js.map +1 -0
- package/dist/esm/transformers/Formatter.js +463 -0
- package/dist/esm/transformers/Formatter.js.map +1 -0
- package/dist/esm/transformers/QueryConverter.js +115 -0
- package/dist/esm/transformers/QueryConverter.js.map +1 -0
- package/dist/esm/transformers/SelectValueCollector.js +245 -0
- package/dist/esm/transformers/SelectValueCollector.js.map +1 -0
- package/dist/esm/transformers/SelectableColumnCollector.js +304 -0
- package/dist/esm/transformers/SelectableColumnCollector.js.map +1 -0
- package/dist/esm/transformers/TableColumnResolver.js +2 -0
- package/dist/esm/transformers/TableColumnResolver.js.map +1 -0
- package/dist/esm/transformers/TableSourceCollector.js +380 -0
- package/dist/esm/transformers/TableSourceCollector.js.map +1 -0
- package/dist/esm/transformers/UpstreamSelectQueryFinder.js +125 -0
- package/dist/esm/transformers/UpstreamSelectQueryFinder.js.map +1 -0
- package/dist/esm/types/index.d.ts +14 -0
- package/dist/esm/types/models/BinarySelectQuery.d.ts +91 -0
- package/dist/esm/types/models/Clause.d.ts +189 -0
- package/dist/esm/types/models/KeywordTrie.d.ts +11 -0
- package/dist/esm/types/models/Lexeme.d.ts +25 -0
- package/dist/esm/types/models/SelectQuery.d.ts +5 -0
- package/dist/esm/types/models/SimpleSelectQuery.d.ts +167 -0
- package/dist/esm/types/models/SqlComponent.d.ts +18 -0
- package/dist/esm/types/models/ValueComponent.d.ts +158 -0
- package/dist/esm/types/models/ValuesQuery.d.ts +10 -0
- package/dist/esm/types/parsers/CommandExpressionParser.d.ts +15 -0
- package/dist/esm/types/parsers/CommonTableParser.d.ts +9 -0
- package/dist/esm/types/parsers/ForClauseParser.d.ts +9 -0
- package/dist/esm/types/parsers/FromClauseParser.d.ts +9 -0
- package/dist/esm/types/parsers/FunctionExpressionParser.d.ts +22 -0
- package/dist/esm/types/parsers/GroupByParser.d.ts +10 -0
- package/dist/esm/types/parsers/HavingParser.d.ts +9 -0
- package/dist/esm/types/parsers/IdentifierParser.d.ts +8 -0
- package/dist/esm/types/parsers/JoinClauseParser.d.ts +14 -0
- package/dist/esm/types/parsers/KeywordParser.d.ts +17 -0
- package/dist/esm/types/parsers/LimitClauseParser.d.ts +9 -0
- package/dist/esm/types/parsers/LiteralParser.d.ts +8 -0
- package/dist/esm/types/parsers/OrderByClauseParser.d.ts +10 -0
- package/dist/esm/types/parsers/OverExpressionParser.d.ts +9 -0
- package/dist/esm/types/parsers/ParameterExpressionParser.d.ts +8 -0
- package/dist/esm/types/parsers/ParenExpressionParser.d.ts +8 -0
- package/dist/esm/types/parsers/PartitionByParser.d.ts +9 -0
- package/dist/esm/types/parsers/SelectClauseParser.d.ts +10 -0
- package/dist/esm/types/parsers/SelectQueryParser.d.ts +13 -0
- package/dist/esm/types/parsers/SourceAliasExpressionParser.d.ts +8 -0
- package/dist/esm/types/parsers/SourceExpressionParser.d.ts +8 -0
- package/dist/esm/types/parsers/SourceParser.d.ts +13 -0
- package/dist/esm/types/parsers/SqlTokenizer.d.ts +64 -0
- package/dist/esm/types/parsers/StringSpecifierExpressionParser.d.ts +8 -0
- package/dist/esm/types/parsers/UnaryExpressionParser.d.ts +8 -0
- package/dist/esm/types/parsers/ValueParser.d.ts +14 -0
- package/dist/esm/types/parsers/ValuesQueryParser.d.ts +10 -0
- package/dist/esm/types/parsers/WhereClauseParser.d.ts +9 -0
- package/dist/esm/types/parsers/WindowClauseParser.d.ts +9 -0
- package/dist/esm/types/parsers/WindowExpressionParser.d.ts +12 -0
- package/dist/esm/types/parsers/WithClauseParser.d.ts +9 -0
- package/dist/esm/types/tokenReaders/BaseTokenReader.d.ts +43 -0
- package/dist/esm/types/tokenReaders/CommandTokenReader.d.ts +7 -0
- package/dist/esm/types/tokenReaders/FunctionTokenReader.d.ts +11 -0
- package/dist/esm/types/tokenReaders/IdentifierTokenReader.d.ts +15 -0
- package/dist/esm/types/tokenReaders/LiteralTokenReader.d.ts +23 -0
- package/dist/esm/types/tokenReaders/OperatorTokenReader.d.ts +5 -0
- package/dist/esm/types/tokenReaders/ParameterTokenReader.d.ts +11 -0
- package/dist/esm/types/tokenReaders/StringSpecifierTokenReader.d.ts +8 -0
- package/dist/esm/types/tokenReaders/SymbolTokenReader.d.ts +12 -0
- package/dist/esm/types/tokenReaders/TokenReaderManager.d.ts +53 -0
- package/dist/esm/types/tokenReaders/TypeTokenReader.d.ts +11 -0
- package/dist/esm/types/transformers/CTEBuilder.d.ts +52 -0
- package/dist/esm/types/transformers/CTECollector.d.ts +81 -0
- package/dist/esm/types/transformers/CTEDisabler.d.ts +77 -0
- package/dist/esm/types/transformers/CTEInjector.d.ts +40 -0
- package/dist/esm/types/transformers/CTENormalizer.d.ts +25 -0
- package/dist/esm/types/transformers/Formatter.d.ts +82 -0
- package/dist/esm/types/transformers/QueryConverter.d.ts +41 -0
- package/dist/esm/types/transformers/SelectValueCollector.d.ts +60 -0
- package/dist/esm/types/transformers/SelectableColumnCollector.d.ts +70 -0
- package/dist/esm/types/transformers/TableColumnResolver.d.ts +10 -0
- package/dist/esm/types/transformers/TableSourceCollector.d.ts +92 -0
- package/dist/esm/types/transformers/UpstreamSelectQueryFinder.d.ts +27 -0
- package/dist/esm/types/utils/charLookupTable.d.ts +11 -0
- package/dist/esm/types/utils/stringUtils.d.ts +43 -0
- package/dist/esm/utils/charLookupTable.js +69 -0
- package/dist/esm/utils/charLookupTable.js.map +1 -0
- package/dist/esm/utils/stringUtils.js +164 -0
- package/dist/esm/utils/stringUtils.js.map +1 -0
- package/package.json +12 -1
@@ -0,0 +1,132 @@
|
|
1
|
+
import { TokenType } from "../models/Lexeme";
|
2
|
+
import { ColumnReference, ValueList } from "../models/ValueComponent";
|
3
|
+
import { SqlTokenizer } from "./SqlTokenizer";
|
4
|
+
import { IdentifierParser } from "./IdentifierParser";
|
5
|
+
import { LiteralParser } from "./LiteralParser";
|
6
|
+
import { ParenExpressionParser } from "./ParenExpressionParser";
|
7
|
+
import { UnaryExpressionParser } from "./UnaryExpressionParser";
|
8
|
+
import { ParameterExpressionParser } from "./ParameterExpressionParser";
|
9
|
+
import { StringSpecifierExpressionParser } from "./StringSpecifierExpressionParser";
|
10
|
+
import { CommandExpressionParser } from "./CommandExpressionParser";
|
11
|
+
import { FunctionExpressionParser } from "./FunctionExpressionParser";
|
12
|
+
export class ValueParser {
|
13
|
+
// Parse SQL string to AST (was: parse)
|
14
|
+
static parse(query) {
|
15
|
+
const tokenizer = new SqlTokenizer(query); // Initialize tokenizer
|
16
|
+
const lexemes = tokenizer.readLexmes(); // Get tokens
|
17
|
+
// Parse
|
18
|
+
const result = this.parseFromLexeme(lexemes, 0);
|
19
|
+
// Error if there are remaining tokens
|
20
|
+
if (result.newIndex < lexemes.length) {
|
21
|
+
throw new Error(`Unexpected token at index ${result.newIndex}: ${lexemes[result.newIndex].value}`);
|
22
|
+
}
|
23
|
+
return result.value;
|
24
|
+
}
|
25
|
+
// Parse from lexeme array (was: parse)
|
26
|
+
static parseFromLexeme(lexemes, index, allowAndOperator = true) {
|
27
|
+
let idx = index;
|
28
|
+
// support comments
|
29
|
+
const comment = lexemes[index].comments;
|
30
|
+
const left = this.parseItem(lexemes, index);
|
31
|
+
left.value.comments = comment;
|
32
|
+
idx = left.newIndex;
|
33
|
+
while (idx < lexemes.length && lexemes[idx].type === TokenType.Operator) {
|
34
|
+
const binaryResult = FunctionExpressionParser.tryParseBinaryExpression(lexemes, idx, left.value, allowAndOperator);
|
35
|
+
if (binaryResult) {
|
36
|
+
left.value = binaryResult.value;
|
37
|
+
idx = binaryResult.newIndex;
|
38
|
+
}
|
39
|
+
else {
|
40
|
+
// If no binary expression is found, break the loop
|
41
|
+
break;
|
42
|
+
}
|
43
|
+
}
|
44
|
+
return { value: left.value, newIndex: idx };
|
45
|
+
}
|
46
|
+
static parseItem(lexemes, index) {
|
47
|
+
let idx = index;
|
48
|
+
// Range check
|
49
|
+
if (idx >= lexemes.length) {
|
50
|
+
throw new Error(`Unexpected end of lexemes at index ${index}`);
|
51
|
+
}
|
52
|
+
const current = lexemes[idx];
|
53
|
+
if (current.type === TokenType.Identifier) {
|
54
|
+
return IdentifierParser.parseFromLexeme(lexemes, idx);
|
55
|
+
}
|
56
|
+
else if (current.type === TokenType.Literal) {
|
57
|
+
return LiteralParser.parseFromLexeme(lexemes, idx);
|
58
|
+
}
|
59
|
+
else if (current.type === TokenType.OpenParen) {
|
60
|
+
return ParenExpressionParser.parseFromLexeme(lexemes, idx);
|
61
|
+
}
|
62
|
+
else if (current.type === TokenType.Function) {
|
63
|
+
return FunctionExpressionParser.parseFromLexeme(lexemes, idx);
|
64
|
+
}
|
65
|
+
else if (current.type === TokenType.Operator) {
|
66
|
+
return UnaryExpressionParser.parseFromLexeme(lexemes, idx);
|
67
|
+
}
|
68
|
+
else if (current.type === TokenType.Parameter) {
|
69
|
+
return ParameterExpressionParser.parseFromLexeme(lexemes, idx);
|
70
|
+
}
|
71
|
+
else if (current.type === TokenType.StringSpecifier) {
|
72
|
+
return StringSpecifierExpressionParser.parseFromLexeme(lexemes, idx);
|
73
|
+
}
|
74
|
+
else if (current.type === TokenType.Command) {
|
75
|
+
return CommandExpressionParser.parseFromLexeme(lexemes, idx);
|
76
|
+
}
|
77
|
+
throw new Error(`Invalid lexeme. index: ${idx}, type: ${lexemes[idx].type}, value: ${lexemes[idx].value}`);
|
78
|
+
}
|
79
|
+
static parseArgument(openToken, closeToken, lexemes, index) {
|
80
|
+
let idx = index;
|
81
|
+
const args = [];
|
82
|
+
// Check for opening parenthesis
|
83
|
+
if (idx < lexemes.length && lexemes[idx].type === openToken) {
|
84
|
+
idx++;
|
85
|
+
if (idx < lexemes.length && lexemes[idx].type === closeToken) {
|
86
|
+
// If there are no arguments, return an empty ValueList
|
87
|
+
idx++;
|
88
|
+
return { value: new ValueList([]), newIndex: idx };
|
89
|
+
}
|
90
|
+
// If the next element is `*`, treat `*` as an Identifier
|
91
|
+
if (idx < lexemes.length && lexemes[idx].value === "*") {
|
92
|
+
const wildcard = new ColumnReference(null, "*");
|
93
|
+
idx++;
|
94
|
+
// The next element must be closeToken
|
95
|
+
if (idx < lexemes.length && lexemes[idx].type === closeToken) {
|
96
|
+
idx++;
|
97
|
+
return { value: wildcard, newIndex: idx };
|
98
|
+
}
|
99
|
+
else {
|
100
|
+
throw new Error(`Expected closing parenthesis at index ${idx}`);
|
101
|
+
}
|
102
|
+
}
|
103
|
+
// Parse the value inside
|
104
|
+
const result = this.parseFromLexeme(lexemes, idx);
|
105
|
+
idx = result.newIndex;
|
106
|
+
args.push(result.value);
|
107
|
+
// Continue reading if the next element is a comma
|
108
|
+
while (idx < lexemes.length && lexemes[idx].type === TokenType.Comma) {
|
109
|
+
idx++;
|
110
|
+
const argResult = this.parseFromLexeme(lexemes, idx);
|
111
|
+
idx = argResult.newIndex;
|
112
|
+
args.push(argResult.value);
|
113
|
+
}
|
114
|
+
// Check for closing parenthesis
|
115
|
+
if (idx < lexemes.length && lexemes[idx].type === closeToken) {
|
116
|
+
idx++;
|
117
|
+
if (args.length === 1) {
|
118
|
+
// Return as is if there is only one argument
|
119
|
+
return { value: args[0], newIndex: idx };
|
120
|
+
}
|
121
|
+
// Create ValueCollection if there are multiple arguments
|
122
|
+
const value = new ValueList(args);
|
123
|
+
return { value, newIndex: idx };
|
124
|
+
}
|
125
|
+
else {
|
126
|
+
throw new Error(`Missing closing parenthesis at index ${idx}`);
|
127
|
+
}
|
128
|
+
}
|
129
|
+
throw new Error(`Expected opening parenthesis at index ${index}`);
|
130
|
+
}
|
131
|
+
}
|
132
|
+
//# sourceMappingURL=ValueParser.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"ValueParser.js","sourceRoot":"","sources":["../../../src/parsers/ValueParser.ts"],"names":[],"mappings":"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"}
|
@@ -0,0 +1,82 @@
|
|
1
|
+
import { TokenType } from "../models/Lexeme";
|
2
|
+
import { ValuesQuery } from "../models/SelectQuery";
|
3
|
+
import { TupleExpression } from "../models/ValueComponent";
|
4
|
+
import { SqlTokenizer } from "./SqlTokenizer";
|
5
|
+
import { ValueParser } from "./ValueParser";
|
6
|
+
export class ValuesQueryParser {
|
7
|
+
static parse(query) {
|
8
|
+
const tokenizer = new SqlTokenizer(query); // Initialize tokenizer
|
9
|
+
const lexemes = tokenizer.readLexmes(); // Get tokens
|
10
|
+
// Parse
|
11
|
+
const result = this.parseFromLexeme(lexemes, 0);
|
12
|
+
// Error if there are remaining tokens
|
13
|
+
if (result.newIndex < lexemes.length) {
|
14
|
+
throw new Error(`Syntax error: Unexpected token "${lexemes[result.newIndex].value}" at position ${result.newIndex}. The VALUES clause is complete but there are additional tokens.`);
|
15
|
+
}
|
16
|
+
return result.value;
|
17
|
+
}
|
18
|
+
static parseFromLexeme(lexemes, index) {
|
19
|
+
let idx = index;
|
20
|
+
if (lexemes[idx].value.toLowerCase() !== 'values') {
|
21
|
+
throw new Error(`Syntax error at position ${idx}: Expected 'VALUES' keyword but found "${lexemes[idx].value}". VALUES clauses must start with the VALUES keyword.`);
|
22
|
+
}
|
23
|
+
idx++;
|
24
|
+
if (idx >= lexemes.length) {
|
25
|
+
throw new Error(`Syntax error: Unexpected end of input after 'VALUES' keyword. The VALUES clause requires at least one tuple expression.`);
|
26
|
+
}
|
27
|
+
const tuples = [];
|
28
|
+
// Parse the first tuple
|
29
|
+
const firstTuple = this.parseTuple(lexemes, idx);
|
30
|
+
tuples.push(firstTuple.value);
|
31
|
+
idx = firstTuple.newIndex;
|
32
|
+
// Parse additional tuples if they exist
|
33
|
+
while (idx < lexemes.length && lexemes[idx].type === TokenType.Comma) {
|
34
|
+
idx++; // Skip comma
|
35
|
+
const tuple = this.parseTuple(lexemes, idx);
|
36
|
+
tuples.push(tuple.value);
|
37
|
+
idx = tuple.newIndex;
|
38
|
+
}
|
39
|
+
const query = new ValuesQuery(tuples);
|
40
|
+
return { value: query, newIndex: idx };
|
41
|
+
}
|
42
|
+
static parseTuple(lexemes, index) {
|
43
|
+
let idx = index;
|
44
|
+
// Check for opening parenthesis
|
45
|
+
if (idx >= lexemes.length || lexemes[idx].type !== TokenType.OpenParen) {
|
46
|
+
throw new Error(`Syntax error at position ${idx}: Expected opening parenthesis but found "${idx < lexemes.length ? lexemes[idx].value : "end of input"}". Tuple expressions in VALUES clause must be enclosed in parentheses.`);
|
47
|
+
}
|
48
|
+
idx++;
|
49
|
+
// Parse values inside the tuple
|
50
|
+
const values = [];
|
51
|
+
// Parse first value
|
52
|
+
if (idx >= lexemes.length) {
|
53
|
+
throw new Error(`Syntax error: Unexpected end of input after opening parenthesis in tuple expression.`);
|
54
|
+
}
|
55
|
+
// Check for empty tuple case
|
56
|
+
if (lexemes[idx].type === TokenType.CloseParen) {
|
57
|
+
idx++; // Skip closing parenthesis
|
58
|
+
return { value: new TupleExpression([]), newIndex: idx };
|
59
|
+
}
|
60
|
+
// Parse the first value
|
61
|
+
const firstValue = ValueParser.parseFromLexeme(lexemes, idx);
|
62
|
+
values.push(firstValue.value);
|
63
|
+
idx = firstValue.newIndex;
|
64
|
+
// Parse additional values
|
65
|
+
while (idx < lexemes.length && lexemes[idx].type === TokenType.Comma) {
|
66
|
+
idx++; // Skip comma
|
67
|
+
if (idx >= lexemes.length) {
|
68
|
+
throw new Error(`Syntax error: Unexpected end of input after comma in tuple expression.`);
|
69
|
+
}
|
70
|
+
const value = ValueParser.parseFromLexeme(lexemes, idx);
|
71
|
+
values.push(value.value);
|
72
|
+
idx = value.newIndex;
|
73
|
+
}
|
74
|
+
// Check for closing parenthesis
|
75
|
+
if (idx >= lexemes.length || lexemes[idx].type !== TokenType.CloseParen) {
|
76
|
+
throw new Error(`Syntax error at position ${idx}: Expected closing parenthesis but found "${idx < lexemes.length ? lexemes[idx].value : "end of input"}". Tuple expressions in VALUES clause must be enclosed in parentheses.`);
|
77
|
+
}
|
78
|
+
idx++; // Skip closing parenthesis
|
79
|
+
return { value: new TupleExpression(values), newIndex: idx };
|
80
|
+
}
|
81
|
+
}
|
82
|
+
//# sourceMappingURL=ValuesQueryParser.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"ValuesQueryParser.js","sourceRoot":"","sources":["../../../src/parsers/ValuesQueryParser.ts"],"names":[],"mappings":"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"}
|
@@ -0,0 +1,32 @@
|
|
1
|
+
import { WhereClause } from "../models/Clause";
|
2
|
+
import { SqlTokenizer } from "./SqlTokenizer";
|
3
|
+
import { ValueParser } from "./ValueParser";
|
4
|
+
export class WhereClauseParser {
|
5
|
+
// Parse SQL string to AST (was: parse)
|
6
|
+
static parse(query) {
|
7
|
+
const tokenizer = new SqlTokenizer(query); // Initialize tokenizer
|
8
|
+
const lexemes = tokenizer.readLexmes(); // Get tokens
|
9
|
+
// Parse
|
10
|
+
const result = this.parseFromLexeme(lexemes, 0);
|
11
|
+
// Error if there are remaining tokens
|
12
|
+
if (result.newIndex < lexemes.length) {
|
13
|
+
throw new Error(`Syntax error: Unexpected token "${lexemes[result.newIndex].value}" at position ${result.newIndex}. The WHERE clause is complete but there are additional tokens.`);
|
14
|
+
}
|
15
|
+
return result.value;
|
16
|
+
}
|
17
|
+
// Parse from lexeme array (was: parse)
|
18
|
+
static parseFromLexeme(lexemes, index) {
|
19
|
+
let idx = index;
|
20
|
+
if (lexemes[idx].value !== 'where') {
|
21
|
+
throw new Error(`Syntax error at position ${idx}: Expected 'WHERE' keyword but found "${lexemes[idx].value}". WHERE clauses must start with the WHERE keyword.`);
|
22
|
+
}
|
23
|
+
idx++;
|
24
|
+
if (idx >= lexemes.length) {
|
25
|
+
throw new Error(`Syntax error: Unexpected end of input after 'WHERE' keyword. The WHERE clause requires a condition expression.`);
|
26
|
+
}
|
27
|
+
const item = ValueParser.parseFromLexeme(lexemes, idx);
|
28
|
+
const clause = new WhereClause(item.value);
|
29
|
+
return { value: clause, newIndex: item.newIndex };
|
30
|
+
}
|
31
|
+
}
|
32
|
+
//# sourceMappingURL=WhereClauseParser.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"WhereClauseParser.js","sourceRoot":"","sources":["../../../src/parsers/WhereClauseParser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,MAAM,OAAO,iBAAiB;IAC1B,uCAAuC;IAChC,MAAM,CAAC,KAAK,CAAC,KAAa;QAC7B,MAAM,SAAS,GAAG,IAAI,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,uBAAuB;QAClE,MAAM,OAAO,GAAG,SAAS,CAAC,UAAU,EAAE,CAAC,CAAC,aAAa;QAErD,QAAQ;QACR,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAEhD,sCAAsC;QACtC,IAAI,MAAM,CAAC,QAAQ,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,mCAAmC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,iBAAiB,MAAM,CAAC,QAAQ,iEAAiE,CAAC,CAAC;QACxL,CAAC;QAED,OAAO,MAAM,CAAC,KAAK,CAAC;IACxB,CAAC;IAED,uCAAuC;IAChC,MAAM,CAAC,eAAe,CAAC,OAAiB,EAAE,KAAa;QAC1D,IAAI,GAAG,GAAG,KAAK,CAAC;QAEhB,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,KAAK,OAAO,EAAE,CAAC;YACjC,MAAM,IAAI,KAAK,CAAC,4BAA4B,GAAG,yCAAyC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,qDAAqD,CAAC,CAAC;QACrK,CAAC;QACD,GAAG,EAAE,CAAC;QAEN,IAAI,GAAG,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,gHAAgH,CAAC,CAAC;QACtI,CAAC;QAED,MAAM,IAAI,GAAG,WAAW,CAAC,eAAe,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACvD,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAE3C,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;IACtD,CAAC;CACJ"}
|
@@ -0,0 +1,41 @@
|
|
1
|
+
import { WindowFrameClause } from "../models/Clause";
|
2
|
+
import { TokenType } from "../models/Lexeme";
|
3
|
+
import { SqlTokenizer } from "./SqlTokenizer";
|
4
|
+
import { WindowExpressionParser } from "./WindowExpressionParser";
|
5
|
+
export class WindowClauseParser {
|
6
|
+
// Parse SQL string to AST (was: parse)
|
7
|
+
static parse(query) {
|
8
|
+
const tokenizer = new SqlTokenizer(query);
|
9
|
+
const lexemes = tokenizer.readLexmes();
|
10
|
+
// Parse
|
11
|
+
const result = this.parseFromLexeme(lexemes, 0);
|
12
|
+
// Error if there are remaining tokens
|
13
|
+
if (result.newIndex < lexemes.length) {
|
14
|
+
throw new Error(`Syntax error: Unexpected token "${lexemes[result.newIndex].value}" at position ${result.newIndex}. The WINDOW clause is complete but there are additional tokens.`);
|
15
|
+
}
|
16
|
+
return result.value;
|
17
|
+
}
|
18
|
+
// Parse from lexeme array (was: parse)
|
19
|
+
static parseFromLexeme(lexemes, index) {
|
20
|
+
let idx = index;
|
21
|
+
if (lexemes[idx].value !== 'window') {
|
22
|
+
throw new Error(`Syntax error at position ${idx}: Expected 'WINDOW' keyword but found "${lexemes[idx].value}". WINDOW clauses must start with the WINDOW keyword.`);
|
23
|
+
}
|
24
|
+
idx++;
|
25
|
+
if (idx >= lexemes.length || lexemes[idx].type !== TokenType.Identifier) {
|
26
|
+
throw new Error(`Syntax error: Expected window name after 'WINDOW' keyword.`);
|
27
|
+
}
|
28
|
+
// Get the window name
|
29
|
+
const name = lexemes[idx].value;
|
30
|
+
idx++;
|
31
|
+
if (idx >= lexemes.length || lexemes[idx].value !== 'as') {
|
32
|
+
throw new Error(`Syntax error at position ${idx}: Expected 'AS' keyword after window name.`);
|
33
|
+
}
|
34
|
+
idx++;
|
35
|
+
const expr = WindowExpressionParser.parseFromLexeme(lexemes, idx);
|
36
|
+
idx = expr.newIndex;
|
37
|
+
const windowFrame = new WindowFrameClause(name, expr.value);
|
38
|
+
return { value: windowFrame, newIndex: idx };
|
39
|
+
}
|
40
|
+
}
|
41
|
+
//# sourceMappingURL=WindowClauseParser.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"WindowClauseParser.js","sourceRoot":"","sources":["../../../src/parsers/WindowClauseParser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAU,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAElE,MAAM,OAAO,kBAAkB;IAC3B,uCAAuC;IAChC,MAAM,CAAC,KAAK,CAAC,KAAa;QAC7B,MAAM,SAAS,GAAG,IAAI,YAAY,CAAC,KAAK,CAAC,CAAC;QAC1C,MAAM,OAAO,GAAG,SAAS,CAAC,UAAU,EAAE,CAAC;QAEvC,QAAQ;QACR,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAEhD,sCAAsC;QACtC,IAAI,MAAM,CAAC,QAAQ,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,mCAAmC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,iBAAiB,MAAM,CAAC,QAAQ,kEAAkE,CAAC,CAAC;QACzL,CAAC;QAED,OAAO,MAAM,CAAC,KAAK,CAAC;IACxB,CAAC;IAED,uCAAuC;IAChC,MAAM,CAAC,eAAe,CAAC,OAAiB,EAAE,KAAa;QAC1D,IAAI,GAAG,GAAG,KAAK,CAAC;QAEhB,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;YAClC,MAAM,IAAI,KAAK,CAAC,4BAA4B,GAAG,0CAA0C,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,uDAAuD,CAAC,CAAC;QACxK,CAAC;QACD,GAAG,EAAE,CAAC;QAEN,IAAI,GAAG,IAAI,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,UAAU,EAAE,CAAC;YACtE,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;QAClF,CAAC;QAED,sBAAsB;QACtB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;QAChC,GAAG,EAAE,CAAC;QAEN,IAAI,GAAG,IAAI,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YACvD,MAAM,IAAI,KAAK,CAAC,4BAA4B,GAAG,4CAA4C,CAAC,CAAC;QACjG,CAAC;QACD,GAAG,EAAE,CAAC;QAEN,MAAM,IAAI,GAAG,sBAAsB,CAAC,eAAe,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAClE,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC;QAEpB,MAAM,WAAW,GAAG,IAAI,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5D,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;IACjD,CAAC;CACJ"}
|
@@ -0,0 +1,159 @@
|
|
1
|
+
import { TokenType } from "../models/Lexeme";
|
2
|
+
import { WindowFrameBound, WindowFrameBoundaryValue, WindowFrameExpression, WindowFrameSpec, WindowFrameType, WindowFrameBoundStatic } from "../models/ValueComponent";
|
3
|
+
import { OrderByClauseParser } from "./OrderByClauseParser";
|
4
|
+
import { PartitionByParser } from "./PartitionByParser";
|
5
|
+
import { SqlTokenizer } from "./SqlTokenizer";
|
6
|
+
import { ValueParser } from "./ValueParser";
|
7
|
+
export class WindowExpressionParser {
|
8
|
+
// Parse SQL string to AST (was: parse)
|
9
|
+
static parse(query) {
|
10
|
+
const tokenizer = new SqlTokenizer(query); // Initialize tokenizer
|
11
|
+
const lexemes = tokenizer.readLexmes(); // Get tokens
|
12
|
+
// Parse
|
13
|
+
const result = this.parseFromLexeme(lexemes, 0);
|
14
|
+
// Error if there are remaining tokens
|
15
|
+
if (result.newIndex < lexemes.length) {
|
16
|
+
throw new Error(`Syntax error: Unexpected token "${lexemes[result.newIndex].value}" at position ${result.newIndex}. The window frame expression is complete but there are additional tokens.`);
|
17
|
+
}
|
18
|
+
return result.value;
|
19
|
+
}
|
20
|
+
// Parse from lexeme array (was: parse)
|
21
|
+
static parseFromLexeme(lexemes, index) {
|
22
|
+
let idx = index;
|
23
|
+
if (lexemes[idx].type !== TokenType.OpenParen) {
|
24
|
+
throw new Error(`Syntax error at position ${idx}: Expected opening parenthesis '(' but found "${lexemes[idx].value}".`);
|
25
|
+
}
|
26
|
+
idx++;
|
27
|
+
let partition = null;
|
28
|
+
let order = null;
|
29
|
+
let frameSpec = null;
|
30
|
+
if (idx < lexemes.length && lexemes[idx].value === 'partition by') {
|
31
|
+
const partitionResult = PartitionByParser.parseFromLexeme(lexemes, idx);
|
32
|
+
partition = partitionResult.value;
|
33
|
+
idx = partitionResult.newIndex;
|
34
|
+
}
|
35
|
+
if (idx < lexemes.length && lexemes[idx].value === 'order by') {
|
36
|
+
const orderResult = OrderByClauseParser.parseFromLexeme(lexemes, idx);
|
37
|
+
order = orderResult.value;
|
38
|
+
idx = orderResult.newIndex;
|
39
|
+
}
|
40
|
+
// Parse frame clause (ROWS/RANGE/GROUPS)
|
41
|
+
if (idx < lexemes.length && this.isFrameTypeKeyword(lexemes[idx].value)) {
|
42
|
+
const frameSpecResult = this.parseFrameSpec(lexemes, idx);
|
43
|
+
frameSpec = frameSpecResult.value;
|
44
|
+
idx = frameSpecResult.newIndex;
|
45
|
+
}
|
46
|
+
if (idx >= lexemes.length || lexemes[idx].type !== TokenType.CloseParen) {
|
47
|
+
throw new Error(`Syntax error at position ${idx}: Missing closing parenthesis ')' for window frame. Each opening parenthesis must have a matching closing parenthesis.`);
|
48
|
+
}
|
49
|
+
// Read close paren
|
50
|
+
idx++;
|
51
|
+
return { value: new WindowFrameExpression(partition, order, frameSpec), newIndex: idx };
|
52
|
+
}
|
53
|
+
static isFrameTypeKeyword(value) {
|
54
|
+
const lowerValue = value;
|
55
|
+
return lowerValue === 'rows' || lowerValue === 'range' || lowerValue === 'groups';
|
56
|
+
}
|
57
|
+
static parseFrameSpec(lexemes, index) {
|
58
|
+
let idx = index;
|
59
|
+
// Determine frame type (ROWS/RANGE/GROUPS)
|
60
|
+
const frameTypeStr = lexemes[idx].value;
|
61
|
+
let frameType;
|
62
|
+
switch (frameTypeStr) {
|
63
|
+
case 'rows':
|
64
|
+
frameType = WindowFrameType.Rows;
|
65
|
+
break;
|
66
|
+
case 'range':
|
67
|
+
frameType = WindowFrameType.Range;
|
68
|
+
break;
|
69
|
+
case 'groups':
|
70
|
+
frameType = WindowFrameType.Groups;
|
71
|
+
break;
|
72
|
+
default:
|
73
|
+
throw new Error(`Syntax error at position ${idx}: Invalid frame type "${lexemes[idx].value}". Expected one of: ROWS, RANGE, GROUPS.`);
|
74
|
+
}
|
75
|
+
idx++;
|
76
|
+
// Check for BETWEEN ... AND ... syntax
|
77
|
+
if (idx < lexemes.length && lexemes[idx].value === 'between') {
|
78
|
+
// BETWEEN ... AND ... syntax
|
79
|
+
idx++;
|
80
|
+
// Parse start boundary
|
81
|
+
const startBoundResult = this.parseFrameBoundary(lexemes, idx);
|
82
|
+
const startBound = startBoundResult.value;
|
83
|
+
idx = startBoundResult.newIndex;
|
84
|
+
// Check for AND keyword - may be recognized as a separate token or part of a compound token
|
85
|
+
if (idx >= lexemes.length || (lexemes[idx].value !== 'and')) {
|
86
|
+
throw new Error(`Syntax error at position ${idx}: Expected 'AND' keyword in BETWEEN clause.`);
|
87
|
+
}
|
88
|
+
idx++; // Skip AND
|
89
|
+
// Parse end boundary
|
90
|
+
const endBoundResult = this.parseFrameBoundary(lexemes, idx);
|
91
|
+
const endBound = endBoundResult.value;
|
92
|
+
idx = endBoundResult.newIndex;
|
93
|
+
return {
|
94
|
+
value: new WindowFrameSpec(frameType, startBound, endBound),
|
95
|
+
newIndex: idx
|
96
|
+
};
|
97
|
+
}
|
98
|
+
else {
|
99
|
+
// Single boundary specification
|
100
|
+
const boundaryResult = this.parseFrameBoundary(lexemes, idx);
|
101
|
+
const startBound = boundaryResult.value;
|
102
|
+
idx = boundaryResult.newIndex;
|
103
|
+
return {
|
104
|
+
value: new WindowFrameSpec(frameType, startBound, null),
|
105
|
+
newIndex: idx
|
106
|
+
};
|
107
|
+
}
|
108
|
+
}
|
109
|
+
static parseFrameBoundary(lexemes, index) {
|
110
|
+
let idx = index;
|
111
|
+
// Check for predefined boundaries
|
112
|
+
if (idx < lexemes.length && lexemes[idx].type === TokenType.Command) {
|
113
|
+
const currentValue = lexemes[idx].value;
|
114
|
+
let frameBound;
|
115
|
+
switch (currentValue) {
|
116
|
+
case 'current row':
|
117
|
+
frameBound = WindowFrameBound.CurrentRow;
|
118
|
+
break;
|
119
|
+
case 'unbounded preceding':
|
120
|
+
frameBound = WindowFrameBound.UnboundedPreceding;
|
121
|
+
break;
|
122
|
+
case 'unbounded following':
|
123
|
+
frameBound = WindowFrameBound.UnboundedFollowing;
|
124
|
+
break;
|
125
|
+
default:
|
126
|
+
throw new Error(`Syntax error at position ${idx}: Invalid frame type "${lexemes[idx].value}". Expected one of: ROWS, RANGE, GROUPS.`);
|
127
|
+
}
|
128
|
+
const bound = new WindowFrameBoundStatic(frameBound);
|
129
|
+
return { value: bound, newIndex: idx + 1 };
|
130
|
+
}
|
131
|
+
else if (idx < lexemes.length && lexemes[idx].type === TokenType.Literal) {
|
132
|
+
// Parse the numeric/literal value
|
133
|
+
const valueResult = ValueParser.parseFromLexeme(lexemes, idx);
|
134
|
+
idx = valueResult.newIndex;
|
135
|
+
// Next token must be 'preceding' or 'following'
|
136
|
+
if (idx < lexemes.length && lexemes[idx].type === TokenType.Command) {
|
137
|
+
const direction = lexemes[idx].value;
|
138
|
+
let isFollowing;
|
139
|
+
if (direction === 'preceding') {
|
140
|
+
isFollowing = false;
|
141
|
+
}
|
142
|
+
else if (direction === 'following') {
|
143
|
+
isFollowing = true;
|
144
|
+
}
|
145
|
+
else {
|
146
|
+
throw new Error(`Syntax error at position ${idx}: Expected 'preceding' or 'following' after numeric value in window frame boundary.`);
|
147
|
+
}
|
148
|
+
idx++;
|
149
|
+
const bound = new WindowFrameBoundaryValue(valueResult.value, isFollowing);
|
150
|
+
return { value: bound, newIndex: idx };
|
151
|
+
}
|
152
|
+
else {
|
153
|
+
throw new Error(`Syntax error at position ${idx}: Expected 'preceding' or 'following' after numeric value in window frame boundary.`);
|
154
|
+
}
|
155
|
+
}
|
156
|
+
throw new Error(`Syntax error at position ${idx}: Expected a valid frame boundary component.`);
|
157
|
+
}
|
158
|
+
}
|
159
|
+
//# sourceMappingURL=WindowExpressionParser.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"WindowExpressionParser.js","sourceRoot":"","sources":["../../../src/parsers/WindowExpressionParser.ts"],"names":[],"mappings":"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"}
|
@@ -0,0 +1,53 @@
|
|
1
|
+
import { WithClause } from "../models/Clause";
|
2
|
+
import { TokenType } from "../models/Lexeme";
|
3
|
+
import { SqlTokenizer } from "./SqlTokenizer";
|
4
|
+
import { CommonTableParser } from "./CommonTableParser";
|
5
|
+
export class WithClauseParser {
|
6
|
+
// Parse SQL string to AST (was: parse)
|
7
|
+
static parse(query) {
|
8
|
+
const tokenizer = new SqlTokenizer(query); // Initialize tokenizer
|
9
|
+
const lexemes = tokenizer.readLexmes(); // Get tokens
|
10
|
+
// Parse
|
11
|
+
const result = this.parseFromLexeme(lexemes, 0);
|
12
|
+
// Error if there are remaining tokens
|
13
|
+
if (result.newIndex < lexemes.length) {
|
14
|
+
throw new Error(`Syntax error: Unexpected token "${lexemes[result.newIndex].value}" at position ${result.newIndex}. The WITH clause is complete but there are additional tokens.`);
|
15
|
+
}
|
16
|
+
return result.value;
|
17
|
+
}
|
18
|
+
// Parse from lexeme array (was: parse)
|
19
|
+
static parseFromLexeme(lexemes, index) {
|
20
|
+
let idx = index;
|
21
|
+
// Expect WITH keyword
|
22
|
+
if (idx < lexemes.length && lexemes[idx].value.toLowerCase() === "with") {
|
23
|
+
idx++;
|
24
|
+
}
|
25
|
+
else {
|
26
|
+
throw new Error(`Syntax error at position ${idx}: Expected WITH keyword.`);
|
27
|
+
}
|
28
|
+
// Check for RECURSIVE keyword
|
29
|
+
const recursive = idx < lexemes.length && lexemes[idx].value.toLowerCase() === "recursive";
|
30
|
+
if (recursive) {
|
31
|
+
idx++;
|
32
|
+
}
|
33
|
+
// Parse CTEs
|
34
|
+
const tables = [];
|
35
|
+
// Parse first CTE (required)
|
36
|
+
const firstCte = CommonTableParser.parseFromLexeme(lexemes, idx);
|
37
|
+
tables.push(firstCte.value);
|
38
|
+
idx = firstCte.newIndex;
|
39
|
+
// Parse additional CTEs (optional)
|
40
|
+
while (idx < lexemes.length && lexemes[idx].type === TokenType.Comma) {
|
41
|
+
idx++; // Skip comma
|
42
|
+
const cteResult = CommonTableParser.parseFromLexeme(lexemes, idx);
|
43
|
+
tables.push(cteResult.value);
|
44
|
+
idx = cteResult.newIndex;
|
45
|
+
}
|
46
|
+
// Create WITH clause
|
47
|
+
return {
|
48
|
+
value: new WithClause(recursive, tables),
|
49
|
+
newIndex: idx
|
50
|
+
};
|
51
|
+
}
|
52
|
+
}
|
53
|
+
//# sourceMappingURL=WithClauseParser.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"WithClauseParser.js","sourceRoot":"","sources":["../../../src/parsers/WithClauseParser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAU,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,MAAM,OAAO,gBAAgB;IACzB,uCAAuC;IAChC,MAAM,CAAC,KAAK,CAAC,KAAa;QAC7B,MAAM,SAAS,GAAG,IAAI,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,uBAAuB;QAClE,MAAM,OAAO,GAAG,SAAS,CAAC,UAAU,EAAE,CAAC,CAAC,aAAa;QAErD,QAAQ;QACR,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAEhD,sCAAsC;QACtC,IAAI,MAAM,CAAC,QAAQ,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,mCAAmC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,iBAAiB,MAAM,CAAC,QAAQ,gEAAgE,CAAC,CAAC;QACvL,CAAC;QAED,OAAO,MAAM,CAAC,KAAK,CAAC;IACxB,CAAC;IAED,uCAAuC;IAChC,MAAM,CAAC,eAAe,CAAC,OAAiB,EAAE,KAAa;QAC1D,IAAI,GAAG,GAAG,KAAK,CAAC;QAEhB,sBAAsB;QACtB,IAAI,GAAG,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,MAAM,EAAE,CAAC;YACtE,GAAG,EAAE,CAAC;QACV,CAAC;aAAM,CAAC;YACJ,MAAM,IAAI,KAAK,CAAC,4BAA4B,GAAG,0BAA0B,CAAC,CAAC;QAC/E,CAAC;QAED,8BAA8B;QAC9B,MAAM,SAAS,GAAG,GAAG,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,WAAW,CAAC;QAC3F,IAAI,SAAS,EAAE,CAAC;YACZ,GAAG,EAAE,CAAC;QACV,CAAC;QAED,aAAa;QACb,MAAM,MAAM,GAAkB,EAAE,CAAC;QAEjC,6BAA6B;QAC7B,MAAM,QAAQ,GAAG,iBAAiB,CAAC,eAAe,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACjE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC5B,GAAG,GAAG,QAAQ,CAAC,QAAQ,CAAC;QAExB,mCAAmC;QACnC,OAAO,GAAG,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,KAAK,EAAE,CAAC;YACnE,GAAG,EAAE,CAAC,CAAC,aAAa;YACpB,MAAM,SAAS,GAAG,iBAAiB,CAAC,eAAe,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;YAClE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YAC7B,GAAG,GAAG,SAAS,CAAC,QAAQ,CAAC;QAC7B,CAAC;QAED,qBAAqB;QACrB,OAAO;YACH,KAAK,EAAE,IAAI,UAAU,CAAC,SAAS,EAAE,MAAM,CAAC;YACxC,QAAQ,EAAE,GAAG;SAChB,CAAC;IACN,CAAC;CACJ"}
|
@@ -0,0 +1,78 @@
|
|
1
|
+
import { TokenType } from '../models/Lexeme';
|
2
|
+
import { StringUtils } from '../utils/stringUtils';
|
3
|
+
/**
|
4
|
+
* Base class for token readers
|
5
|
+
*/
|
6
|
+
export class BaseTokenReader {
|
7
|
+
constructor(input, position = 0) {
|
8
|
+
this.input = input;
|
9
|
+
this.position = position;
|
10
|
+
}
|
11
|
+
/**
|
12
|
+
* Get the current position in the input
|
13
|
+
*/
|
14
|
+
getPosition() {
|
15
|
+
return this.position;
|
16
|
+
}
|
17
|
+
/**
|
18
|
+
* Set the position in the input
|
19
|
+
*/
|
20
|
+
setPosition(position) {
|
21
|
+
this.position = position;
|
22
|
+
}
|
23
|
+
/**
|
24
|
+
* Check if we've reached the end of input
|
25
|
+
*/
|
26
|
+
isEndOfInput(shift = 0) {
|
27
|
+
return this.position + shift >= this.input.length;
|
28
|
+
}
|
29
|
+
/**
|
30
|
+
* Check if we can read more characters
|
31
|
+
*/
|
32
|
+
canRead(shift = 0) {
|
33
|
+
return !this.isEndOfInput(shift);
|
34
|
+
}
|
35
|
+
/**
|
36
|
+
* Read an expected character
|
37
|
+
*/
|
38
|
+
read(expectChar) {
|
39
|
+
if (this.isEndOfInput()) {
|
40
|
+
throw new Error(`Unexpected character. expect: ${expectChar}, actual: EndOfInput, position: ${this.position}`);
|
41
|
+
}
|
42
|
+
if (this.input[this.position] !== expectChar) {
|
43
|
+
throw new Error(`Unexpected character. expect: ${expectChar}, actual: ${this.input[this.position]}, position: ${this.position}`);
|
44
|
+
}
|
45
|
+
const char = this.input[this.position];
|
46
|
+
this.position++;
|
47
|
+
return char;
|
48
|
+
}
|
49
|
+
/**
|
50
|
+
* Create a lexeme with the specified type and value
|
51
|
+
*/
|
52
|
+
createLexeme(type, value, maybeType = null, comments = null) {
|
53
|
+
if (type === TokenType.Command || type === TokenType.Operator || type === TokenType.Function) {
|
54
|
+
// Benchmark tests showed that directly calling toLowerCase() is ~5x faster
|
55
|
+
// than first checking if the string is already lowercase.
|
56
|
+
// See benchmarks/lowercase-benchmark.js for detailed performance analysis.
|
57
|
+
return {
|
58
|
+
type,
|
59
|
+
value: value.toLowerCase(),
|
60
|
+
comments: comments,
|
61
|
+
maybeType: maybeType,
|
62
|
+
};
|
63
|
+
}
|
64
|
+
return {
|
65
|
+
type,
|
66
|
+
value,
|
67
|
+
comments: comments,
|
68
|
+
maybeType: maybeType,
|
69
|
+
};
|
70
|
+
}
|
71
|
+
/**
|
72
|
+
* Get debug info for error reporting
|
73
|
+
*/
|
74
|
+
getDebugPositionInfo(errPosition) {
|
75
|
+
return StringUtils.getDebugPositionInfo(this.input, errPosition);
|
76
|
+
}
|
77
|
+
}
|
78
|
+
//# sourceMappingURL=BaseTokenReader.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"BaseTokenReader.js","sourceRoot":"","sources":["../../../src/tokenReaders/BaseTokenReader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD;;GAEG;AACH,MAAM,OAAgB,eAAe;IAIjC,YAAY,KAAa,EAAE,WAAmB,CAAC;QAC3C,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC7B,CAAC;IAED;;OAEG;IACI,WAAW;QACd,OAAO,IAAI,CAAC,QAAQ,CAAC;IACzB,CAAC;IAED;;OAEG;IACI,WAAW,CAAC,QAAgB;QAC/B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC7B,CAAC;IAED;;OAEG;IACO,YAAY,CAAC,QAAgB,CAAC;QACpC,OAAO,IAAI,CAAC,QAAQ,GAAG,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;IACtD,CAAC;IAED;;OAEG;IACO,OAAO,CAAC,QAAgB,CAAC;QAC/B,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IACrC,CAAC;IAED;;OAEG;IACO,IAAI,CAAC,UAAkB;QAC7B,IAAI,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,iCAAiC,UAAU,mCAAmC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QACnH,CAAC;QAED,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,UAAU,EAAE,CAAC;YAC3C,MAAM,IAAI,KAAK,CAAC,iCAAiC,UAAU,aAAa,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,eAAe,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QACrI,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvC,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChB,OAAO,IAAI,CAAC;IAChB,CAAC;IAED;;OAEG;IACO,YAAY,CAAC,IAAe,EAAE,KAAa,EAAE,YAA4B,IAAI,EAAE,WAA4B,IAAI;QACrH,IAAI,IAAI,KAAK,SAAS,CAAC,OAAO,IAAI,IAAI,KAAK,SAAS,CAAC,QAAQ,IAAI,IAAI,KAAK,SAAS,CAAC,QAAQ,EAAE,CAAC;YAC3F,2EAA2E;YAC3E,0DAA0D;YAC1D,2EAA2E;YAC3E,OAAO;gBACH,IAAI;gBACJ,KAAK,EAAE,KAAK,CAAC,WAAW,EAAE;gBAC1B,QAAQ,EAAE,QAAQ;gBAClB,SAAS,EAAE,SAAS;aACvB,CAAC;QACN,CAAC;QACD,OAAO;YACH,IAAI;YACJ,KAAK;YACL,QAAQ,EAAE,QAAQ;YAClB,SAAS,EAAE,SAAS;SACvB,CAAC;IACN,CAAC;IAED;;OAEG;IACO,oBAAoB,CAAC,WAAmB;QAC9C,OAAO,WAAW,CAAC,oBAAoB,CAAC,IAAI,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;IACrE,CAAC;CAQJ"}
|