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
JavaScript
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