UNPKG

rawsql-ts

Version:

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

370 lines 13.1 kB
import { CommonTable, DeleteClause, FromClause, FunctionSource, GroupByClause, HavingClause, InsertClause, JoinClause, JoinOnClause, JoinUsingClause, LimitClause, OnConflictClause, OrderByClause, OrderByItem, ParenSource, ReturningClause, SelectClause, SelectItem, SetClause, SourceExpression, SubQuerySource, UpdateClause, UsingClause, WhereClause, WindowFrameClause, WindowsClause, WithClause } from "../models/Clause"; import { DeleteQuery } from "../models/DeleteQuery"; import { InsertQuery } from "../models/InsertQuery"; import { MergeDeleteAction, MergeInsertAction, MergeQuery, MergeUpdateAction, MergeWhenClause } from "../models/MergeQuery"; import { BinarySelectQuery, SimpleSelectQuery, ValuesQuery } from "../models/SelectQuery"; import { UpdateQuery } from "../models/UpdateQuery"; import { ArrayExpression, ArrayIndexExpression, ArrayQueryExpression, ArraySliceExpression, BetweenExpression, BinaryExpression, CaseExpression, CaseKeyValuePair, CastExpression, FunctionCall, InlineQuery, JsonPredicateExpression, ParenExpression, SwitchCaseArgument, TupleExpression, TypeValue, UnaryExpression, ValueList, WindowFrameBoundaryValue, WindowFrameExpression, WindowFrameSpec } from "../models/ValueComponent"; import { SelectQueryWithClauseHelper } from "../utils/SelectQueryWithClauseHelper"; /** * Extracts named query definitions, starting with CTE definitions from `WITH` clauses. * * @remarks Definitions are emitted in SQL source order. For nested CTEs, the outer * CTE definition is emitted when its name is encountered, then definitions inside * that CTE body are emitted before later sibling CTE definitions. */ export class NamedQueryDefinitionExtractor { constructor() { this.definitions = []; this.visited = new Set(); } /** * Extract named query definitions from an AST component. */ static extract(input) { if (!input) { return []; } const extractor = new NamedQueryDefinitionExtractor(); extractor.visit(input); return extractor.definitions; } visit(value) { if (!value || typeof value !== "object") { return; } if (this.visited.has(value)) { return; } this.visited.add(value); if (value instanceof WithClause) { this.visitWithClause(value); return; } if (value instanceof CommonTable) { this.visitCommonTable(value); return; } if (value instanceof SimpleSelectQuery || value instanceof BinarySelectQuery || value instanceof ValuesQuery) { this.visitSelectQuery(value); return; } if (value instanceof InsertQuery) { this.visitInsertQuery(value); return; } if (value instanceof UpdateQuery) { this.visitUpdateQuery(value); return; } if (value instanceof DeleteQuery) { this.visitDeleteQuery(value); return; } if (value instanceof MergeQuery) { this.visitMergeQuery(value); return; } if (this.visitKnownValueComponent(value)) { return; } if (this.visitKnownSqlComponent(value)) { return; } if (Array.isArray(value)) { for (const item of value) { this.visit(item); } return; } for (const key of Object.keys(value)) { this.visit(value[key]); } } visitSelectQuery(query, includeWith = true) { if (query instanceof SimpleSelectQuery) { this.visitSimpleSelectQuery(query, includeWith); return; } if (query instanceof BinarySelectQuery) { this.visitSelectQuery(query.left, includeWith); this.visitSelectQuery(query.right); return; } if (query instanceof ValuesQuery) { if (includeWith) { this.visit(query.withClause); } this.visit(query.tuples); } } visitSimpleSelectQuery(query, includeWith) { if (includeWith) { this.visit(query.withClause); } this.visit(query.selectClause); this.visit(query.fromClause); this.visit(query.whereClause); this.visit(query.groupByClause); this.visit(query.havingClause); this.visit(query.windowClause); this.visit(query.orderByClause); this.visit(query.limitClause); this.visit(query.offsetClause); this.visit(query.fetchClause); this.visit(query.forClause); } visitInsertQuery(query) { const withClause = SelectQueryWithClauseHelper.getWithClause(query.selectQuery); this.visit(withClause); this.visit(query.insertClause); if (query.selectQuery) { this.visitSelectQuery(query.selectQuery, false); } this.visit(query.onConflictClause); this.visit(query.returningClause); } visitUpdateQuery(query) { this.visit(query.withClause); this.visit(query.updateClause); this.visit(query.setClause); this.visit(query.fromClause); this.visit(query.whereClause); this.visit(query.returningClause); } visitDeleteQuery(query) { this.visit(query.withClause); this.visit(query.deleteClause); this.visit(query.usingClause); this.visit(query.whereClause); this.visit(query.returningClause); } visitMergeQuery(query) { this.visit(query.withClause); this.visit(query.target); this.visit(query.source); this.visit(query.onCondition); this.visit(query.whenClauses); this.visit(query.returningClause); } visitWithClause(withClause) { for (const commonTable of withClause.tables) { this.visitCommonTable(commonTable, withClause.recursive); } } visitCommonTable(commonTable, recursive) { const definition = { name: commonTable.getSourceAliasName(), query: commonTable.query, range: null, nameRange: null }; if (recursive !== undefined) { definition.recursive = recursive; } this.definitions.push(definition); this.visit(commonTable.query); } visitKnownSqlComponent(value) { if (value instanceof SelectClause) { this.visit(value.distinct); this.visit(value.hints); this.visit(value.items); return true; } if (value instanceof SelectItem) { this.visit(value.value); return true; } if (value instanceof FromClause) { this.visit(value.source); this.visit(value.joins); return true; } if (value instanceof JoinClause) { this.visit(value.source); this.visit(value.condition); return true; } if (value instanceof JoinOnClause || value instanceof JoinUsingClause) { this.visit(value.condition); return true; } if (value instanceof SourceExpression) { this.visit(value.datasource); return true; } if (value instanceof SubQuerySource) { this.visitSelectQuery(value.query); return true; } if (value instanceof FunctionSource) { this.visit(value.argument); return true; } if (value instanceof ParenSource) { this.visit(value.source); return true; } if (value instanceof WhereClause || value instanceof HavingClause) { this.visit(value.condition); return true; } if (value instanceof LimitClause) { this.visit(value.value); return true; } if (value instanceof GroupByClause) { this.visit(value.grouping); return true; } if (value instanceof WindowsClause) { this.visit(value.windows); return true; } if (value instanceof WindowFrameClause) { this.visit(value.expression); return true; } if (value instanceof OrderByClause) { this.visit(value.order); return true; } if (value instanceof OrderByItem) { this.visit(value.value); return true; } if (value instanceof ReturningClause) { this.visit(value.items); return true; } if (value instanceof OnConflictClause) { this.visit(value.setClause); this.visit(value.whereClause); this.visit(value.forClause); return true; } if (value instanceof SetClause) { for (const item of value.items) { this.visit(item.value); } return true; } if (value instanceof UpdateClause || value instanceof DeleteClause || value instanceof InsertClause) { this.visit(value.source); return true; } if (value instanceof UsingClause) { this.visit(value.sources); return true; } if (value instanceof MergeWhenClause) { this.visit(value.condition); this.visit(value.action); return true; } if (value instanceof MergeUpdateAction) { this.visit(value.setClause); this.visit(value.whereClause); return true; } if (value instanceof MergeDeleteAction) { this.visit(value.whereClause); return true; } if (value instanceof MergeInsertAction) { this.visit(value.values); return true; } return false; } visitKnownValueComponent(value) { if (value instanceof ValueList || value instanceof TupleExpression) { this.visit(value.values); return true; } if (value instanceof FunctionCall) { this.visit(value.argument); this.visit(value.internalOrderBy); this.visit(value.withinGroup); this.visit(value.filterCondition); this.visit(value.over); return true; } if (value instanceof WindowFrameExpression) { this.visit(value.partition); this.visit(value.order); this.visit(value.frameSpec); return true; } if (value instanceof WindowFrameSpec) { this.visit(value.startBound); this.visit(value.endBound); return true; } if (value instanceof WindowFrameBoundaryValue) { this.visit(value.value); return true; } if (value instanceof UnaryExpression || value instanceof ParenExpression || value instanceof ArrayExpression || value instanceof JsonPredicateExpression) { this.visit(value.expression); return true; } if (value instanceof BinaryExpression) { this.visit(value.left); this.visit(value.right); return true; } if (value instanceof SwitchCaseArgument) { this.visit(value.cases); this.visit(value.elseValue); return true; } if (value instanceof CaseKeyValuePair) { this.visit(value.key); this.visit(value.value); return true; } if (value instanceof CastExpression) { this.visit(value.input); this.visit(value.castType); return true; } if (value instanceof CaseExpression) { this.visit(value.condition); this.visit(value.switchCase); return true; } if (value instanceof ArrayQueryExpression) { this.visitSelectQuery(value.query); return true; } if (value instanceof InlineQuery) { this.visitSelectQuery(value.selectQuery); return true; } if (value instanceof BetweenExpression) { this.visit(value.expression); this.visit(value.lower); this.visit(value.upper); return true; } if (value instanceof TypeValue) { this.visit(value.argument); return true; } if (value instanceof ArraySliceExpression) { this.visit(value.array); this.visit(value.startIndex); this.visit(value.endIndex); return true; } if (value instanceof ArrayIndexExpression) { this.visit(value.array); this.visit(value.index); return true; } return false; } } //# sourceMappingURL=NamedQueryDefinitionExtractor.js.map