UNPKG

rawsql-ts

Version:

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

198 lines 9.31 kB
import { FunctionSource, HavingClause, JoinOnClause, OrderByItem, ParenSource, SubQuerySource, WhereClause } from "../models/Clause"; import { BinarySelectQuery, SimpleSelectQuery } from "../models/SelectQuery"; import { ArrayExpression, ArrayIndexExpression, ArrayQueryExpression, ArraySliceExpression, BetweenExpression, BinaryExpression, CaseExpression, CastExpression, FunctionCall, InlineQuery, JsonPredicateExpression, ParenExpression, TupleExpression, TypeValue, UnaryExpression, ValueList } from "../models/ValueComponent"; import { dedupeTopLevelAndConditionsWithMetadata } from "./TopLevelAndConditionDeduper"; export class ConditionDeduplicationOptimizer { constructor() { this.visited = new WeakSet(); this.applied = []; } optimize(query, options) { this.visited = new WeakSet(); this.applied = []; if (!query) { return { query: null, applied: [] }; } this.visitSelectQuery(query, "root", options); return { query, applied: [...this.applied] }; } visitSelectQuery(query, scopeId, options) { var _a, _b, _c, _d, _e, _f, _g, _h; if (this.visited.has(query)) { return; } this.visited.add(query); if (query instanceof BinarySelectQuery) { this.visitSelectQuery(query.left, `${scopeId}.left`, options); this.visitSelectQuery(query.right, `${scopeId}.right`, options); return; } if (!(query instanceof SimpleSelectQuery)) { return; } for (const cte of (_b = (_a = query.withClause) === null || _a === void 0 ? void 0 : _a.tables) !== null && _b !== void 0 ? _b : []) { const cteQuery = cte.query; if (cteQuery instanceof SimpleSelectQuery || cteQuery instanceof BinarySelectQuery) { this.visitSelectQuery(cteQuery, `${scopeId}.cte:${cte.getSourceAliasName()}`, options); } } for (const item of query.selectClause.items) { this.visitValueComponent(item.value, `${scopeId}.select`, options); } if (query.fromClause) { this.visitSourceExpression(query.fromClause.source, `${scopeId}.from`, options); for (const join of (_c = query.fromClause.joins) !== null && _c !== void 0 ? _c : []) { const joinScope = `${scopeId}.join:${(_d = join.source.getAliasName()) !== null && _d !== void 0 ? _d : "unknown"}`; this.visitSourceExpression(join.source, joinScope, options); if (join.condition instanceof JoinOnClause) { join.condition.condition = this.dedupeCondition(join.condition.condition, `${joinScope}.on`, "Removed a duplicate top-level AND condition from a JOIN ON clause.", options); this.visitValueComponent(join.condition.condition, `${joinScope}.on`, options); } } } if (query.whereClause) { query.whereClause = new WhereClause(this.dedupeCondition(query.whereClause.condition, `${scopeId}.where`, "Removed a duplicate top-level AND condition from a WHERE clause.", options)); this.visitValueComponent(query.whereClause.condition, `${scopeId}.where`, options); } if (query.havingClause) { query.havingClause = new HavingClause(this.dedupeCondition(query.havingClause.condition, `${scopeId}.having`, "Removed a duplicate top-level AND condition from a HAVING clause.", options)); this.visitValueComponent(query.havingClause.condition, `${scopeId}.having`, options); } for (const item of (_f = (_e = query.groupByClause) === null || _e === void 0 ? void 0 : _e.grouping) !== null && _f !== void 0 ? _f : []) { this.visitValueComponent(item, `${scopeId}.group_by`, options); } for (const item of (_h = (_g = query.orderByClause) === null || _g === void 0 ? void 0 : _g.order) !== null && _h !== void 0 ? _h : []) { if (item instanceof OrderByItem) { this.visitValueComponent(item.value, `${scopeId}.order_by`, options); } else { this.visitValueComponent(item, `${scopeId}.order_by`, options); } } } visitSourceExpression(source, scopeId, options) { const datasource = source.datasource; if (datasource instanceof SubQuerySource) { this.visitSelectQuery(datasource.query, `${scopeId}.subquery`, options); return; } if (datasource instanceof ParenSource) { const nested = datasource.source; if (nested instanceof SubQuerySource) { this.visitSelectQuery(nested.query, `${scopeId}.subquery`, options); } return; } if (datasource instanceof FunctionSource && datasource.argument) { this.visitValueComponent(datasource.argument, `${scopeId}.function`, options); } } visitValueComponent(value, scopeId, options) { if (this.visited.has(value)) { return; } this.visited.add(value); if (value instanceof InlineQuery) { this.visitSelectQuery(value.selectQuery, `${scopeId}.inline_query`, options); return; } if (value instanceof ArrayQueryExpression) { this.visitSelectQuery(value.query, `${scopeId}.array_query`, options); return; } if (value instanceof ParenExpression) { this.visitValueComponent(value.expression, scopeId, options); return; } if (value instanceof BinaryExpression) { this.visitValueComponent(value.left, scopeId, options); this.visitValueComponent(value.right, scopeId, options); return; } if (value instanceof UnaryExpression) { this.visitValueComponent(value.expression, scopeId, options); return; } if (value instanceof FunctionCall) { if (value.argument) { this.visitValueComponent(value.argument, scopeId, options); } if (value.filterCondition) { this.visitValueComponent(value.filterCondition, `${scopeId}.filter`, options); } return; } if (value instanceof CastExpression) { this.visitValueComponent(value.input, scopeId, options); if (value.castType.argument) { this.visitValueComponent(value.castType.argument, scopeId, options); } return; } if (value instanceof CaseExpression) { if (value.condition) { this.visitValueComponent(value.condition, scopeId, options); } for (const item of value.switchCase.cases) { this.visitValueComponent(item.key, scopeId, options); this.visitValueComponent(item.value, scopeId, options); } if (value.switchCase.elseValue) { this.visitValueComponent(value.switchCase.elseValue, scopeId, options); } return; } if (value instanceof BetweenExpression) { this.visitValueComponent(value.expression, scopeId, options); this.visitValueComponent(value.lower, scopeId, options); this.visitValueComponent(value.upper, scopeId, options); return; } if (value instanceof JsonPredicateExpression) { this.visitValueComponent(value.expression, scopeId, options); return; } if (value instanceof ArrayExpression) { this.visitValueComponent(value.expression, scopeId, options); return; } if (value instanceof ArrayIndexExpression) { this.visitValueComponent(value.array, scopeId, options); this.visitValueComponent(value.index, scopeId, options); return; } if (value instanceof ArraySliceExpression) { this.visitValueComponent(value.array, scopeId, options); if (value.startIndex) { this.visitValueComponent(value.startIndex, scopeId, options); } if (value.endIndex) { this.visitValueComponent(value.endIndex, scopeId, options); } return; } if (value instanceof ValueList || value instanceof TupleExpression) { value.values.forEach(item => this.visitValueComponent(item, scopeId, options)); return; } if (value instanceof TypeValue && value.argument) { this.visitValueComponent(value.argument, scopeId, options); } } dedupeCondition(condition, scopeId, reason, options) { const result = dedupeTopLevelAndConditionsWithMetadata(condition, options); for (const conditionSql of result.removedConditionSql) { this.applied.push({ kind: "dedupe_condition", conditionSql, scopeId, reason }); } return result.expression; } } //# sourceMappingURL=ConditionDeduplicationOptimizer.js.map