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