rawsql-ts
Version:
[beta]High-performance SQL parser and AST analyzer written in TypeScript. Provides fast parsing and advanced transformation capabilities.
120 lines • 5.66 kB
JavaScript
import { TokenType } from "../models/Lexeme";
import { ArrayExpression, CaseExpression, CaseKeyValuePair, SwitchCaseArgument, UnaryExpression } from "../models/ValueComponent";
import { ValueParser } from "./ValueParser";
export class CommandExpressionParser {
static parseFromLexeme(lexemes, index) {
let idx = index;
const current = lexemes[idx];
if (current.value === "case") {
idx++;
return this.parseCaseExpression(lexemes, idx);
}
else if (current.value === "case when") {
idx++;
return this.parseCaseWhenExpression(lexemes, idx);
}
else if (current.value === "array") {
idx++;
return this.parseArrayExpression(lexemes, idx);
}
return this.parseModifierUnaryExpression(lexemes, idx);
}
static parseModifierUnaryExpression(lexemes, index) {
let idx = index;
// Check for modifier unary expression
if (idx < lexemes.length && (lexemes[idx].type & TokenType.Command)) {
const command = lexemes[idx].value;
idx++;
const result = ValueParser.parseFromLexeme(lexemes, idx);
return { value: new UnaryExpression(command, result.value), newIndex: result.newIndex };
}
throw new Error(`Invalid modifier unary expression at index ${idx}, Lexeme: ${lexemes[idx].value}`);
}
static parseCaseExpression(lexemes, index) {
let idx = index;
const condition = ValueParser.parseFromLexeme(lexemes, idx);
idx = condition.newIndex;
const switchCaseResult = this.parseSwitchCaseArgument(lexemes, idx, []);
idx = switchCaseResult.newIndex;
// Create CASE expression
const result = new CaseExpression(condition.value, switchCaseResult.value);
return { value: result, newIndex: idx };
}
static parseCaseWhenExpression(lexemes, index) {
let idx = index;
// Parse the first WHEN clause
const casewhenResult = this.parseCaseConditionValuePair(lexemes, idx);
idx = casewhenResult.newIndex;
// Add the initial WHEN-THEN pair to the list
const caseWhenList = [casewhenResult.value];
// Process remaining WHEN-ELSE-END parts
const switchCaseResult = this.parseSwitchCaseArgument(lexemes, idx, caseWhenList);
idx = switchCaseResult.newIndex;
// Create CASE expression with condition null (uses WHEN conditions instead of a simple CASE)
const result = new CaseExpression(null, switchCaseResult.value);
return { value: result, newIndex: idx };
}
// parseSwitchCaseArgument method processes the WHEN, ELSE, and END clauses of a CASE expression.
static parseSwitchCaseArgument(lexemes, index, initialWhenThenList) {
let idx = index;
const whenThenList = [...initialWhenThenList];
let elseValue = null;
// Process WHEN clauses
while (idx < lexemes.length && this.isCommandWithValue(lexemes[idx], "when")) {
idx++;
const whenResult = this.parseCaseConditionValuePair(lexemes, idx);
idx = whenResult.newIndex;
whenThenList.push(whenResult.value);
}
// Process ELSE
if (idx < lexemes.length && this.isCommandWithValue(lexemes[idx], "else")) {
idx++;
const elseResult = ValueParser.parseFromLexeme(lexemes, idx);
elseValue = elseResult.value;
idx = elseResult.newIndex;
}
// Process END
if (idx < lexemes.length && this.isCommandWithValue(lexemes[idx], "end")) {
idx++;
}
else {
throw new Error(`The CASE expression requires 'end' keyword at the end (index ${idx})`);
}
if (whenThenList.length === 0) {
throw new Error(`The CASE expression requires at least one WHEN clause (index ${idx})`);
}
// Create SwitchCaseArgument
const value = new SwitchCaseArgument(whenThenList, elseValue);
return { value, newIndex: idx };
}
// Helper method: Check if a lexeme is a Command token with the specified value
static isCommandWithValue(lexeme, value) {
return ((lexeme.type & TokenType.Command) !== 0) && lexeme.value === value;
}
static parseCaseConditionValuePair(lexemes, index) {
let idx = index;
const condition = ValueParser.parseFromLexeme(lexemes, idx);
idx = condition.newIndex;
// Check for the existence of the THEN keyword
if (idx >= lexemes.length || !(lexemes[idx].type & TokenType.Command) || lexemes[idx].value !== "then") {
throw new Error(`Expected 'then' after WHEN condition at index ${idx}`);
}
idx++; // Skip the THEN keyword
// Parse the value after THEN
const value = ValueParser.parseFromLexeme(lexemes, idx);
idx = value.newIndex;
return { value: new CaseKeyValuePair(condition.value, value.value), newIndex: idx };
}
static parseArrayExpression(lexemes, index) {
let idx = index;
// Array function is enclosed in []
if (idx < lexemes.length && (lexemes[idx].type & TokenType.OpenBracket)) {
const arg = ValueParser.parseArgument(TokenType.OpenBracket, TokenType.CloseBracket, lexemes, idx);
idx = arg.newIndex;
const value = new ArrayExpression(arg.value);
return { value, newIndex: idx };
}
throw new Error(`Expected opening bracket '[' for array expression at index ${idx}`);
}
}
//# sourceMappingURL=CommandExpressionParser.js.map