rawsql-ts 0.1.0-beta.10 → 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 +165 -174
- 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/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/transformers/SelectValueCollector.d.ts +2 -4
- package/dist/transformers/SelectValueCollector.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 +17 -1
@@ -0,0 +1,115 @@
|
|
1
|
+
import { FunctionSource, SubQuerySource, TableSource } from "../models/Clause";
|
2
|
+
import { TokenType } from "../models/Lexeme";
|
3
|
+
import { SelectQueryParser } from "./SelectQueryParser";
|
4
|
+
import { SqlTokenizer } from "./SqlTokenizer";
|
5
|
+
import { ValueParser } from "./ValueParser";
|
6
|
+
export class SourceParser {
|
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 source component 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
|
+
const idx = index;
|
22
|
+
// Handle subquery
|
23
|
+
if (idx < lexemes.length && lexemes[idx].type === TokenType.OpenParen) {
|
24
|
+
return this.parseParenSource(lexemes, idx);
|
25
|
+
}
|
26
|
+
// Handle function-based source
|
27
|
+
if (idx < lexemes.length && lexemes[idx].type === TokenType.Function) {
|
28
|
+
return this.parseFunctionSource(lexemes, idx);
|
29
|
+
}
|
30
|
+
// Handle table source (regular table, potentially schema-qualified)
|
31
|
+
return this.parseTableSource(lexemes, idx);
|
32
|
+
}
|
33
|
+
static parseTableSource(lexemes, index) {
|
34
|
+
// Check for column reference pattern ([identifier dot] * n + identifier)
|
35
|
+
let idx = index;
|
36
|
+
const identifiers = [];
|
37
|
+
// Add the first identifier
|
38
|
+
identifiers.push(lexemes[idx].value);
|
39
|
+
idx++;
|
40
|
+
// Look for dot and identifier pattern
|
41
|
+
while (idx < lexemes.length &&
|
42
|
+
idx + 1 < lexemes.length &&
|
43
|
+
lexemes[idx].type === TokenType.Dot &&
|
44
|
+
lexemes[idx + 1].type === TokenType.Identifier) {
|
45
|
+
// Skip the dot and add the next identifier
|
46
|
+
idx++;
|
47
|
+
identifiers.push(lexemes[idx].value);
|
48
|
+
idx++;
|
49
|
+
}
|
50
|
+
if (identifiers.length > 1) {
|
51
|
+
// If there are multiple identifiers, treat it as a column reference
|
52
|
+
const lastIdentifier = identifiers.pop() || '';
|
53
|
+
const value = new TableSource(identifiers, lastIdentifier);
|
54
|
+
return { value, newIndex: idx };
|
55
|
+
}
|
56
|
+
else {
|
57
|
+
// If there is a single identifier, treat it as a simple identifier
|
58
|
+
const value = new TableSource(null, identifiers[0]);
|
59
|
+
return { value, newIndex: idx };
|
60
|
+
}
|
61
|
+
}
|
62
|
+
static parseFunctionSource(lexemes, index) {
|
63
|
+
let idx = index;
|
64
|
+
const functionName = lexemes[idx].value;
|
65
|
+
idx++;
|
66
|
+
const argument = ValueParser.parseArgument(TokenType.OpenParen, TokenType.CloseParen, lexemes, idx);
|
67
|
+
idx = argument.newIndex;
|
68
|
+
const result = new FunctionSource(functionName, argument.value);
|
69
|
+
return { value: result, newIndex: idx };
|
70
|
+
}
|
71
|
+
static parseParenSource(lexemes, index) {
|
72
|
+
let idx = index;
|
73
|
+
// skip the open parenthesis
|
74
|
+
idx++;
|
75
|
+
if (idx >= lexemes.length) {
|
76
|
+
throw new Error(`Syntax error: Unexpected end of input at position ${idx}. Expected a subquery or nested expression after opening parenthesis.`);
|
77
|
+
}
|
78
|
+
// Support both SELECT and VALUES in subqueries
|
79
|
+
const keyword = lexemes[idx].value;
|
80
|
+
if (keyword === "select" || keyword === "values" || keyword === "with") {
|
81
|
+
const result = this.parseSubQuerySource(lexemes, idx);
|
82
|
+
idx = result.newIndex;
|
83
|
+
if (idx < lexemes.length && lexemes[idx].type == TokenType.CloseParen) {
|
84
|
+
// skip the closing parenthesis
|
85
|
+
idx++;
|
86
|
+
}
|
87
|
+
else {
|
88
|
+
throw new Error(`Syntax error at position ${idx}: Missing closing parenthesis. Each opening parenthesis must have a matching closing parenthesis.`);
|
89
|
+
}
|
90
|
+
return { value: result.value, newIndex: idx };
|
91
|
+
}
|
92
|
+
else if (lexemes[idx].type == TokenType.OpenParen) {
|
93
|
+
const result = this.parseParenSource(lexemes, idx);
|
94
|
+
idx = result.newIndex;
|
95
|
+
if (idx < lexemes.length && lexemes[idx].type == TokenType.CloseParen) {
|
96
|
+
// skip the closing parenthesis
|
97
|
+
idx++;
|
98
|
+
}
|
99
|
+
else {
|
100
|
+
throw new Error(`Syntax error at position ${idx}: Missing closing parenthesis. Each opening parenthesis must have a matching closing parenthesis.`);
|
101
|
+
}
|
102
|
+
return { value: result.value, newIndex: idx };
|
103
|
+
}
|
104
|
+
throw new Error(`Syntax error at position ${idx}: Expected 'SELECT' keyword, 'VALUES' keyword, or opening parenthesis '(' but found "${lexemes[idx].value}".`);
|
105
|
+
}
|
106
|
+
static parseSubQuerySource(lexemes, index) {
|
107
|
+
let idx = index;
|
108
|
+
// Use the new parseFromLexeme method and destructure the result
|
109
|
+
const { value: selectQuery, newIndex } = SelectQueryParser.parseFromLexeme(lexemes, idx);
|
110
|
+
idx = newIndex;
|
111
|
+
const subQuerySource = new SubQuerySource(selectQuery);
|
112
|
+
return { value: subQuerySource, newIndex: idx };
|
113
|
+
}
|
114
|
+
}
|
115
|
+
//# sourceMappingURL=SourceParser.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"SourceParser.js","sourceRoot":"","sources":["../../../src/parsers/SourceParser.ts"],"names":[],"mappings":"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"}
|
@@ -0,0 +1,170 @@
|
|
1
|
+
import { TokenType } from '../models/Lexeme';
|
2
|
+
import { IdentifierTokenReader } from '../tokenReaders/IdentifierTokenReader';
|
3
|
+
import { LiteralTokenReader } from '../tokenReaders/LiteralTokenReader';
|
4
|
+
import { ParameterTokenReader } from '../tokenReaders/ParameterTokenReader';
|
5
|
+
import { SpecialSymbolTokenReader } from '../tokenReaders/SymbolTokenReader';
|
6
|
+
import { TokenReaderManager } from '../tokenReaders/TokenReaderManager';
|
7
|
+
import { OperatorTokenReader } from '../tokenReaders/OperatorTokenReader';
|
8
|
+
import { StringUtils } from '../utils/stringUtils';
|
9
|
+
import { CommandTokenReader } from '../tokenReaders/CommandTokenReader';
|
10
|
+
import { StringSpecifierTokenReader } from '../tokenReaders/StringSpecifierTokenReader';
|
11
|
+
import { FunctionTokenReader } from '../tokenReaders/FunctionTokenReader';
|
12
|
+
import { TypeTokenReader } from '../tokenReaders/TypeTokenReader';
|
13
|
+
/**
|
14
|
+
* Class responsible for tokenizing SQL input.
|
15
|
+
*/
|
16
|
+
export class SqlTokenizer {
|
17
|
+
/**
|
18
|
+
* Initializes a new instance of the SqlTokenizer.
|
19
|
+
*/
|
20
|
+
constructor(input) {
|
21
|
+
this.input = input;
|
22
|
+
this.position = 0;
|
23
|
+
// Initialize the token reader manager and register all readers
|
24
|
+
this.readerManager = new TokenReaderManager(input)
|
25
|
+
.register(new ParameterTokenReader(input))
|
26
|
+
.register(new StringSpecifierTokenReader(input))
|
27
|
+
// LiteralTokenReader should be registered before SpecialSymbolTokenReader and OperatorTokenReader
|
28
|
+
// Reason: To prevent numeric literals starting with a dot or sign from being misrecognized as operators
|
29
|
+
// e.g. `1.0` is a literal, not an operator
|
30
|
+
.register(new LiteralTokenReader(input))
|
31
|
+
.register(new SpecialSymbolTokenReader(input))
|
32
|
+
.register(new CommandTokenReader(input))
|
33
|
+
.register(new OperatorTokenReader(input))
|
34
|
+
// TypeTokenReader should be registered before FunctionTokenReader
|
35
|
+
// Reason: To prevent types containing parentheses from being misrecognized as functions
|
36
|
+
// e.g. `numeric(10, 2)` is a type, not a function
|
37
|
+
.register(new TypeTokenReader(input))
|
38
|
+
.register(new FunctionTokenReader(input))
|
39
|
+
.register(new IdentifierTokenReader(input)) // IdentifierTokenReader should be registered last
|
40
|
+
;
|
41
|
+
}
|
42
|
+
/**
|
43
|
+
* Checks if the end of input is reached.
|
44
|
+
*
|
45
|
+
* @param shift - The shift to consider beyond the current position.
|
46
|
+
* @returns True if the end of input is reached; otherwise, false.
|
47
|
+
*/
|
48
|
+
isEndOfInput(shift = 0) {
|
49
|
+
return this.position + shift >= this.input.length;
|
50
|
+
}
|
51
|
+
/**
|
52
|
+
* Checks if more input can be read.
|
53
|
+
*
|
54
|
+
* @param shift - The shift to consider beyond the current position.
|
55
|
+
* @returns True if more input can be read; otherwise, false.
|
56
|
+
*/
|
57
|
+
canRead(shift = 0) {
|
58
|
+
return !this.isEndOfInput(shift);
|
59
|
+
}
|
60
|
+
/**
|
61
|
+
* Reads the lexemes from the input string.
|
62
|
+
*
|
63
|
+
* @returns An array of lexemes extracted from the input string.
|
64
|
+
* @throws Error if an unexpected character is encountered.
|
65
|
+
*/
|
66
|
+
readLexmes() {
|
67
|
+
// Pre-allocate array with estimated capacity for better performance
|
68
|
+
const estimatedTokens = Math.ceil(this.input.length / 8); // Assuming average token length of 8 chars
|
69
|
+
const lexemes = new Array(estimatedTokens);
|
70
|
+
let lexemeCount = 0;
|
71
|
+
// Read initial prefix comments
|
72
|
+
const comment = this.readComment();
|
73
|
+
let pendingComments = comment.lines;
|
74
|
+
this.position = comment.position;
|
75
|
+
// Track the previous token
|
76
|
+
let previous = null;
|
77
|
+
// Read tokens until the end of input is reached
|
78
|
+
while (this.canRead()) {
|
79
|
+
// Semicolon is a delimiter, so stop reading
|
80
|
+
if (this.input[this.position] === ';') {
|
81
|
+
break;
|
82
|
+
}
|
83
|
+
// Read using the token reader manager
|
84
|
+
const lexeme = this.readerManager.tryRead(this.position, previous);
|
85
|
+
if (lexeme === null) {
|
86
|
+
throw new Error(`Unexpected character. actual: ${this.input[this.position]}, position: ${this.position}\n${this.getDebugPositionInfo(this.position)}`);
|
87
|
+
}
|
88
|
+
// Update position
|
89
|
+
this.position = this.readerManager.getMaxPosition();
|
90
|
+
// Read suffix comments
|
91
|
+
const currentComment = this.readComment();
|
92
|
+
this.position = currentComment.position;
|
93
|
+
if (lexeme.type === TokenType.Comma || lexeme.type === TokenType.Operator) {
|
94
|
+
// Carry over comments after commas or operators
|
95
|
+
if (currentComment.lines.length > 0) {
|
96
|
+
pendingComments.push(...currentComment.lines);
|
97
|
+
}
|
98
|
+
}
|
99
|
+
else {
|
100
|
+
// Add comments to the current token if any
|
101
|
+
const hasComments = pendingComments.length > 0 || currentComment.lines.length > 0;
|
102
|
+
if (hasComments) {
|
103
|
+
this.addCommentsToToken(lexeme, pendingComments, currentComment.lines);
|
104
|
+
}
|
105
|
+
pendingComments = []; // Clear as they are processed
|
106
|
+
}
|
107
|
+
lexemes[lexemeCount++] = lexeme;
|
108
|
+
previous = lexeme;
|
109
|
+
}
|
110
|
+
// Add any pending comments to the last token
|
111
|
+
if (pendingComments.length > 0 && lexemeCount > 0) {
|
112
|
+
const lastToken = lexemes[lexemeCount - 1];
|
113
|
+
if (lastToken.comments === null) {
|
114
|
+
lastToken.comments = [];
|
115
|
+
}
|
116
|
+
lastToken.comments.push(...pendingComments);
|
117
|
+
}
|
118
|
+
// Trim the array to actual size used
|
119
|
+
return lexemeCount === estimatedTokens ? lexemes : lexemes.slice(0, lexemeCount);
|
120
|
+
}
|
121
|
+
/**
|
122
|
+
* Adds pending comments to the last token.
|
123
|
+
*/
|
124
|
+
addPendingCommentsToLastToken(lexemes, pendingComments) {
|
125
|
+
if (pendingComments.length > 0 && lexemes.length > 0) {
|
126
|
+
const lastToken = lexemes[lexemes.length - 1];
|
127
|
+
if (lastToken.comments === null) {
|
128
|
+
lastToken.comments = [];
|
129
|
+
}
|
130
|
+
lastToken.comments.push(...pendingComments);
|
131
|
+
}
|
132
|
+
}
|
133
|
+
/**
|
134
|
+
* Adds comments to the token.
|
135
|
+
*/
|
136
|
+
addCommentsToToken(lexeme, prefixComments, suffixComments) {
|
137
|
+
const hasComments = prefixComments.length > 0 || suffixComments.length > 0;
|
138
|
+
if (hasComments) {
|
139
|
+
if (lexeme.comments === null) {
|
140
|
+
lexeme.comments = [];
|
141
|
+
}
|
142
|
+
// Add prefix comments to the beginning.
|
143
|
+
if (prefixComments.length > 0) {
|
144
|
+
lexeme.comments.unshift(...prefixComments);
|
145
|
+
}
|
146
|
+
// Add suffix comments to the end.
|
147
|
+
if (suffixComments.length > 0) {
|
148
|
+
lexeme.comments.push(...suffixComments);
|
149
|
+
}
|
150
|
+
}
|
151
|
+
}
|
152
|
+
/**
|
153
|
+
* Skips whitespace characters and SQL comments in the input.
|
154
|
+
*
|
155
|
+
* @remarks This method updates the position pointer.
|
156
|
+
*/
|
157
|
+
readComment() {
|
158
|
+
return StringUtils.readWhiteSpaceAndComment(this.input, this.position);
|
159
|
+
}
|
160
|
+
/**
|
161
|
+
* Gets debug information for error reporting.
|
162
|
+
*
|
163
|
+
* @param errPosition - The position where the error occurred.
|
164
|
+
* @returns A string containing the debug position information.
|
165
|
+
*/
|
166
|
+
getDebugPositionInfo(errPosition) {
|
167
|
+
return StringUtils.getDebugPositionInfo(this.input, errPosition);
|
168
|
+
}
|
169
|
+
}
|
170
|
+
//# sourceMappingURL=SqlTokenizer.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"SqlTokenizer.js","sourceRoot":"","sources":["../../../src/parsers/SqlTokenizer.ts"],"names":[],"mappings":"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"}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import { TokenType } from "../models/Lexeme";
|
2
|
+
import { StringSpecifierExpression } from "../models/ValueComponent";
|
3
|
+
export class StringSpecifierExpressionParser {
|
4
|
+
static parseFromLexeme(lexemes, index) {
|
5
|
+
let idx = index;
|
6
|
+
const specifer = lexemes[idx].value;
|
7
|
+
idx++;
|
8
|
+
if (idx >= lexemes.length || lexemes[idx].type !== TokenType.Literal) {
|
9
|
+
throw new Error(`Expected string literal after string specifier at index ${idx}`);
|
10
|
+
}
|
11
|
+
const value = lexemes[idx].value;
|
12
|
+
idx++;
|
13
|
+
// Create StringSpecifierExpression
|
14
|
+
const result = new StringSpecifierExpression(specifer, value);
|
15
|
+
return { value: result, newIndex: idx };
|
16
|
+
}
|
17
|
+
}
|
18
|
+
//# sourceMappingURL=StringSpecifierExpressionParser.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"StringSpecifierExpressionParser.js","sourceRoot":"","sources":["../../../src/parsers/StringSpecifierExpressionParser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,yBAAyB,EAAkB,MAAM,0BAA0B,CAAC;AAErF,MAAM,OAAO,+BAA+B;IACjC,MAAM,CAAC,eAAe,CAAC,OAAiB,EAAE,KAAa;QAC1D,IAAI,GAAG,GAAG,KAAK,CAAC;QAChB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;QACpC,GAAG,EAAE,CAAC;QACN,IAAI,GAAG,IAAI,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,OAAO,EAAE,CAAC;YACnE,MAAM,IAAI,KAAK,CAAC,2DAA2D,GAAG,EAAE,CAAC,CAAC;QACtF,CAAC;QACD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;QACjC,GAAG,EAAE,CAAC;QACN,mCAAmC;QACnC,MAAM,MAAM,GAAG,IAAI,yBAAyB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAE9D,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;IAC5C,CAAC;CACJ"}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import { TokenType } from "../models/Lexeme";
|
2
|
+
import { ColumnReference, UnaryExpression } from "../models/ValueComponent";
|
3
|
+
import { ValueParser } from "./ValueParser";
|
4
|
+
export class UnaryExpressionParser {
|
5
|
+
static parseFromLexeme(lexemes, index) {
|
6
|
+
let idx = index;
|
7
|
+
// Process unary operator
|
8
|
+
if (idx < lexemes.length && lexemes[idx].type === TokenType.Operator) {
|
9
|
+
const operator = lexemes[idx].value;
|
10
|
+
idx++;
|
11
|
+
// Treat the asterisk as an Identifier, not as a unary operator
|
12
|
+
if (operator === '*') {
|
13
|
+
const v = new ColumnReference(null, '*');
|
14
|
+
return { value: v, newIndex: idx };
|
15
|
+
}
|
16
|
+
// Get the right-hand side value of the unary operator
|
17
|
+
const result = ValueParser.parseFromLexeme(lexemes, idx);
|
18
|
+
idx = result.newIndex;
|
19
|
+
// Create unary expression
|
20
|
+
const value = new UnaryExpression(operator, result.value);
|
21
|
+
return { value, newIndex: idx };
|
22
|
+
}
|
23
|
+
throw new Error(`Invalid unary expression at index ${index}: ${lexemes[index].value}`);
|
24
|
+
}
|
25
|
+
}
|
26
|
+
//# sourceMappingURL=UnaryExpressionParser.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"UnaryExpressionParser.js","sourceRoot":"","sources":["../../../src/parsers/UnaryExpressionParser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAoB,eAAe,EAAkB,MAAM,0BAA0B,CAAC;AAC9G,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,yBAAyB;QACzB,IAAI,GAAG,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,QAAQ,EAAE,CAAC;YACnE,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;YACpC,GAAG,EAAE,CAAC;YAEN,+DAA+D;YAC/D,IAAI,QAAQ,KAAK,GAAG,EAAE,CAAC;gBACnB,MAAM,CAAC,GAAG,IAAI,eAAe,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;gBACzC,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;YACvC,CAAC;YAED,sDAAsD;YACtD,MAAM,MAAM,GAAG,WAAW,CAAC,eAAe,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;YACzD,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC;YAEtB,0BAA0B;YAC1B,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;YAC1D,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;QACpC,CAAC;QAED,MAAM,IAAI,KAAK,CAAC,qCAAqC,KAAK,KAAK,OAAO,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;IAC3F,CAAC;CACJ"}
|
@@ -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"}
|