rawsql-ts
Version:
[beta]High-performance SQL parser and AST analyzer written in TypeScript. Provides fast parsing and advanced transformation capabilities.
117 lines • 5.16 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.JoinClauseParser = void 0;
const Clause_1 = require("../models/Clause");
const Lexeme_1 = require("../models/Lexeme");
const CommandTokenReader_1 = require("../tokenReaders/CommandTokenReader");
const SourceExpressionParser_1 = require("./SourceExpressionParser");
const JoinOnClauseParser_1 = require("./JoinOnClauseParser");
const JoinUsingClauseParser_1 = require("./JoinUsingClauseParser");
class JoinClauseParser {
static tryParse(lexemes, index) {
let idx = index;
const joins = [];
while (this.isJoinCommand(lexemes, idx)) {
const joinClause = this.parseJoinClause(lexemes, idx);
joins.push(joinClause.value);
idx = joinClause.newIndex;
}
if (joins.length > 0) {
return { value: joins, newIndex: idx };
}
return null;
}
static isJoinKeyword(value) {
// Although performance is not ideal,
// we use keyword token reader to centralize keyword management
const result = CommandTokenReader_1.joinkeywordParser.parse(value, 0);
if (result) {
return true;
}
return false;
}
static parseLateral(lexemes, index) {
let idx = index;
if (idx < lexemes.length && lexemes[idx].value === 'lateral') {
// Skip 'lateral' keyword
idx++;
return { value: true, newIndex: idx };
}
return { value: false, newIndex: idx };
}
static isJoinCommand(lexemes, index) {
if (index >= lexemes.length) {
return false;
}
if (lexemes[index].type & Lexeme_1.TokenType.Comma || this.isJoinKeyword(lexemes[index].value) === true) {
return true;
}
return false;
}
static parseJoinClause(lexemes, index) {
let idx = index;
// Extract JOIN keyword and comments
const { joinType, joinComments, newIndex: joinIndex } = this.parseJoinKeyword(lexemes, idx);
idx = joinIndex;
// Parse lateral join
const lateralResult = this.parseLateral(lexemes, idx);
const lateral = lateralResult.value;
idx = lateralResult.newIndex;
// Parse the source expression to join with
const sourceResult = SourceExpressionParser_1.SourceExpressionParser.parseFromLexeme(lexemes, idx);
idx = sourceResult.newIndex;
// Try to parse join condition (ON or USING)
const joinClause = this.parseJoinCondition(lexemes, idx, joinType, sourceResult.value, lateral, joinComments);
if (joinClause) {
return joinClause;
}
// Natural join (no condition)
const naturalJoinClause = new Clause_1.JoinClause(joinType, sourceResult.value, null, lateral);
this.applyJoinComments(naturalJoinClause, joinComments);
return { value: naturalJoinClause, newIndex: idx };
}
// Extract JOIN keyword and its comments
static parseJoinKeyword(lexemes, index) {
const joinType = lexemes[index].value === "," ? "cross join" : lexemes[index].value;
const joinComments = this.extractJoinKeywordComments(lexemes[index]);
return { joinType, joinComments, newIndex: index + 1 };
}
// Extract comments from JOIN keyword token
static extractJoinKeywordComments(token) {
return {
positioned: token.positionedComments && token.positionedComments.length > 0 ? token.positionedComments : null,
legacy: token.comments && token.comments.length > 0 ? token.comments : null
};
}
// Parse join condition (ON or USING)
static parseJoinCondition(lexemes, index, joinType, sourceValue, lateral, joinComments) {
if (index >= lexemes.length)
return null;
// Try JoinOnClauseParser
const onResult = JoinOnClauseParser_1.JoinOnClauseParser.tryParse(lexemes, index);
if (onResult) {
const joinClause = new Clause_1.JoinClause(joinType, sourceValue, onResult.value, lateral);
this.applyJoinComments(joinClause, joinComments);
return { value: joinClause, newIndex: onResult.newIndex };
}
// Try JoinUsingClauseParser
const usingResult = JoinUsingClauseParser_1.JoinUsingClauseParser.tryParse(lexemes, index);
if (usingResult) {
const joinClause = new Clause_1.JoinClause(joinType, sourceValue, usingResult.value, lateral);
this.applyJoinComments(joinClause, joinComments);
return { value: joinClause, newIndex: usingResult.newIndex };
}
return null;
}
// Apply comments to JoinClause directly (no collection then assignment)
static applyJoinComments(joinClause, joinComments) {
if (joinComments.positioned) {
joinClause.joinKeywordPositionedComments = joinComments.positioned;
}
else if (joinComments.legacy) {
joinClause.joinKeywordComments = joinComments.legacy;
}
}
}
exports.JoinClauseParser = JoinClauseParser;
//# sourceMappingURL=JoinClauseParser.js.map