UNPKG

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
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