rawsql-ts
Version:
[beta]High-performance SQL parser and AST analyzer written in TypeScript. Provides fast parsing and advanced transformation capabilities.
65 lines • 3.33 kB
JavaScript
import { SourceExpression } from "../models/Clause";
import { SqlTokenizer } from "./SqlTokenizer";
import { TokenType } from "../models/Lexeme";
import { SourceParser } from "./SourceParser";
import { SourceAliasExpressionParser } from "./SourceAliasExpressionParser";
export class SourceExpressionParser {
/**
* Parse SQL string to SourceExpression (e.g. "table", "table as t", "schema.table t")
*/
static parse(query) {
const tokenizer = new SqlTokenizer(query);
const lexemes = tokenizer.readLexmes();
const result = this.parseFromLexeme(lexemes, 0);
if (result.newIndex < lexemes.length) {
throw new Error(`Syntax error: Unexpected token "${lexemes[result.newIndex].value}" at position ${result.newIndex}. The source expression is complete but there are additional tokens.`);
}
return result.value;
}
static parseTableSourceFromLexemes(lexemes, index) {
const result = SourceParser.parseTableSourceFromLexemes(lexemes, index);
// No alias for table source
const sourceExpr = new SourceExpression(result.value, null);
return { value: sourceExpr, newIndex: result.newIndex };
}
// Parse from lexeme array (was: parse)
static parseFromLexeme(lexemes, index) {
let idx = index;
const sourceResult = SourceParser.parseFromLexeme(lexemes, idx);
idx = sourceResult.newIndex;
if (idx < lexemes.length) {
if (lexemes[idx].value === "as") {
idx++;
const aliasResult = SourceAliasExpressionParser.parseFromLexeme(lexemes, idx);
idx = aliasResult.newIndex;
const sourceExpr = new SourceExpression(sourceResult.value, aliasResult.value);
return { value: sourceExpr, newIndex: idx };
}
/**
* Explanation:
* Source aliases are typically identified as TokenType.Identifier.
* However, when the 'AS' keyword is omitted and column alias names are specified,
* they may sometimes be classified as TokenType.Function.
* Since the TokenReader's responsibility is to perform coarse-grained classification,
* the parser must interpret subsequent 'Function' tokens as source alias expressions
* when they follow a source definition.
* Example:
* SQL: select t.* from (values(1)) t(id)
* Explanation: The alias 't' and its column alias 'id' are parsed as a source alias expression.
*/
if (idx < lexemes.length && this.isTokenTypeAliasCandidate(lexemes[idx].type)) {
const aliasResult = SourceAliasExpressionParser.parseFromLexeme(lexemes, idx);
idx = aliasResult.newIndex;
const sourceExpr = new SourceExpression(sourceResult.value, aliasResult.value);
return { value: sourceExpr, newIndex: idx };
}
}
// no alias
const expr = new SourceExpression(sourceResult.value, null);
return { value: expr, newIndex: idx };
}
static isTokenTypeAliasCandidate(type) {
return (type & TokenType.Identifier) !== 0 || (type & TokenType.Function) !== 0;
}
}
//# sourceMappingURL=SourceExpressionParser.js.map