Major version update. Major bugfixes. Security vulnerabilites fixed

This commit is contained in:
2026-10-14 03:02:07 +01:00
parent 4e47bd8ce0
commit 7c095f6f16
112 changed files with 2479 additions and 1219 deletions
+84 -64
View File
@@ -1,92 +1,112 @@
import sqlGenOperatorGen from "./sql-gen-operator-gen";
import { sqlField, sqlIdent, sqlOperator, sqlRawEquality } from "./sql-safe";
function isPresent(val) {
return val !== undefined && val !== null;
}
function isValuesObject(val) {
return typeof val == "object" && val !== null && !ArrayBuffer.isView(val);
}
export default function sqlGenGenSearchStr({ queryObj, join, field, table_name, }) {
let sqlSearhValues = [];
const safeField = sqlField(field);
const finalFieldName = (() => {
if (queryObj?.tableName) {
return `${queryObj.tableName}.${field}`;
return `${sqlIdent(queryObj.tableName, "table name")}.${safeField}`;
}
if (join) {
return `${table_name}.${field}`;
return `${table_name}.${safeField}`;
}
return field;
return safeField;
})();
let str = `${finalFieldName}=?`;
function grabValue(val) {
const valueParsed = val;
if (!valueParsed)
if (!isPresent(val))
return;
const valueString = typeof valueParsed == "string" || typeof valueParsed == "number"
? valueParsed
: valueParsed
? valueParsed.fieldName && valueParsed.tableName
? `${valueParsed.tableName}.${valueParsed.fieldName}`
: valueParsed.value
: undefined;
const valueEquality = typeof valueParsed == "object"
? valueParsed.equality || queryObj.equality
: queryObj.equality;
const operatorStrParam = sqlGenOperatorGen({
if (isValuesObject(val)) {
const isFieldValue = Boolean(val.fieldName && val.tableName);
return sqlGenOperatorGen({
queryObj,
equality: val.equality || queryObj.equality,
fieldName: finalFieldName,
value: isFieldValue
? `${sqlIdent(val.tableName, "table name")}.${sqlIdent(val.fieldName, "field name")}`
: val.value,
isValueFieldValue: isFieldValue,
});
}
return sqlGenOperatorGen({
queryObj,
equality: valueEquality,
fieldName: finalFieldName || "",
value: valueString || "",
isValueFieldValue: Boolean(typeof valueParsed == "object" &&
valueParsed.fieldName &&
valueParsed.tableName),
equality: queryObj.equality,
fieldName: finalFieldName,
value: val,
});
return operatorStrParam;
}
let str;
if (Array.isArray(queryObj.value)) {
const strArray = [];
queryObj.value.forEach((val) => {
const operatorStrParam = grabValue(val);
if (!operatorStrParam)
return;
if (operatorStrParam.str && operatorStrParam.param) {
const items = queryObj.value.filter(isPresent);
const rawValues = items
.map((v) => (isValuesObject(v) ? v.value : v))
.filter(isPresent);
const equality = queryObj.equality;
if ((equality == "IN" || equality == "NOT IN") && !rawValues.length) {
// Empty IN () is invalid SQL: IN matches nothing, NOT IN matches everything
str = equality == "IN" ? "1 = 0" : "1 = 1";
}
else if (equality == "IN" || equality == "NOT IN") {
str = `${finalFieldName} ${equality} (${rawValues
.map(() => "?")
.join(", ")})`;
sqlSearhValues.push(...rawValues);
}
else if (equality == "BETWEEN" || equality == "NOT BETWEEN") {
if (rawValues.length !== 2) {
throw new Error(`\`${equality}\` on \`${finalFieldName}\` requires exactly two values`);
}
str = `${finalFieldName} ${equality} ? AND ?`;
sqlSearhValues.push(...rawValues);
}
else {
if (!items.length) {
throw new Error(`Empty value array for \`${finalFieldName}\``);
}
const strArray = [];
for (const val of items) {
const operatorStrParam = grabValue(val);
if (!operatorStrParam)
continue;
strArray.push(operatorStrParam.str);
sqlSearhValues.push(operatorStrParam.param);
}
else if (operatorStrParam.str) {
strArray.push(operatorStrParam.str);
}
});
str = "(" + strArray.join(` ${queryObj.operator || "AND"} `) + ")";
}
else if (typeof queryObj.value == "object") {
const operatorStrParam = grabValue(queryObj.value);
if (operatorStrParam?.str) {
str = operatorStrParam.str;
if (operatorStrParam.param) {
sqlSearhValues.push(operatorStrParam.param);
sqlSearhValues.push(...operatorStrParam.params);
}
str =
"(" +
strArray.join(` ${sqlOperator(queryObj.operator)} `) +
")";
}
}
else if (queryObj.raw_equality && queryObj.value) {
str = `${finalFieldName} ${queryObj.raw_equality} ?`;
sqlSearhValues.push(queryObj.value);
else if (queryObj.raw_equality && isPresent(queryObj.value)) {
const value = isValuesObject(queryObj.value)
? queryObj.value.value
: queryObj.value;
str = `${finalFieldName} ${sqlRawEquality(queryObj.raw_equality)} ?`;
sqlSearhValues.push(value ?? null);
}
else if (queryObj.between) {
str = `${finalFieldName} BETWEEN ? AND ?`;
sqlSearhValues.push(queryObj.between.min, queryObj.between.max);
}
else if (queryObj.not_between) {
str = `${finalFieldName} NOT BETWEEN ? AND ?`;
sqlSearhValues.push(queryObj.not_between.min, queryObj.not_between.max);
}
else {
const valueParsed = queryObj.value ? queryObj.value : undefined;
const operatorStrParam = sqlGenOperatorGen({
equality: queryObj.equality,
fieldName: finalFieldName || "",
value: valueParsed,
queryObj,
});
if (operatorStrParam.str && operatorStrParam.param) {
str = operatorStrParam.str;
sqlSearhValues.push(operatorStrParam.param);
}
else if (operatorStrParam.str && !operatorStrParam.str.match(/\?/)) {
str = operatorStrParam.str;
}
else {
sqlSearhValues.push(valueParsed || "");
}
const operatorStrParam = grabValue(queryObj.value) ||
sqlGenOperatorGen({
equality: queryObj.equality,
fieldName: finalFieldName,
value: undefined,
queryObj,
});
str = operatorStrParam.str;
sqlSearhValues.push(...operatorStrParam.params);
}
return { str, values: sqlSearhValues };
}