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 `${sqlIdent(queryObj.tableName, "table name")}.${safeField}`; } if (join) { return `${table_name}.${safeField}`; } return safeField; })(); function grabValue(val) { if (!isPresent(val)) return; 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: queryObj.equality, fieldName: finalFieldName, value: val, }); } let str; if (Array.isArray(queryObj.value)) { 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.params); } str = "(" + strArray.join(` ${sqlOperator(queryObj.operator)} `) + ")"; } } 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 operatorStrParam = grabValue(queryObj.value) || sqlGenOperatorGen({ equality: queryObj.equality, fieldName: finalFieldName, value: undefined, queryObj, }); str = operatorStrParam.str; sqlSearhValues.push(...operatorStrParam.params); } return { str, values: sqlSearhValues }; }