rawsql-ts 0.1.0-beta.9 → 0.1.1-beta.2
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 +214 -176
- 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 +384 -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 +318 -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 +82 -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 +72 -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/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/transformers/CTECollector.d.ts +2 -1
- package/dist/transformers/CTECollector.js +5 -1
- package/dist/transformers/CTECollector.js.map +1 -1
- package/dist/transformers/CTEDisabler.js +1 -1
- package/dist/transformers/CTEDisabler.js.map +1 -1
- package/dist/transformers/Formatter.js +1 -1
- package/dist/transformers/Formatter.js.map +1 -1
- package/dist/transformers/SelectValueCollector.d.ts +2 -4
- package/dist/transformers/SelectValueCollector.js.map +1 -1
- package/dist/transformers/SelectableColumnCollector.d.ts +2 -0
- package/dist/transformers/SelectableColumnCollector.js +17 -3
- package/dist/transformers/SelectableColumnCollector.js.map +1 -1
- package/dist/transformers/TableColumnResolver.d.ts +10 -0
- package/dist/transformers/TableColumnResolver.js +3 -0
- package/dist/transformers/TableColumnResolver.js.map +1 -0
- package/package.json +15 -2
@@ -0,0 +1,101 @@
|
|
1
|
+
import { JoinClause, JoinOnClause, JoinUsingClause } from "../models/Clause";
|
2
|
+
import { TokenType } from "../models/Lexeme";
|
3
|
+
import { joinkeywordParser } from "../tokenReaders/CommandTokenReader";
|
4
|
+
import { SourceExpressionParser } from "./SourceExpressionParser";
|
5
|
+
import { ValueParser } from "./ValueParser";
|
6
|
+
export class JoinClauseParser {
|
7
|
+
static tryParse(lexemes, index) {
|
8
|
+
let idx = index;
|
9
|
+
const joins = [];
|
10
|
+
while (this.isJoinCommand(lexemes, idx)) {
|
11
|
+
const joinClause = this.parseJoinClause(lexemes, idx);
|
12
|
+
joins.push(joinClause.value);
|
13
|
+
idx = joinClause.newIndex;
|
14
|
+
}
|
15
|
+
if (joins.length > 0) {
|
16
|
+
return { value: joins, newIndex: idx };
|
17
|
+
}
|
18
|
+
return null;
|
19
|
+
}
|
20
|
+
static isJoinKeyword(value) {
|
21
|
+
// Although performance is not ideal,
|
22
|
+
// we use keyword token reader to centralize keyword management
|
23
|
+
const result = joinkeywordParser.parse(value, 0);
|
24
|
+
if (result) {
|
25
|
+
return true;
|
26
|
+
}
|
27
|
+
return false;
|
28
|
+
}
|
29
|
+
static parseLateral(lexemes, index) {
|
30
|
+
let idx = index;
|
31
|
+
if (idx < lexemes.length && lexemes[idx].value === 'lateral') {
|
32
|
+
// Skip 'lateral' keyword
|
33
|
+
idx++;
|
34
|
+
return { value: true, newIndex: idx };
|
35
|
+
}
|
36
|
+
return { value: false, newIndex: idx };
|
37
|
+
}
|
38
|
+
static isJoinCommand(lexemes, index) {
|
39
|
+
if (index >= lexemes.length) {
|
40
|
+
return false;
|
41
|
+
}
|
42
|
+
if (lexemes[index].type === TokenType.Comma || this.isJoinKeyword(lexemes[index].value) === true) {
|
43
|
+
return true;
|
44
|
+
}
|
45
|
+
return false;
|
46
|
+
}
|
47
|
+
static parseJoinClause(lexemes, index) {
|
48
|
+
let idx = index;
|
49
|
+
// Get the join type
|
50
|
+
const joinType = lexemes[idx].value === "," ? "cross join" : lexemes[idx].value;
|
51
|
+
idx++;
|
52
|
+
// Check for lateral join
|
53
|
+
const lateralResult = this.parseLateral(lexemes, idx);
|
54
|
+
const lateral = lateralResult.value;
|
55
|
+
idx = lateralResult.newIndex;
|
56
|
+
// Parse the source expression to join with
|
57
|
+
const sourceResult = SourceExpressionParser.parseFromLexeme(lexemes, idx);
|
58
|
+
idx = sourceResult.newIndex;
|
59
|
+
if (idx < lexemes.length) {
|
60
|
+
let result = this.tryParseJoinOn(lexemes, idx, joinType, sourceResult.value, lateral);
|
61
|
+
if (result) {
|
62
|
+
return { value: result.value, newIndex: result.newIndex };
|
63
|
+
}
|
64
|
+
result = this.tryParseJoinUsing(lexemes, idx, joinType, sourceResult.value, lateral);
|
65
|
+
if (result) {
|
66
|
+
return { value: result.value, newIndex: result.newIndex };
|
67
|
+
}
|
68
|
+
}
|
69
|
+
// If we reach the end of the input, we can treat it as a natural join
|
70
|
+
const joinClause = new JoinClause(joinType, sourceResult.value, null, lateral);
|
71
|
+
return { value: joinClause, newIndex: idx };
|
72
|
+
}
|
73
|
+
static tryParseJoinOn(lexemes, index, joinType, source, lateral) {
|
74
|
+
let idx = index;
|
75
|
+
if (idx < lexemes.length && lexemes[idx].value === 'on') {
|
76
|
+
idx++; // Skip 'on' keyword
|
77
|
+
// Parse the condition expression
|
78
|
+
const condition = ValueParser.parseFromLexeme(lexemes, idx);
|
79
|
+
idx = condition.newIndex;
|
80
|
+
const joinOn = new JoinOnClause(condition.value);
|
81
|
+
const joinClause = new JoinClause(joinType, source, joinOn, lateral);
|
82
|
+
return { value: joinClause, newIndex: condition.newIndex };
|
83
|
+
}
|
84
|
+
return null;
|
85
|
+
}
|
86
|
+
static tryParseJoinUsing(lexemes, index, joinType, source, lateral) {
|
87
|
+
let idx = index;
|
88
|
+
if (idx < lexemes.length && lexemes[idx].value === 'using') {
|
89
|
+
idx++; // Skip 'using' keyword
|
90
|
+
// Parse the columns in parentheses
|
91
|
+
const result = ValueParser.parseArgument(TokenType.OpenParen, TokenType.CloseParen, lexemes, idx);
|
92
|
+
const usingColumns = result.value;
|
93
|
+
idx = result.newIndex;
|
94
|
+
const joinUsing = new JoinUsingClause(usingColumns);
|
95
|
+
const joinClause = new JoinClause(joinType, source, joinUsing, lateral);
|
96
|
+
return { value: joinClause, newIndex: result.newIndex };
|
97
|
+
}
|
98
|
+
return null;
|
99
|
+
}
|
100
|
+
}
|
101
|
+
//# sourceMappingURL=JoinClauseParser.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"JoinClauseParser.js","sourceRoot":"","sources":["../../../src/parsers/JoinClauseParser.ts"],"names":[],"mappings":"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"}
|
@@ -0,0 +1,87 @@
|
|
1
|
+
import { StringUtils } from "../utils/stringUtils";
|
2
|
+
export var KeywordMatchResult;
|
3
|
+
(function (KeywordMatchResult) {
|
4
|
+
KeywordMatchResult[KeywordMatchResult["NotAKeyword"] = 0] = "NotAKeyword";
|
5
|
+
KeywordMatchResult[KeywordMatchResult["PartialOnly"] = 1] = "PartialOnly";
|
6
|
+
KeywordMatchResult[KeywordMatchResult["PartialOrFinal"] = 2] = "PartialOrFinal";
|
7
|
+
KeywordMatchResult[KeywordMatchResult["Final"] = 3] = "Final"; // "Complete match (no longer keywords after this)"
|
8
|
+
})(KeywordMatchResult || (KeywordMatchResult = {}));
|
9
|
+
export class KeywordParser {
|
10
|
+
constructor(trie) {
|
11
|
+
this.trie = trie;
|
12
|
+
}
|
13
|
+
isEndOfInput(input, position, shift = 0) {
|
14
|
+
return position + shift >= input.length;
|
15
|
+
}
|
16
|
+
canParse(input, position, shift = 0) {
|
17
|
+
return !this.isEndOfInput(input, position, shift);
|
18
|
+
}
|
19
|
+
parse(input, position) {
|
20
|
+
if (this.isEndOfInput(input, position)) {
|
21
|
+
return null;
|
22
|
+
}
|
23
|
+
// reset trie node
|
24
|
+
this.trie.reset();
|
25
|
+
const result = StringUtils.tryReadRegularIdentifier(input, position);
|
26
|
+
if (result === null) {
|
27
|
+
return null;
|
28
|
+
}
|
29
|
+
let matchResult = this.trie.pushLexeme(result.identifier.toLowerCase());
|
30
|
+
if (matchResult === KeywordMatchResult.NotAKeyword) {
|
31
|
+
return null;
|
32
|
+
}
|
33
|
+
if (matchResult === KeywordMatchResult.Final) {
|
34
|
+
return {
|
35
|
+
keyword: result.identifier,
|
36
|
+
newPosition: result.newPosition
|
37
|
+
};
|
38
|
+
}
|
39
|
+
// multi-word keyword
|
40
|
+
let lexeme = result.identifier;
|
41
|
+
position = StringUtils.readWhiteSpaceAndComment(input, result.newPosition).position;
|
42
|
+
// end of input
|
43
|
+
if (this.isEndOfInput(input, position)) {
|
44
|
+
if (matchResult === KeywordMatchResult.PartialOrFinal) {
|
45
|
+
// if the last match was partial or final, it means that the keyword is finished
|
46
|
+
return {
|
47
|
+
keyword: lexeme,
|
48
|
+
newPosition: position
|
49
|
+
};
|
50
|
+
}
|
51
|
+
else {
|
52
|
+
return null;
|
53
|
+
}
|
54
|
+
}
|
55
|
+
while (this.canParse(input, position)) {
|
56
|
+
const previousMatchResult = matchResult;
|
57
|
+
const result = StringUtils.tryReadRegularIdentifier(input, position);
|
58
|
+
if (result !== null) {
|
59
|
+
matchResult = this.trie.pushLexeme(result.identifier.toLowerCase());
|
60
|
+
if (matchResult === KeywordMatchResult.NotAKeyword) {
|
61
|
+
if (previousMatchResult === KeywordMatchResult.PartialOrFinal) {
|
62
|
+
break;
|
63
|
+
}
|
64
|
+
else {
|
65
|
+
return null;
|
66
|
+
}
|
67
|
+
}
|
68
|
+
lexeme += ' ' + result.identifier;
|
69
|
+
position = StringUtils.readWhiteSpaceAndComment(input, result.newPosition).position;
|
70
|
+
if (matchResult === KeywordMatchResult.Final) {
|
71
|
+
break;
|
72
|
+
}
|
73
|
+
}
|
74
|
+
else if (previousMatchResult === KeywordMatchResult.PartialOrFinal) {
|
75
|
+
break;
|
76
|
+
}
|
77
|
+
else {
|
78
|
+
return null;
|
79
|
+
}
|
80
|
+
}
|
81
|
+
return {
|
82
|
+
keyword: lexeme,
|
83
|
+
newPosition: position
|
84
|
+
};
|
85
|
+
}
|
86
|
+
}
|
87
|
+
//# sourceMappingURL=KeywordParser.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"KeywordParser.js","sourceRoot":"","sources":["../../../src/parsers/KeywordParser.ts"],"names":[],"mappings":"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"}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
import { LimitClause as LimitClause } from "../models/Clause";
|
2
|
+
import { SqlTokenizer } from "./SqlTokenizer";
|
3
|
+
import { ValueParser } from "./ValueParser";
|
4
|
+
export class LimitClauseParser {
|
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 LIMIT 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 !== 'limit') {
|
21
|
+
throw new Error(`Syntax error at position ${idx}: Expected 'LIMIT' keyword but found "${lexemes[idx].value}". LIMIT clauses must start with the LIMIT keyword.`);
|
22
|
+
}
|
23
|
+
idx++;
|
24
|
+
if (idx >= lexemes.length) {
|
25
|
+
throw new Error(`Syntax error: Unexpected end of input after 'LIMIT' keyword. The LIMIT clause requires a numeric expression.`);
|
26
|
+
}
|
27
|
+
// Parse LIMIT value
|
28
|
+
const limitItem = ValueParser.parseFromLexeme(lexemes, idx);
|
29
|
+
idx = limitItem.newIndex;
|
30
|
+
let offsetItem = null;
|
31
|
+
// Check if there is an OFFSET clause
|
32
|
+
if (idx < lexemes.length && lexemes[idx].value === 'offset') {
|
33
|
+
idx++;
|
34
|
+
if (idx >= lexemes.length) {
|
35
|
+
throw new Error(`Syntax error: Unexpected end of input after 'OFFSET' keyword. The OFFSET clause requires a numeric expression.`);
|
36
|
+
}
|
37
|
+
// Parse OFFSET value
|
38
|
+
const offsetValueItem = ValueParser.parseFromLexeme(lexemes, idx);
|
39
|
+
offsetItem = offsetValueItem.value;
|
40
|
+
idx = offsetValueItem.newIndex;
|
41
|
+
}
|
42
|
+
const clause = new LimitClause(limitItem.value, offsetItem);
|
43
|
+
return { value: clause, newIndex: idx };
|
44
|
+
}
|
45
|
+
}
|
46
|
+
//# sourceMappingURL=LimitClauseParser.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"LimitClauseParser.js","sourceRoot":"","sources":["../../../src/parsers/LimitClauseParser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,IAAI,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE9D,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,8GAA8G,CAAC,CAAC;QACpI,CAAC;QAED,oBAAoB;QACpB,MAAM,SAAS,GAAG,WAAW,CAAC,eAAe,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAC5D,GAAG,GAAG,SAAS,CAAC,QAAQ,CAAC;QAEzB,IAAI,UAAU,GAAG,IAAI,CAAC;QAEtB,qCAAqC;QACrC,IAAI,GAAG,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC1D,GAAG,EAAE,CAAC;YAEN,IAAI,GAAG,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;gBACxB,MAAM,IAAI,KAAK,CAAC,gHAAgH,CAAC,CAAC;YACtI,CAAC;YAED,qBAAqB;YACrB,MAAM,eAAe,GAAG,WAAW,CAAC,eAAe,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;YAClE,UAAU,GAAG,eAAe,CAAC,KAAK,CAAC;YACnC,GAAG,GAAG,eAAe,CAAC,QAAQ,CAAC;QACnC,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,SAAS,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;QAE5D,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;IAC5C,CAAC;CACJ"}
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import { LiteralValue, RawString } from "../models/ValueComponent";
|
2
|
+
import { literalKeywordParser } from "../tokenReaders/LiteralTokenReader";
|
3
|
+
export class LiteralParser {
|
4
|
+
static parseFromLexeme(lexemes, index) {
|
5
|
+
// Process literal value
|
6
|
+
let idx = index;
|
7
|
+
const valueText = lexemes[idx].value;
|
8
|
+
let parsedValue;
|
9
|
+
const lex = literalKeywordParser.parse(valueText.toLowerCase(), 0);
|
10
|
+
if (lex) {
|
11
|
+
const value = new RawString(lex.keyword);
|
12
|
+
idx++;
|
13
|
+
return { value, newIndex: idx };
|
14
|
+
}
|
15
|
+
// Check if it is a number
|
16
|
+
if (/^[+-]?\d+(\.\d+)?([eE][+-]?\d+)?$/.test(valueText)) {
|
17
|
+
parsedValue = Number(valueText);
|
18
|
+
}
|
19
|
+
// Otherwise, treat it as a string
|
20
|
+
else {
|
21
|
+
// Remove single quotes if enclosed
|
22
|
+
if (valueText.startsWith("'") && valueText.endsWith("'")) {
|
23
|
+
parsedValue = valueText.slice(1, -1);
|
24
|
+
}
|
25
|
+
else {
|
26
|
+
parsedValue = valueText;
|
27
|
+
}
|
28
|
+
}
|
29
|
+
idx++;
|
30
|
+
const value = new LiteralValue(parsedValue);
|
31
|
+
return { value, newIndex: idx };
|
32
|
+
}
|
33
|
+
}
|
34
|
+
//# sourceMappingURL=LiteralParser.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"LiteralParser.js","sourceRoot":"","sources":["../../../src/parsers/LiteralParser.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,SAAS,EAAkB,MAAM,0BAA0B,CAAC;AACnF,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAE1E,MAAM,OAAO,aAAa;IACf,MAAM,CAAC,eAAe,CAAC,OAAiB,EAAE,KAAa;QAC1D,wBAAwB;QACxB,IAAI,GAAG,GAAG,KAAK,CAAC;QAChB,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;QACrC,IAAI,WAA6C,CAAC;QAElD,MAAM,GAAG,GAAG,oBAAoB,CAAC,KAAK,CAAC,SAAS,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC;QACnE,IAAI,GAAG,EAAE,CAAC;YACN,MAAM,KAAK,GAAG,IAAI,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACzC,GAAG,EAAE,CAAA;YACL,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;QACpC,CAAC;QAED,0BAA0B;QAC1B,IAAI,mCAAmC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;YACtD,WAAW,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;QACpC,CAAC;QACD,kCAAkC;aAC7B,CAAC;YACF,mCAAmC;YACnC,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBACvD,WAAW,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACzC,CAAC;iBAAM,CAAC;gBACJ,WAAW,GAAG,SAAS,CAAC;YAC5B,CAAC;QACL,CAAC;QACD,GAAG,EAAE,CAAA;QACL,MAAM,KAAK,GAAG,IAAI,YAAY,CAAC,WAAW,CAAC,CAAC;QAC5C,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;IACpC,CAAC;CACJ"}
|
@@ -0,0 +1,73 @@
|
|
1
|
+
import { NullsSortDirection, OrderByClause, OrderByItem, SortDirection } from "../models/Clause";
|
2
|
+
import { TokenType } from "../models/Lexeme";
|
3
|
+
import { SqlTokenizer } from "./SqlTokenizer";
|
4
|
+
import { ValueParser } from "./ValueParser";
|
5
|
+
export class OrderByClauseParser {
|
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 ORDER BY 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 !== 'order by') {
|
22
|
+
throw new Error(`Syntax error at position ${idx}: Expected 'ORDER BY' keyword but found "${lexemes[idx].value}". ORDER BY clauses must start with the ORDER BY keywords.`);
|
23
|
+
}
|
24
|
+
idx++;
|
25
|
+
const items = [];
|
26
|
+
const item = this.parseItem(lexemes, idx);
|
27
|
+
items.push(item.value);
|
28
|
+
idx = item.newIndex;
|
29
|
+
while (idx < lexemes.length && lexemes[idx].type === TokenType.Comma) {
|
30
|
+
idx++;
|
31
|
+
const item = this.parseItem(lexemes, idx);
|
32
|
+
items.push(item.value);
|
33
|
+
idx = item.newIndex;
|
34
|
+
}
|
35
|
+
if (items.length === 0) {
|
36
|
+
throw new Error(`Syntax error at position ${index}: No ordering expressions found. The ORDER BY clause requires at least one expression to order by.`);
|
37
|
+
}
|
38
|
+
else {
|
39
|
+
const clause = new OrderByClause(items);
|
40
|
+
return { value: clause, newIndex: idx };
|
41
|
+
}
|
42
|
+
}
|
43
|
+
static parseItem(lexemes, index) {
|
44
|
+
let idx = index;
|
45
|
+
const parsedValue = ValueParser.parseFromLexeme(lexemes, idx);
|
46
|
+
const value = parsedValue.value;
|
47
|
+
idx = parsedValue.newIndex;
|
48
|
+
if (idx >= lexemes.length) {
|
49
|
+
return { value: value, newIndex: idx };
|
50
|
+
}
|
51
|
+
// asc, desc
|
52
|
+
const sortDirection = idx >= lexemes.length
|
53
|
+
? null
|
54
|
+
: lexemes[idx].value === 'asc'
|
55
|
+
? (idx++, SortDirection.Ascending)
|
56
|
+
: lexemes[idx].value === 'desc'
|
57
|
+
? (idx++, SortDirection.Descending)
|
58
|
+
: null;
|
59
|
+
// nulls first, nulls last
|
60
|
+
const nullsSortDirection = idx >= lexemes.length
|
61
|
+
? null
|
62
|
+
: lexemes[idx].value === 'nulls first'
|
63
|
+
? (idx++, NullsSortDirection.First)
|
64
|
+
: lexemes[idx].value === 'nulls last'
|
65
|
+
? (idx++, NullsSortDirection.Last)
|
66
|
+
: null;
|
67
|
+
if (sortDirection === null && nullsSortDirection === null) {
|
68
|
+
return { value: value, newIndex: idx };
|
69
|
+
}
|
70
|
+
return { value: new OrderByItem(value, sortDirection, nullsSortDirection), newIndex: idx };
|
71
|
+
}
|
72
|
+
}
|
73
|
+
//# sourceMappingURL=OrderByClauseParser.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"OrderByClauseParser.js","sourceRoot":"","sources":["../../../src/parsers/OrderByClauseParser.ts"],"names":[],"mappings":"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"}
|
@@ -0,0 +1,40 @@
|
|
1
|
+
import { TokenType } from "../models/Lexeme";
|
2
|
+
import { IdentifierString } from "../models/ValueComponent";
|
3
|
+
import { SqlTokenizer } from "./SqlTokenizer";
|
4
|
+
import { WindowExpressionParser } from "./WindowExpressionParser";
|
5
|
+
export class OverExpressionParser {
|
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 OVER expression is complete but there are additional tokens.`);
|
14
|
+
}
|
15
|
+
return result.value;
|
16
|
+
}
|
17
|
+
static parseFromLexeme(lexemes, index) {
|
18
|
+
let idx = index;
|
19
|
+
if (lexemes[idx].value !== 'over') {
|
20
|
+
throw new Error(`Syntax error at position ${idx}: Expected 'OVER' keyword but found "${lexemes[idx].value}". OVER expressions must start with the OVER keyword.`);
|
21
|
+
}
|
22
|
+
idx++;
|
23
|
+
if (idx >= lexemes.length) {
|
24
|
+
throw new Error(`Syntax error: Unexpected end of input after 'OVER' keyword. Expected either a window name or an opening parenthesis '('.`);
|
25
|
+
}
|
26
|
+
if (lexemes[idx].type === TokenType.Identifier) {
|
27
|
+
// named window frame
|
28
|
+
const name = lexemes[idx].value;
|
29
|
+
idx++;
|
30
|
+
return { value: new IdentifierString(name), newIndex: idx };
|
31
|
+
}
|
32
|
+
if (lexemes[idx].type === TokenType.OpenParen) {
|
33
|
+
// Delegate processing to WindowFrameExpressionParser
|
34
|
+
const result = WindowExpressionParser.parseFromLexeme(lexemes, idx);
|
35
|
+
return result;
|
36
|
+
}
|
37
|
+
throw new Error(`Syntax error at position ${idx}: Expected a window name or opening parenthesis '(' after OVER keyword, but found "${lexemes[idx].value}".`);
|
38
|
+
}
|
39
|
+
}
|
40
|
+
//# sourceMappingURL=OverExpressionParser.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"OverExpressionParser.js","sourceRoot":"","sources":["../../../src/parsers/OverExpressionParser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAkB,MAAM,0BAA0B,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAElE,MAAM,OAAO,oBAAoB;IACtB,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,oEAAoE,CAAC,CAAC;QAC3L,CAAC;QAED,OAAO,MAAM,CAAC,KAAK,CAAC;IACxB,CAAC;IAEM,MAAM,CAAC,eAAe,CAAC,OAAiB,EAAE,KAAa;QAC1D,IAAI,GAAG,GAAG,KAAK,CAAC;QAEhB,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,KAAK,MAAM,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CAAC,4BAA4B,GAAG,wCAAwC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,uDAAuD,CAAC,CAAC;QACtK,CAAC;QACD,GAAG,EAAE,CAAC;QAEN,IAAI,GAAG,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,0HAA0H,CAAC,CAAC;QAChJ,CAAC;QAED,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,UAAU,EAAE,CAAC;YAC7C,qBAAqB;YACrB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;YAChC,GAAG,EAAE,CAAC;YACN,OAAO,EAAE,KAAK,EAAE,IAAI,gBAAgB,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;QAChE,CAAC;QAED,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,SAAS,EAAE,CAAC;YAC5C,qDAAqD;YACrD,MAAM,MAAM,GAAG,sBAAsB,CAAC,eAAe,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;YACpE,OAAO,MAAM,CAAC;QAClB,CAAC;QAED,MAAM,IAAI,KAAK,CAAC,4BAA4B,GAAG,sFAAsF,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;IACjK,CAAC;CACJ"}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import { ParameterExpression } from "../models/ValueComponent";
|
2
|
+
export class ParameterExpressionParser {
|
3
|
+
static parseFromLexeme(lexemes, index) {
|
4
|
+
let idx = index;
|
5
|
+
// Exclude the parameter symbol (first character)
|
6
|
+
const value = new ParameterExpression(lexemes[idx].value.slice(1));
|
7
|
+
idx++;
|
8
|
+
return { value, newIndex: idx };
|
9
|
+
}
|
10
|
+
}
|
11
|
+
//# sourceMappingURL=ParameterExpressionParser.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"ParameterExpressionParser.js","sourceRoot":"","sources":["../../../src/parsers/ParameterExpressionParser.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAkB,MAAM,0BAA0B,CAAC;AAE/E,MAAM,OAAO,yBAAyB;IAC3B,MAAM,CAAC,eAAe,CAAC,OAAiB,EAAE,KAAa;QAC1D,IAAI,GAAG,GAAG,KAAK,CAAC;QAChB,iDAAiD;QACjD,MAAM,KAAK,GAAG,IAAI,mBAAmB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACnE,GAAG,EAAE,CAAC;QACN,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;IACpC,CAAC;CACJ"}
|
@@ -0,0 +1,29 @@
|
|
1
|
+
import { TokenType } from "../models/Lexeme";
|
2
|
+
import { InlineQuery, ParenExpression } from "../models/ValueComponent";
|
3
|
+
import { SelectQueryParser } from "./SelectQueryParser";
|
4
|
+
import { ValueParser } from "./ValueParser";
|
5
|
+
export class ParenExpressionParser {
|
6
|
+
static parseFromLexeme(lexemes, index) {
|
7
|
+
let idx = index;
|
8
|
+
// check inline query
|
9
|
+
if (idx + 1 < lexemes.length && lexemes[idx].type === TokenType.OpenParen && (lexemes[idx + 1].value === "select" || lexemes[idx + 1].value === "values" || lexemes[idx + 1].value === "with")) {
|
10
|
+
idx += 1; // Skip the '(' token
|
11
|
+
const result = SelectQueryParser.parseFromLexeme(lexemes, idx);
|
12
|
+
idx = result.newIndex;
|
13
|
+
// Check for closing parenthesis
|
14
|
+
if (idx >= lexemes.length || lexemes[idx].type !== TokenType.CloseParen) {
|
15
|
+
throw new Error(`Expected ')' at index ${idx}, but found ${lexemes[idx].value}`);
|
16
|
+
}
|
17
|
+
idx++; // Skip the ')' token
|
18
|
+
const value = new InlineQuery(result.value);
|
19
|
+
return { value, newIndex: idx };
|
20
|
+
}
|
21
|
+
else {
|
22
|
+
const result = ValueParser.parseArgument(TokenType.OpenParen, TokenType.CloseParen, lexemes, index);
|
23
|
+
idx = result.newIndex;
|
24
|
+
const value = new ParenExpression(result.value);
|
25
|
+
return { value, newIndex: idx };
|
26
|
+
}
|
27
|
+
}
|
28
|
+
}
|
29
|
+
//# sourceMappingURL=ParenExpressionParser.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"ParenExpressionParser.js","sourceRoot":"","sources":["../../../src/parsers/ParenExpressionParser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,eAAe,EAAkB,MAAM,0BAA0B,CAAC;AACxF,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,MAAM,OAAO,qBAAqB;IACvB,MAAM,CAAC,eAAe,CAAC,OAAiB,EAAE,KAAa;QAC1D,IAAI,GAAG,GAAG,KAAK,CAAC;QAEhB,qBAAqB;QACrB,IAAI,GAAG,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,SAAS,IAAI,CACzE,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ,IAAI,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ,IAAI,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,KAAK,MAAM,CAClH,EAAE,CAAC;YACA,GAAG,IAAI,CAAC,CAAC,CAAC,qBAAqB;YAC/B,MAAM,MAAM,GAAG,iBAAiB,CAAC,eAAe,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;YAC/D,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC;YAEtB,gCAAgC;YAChC,IAAI,GAAG,IAAI,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,UAAU,EAAE,CAAC;gBACtE,MAAM,IAAI,KAAK,CAAC,yBAAyB,GAAG,eAAe,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;YACrF,CAAC;YACD,GAAG,EAAE,CAAC,CAAC,qBAAqB;YAE5B,MAAM,KAAK,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC5C,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;QACpC,CAAC;aAAM,CAAC;YACJ,MAAM,MAAM,GAAG,WAAW,CAAC,aAAa,CAAC,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC,UAAU,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;YACpG,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC;YAEtB,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAChD,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;QACpC,CAAC;IACL,CAAC;CACJ"}
|
@@ -0,0 +1,49 @@
|
|
1
|
+
import { PartitionByClause } from "../models/Clause";
|
2
|
+
import { TokenType } from "../models/Lexeme";
|
3
|
+
import { ValueList } from "../models/ValueComponent";
|
4
|
+
import { SqlTokenizer } from "./SqlTokenizer";
|
5
|
+
import { ValueParser } from "./ValueParser";
|
6
|
+
export class PartitionByParser {
|
7
|
+
// Parse SQL string to AST (was: parse)
|
8
|
+
static parse(query) {
|
9
|
+
const tokenizer = new SqlTokenizer(query); // Initialize tokenizer
|
10
|
+
const lexemes = tokenizer.readLexmes(); // Get tokens
|
11
|
+
// Parse
|
12
|
+
const result = this.parseFromLexeme(lexemes, 0);
|
13
|
+
// Error if there are remaining tokens
|
14
|
+
if (result.newIndex < lexemes.length) {
|
15
|
+
throw new Error(`Syntax error: Unexpected token "${lexemes[result.newIndex].value}" at position ${result.newIndex}. The PARTITION BY clause is complete but there are additional tokens.`);
|
16
|
+
}
|
17
|
+
return result.value;
|
18
|
+
}
|
19
|
+
// Parse from lexeme array (was: parse)
|
20
|
+
static parseFromLexeme(lexemes, index) {
|
21
|
+
let idx = index;
|
22
|
+
if (lexemes[idx].value !== 'partition by') {
|
23
|
+
throw new Error(`Syntax error at position ${idx}: Expected 'PARTITION BY' keyword but found "${lexemes[idx].value}". PARTITION BY clauses must start with the PARTITION BY keywords.`);
|
24
|
+
}
|
25
|
+
idx++;
|
26
|
+
const items = [];
|
27
|
+
const item = ValueParser.parseFromLexeme(lexemes, idx);
|
28
|
+
items.push(item.value);
|
29
|
+
idx = item.newIndex;
|
30
|
+
while (idx < lexemes.length && lexemes[idx].type === TokenType.Comma) {
|
31
|
+
idx++;
|
32
|
+
const item = ValueParser.parseFromLexeme(lexemes, idx);
|
33
|
+
items.push(item.value);
|
34
|
+
idx = item.newIndex;
|
35
|
+
}
|
36
|
+
if (items.length === 0) {
|
37
|
+
throw new Error(`Syntax error at position ${index}: No partition expressions found. The PARTITION BY clause requires at least one expression to partition by.`);
|
38
|
+
}
|
39
|
+
else if (items.length === 1) {
|
40
|
+
const clause = new PartitionByClause(items[0]);
|
41
|
+
return { value: clause, newIndex: idx };
|
42
|
+
}
|
43
|
+
else {
|
44
|
+
const clause = new PartitionByClause(new ValueList(items));
|
45
|
+
return { value: clause, newIndex: idx };
|
46
|
+
}
|
47
|
+
}
|
48
|
+
}
|
49
|
+
//# sourceMappingURL=PartitionByParser.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"PartitionByParser.js","sourceRoot":"","sources":["../../../src/parsers/PartitionByParser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAU,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAkB,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrE,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,wEAAwE,CAAC,CAAC;QAC/L,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;QAChB,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,KAAK,cAAc,EAAE,CAAC;YACxC,MAAM,IAAI,KAAK,CAAC,4BAA4B,GAAG,gDAAgD,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,oEAAoE,CAAC,CAAC;QAC3L,CAAC;QACD,GAAG,EAAE,CAAC;QACN,MAAM,KAAK,GAAqB,EAAE,CAAC;QACnC,MAAM,IAAI,GAAG,WAAW,CAAC,eAAe,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACvD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvB,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC;QACpB,OAAO,GAAG,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,KAAK,EAAE,CAAC;YACnE,GAAG,EAAE,CAAC;YACN,MAAM,IAAI,GAAG,WAAW,CAAC,eAAe,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;YACvD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACvB,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC;QACxB,CAAC;QACD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,4BAA4B,KAAK,6GAA6G,CAAC,CAAC;QACpK,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,MAAM,MAAM,GAAG,IAAI,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YAC/C,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;QAC5C,CAAC;aAAM,CAAC;YACJ,MAAM,MAAM,GAAG,IAAI,iBAAiB,CAAC,IAAI,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;YAC3D,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;QAC5C,CAAC;IACL,CAAC;CACJ"}
|
@@ -0,0 +1,80 @@
|
|
1
|
+
import { Distinct, DistinctOn, SelectClause, SelectItem } from "../models/Clause";
|
2
|
+
import { TokenType } from "../models/Lexeme";
|
3
|
+
import { SqlTokenizer } from "./SqlTokenizer";
|
4
|
+
import { ValueParser } from "./ValueParser";
|
5
|
+
export class SelectClauseParser {
|
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 SELECT 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
|
+
let distinct = null;
|
22
|
+
if (lexemes[idx].value !== 'select') {
|
23
|
+
throw new Error(`Syntax error at position ${idx}: Expected 'SELECT' keyword but found "${lexemes[idx].value}". SELECT clauses must start with the SELECT keyword.`);
|
24
|
+
}
|
25
|
+
idx++;
|
26
|
+
if (idx < lexemes.length && lexemes[idx].value === 'distinct') {
|
27
|
+
idx++;
|
28
|
+
distinct = new Distinct();
|
29
|
+
}
|
30
|
+
else if (idx < lexemes.length && lexemes[idx].value === 'distinct on') {
|
31
|
+
idx++;
|
32
|
+
const argument = ValueParser.parseArgument(TokenType.OpenParen, TokenType.CloseParen, lexemes, idx);
|
33
|
+
distinct = new DistinctOn(argument.value);
|
34
|
+
idx = argument.newIndex;
|
35
|
+
}
|
36
|
+
const items = [];
|
37
|
+
const item = this.parseItem(lexemes, idx);
|
38
|
+
items.push(item.value);
|
39
|
+
idx = item.newIndex;
|
40
|
+
while (idx < lexemes.length && lexemes[idx].type === TokenType.Comma) {
|
41
|
+
idx++;
|
42
|
+
const item = this.parseItem(lexemes, idx);
|
43
|
+
items.push(item.value);
|
44
|
+
idx = item.newIndex;
|
45
|
+
}
|
46
|
+
if (items.length === 0) {
|
47
|
+
throw new Error(`Syntax error at position ${index}: No select items found. The SELECT clause requires at least one expression to select.`);
|
48
|
+
}
|
49
|
+
else {
|
50
|
+
const clause = new SelectClause(items, distinct);
|
51
|
+
return { value: clause, newIndex: idx };
|
52
|
+
}
|
53
|
+
}
|
54
|
+
static parseItem(lexemes, index) {
|
55
|
+
let idx = index;
|
56
|
+
const parsedValue = ValueParser.parseFromLexeme(lexemes, idx);
|
57
|
+
const value = parsedValue.value;
|
58
|
+
idx = parsedValue.newIndex;
|
59
|
+
if (idx < lexemes.length && lexemes[idx].value === 'as') {
|
60
|
+
// Skip 'AS' keyword
|
61
|
+
idx++;
|
62
|
+
}
|
63
|
+
if (idx < lexemes.length && lexemes[idx].type === TokenType.Identifier) {
|
64
|
+
const alias = lexemes[idx].value;
|
65
|
+
idx++;
|
66
|
+
return {
|
67
|
+
value: new SelectItem(value, alias),
|
68
|
+
newIndex: idx,
|
69
|
+
};
|
70
|
+
}
|
71
|
+
else {
|
72
|
+
// alias nameless
|
73
|
+
return {
|
74
|
+
value,
|
75
|
+
newIndex: idx,
|
76
|
+
};
|
77
|
+
}
|
78
|
+
}
|
79
|
+
}
|
80
|
+
//# sourceMappingURL=SelectClauseParser.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"SelectClauseParser.js","sourceRoot":"","sources":["../../../src/parsers/SelectClauseParser.ts"],"names":[],"mappings":"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"}
|