UNPKG

rawsql-ts

Version:

[beta]High-performance SQL parser and AST analyzer written in TypeScript. Provides fast parsing and advanced transformation capabilities.

125 lines 6.35 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SetClauseParser = void 0; // Provides parsing for SET clauses in UPDATE queries. const Lexeme_1 = require("../models/Lexeme"); const Clause_1 = require("../models/Clause"); const ValueParser_1 = require("./ValueParser"); const FullNameParser_1 = require("./FullNameParser"); const LexemeCommentUtils_1 = require("./utils/LexemeCommentUtils"); /** * Parse SET clause from lexemes (including 'SET' keyword check). */ class SetClauseParser { static parseFromLexeme(lexemes, idx) { var _a; if (lexemes[idx].value !== "set") { throw new Error(`Syntax error at position ${idx}: Expected 'SET' but found '${lexemes[idx].value}'.`); } const setLexeme = lexemes[idx]; const setKeywordComments = (0, LexemeCommentUtils_1.extractLexemeComments)(setLexeme); idx++; const items = []; let pendingBeforeForNext = [...setKeywordComments.after]; const mergeUnique = (target, source) => { for (const comment of source) { if (!target.includes(comment)) { target.push(comment); } } }; const addUniquePositionedComments = (component, position, comments) => { if (comments.length === 0) { return; } const existing = component.getPositionedComments(position); const newOnes = comments.filter(comment => !existing.includes(comment)); if (newOnes.length > 0) { component.addPositionedComments(position, newOnes); } }; while (idx < lexemes.length) { const currentLexeme = lexemes[idx]; if (!currentLexeme) { break; } // Break once we reach the start of the next clause (e.g. WHERE, FROM, RETURNING) if (currentLexeme.value === "where" || currentLexeme.value === "from" || currentLexeme.value === "returning") { break; } if (!(currentLexeme.type & (Lexeme_1.TokenType.Identifier | Lexeme_1.TokenType.Function | Lexeme_1.TokenType.Type | Lexeme_1.TokenType.OpenBracket))) { break; } const columnStartComments = (0, LexemeCommentUtils_1.extractLexemeComments)(currentLexeme); const columnParseResult = FullNameParser_1.FullNameParser.parseFromLexeme(lexemes, idx); idx = columnParseResult.newIndex; const equalsLexeme = lexemes[idx]; if (!equalsLexeme || !(equalsLexeme.type & Lexeme_1.TokenType.Operator) || equalsLexeme.value !== "=") { throw new Error(`Syntax error at position ${idx}: Expected '=' after column name in SET clause.`); } const equalsComments = (0, LexemeCommentUtils_1.extractLexemeComments)(equalsLexeme); idx++; // Parse value expression for the assignment. const valueParseResult = ValueParser_1.ValueParser.parseFromLexeme(lexemes, idx); idx = valueParseResult.newIndex; const setItem = new Clause_1.SetClauseItem({ namespaces: columnParseResult.namespaces, column: columnParseResult.name }, valueParseResult.value); // Attach comments that should appear before the assignment. const beforeComments = []; mergeUnique(beforeComments, pendingBeforeForNext); mergeUnique(beforeComments, columnStartComments.before); if (beforeComments.length > 0) { addUniquePositionedComments(columnParseResult.name, "before", beforeComments); } pendingBeforeForNext = []; // Preserve comments that trail the column identifier itself. if (columnStartComments.after.length > 0) { const afterComments = []; mergeUnique(afterComments, columnStartComments.after); addUniquePositionedComments(columnParseResult.name, "after", afterComments); } // Comments immediately before '=' belong to the assignment item. if (equalsComments.before.length > 0) { const equalsBefore = []; mergeUnique(equalsBefore, equalsComments.before); addUniquePositionedComments(columnParseResult.name, "after", equalsBefore); } // Comments captured after '=' should precede the value expression. if (equalsComments.after.length > 0) { const equalsAfter = []; mergeUnique(equalsAfter, equalsComments.after); addUniquePositionedComments(valueParseResult.value, "before", equalsAfter); } items.push(setItem); if (((_a = lexemes[idx]) === null || _a === void 0 ? void 0 : _a.type) === Lexeme_1.TokenType.Comma) { const commaLexeme = lexemes[idx]; const commaComments = (0, LexemeCommentUtils_1.extractLexemeComments)(commaLexeme); idx++; // Comments that appear before the comma belong to the current item. if (commaComments.before.length > 0) { const commaBefore = []; mergeUnique(commaBefore, commaComments.before); addUniquePositionedComments(setItem, "after", commaBefore); } const nextBefore = []; mergeUnique(nextBefore, commaComments.after); pendingBeforeForNext = nextBefore; continue; } break; } if (pendingBeforeForNext.length > 0 && items.length > 0) { const trailingComments = []; mergeUnique(trailingComments, pendingBeforeForNext); if (trailingComments.length > 0) { addUniquePositionedComments(items[items.length - 1], "after", trailingComments); } } const setClause = new Clause_1.SetClause(items); if (setKeywordComments.before.length > 0) { setClause.addPositionedComments("before", setKeywordComments.before); } return { setClause, newIndex: idx }; } } exports.SetClauseParser = SetClauseParser; //# sourceMappingURL=SetClauseParser.js.map