UNPKG

rawsql-ts

Version:

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

137 lines 7.43 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SqlParamInjector = void 0; const SelectableColumnCollector_1 = require("./SelectableColumnCollector"); const ValueComponent_1 = require("../models/ValueComponent"); const UpstreamSelectQueryFinder_1 = require("./UpstreamSelectQueryFinder"); const SelectQueryParser_1 = require("../parsers/SelectQueryParser"); /** * SqlParamInjector injects state parameters into a SelectQuery model, * creating WHERE conditions and setting parameter values. */ class SqlParamInjector { constructor(optionsOrResolver, options) { // Type-check to decide which argument was provided if (typeof optionsOrResolver === 'function') { this.tableColumnResolver = optionsOrResolver; this.options = options || {}; } else { this.tableColumnResolver = undefined; this.options = optionsOrResolver || {}; } } /** * Injects parameters as WHERE conditions into the given query model. * @param query The SelectQuery to modify * @param state A record of parameter names and values * @returns The modified SelectQuery */ inject(query, state) { // Convert string query to SimpleSelectQuery using SelectQueryParser if needed if (typeof query === 'string') { query = SelectQueryParser_1.SelectQueryParser.parse(query); } // Pass tableColumnResolver to finder and collector const finder = new UpstreamSelectQueryFinder_1.UpstreamSelectQueryFinder(this.tableColumnResolver, this.options); const collector = new SelectableColumnCollector_1.SelectableColumnCollector(this.tableColumnResolver); // Normalization is handled locally below. const normalize = (s) => this.options.ignoreCaseAndUnderscore ? s.toLowerCase().replace(/_/g, '') : s; const allowedOps = ['min', 'max', 'like', 'in', 'any', '=', '<', '>', '!=', '<>', '<=', '>=']; for (const [name, stateValue] of Object.entries(state)) { // skip undefined values if (stateValue === undefined) continue; const queries = finder.find(query, name); if (queries.length === 0) { throw new Error(`Column '${name}' not found in query`); } for (const q of queries) { const columns = collector.collect(q); const entry = columns.find(item => normalize(item.name) === normalize(name)); if (!entry) { throw new Error(`Column '${name}' not found in query`); } const columnRef = entry.value; // if object, validate its keys if (stateValue !== null && typeof stateValue === 'object' && !Array.isArray(stateValue) && Object.getPrototypeOf(stateValue) === Object.prototype) { validateOperators(stateValue, allowedOps, name); } if (stateValue === null || typeof stateValue !== 'object' || Array.isArray(stateValue) || stateValue instanceof Date) { injectSimpleCondition(q, columnRef, name, stateValue); } else { injectComplexConditions(q, columnRef, name, stateValue); } } } function validateOperators(stateValue, allowedOps, name) { Object.keys(stateValue).forEach(op => { if (!allowedOps.includes(op)) { throw new Error(`Unsupported operator '${op}' for state key '${name}'`); } }); } function injectSimpleCondition(q, columnRef, name, stateValue) { const paramExpr = new ValueComponent_1.ParameterExpression(name, stateValue); q.appendWhere(new ValueComponent_1.BinaryExpression(columnRef, "=", paramExpr)); } function injectComplexConditions(q, columnRef, name, stateValue) { if ('=' in stateValue) { const paramEq = new ValueComponent_1.ParameterExpression(name, stateValue['=']); q.appendWhere(new ValueComponent_1.BinaryExpression(columnRef, "=", paramEq)); } if ('min' in stateValue) { const paramMin = new ValueComponent_1.ParameterExpression(name + "_min", stateValue.min); q.appendWhere(new ValueComponent_1.BinaryExpression(columnRef, ">=", paramMin)); } if ('max' in stateValue) { const paramMax = new ValueComponent_1.ParameterExpression(name + "_max", stateValue.max); q.appendWhere(new ValueComponent_1.BinaryExpression(columnRef, "<=", paramMax)); } if ('like' in stateValue) { const paramLike = new ValueComponent_1.ParameterExpression(name + "_like", stateValue.like); q.appendWhere(new ValueComponent_1.BinaryExpression(columnRef, "like", paramLike)); } if ('in' in stateValue) { const arr = stateValue['in']; const prms = arr.map((v, i) => new ValueComponent_1.ParameterExpression(`${name}_in_${i}`, v)); q.appendWhere(new ValueComponent_1.BinaryExpression(columnRef, "in", new ValueComponent_1.ParenExpression(new ValueComponent_1.ValueList(prms)))); } if ('any' in stateValue) { const paramAny = new ValueComponent_1.ParameterExpression(name + "_any", stateValue.any); q.appendWhere(new ValueComponent_1.BinaryExpression(columnRef, "=", new ValueComponent_1.FunctionCall(null, "any", paramAny, null))); } if ('<' in stateValue) { const paramLT = new ValueComponent_1.ParameterExpression(name + "_lt", stateValue['<']); q.appendWhere(new ValueComponent_1.BinaryExpression(columnRef, "<", paramLT)); } if ('>' in stateValue) { const paramGT = new ValueComponent_1.ParameterExpression(name + "_gt", stateValue['>']); q.appendWhere(new ValueComponent_1.BinaryExpression(columnRef, ">", paramGT)); } if ('!=' in stateValue) { const paramNEQ = new ValueComponent_1.ParameterExpression(name + "_neq", stateValue['!=']); q.appendWhere(new ValueComponent_1.BinaryExpression(columnRef, "!=", paramNEQ)); } if ('<>' in stateValue) { const paramNE = new ValueComponent_1.ParameterExpression(name + "_ne", stateValue['<>']); q.appendWhere(new ValueComponent_1.BinaryExpression(columnRef, "<>", paramNE)); } if ('<=' in stateValue) { const paramLE = new ValueComponent_1.ParameterExpression(name + "_le", stateValue['<=']); q.appendWhere(new ValueComponent_1.BinaryExpression(columnRef, "<=", paramLE)); } if ('>=' in stateValue) { const paramGE = new ValueComponent_1.ParameterExpression(name + "_ge", stateValue['>=']); q.appendWhere(new ValueComponent_1.BinaryExpression(columnRef, ">=", paramGE)); } } return query; } } exports.SqlParamInjector = SqlParamInjector; //# sourceMappingURL=SqlParamInjector.js.map