UNPKG

react-querybuilder

Version:

React Query Builder component for constructing queries and filters, with utilities for executing them in various database and evaluation contexts

1,194 lines (1,173 loc) 81.2 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/utils/formatQuery/index.ts var formatQuery_exports = {}; __export(formatQuery_exports, { celCombinatorMap: () => celCombinatorMap, defaultCELValueProcessor: () => defaultCELValueProcessor, defaultExportOperatorMap: () => defaultExportOperatorMap, defaultMongoDBValueProcessor: () => defaultMongoDBValueProcessor, defaultNLTranslations: () => defaultNLTranslations, defaultOperatorProcessorNL: () => defaultOperatorProcessorNL, defaultRuleProcessorCEL: () => defaultRuleProcessorCEL, defaultRuleProcessorElasticSearch: () => defaultRuleProcessorElasticSearch, defaultRuleProcessorJSONata: () => defaultRuleProcessorJSONata, defaultRuleProcessorJsonLogic: () => defaultRuleProcessorJsonLogic, defaultRuleProcessorMongoDB: () => defaultRuleProcessorMongoDB, defaultRuleProcessorMongoDBQuery: () => defaultRuleProcessorMongoDBQuery, defaultRuleProcessorNL: () => defaultRuleProcessorNL, defaultRuleProcessorParameterized: () => defaultRuleProcessorParameterized, defaultRuleProcessorSQL: () => defaultRuleProcessorSQL, defaultRuleProcessorSpEL: () => defaultRuleProcessorSpEL, defaultSpELValueProcessor: () => defaultSpELValueProcessor, defaultValueProcessor: () => defaultValueProcessor, defaultValueProcessorByRule: () => defaultValueProcessorByRule, defaultValueProcessorCELByRule: () => defaultValueProcessorCELByRule, defaultValueProcessorMongoDBByRule: () => defaultValueProcessorMongoDBByRule, defaultValueProcessorNL: () => defaultValueProcessorNL, defaultValueProcessorSpELByRule: () => defaultValueProcessorSpELByRule, formatQuery: () => formatQuery, getNLTranslataion: () => getNLTranslataion, getQuoteFieldNamesWithArray: () => getQuoteFieldNamesWithArray, getQuotedFieldName: () => getQuotedFieldName, isValidValue: () => isValidValue, isValueProcessorLegacy: () => isValueProcessorLegacy, jsonLogicAdditionalOperators: () => jsonLogicAdditionalOperators, mapSQLOperator: () => mapSQLOperator, mongoOperators: () => mongoOperators, normalizeConstituentWordOrder: () => normalizeConstituentWordOrder, numerifyValues: () => numerifyValues, shouldRenderAsNumber: () => shouldRenderAsNumber, sqlDialectPresets: () => sqlDialectPresets }); module.exports = __toCommonJS(formatQuery_exports); // src/defaults.ts var defaultPlaceholderName = "~"; var defaultPlaceholderFieldName = defaultPlaceholderName; var defaultPlaceholderOperatorName = defaultPlaceholderName; var defaultJoinChar = ","; var defaultCombinators = [ { name: "and", value: "and", label: "AND" }, { name: "or", value: "or", label: "OR" } ]; var defaultCombinatorsExtended = [ ...defaultCombinators, { name: "xor", value: "xor", label: "XOR" } ]; // src/utils/arrayUtils.ts var splitBy = (str, splitChar = defaultJoinChar) => typeof str === "string" ? str.split(`\\${splitChar}`).map((c) => c.split(splitChar)).reduce((prev, curr, idx) => { if (idx === 0) { return curr; } return [...prev.slice(0, -1), `${prev.at(-1)}${splitChar}${curr[0]}`, ...curr.slice(1)]; }, []) : []; var joinWith = (strArr, joinChar = defaultJoinChar) => strArr.map((str) => `${str ?? ""}`.replaceAll(joinChar[0], `\\${joinChar[0]}`)).join(joinChar); var trimIfString = (val) => typeof val === "string" ? val.trim() : val; var toArray = (v, { retainEmptyStrings } = {}) => Array.isArray(v) ? v.map((v2) => trimIfString(v2)) : typeof v === "string" ? splitBy(v, defaultJoinChar).filter(retainEmptyStrings ? () => true : (s) => !/^\s*$/.test(s)).map((s) => s.trim()) : typeof v === "number" ? [v] : []; // src/utils/misc.ts var import_numeric_quantity = require("numeric-quantity"); var numericRegex = new RegExp( import_numeric_quantity.numericRegex.source.replace(/^\^/, String.raw`^\s*`).replace(/\$$/, String.raw`\s*$`) ); var isPojo = (obj) => obj === null || typeof obj !== "object" ? false : Object.getPrototypeOf(obj) === Object.prototype; var nullOrUndefinedOrEmpty = (value) => value === null || value === void 0 || value === ""; // src/utils/parseNumber.ts var import_numeric_quantity2 = require("numeric-quantity"); var parseNumber = (val, { parseNumbers } = {}) => { if (!parseNumbers || typeof val === "bigint" || typeof val === "number") { return val; } if (parseNumbers === "native") { return parseFloat(val); } const valAsNum = ( // TODO: Should these options be configurable? (0, import_numeric_quantity2.numericQuantity)(val, { allowTrailingInvalid: parseNumbers === "enhanced", romanNumerals: false, round: false }) ); return isNaN(valAsNum) ? val : valAsNum; }; // src/utils/getParseNumberMethod.ts var getParseNumberMethod = ({ parseNumbers, inputType }) => { if (typeof parseNumbers === "string") { const [method, level] = parseNumbers.split("-"); if (level === "limited") { return inputType === "number" ? method : false; } return method; } return parseNumbers ? "strict" : false; }; // src/utils/isRuleGroup.ts var isRuleGroup = (rg) => isPojo(rg) && Array.isArray(rg.rules); var isRuleGroupType = (rg) => isRuleGroup(rg) && typeof rg.combinator === "string"; var isRuleGroupTypeIC = (rg) => isRuleGroup(rg) && rg.combinator === void 0; // src/utils/optGroupUtils.ts var import_immer = require("immer"); var isOptionWithName = (opt) => isPojo(opt) && "name" in opt && typeof opt.name === "string"; var isOptionWithValue = (opt) => isPojo(opt) && "value" in opt && typeof opt.value === "string"; function toFullOption(opt, baseProperties) { const recipe = (0, import_immer.produce)((draft) => { const idObj = {}; let needsUpdating = !!baseProperties; if (isOptionWithName(draft) && !isOptionWithValue(draft)) { idObj.value = draft.name; needsUpdating = true; } else if (!isOptionWithName(draft) && isOptionWithValue(draft)) { idObj.name = draft.value; needsUpdating = true; } if (needsUpdating) { return Object.assign({}, baseProperties, draft, idObj); } }); return recipe(opt); } function toFullOptionList(optList, baseProperties) { if (!Array.isArray(optList)) { return []; } const recipe = (0, import_immer.produce)((draft) => { if (isFlexibleOptionGroupArray(draft)) { for (const optGroup of draft) { for (const [idx, opt] of optGroup.options.entries()) optGroup.options[idx] = toFullOption(opt, baseProperties); } } else { for (const [idx, opt] of draft.entries()) draft[idx] = toFullOption(opt, baseProperties); } }); return recipe(optList); } var uniqByIdentifier = (originalArray) => { const names = /* @__PURE__ */ new Set(); const newArray = []; for (const el of originalArray) { if (!names.has(el.value ?? el.name)) { names.add(el.value ?? el.name); newArray.push(el); } } return originalArray.length === newArray.length ? originalArray : newArray; }; var isOptionGroupArray = (arr) => Array.isArray(arr) && arr.length > 0 && isPojo(arr[0]) && "options" in arr[0] && Array.isArray(arr[0].options); var isFlexibleOptionArray = (arr) => { let isFOA = false; if (Array.isArray(arr)) { for (const o of arr) { if (isOptionWithName(o) || isOptionWithValue(o)) { isFOA = true; } else { return false; } } } return isFOA; }; var isFlexibleOptionGroupArray = (arr, { allowEmpty = false } = {}) => { let isFOGA = false; if (Array.isArray(arr)) { for (const og of arr) { if (isPojo(og) && "options" in og && (isFlexibleOptionArray(og.options) || allowEmpty && Array.isArray(og.options) && og.options.length === 0)) { isFOGA = true; } else { return false; } } } return isFOGA; }; var getOption = (arr, name) => (isFlexibleOptionGroupArray(arr, { allowEmpty: true }) ? arr.flatMap((og) => og.options) : arr).find((op) => op.value === name || op.name === name); var toFlatOptionArray = (arr) => uniqByIdentifier(isOptionGroupArray(arr) ? arr.flatMap((og) => og.options) : arr); // src/utils/formatQuery/utils.ts var mapSQLOperator = (rqbOperator) => { switch (rqbOperator.toLowerCase()) { case "null": return "is null"; case "notnull": return "is not null"; case "notin": return "not in"; case "notbetween": return "not between"; case "contains": case "beginswith": case "endswith": return "like"; case "doesnotcontain": case "doesnotbeginwith": case "doesnotendwith": return "not like"; default: return rqbOperator; } }; var mongoOperators = { "=": "$eq", "!=": "$ne", "<": "$lt", "<=": "$lte", ">": "$gt", ">=": "$gte", in: "$in", notin: "$nin", notIn: "$nin" // only here for backwards compatibility }; var celCombinatorMap = { and: "&&", or: "||" }; var jsonLogicAdditionalOperators = { startsWith: (a, b) => typeof a === "string" && a.startsWith(b), endsWith: (a, b) => typeof a === "string" && a.endsWith(b) }; var numerifyValues = (rg, options) => ({ ...rg, // @ts-expect-error TS doesn't keep track of odd/even indexes here rules: rg.rules.map((r) => { if (typeof r === "string") { return r; } if (isRuleGroup(r)) { return numerifyValues(r, options); } const fieldData = getOption(options.fields, r.field); const parseNumbers = getParseNumberMethod({ parseNumbers: options.parseNumbers, inputType: fieldData?.inputType }); if (Array.isArray(r.value)) { return { ...r, value: r.value.map((v) => parseNumber(v, { parseNumbers })) }; } const valAsArray = toArray(r.value, { retainEmptyStrings: true }).map( (v) => parseNumber(v, { parseNumbers }) ); if (valAsArray.every((v) => typeof v === "number")) { if (valAsArray.length > 1) { return { ...r, value: valAsArray }; } else if (valAsArray.length === 1) { return { ...r, value: valAsArray[0] }; } } return r; }) }); var isValidValue = (value) => typeof value === "string" && value.length > 0 || typeof value === "number" && !isNaN(value) || typeof value !== "string" && typeof value !== "number"; var shouldRenderAsNumber = (value, parseNumbers) => !!parseNumbers && (typeof value === "number" || typeof value === "bigint" || typeof value === "string" && numericRegex.test(value)); var isValueProcessorLegacy = (valueProcessor) => valueProcessor.length >= 3; var getQuoteFieldNamesWithArray = (quoteFieldNamesWith = ["", ""]) => Array.isArray(quoteFieldNamesWith) ? quoteFieldNamesWith : typeof quoteFieldNamesWith === "string" ? [quoteFieldNamesWith, quoteFieldNamesWith] : quoteFieldNamesWith ?? ["", ""]; var getQuotedFieldName = (fieldName, { quoteFieldNamesWith, fieldIdentifierSeparator }) => { const [qPre, qPost] = getQuoteFieldNamesWithArray(quoteFieldNamesWith); return typeof fieldIdentifierSeparator === "string" && fieldIdentifierSeparator.length > 0 ? joinWith( splitBy(fieldName, fieldIdentifierSeparator).map((part) => `${qPre}${part}${qPost}`), fieldIdentifierSeparator ) : `${qPre}${fieldName}${qPost}`; }; var defaultWordOrder = ["S", "V", "O"]; var normalizeConstituentWordOrder = (input) => { const result = []; const letterSet = new Set(defaultWordOrder); for (const char of input.toUpperCase()) { if (letterSet.has(char)) { result.push(char); letterSet.delete(char); if (letterSet.size === 0) break; } } for (const letter of defaultWordOrder) { if (letterSet.has(letter)) { result.push(letter); } } return result; }; var defaultNLTranslations = { // and: 'and', // or: 'or', // true: 'true', // false: 'false', groupPrefix: "", // groupPrefix_not: '', groupPrefix_not_xor: "either zero or more than one of", groupPrefix_xor: "exactly one of", groupSuffix: "is true", groupSuffix_not: "is not true" // groupSuffix_not_xor: 'is true', // groupSuffix_xor: 'is true', }; var translationMatchFilter = (key, keyToTest, conditions) => ( // The translation matches the base key keyToTest.startsWith(key) && // The translation specifies all conditions conditions.every( (c) => ( // This translation specifies _this_ condition keyToTest.includes(`_${c}`) && // This translation specifies the same _total number_ of conditions keyToTest.match(/_/g)?.length === conditions.length ) ) ); var getNLTranslataion = (key, translations, conditions = []) => conditions.length === 0 ? translations[key] ?? defaultNLTranslations[key] ?? /* istanbul ignore next */ "" : Object.entries(translations).find( ([keyToTest]) => translationMatchFilter(key, keyToTest, conditions) )?.[1] ?? Object.entries(defaultNLTranslations).find( ([keyToTest]) => translationMatchFilter(key, keyToTest, conditions) )?.[1] ?? defaultNLTranslations[key] ?? /* istanbul ignore next */ ""; // src/utils/formatQuery/defaultRuleProcessorCEL.ts var shouldNegate = (op) => op.startsWith("not") || op.startsWith("doesnot"); var escapeDoubleQuotes = (v, escapeQuotes) => typeof v !== "string" || !escapeQuotes ? v : v.replaceAll(`"`, `\\"`); var defaultRuleProcessorCEL = ({ field, operator, value, valueSource }, { escapeQuotes, parseNumbers, preserveValueOrder } = {}) => { const valueIsField = valueSource === "field"; const operatorTL = (operator === "=" ? "==" : operator).toLowerCase(); const useBareValue = typeof value === "number" || typeof value === "boolean" || typeof value === "bigint" || shouldRenderAsNumber(value, parseNumbers); switch (operatorTL) { case "<": case "<=": case "==": case "!=": case ">": case ">=": return `${field} ${operatorTL} ${valueIsField || useBareValue ? trimIfString(value) : `"${escapeDoubleQuotes(value, escapeQuotes)}"`}`; case "contains": case "doesnotcontain": { const negate2 = shouldNegate(operatorTL) ? "!" : ""; return `${negate2}${field}.contains(${valueIsField ? trimIfString(value) : `"${escapeDoubleQuotes(value, escapeQuotes)}"`})`; } case "beginswith": case "doesnotbeginwith": { const negate2 = shouldNegate(operatorTL) ? "!" : ""; return `${negate2}${field}.startsWith(${valueIsField ? trimIfString(value) : `"${escapeDoubleQuotes(value, escapeQuotes)}"`})`; } case "endswith": case "doesnotendwith": { const negate2 = shouldNegate(operatorTL) ? "!" : ""; return `${negate2}${field}.endsWith(${valueIsField ? trimIfString(value) : `"${escapeDoubleQuotes(value, escapeQuotes)}"`})`; } case "null": return `${field} == null`; case "notnull": return `${field} != null`; case "in": case "notin": { const [prefix, suffix] = shouldNegate(operatorTL) ? ["!(", ")"] : ["", ""]; const valueAsArray = toArray(value); return `${prefix}${field} in [${valueAsArray.map( (val) => valueIsField || shouldRenderAsNumber(val, parseNumbers) ? `${trimIfString(val)}` : `"${escapeDoubleQuotes(val, escapeQuotes)}"` ).join(", ")}]${suffix}`; } case "between": case "notbetween": { const valueAsArray = toArray(value); if (valueAsArray.length >= 2 && !nullOrUndefinedOrEmpty(valueAsArray[0]) && !nullOrUndefinedOrEmpty(valueAsArray[1])) { const [first, second] = valueAsArray; const firstNum = shouldRenderAsNumber(first, true) ? parseNumber(first, { parseNumbers: true }) : NaN; const secondNum = shouldRenderAsNumber(second, true) ? parseNumber(second, { parseNumbers: true }) : NaN; let firstValue = isNaN(firstNum) ? valueIsField ? `${first}` : `"${escapeDoubleQuotes(first, escapeQuotes)}"` : firstNum; let secondValue = isNaN(secondNum) ? valueIsField ? `${second}` : `"${escapeDoubleQuotes(second, escapeQuotes)}"` : secondNum; if (!preserveValueOrder && firstValue === firstNum && secondValue === secondNum && secondNum < firstNum) { const tempNum = secondNum; secondValue = firstNum; firstValue = tempNum; } return operatorTL === "between" ? `(${field} >= ${firstValue} && ${field} <= ${secondValue})` : `(${field} < ${firstValue} || ${field} > ${secondValue})`; } else { return ""; } } } return ""; }; // src/utils/formatQuery/defaultRuleProcessorMongoDBQuery.ts var defaultRuleProcessorMongoDBQuery = ({ field, operator, value, valueSource }, { parseNumbers, preserveValueOrder } = {}) => { const valueIsField = valueSource === "field"; if (operator === "=" && !valueIsField) { return { [field]: shouldRenderAsNumber(value, parseNumbers) ? parseNumber(value, { parseNumbers: "strict" }) : value }; } const operatorLC = operator.toLowerCase(); switch (operatorLC) { case "<": case "<=": case "=": case "!=": case ">": case ">=": { const mongoOperator = mongoOperators[operatorLC]; return valueIsField ? { $expr: { [mongoOperator]: [`$${field}`, `$${value}`] } } : { [field]: { [mongoOperator]: shouldRenderAsNumber(value, parseNumbers) ? parseNumber(value, { parseNumbers: "strict" }) : value } }; } case "contains": return valueIsField ? { $where: `this.${field}.includes(this.${value})` } : { [field]: { $regex: value } }; case "beginswith": return valueIsField ? { $where: `this.${field}.startsWith(this.${value})` } : { [field]: { $regex: `^${value}` } }; case "endswith": return valueIsField ? { $where: `this.${field}.endsWith(this.${value})` } : { [field]: { $regex: `${value}$` } }; case "doesnotcontain": return valueIsField ? { $where: `!this.${field}.includes(this.${value})` } : { [field]: { $not: { $regex: value } } }; case "doesnotbeginwith": return valueIsField ? { $where: `!this.${field}.startsWith(this.${value})` } : { [field]: { $not: { $regex: `^${value}` } } }; case "doesnotendwith": return valueIsField ? { $where: `!this.${field}.endsWith(this.${value})` } : { [field]: { $not: { $regex: `${value}$` } } }; case "null": return { [field]: null }; case "notnull": return { [field]: { $ne: null } }; case "in": case "notin": { const valueAsArray = toArray(value); return valueIsField ? { $where: `${operatorLC === "notin" ? "!" : ""}[${valueAsArray.map((val) => `this.${val}`).join(",")}].includes(this.${field})` } : { [field]: { [mongoOperators[operatorLC]]: valueAsArray.map( (val) => shouldRenderAsNumber(val, parseNumbers) ? parseNumber(val, { parseNumbers: "strict" }) : val ) } }; } case "between": case "notbetween": { const valueAsArray = toArray(value); if (valueAsArray.length >= 2 && isValidValue(valueAsArray[0]) && isValidValue(valueAsArray[1])) { const [first, second] = valueAsArray; const firstNum = shouldRenderAsNumber(first, true) ? parseNumber(first, { parseNumbers: "strict" }) : NaN; const secondNum = shouldRenderAsNumber(second, true) ? parseNumber(second, { parseNumbers: "strict" }) : NaN; let firstValue = valueIsField ? first : isNaN(firstNum) ? first : firstNum; let secondValue = valueIsField ? second : isNaN(secondNum) ? second : secondNum; if (!preserveValueOrder && firstValue === firstNum && secondValue === secondNum && secondNum < firstNum) { const tempNum = secondNum; secondValue = firstNum; firstValue = tempNum; } if (operatorLC === "between") { return valueIsField ? { $and: [ { $expr: { $gte: [`$${field}`, `$${firstValue}`] } }, { $expr: { $lte: [`$${field}`, `$${secondValue}`] } } ] } : { [field]: { $gte: firstValue, $lte: secondValue } }; } else { return valueIsField ? { $or: [ { $expr: { $lt: [`$${field}`, `$${firstValue}`] } }, { $expr: { $gt: [`$${field}`, `$${secondValue}`] } } ] } : { $or: [{ [field]: { $lt: firstValue } }, { [field]: { $gt: secondValue } }] }; } } else { return ""; } } } return ""; }; // src/utils/formatQuery/defaultRuleProcessorMongoDB.ts var defaultRuleProcessorMongoDB = (rule, options) => { const queryObj = defaultRuleProcessorMongoDBQuery(rule, options); return queryObj ? JSON.stringify(queryObj) : ""; }; // src/utils/formatQuery/defaultRuleProcessorSpEL.ts var shouldNegate2 = (op) => op.startsWith("not") || op.startsWith("doesnot"); var wrapInNegation = (clause, negate2) => negate2 ? `!(${clause})` : `${clause}`; var escapeSingleQuotes = (v, escapeQuotes) => typeof v !== "string" || !escapeQuotes ? v : v.replaceAll(`'`, `\\'`); var defaultRuleProcessorSpEL = ({ field, operator, value, valueSource }, { escapeQuotes, parseNumbers, preserveValueOrder } = {}) => { const valueIsField = valueSource === "field"; const operatorTL = (operator === "=" ? "==" : operator).toLowerCase(); const useBareValue = typeof value === "number" || typeof value === "boolean" || typeof value === "bigint" || shouldRenderAsNumber(value, parseNumbers); switch (operatorTL) { case "<": case "<=": case "==": case "!=": case ">": case ">=": return `${field} ${operatorTL} ${valueIsField || useBareValue ? trimIfString(value) : `'${escapeSingleQuotes(value, escapeQuotes)}'`}`; case "contains": case "doesnotcontain": return wrapInNegation( `${field} matches ${valueIsField || useBareValue ? trimIfString(value) : `'${escapeSingleQuotes(value, escapeQuotes)}'`}`, shouldNegate2(operatorTL) ); case "beginswith": case "doesnotbeginwith": { const valueTL = valueIsField ? `'^'.concat(${trimIfString(value)})` : `'${typeof value === "string" && !value.startsWith("^") || useBareValue ? "^" : ""}${escapeSingleQuotes(value, escapeQuotes)}'`; return wrapInNegation(`${field} matches ${valueTL}`, shouldNegate2(operatorTL)); } case "endswith": case "doesnotendwith": { const valueTL = valueIsField ? `${trimIfString(value)}.concat('$')` : `'${escapeSingleQuotes(value, escapeQuotes)}${typeof value === "string" && !value.endsWith("$") || useBareValue ? "$" : ""}'`; return wrapInNegation(`${field} matches ${valueTL}`, shouldNegate2(operatorTL)); } case "null": return `${field} == null`; case "notnull": return `${field} != null`; case "in": case "notin": { const negate2 = shouldNegate2(operatorTL) ? "!" : ""; const valueAsArray = toArray(value); return valueAsArray.length > 0 ? `${negate2}(${valueAsArray.map( (val) => `${field} == ${valueIsField || shouldRenderAsNumber(val, parseNumbers) ? `${trimIfString(val)}` : `'${escapeSingleQuotes(val, escapeQuotes)}'`}` ).join(" or ")})` : ""; } case "between": case "notbetween": { const valueAsArray = toArray(value); if (valueAsArray.length >= 2 && !nullOrUndefinedOrEmpty(valueAsArray[0]) && !nullOrUndefinedOrEmpty(valueAsArray[1])) { const [first, second] = valueAsArray; const firstNum = shouldRenderAsNumber(first, true) ? parseNumber(first, { parseNumbers: true }) : NaN; const secondNum = shouldRenderAsNumber(second, true) ? parseNumber(second, { parseNumbers: true }) : NaN; let firstValue = isNaN(firstNum) ? valueIsField ? `${first}` : `'${escapeSingleQuotes(first, escapeQuotes)}'` : firstNum; let secondValue = isNaN(secondNum) ? valueIsField ? `${second}` : `'${escapeSingleQuotes(second, escapeQuotes)}'` : secondNum; if (!preserveValueOrder && firstValue === firstNum && secondValue === secondNum && secondNum < firstNum) { const tempNum = secondNum; secondValue = firstNum; firstValue = tempNum; } return operatorTL === "between" ? `(${field} >= ${firstValue} and ${field} <= ${secondValue})` : `(${field} < ${firstValue} or ${field} > ${secondValue})`; } else { return ""; } } } return ""; }; // src/utils/formatQuery/defaultValueProcessorByRule.ts var escapeStringValueQuotes = (v, quoteChar, escapeQuotes) => escapeQuotes && typeof v === "string" ? v.replaceAll(`${quoteChar}`, `${quoteChar}${quoteChar}`) : v; var defaultValueProcessorByRule = ({ operator, value, valueSource }, { escapeQuotes, parseNumbers, preserveValueOrder, quoteFieldNamesWith, quoteValuesWith, concatOperator = "||", fieldIdentifierSeparator, wrapValueWith = ["", ""], translations } = {}) => { const valueIsField = valueSource === "field"; const operatorLowerCase = operator.toLowerCase(); const quoteChar = quoteValuesWith || "'"; const quoteValue = (v) => `${wrapValueWith[0]}${quoteChar}${v}${quoteChar}${wrapValueWith[1]}`; const escapeValue = (v) => escapeStringValueQuotes(v, quoteChar, escapeQuotes); const wrapAndEscape = (v) => quoteValue(escapeValue(v)); const wrapFieldName = (v) => getQuotedFieldName(v, { quoteFieldNamesWith, fieldIdentifierSeparator }); const concat = (...values) => concatOperator.toUpperCase() === "CONCAT" ? `CONCAT(${values.join(", ")})` : values.join(` ${concatOperator} `); switch (operatorLowerCase) { case "null": case "notnull": { return ""; } case "in": case "notin": { const valueAsArray = toArray(value); if (valueAsArray.length > 0) { return `(${valueAsArray.map( (v) => valueIsField ? wrapFieldName(v) : shouldRenderAsNumber(v, parseNumbers) ? `${trimIfString(v)}` : `${wrapAndEscape(v)}` ).join(", ")})`; } return ""; } case "between": case "notbetween": { const valueAsArray = toArray(value, { retainEmptyStrings: true }); if (valueAsArray.length < 2 || !isValidValue(valueAsArray[0]) || !isValidValue(valueAsArray[1])) { return ""; } const [first, second] = valueAsArray; const firstNum = shouldRenderAsNumber(first, parseNumbers) ? parseNumber(first, { parseNumbers: "strict" }) : NaN; const secondNum = shouldRenderAsNumber(second, parseNumbers) ? parseNumber(second, { parseNumbers: "strict" }) : NaN; const firstValue = isNaN(firstNum) ? valueIsField ? `${first}` : first : firstNum; const secondValue = isNaN(secondNum) ? valueIsField ? `${second}` : second : secondNum; const valsOneAndTwoOnly = [firstValue, secondValue]; if (!preserveValueOrder && firstValue === firstNum && secondValue === secondNum && secondNum < firstNum) { valsOneAndTwoOnly[0] = secondNum; valsOneAndTwoOnly[1] = firstNum; } return (valueIsField ? valsOneAndTwoOnly.map((v) => wrapFieldName(v)) : valsOneAndTwoOnly.every((v) => shouldRenderAsNumber(v, parseNumbers)) ? valsOneAndTwoOnly.map((v) => parseNumber(v, { parseNumbers: "strict" })) : valsOneAndTwoOnly.map((v) => wrapAndEscape(v))).join(` ${translations?.and ?? "and"} `); } case "contains": case "doesnotcontain": return valueIsField ? concat(quoteValue("%"), wrapFieldName(value), quoteValue("%")) : quoteValue(`%${escapeValue(value)}%`); case "beginswith": case "doesnotbeginwith": return valueIsField ? concat(wrapFieldName(value), quoteValue("%")) : quoteValue(`${escapeValue(value)}%`); case "endswith": case "doesnotendwith": return valueIsField ? concat(quoteValue("%"), wrapFieldName(value)) : quoteValue(`%${escapeValue(value)}`); } if (typeof value === "boolean") { return value ? "TRUE" : "FALSE"; } return valueIsField ? wrapFieldName(value) : shouldRenderAsNumber(value, parseNumbers) ? `${trimIfString(value)}` : `${wrapAndEscape(value)}`; }; // src/utils/formatQuery/defaultRuleProcessorElasticSearch.ts var rangeOperatorMap = { "<": "lt", "<=": "lte", ">": "gt", ">=": "gte" }; var negateIfNotOp = (op, elasticSearchRule) => op.startsWith("not") || op.startsWith("doesnot") ? { bool: { must_not: elasticSearchRule } } : elasticSearchRule; var escapeSQ = (s) => s?.replace(/('|\\)/g, `\\$1`); var textFunctionMap = { beginswith: "startsWith", doesnotbeginwith: "startsWith", doesnotcontain: "contains", doesnotendwith: "endsWith", endswith: "endsWith" }; var getTextScript = (f, o, v) => { const script = `doc['${f}'].value.${textFunctionMap[o] ?? o}(doc['${v}'].value)`; return o.startsWith("d") ? `!${script}` : script; }; var valueRenderer = (v, parseNumbers) => typeof v === "boolean" ? v : shouldRenderAsNumber(v, parseNumbers) ? parseNumber(v, { parseNumbers }) : v; var defaultRuleProcessorElasticSearch = ({ field, operator, value, valueSource }, { parseNumbers, preserveValueOrder } = {}) => { const operatorLC = operator.toLowerCase(); if (valueSource === "field") { if (toArray(value).some((v) => typeof v !== "string")) return false; const fieldForScript = escapeSQ(field); switch (operatorLC) { case "=": case "!=": case ">": case ">=": case "<": case "<=": { const operatorForScript = operatorLC === "=" ? "==" : operatorLC; const valueForScript = escapeSQ(value); return valueForScript ? { bool: { filter: { script: { script: `doc['${fieldForScript}'].value ${operatorForScript} doc['${valueForScript}'].value` } } } } : false; } case "in": case "notin": { const valueAsArray = toArray(value); if (valueAsArray.length > 0) { const arr = valueAsArray.map((v) => ({ bool: { filter: { script: { script: `doc['${fieldForScript}'].value == doc['${v}'].value` } } } })); return { bool: operatorLC === "in" ? { should: arr } : { must_not: arr } }; } return false; } case "between": case "notbetween": { const valueAsArray = toArray(value); if (valueAsArray.length >= 2 && valueAsArray[0] && valueAsArray[1]) { const script = `doc['${fieldForScript}'].value >= doc['${valueAsArray[0]}'].value && doc['${fieldForScript}'].value <= doc['${valueAsArray[1]}'].value`; return { bool: { filter: { script: { script: operatorLC === "notbetween" ? `!(${script})` : script } } } }; } return false; } case "contains": case "doesnotcontain": case "beginswith": case "doesnotbeginwith": case "endswith": case "doesnotendwith": { const valueForScript = escapeSQ(value); if (!valueForScript) return false; const script = getTextScript(fieldForScript, operatorLC, valueForScript); return { bool: { filter: { script: { script } } } }; } } } switch (operatorLC) { case "<": case "<=": case ">": case ">=": return { range: { [field]: { [rangeOperatorMap[operatorLC]]: valueRenderer(value, parseNumbers) } } }; case "=": return { term: { [field]: valueRenderer(value, parseNumbers) } }; case "!=": return { bool: { must_not: { term: { [field]: valueRenderer(value, parseNumbers) } } } }; case "null": return { bool: { must_not: { exists: { field } } } }; case "notnull": return { exists: { field } }; case "in": case "notin": { const valueAsArray = toArray(value).map((v) => valueRenderer(v, parseNumbers)); if (valueAsArray.length > 0) { const arr = valueAsArray.map((v) => ({ term: { [field]: valueRenderer(v, parseNumbers) } })); return { bool: operatorLC === "in" ? { should: arr } : { must_not: arr } }; } return false; } case "between": case "notbetween": { const valueAsArray = toArray(value); if (valueAsArray.length >= 2 && isValidValue(valueAsArray[0]) && isValidValue(valueAsArray[1])) { let [first, second] = valueAsArray; if (shouldRenderAsNumber(first, true) && shouldRenderAsNumber(second, true)) { const firstNum = parseNumber(first, { parseNumbers: true }); const secondNum = parseNumber(second, { parseNumbers: true }); if (!preserveValueOrder && secondNum < firstNum) { const tempNum = secondNum; second = firstNum; first = tempNum; } else { first = firstNum; second = secondNum; } } return negateIfNotOp(operatorLC, { range: { [field]: { gte: first, lte: second } } }); } return false; } case "contains": case "doesnotcontain": return negateIfNotOp(operatorLC, { regexp: { [field]: { value: `.*${value}.*` } } }); case "beginswith": case "doesnotbeginwith": return negateIfNotOp(operatorLC, { regexp: { [field]: { value: `${value}.*` } } }); case "endswith": case "doesnotendwith": return negateIfNotOp(operatorLC, { regexp: { [field]: { value: `.*${value}` } } }); } return false; }; // src/utils/formatQuery/defaultRuleProcessorJSONata.ts var shouldNegate3 = (op) => op.startsWith("not") || op.startsWith("doesnot"); var quote = (v, escapeQuotes) => `"${typeof v !== "string" || !escapeQuotes ? v : v.replaceAll(`"`, `\\"`)}"`; var negate = (clause, negate2) => negate2 ? `$not(${clause})` : `${clause}`; var escapeStringRegex = (s) => `${s}`.replaceAll(/[$()*+.?[\\\]^{|}]/g, String.raw`\$&`).replaceAll("-", String.raw`\x2d`); var defaultRuleProcessorJSONata = ({ field, operator, value, valueSource }, { escapeQuotes, parseNumbers = true, preserveValueOrder, quoteFieldNamesWith = ["", ""], fieldIdentifierSeparator = "" } = {}) => { const valueIsField = valueSource === "field"; const useBareValue = typeof value === "number" || typeof value === "boolean" || typeof value === "bigint" || shouldRenderAsNumber(value, parseNumbers); const qfn = (f) => getQuotedFieldName(f, { quoteFieldNamesWith, fieldIdentifierSeparator }); const operatorLC = operator.toLowerCase(); switch (operatorLC) { case "<": case "<=": case "=": case "!=": case ">": case ">=": return `${qfn(field)} ${operatorLC} ${valueIsField ? qfn(trimIfString(value)) : useBareValue ? trimIfString(value) : quote(value, escapeQuotes)}`; case "contains": case "doesnotcontain": return negate( `$contains(${qfn(field)}, ${valueIsField ? qfn(trimIfString(value)) : quote(value, escapeQuotes)})`, shouldNegate3(operatorLC) ); case "beginswith": case "doesnotbeginwith": return negate( valueIsField ? `$substring(${qfn(field)}, 0, $length(${qfn(trimIfString(value))})) = ${qfn(trimIfString(value))}` : `$contains(${qfn(field)}, /^${escapeStringRegex(value)}/)`, shouldNegate3(operatorLC) ); case "endswith": case "doesnotendwith": return negate( valueIsField ? `$substring(${qfn(field)}, $length(${qfn(field)}) - $length(${qfn(trimIfString(value))})) = ${qfn(trimIfString(value))}` : `$contains(${qfn(field)}, /${escapeStringRegex(value)}$/)`, shouldNegate3(operatorLC) ); case "null": return `${qfn(field)} = null`; case "notnull": return `${qfn(field)} != null`; case "in": case "notin": { const valueAsArray = toArray(value); return negate( `${qfn(field)} in [${valueAsArray.map( (val) => valueIsField ? `${qfn(trimIfString(val))}` : shouldRenderAsNumber(val, parseNumbers) ? `${trimIfString(val)}` : quote(val, escapeQuotes) ).join(", ")}]`, shouldNegate3(operatorLC) ); } case "between": case "notbetween": { const valueAsArray = toArray(value); if (valueAsArray.length < 2 || nullOrUndefinedOrEmpty(valueAsArray[0]) || nullOrUndefinedOrEmpty(valueAsArray[1])) { return ""; } const [first, second] = valueAsArray; const firstNum = shouldRenderAsNumber(first, true) ? parseNumber(first, { parseNumbers: true }) : NaN; const secondNum = shouldRenderAsNumber(second, true) ? parseNumber(second, { parseNumbers: true }) : NaN; let firstValue = isNaN(firstNum) ? valueIsField ? `${first}` : first : firstNum; let secondValue = isNaN(secondNum) ? valueIsField ? `${second}` : second : secondNum; if (!preserveValueOrder && firstValue === firstNum && secondValue === secondNum && secondNum < firstNum) { const tempNum = secondNum; secondValue = firstNum; firstValue = tempNum; } const renderAsNumbers = shouldRenderAsNumber(first, parseNumbers) && shouldRenderAsNumber(second, parseNumbers); const expression = `${qfn(field)} >= ${valueIsField ? qfn(first) : renderAsNumbers ? firstValue : quote(firstValue, escapeQuotes)} and ${qfn(field)} <= ${valueIsField ? qfn(second) : renderAsNumbers ? secondValue : quote(secondValue, escapeQuotes)}`; return operatorLC === "between" ? `(${expression})` : negate(expression, true); } } return ""; }; // src/utils/formatQuery/defaultRuleProcessorJsonLogic.ts var convertOperator = (op) => op.replace(/^(=)$/, "$1=").replace(/^notnull$/i, "!=").replace(/^null$/i, "=="); var negateIfNotOp2 = (op, jsonRule) => op.startsWith("not") || op.startsWith("doesnot") ? { "!": jsonRule } : jsonRule; var defaultRuleProcessorJsonLogic = ({ field, operator, value, valueSource }, { parseNumbers, preserveValueOrder } = {}) => { const valueIsField = valueSource === "field"; const fieldObject = { var: field }; const fieldOrNumberRenderer = (v) => valueIsField ? { var: `${v}` } : shouldRenderAsNumber(v, parseNumbers) ? parseNumber(v, { parseNumbers }) : v; const operatorLC = operator.toLowerCase(); switch (operatorLC) { case "<": case "<=": case "=": case "!=": case ">": case ">=": return { [convertOperator(operatorLC)]: [fieldObject, fieldOrNumberRenderer(value)] }; case "null": case "notnull": { return { [`${operatorLC === "notnull" ? "!" : "="}=`]: [fieldObject, null] }; } case "in": case "notin": { const valueAsArray = toArray(value).map((v) => fieldOrNumberRenderer(v)); return negateIfNotOp2(operatorLC, { in: [fieldObject, valueAsArray] }); } case "between": case "notbetween": { const valueAsArray = toArray(value); if (valueAsArray.length >= 2 && isValidValue(valueAsArray[0]) && isValidValue(valueAsArray[1])) { let [first, second] = valueAsArray; if (!valueIsField && shouldRenderAsNumber(first, true) && shouldRenderAsNumber(second, true)) { const firstNum = parseNumber(first, { parseNumbers: true }); const secondNum = parseNumber(second, { parseNumbers: true }); if (!preserveValueOrder && secondNum < firstNum) { const tempNum = secondNum; second = firstNum; first = tempNum; } else { first = firstNum; second = secondNum; } } else if (valueIsField) { first = { var: first }; second = { var: second }; } const jsonRule = { "<=": [first, fieldObject, second] }; return negateIfNotOp2(operatorLC, jsonRule); } return false; } case "contains": case "doesnotcontain": { const jsonRule = { in: [fieldOrNumberRenderer(value), fieldObject] }; return negateIfNotOp2(operatorLC, jsonRule); } case "beginswith": case "doesnotbeginwith": { const jsonRule = { startsWith: [fieldObject, fieldOrNumberRenderer(value)] }; return negateIfNotOp2(operatorLC, jsonRule); } case "endswith": case "doesnotendwith": { const jsonRule = { endsWith: [fieldObject, fieldOrNumberRenderer(value)] }; return negateIfNotOp2(operatorLC, jsonRule); } } return false; }; // src/utils/formatQuery/defaultValueProcessorNL.ts var escapeStringValueQuotes2 = (v, quoteChar, escapeQuotes) => escapeQuotes && typeof v === "string" ? v.replaceAll(`${quoteChar}`, `${quoteChar}${quoteChar}`) : ( /* istanbul ignore next */ v ); var defaultValueProcessorNL = (rule, opts = {}) => { const { escapeQuotes, fields, parseNumbers, quoteFieldNamesWith, quoteValuesWith, fieldIdentifierSeparator, translations } = opts; const valueIsField = rule.valueSource === "field"; const operatorLowerCase = rule.operator.toLowerCase(); const quoteChar = quoteValuesWith || /* istanbul ignore next */ "'"; const quoteValue = (v) => `${quoteChar}${v}${quoteChar}`; const escapeValue = (v) => escapeStringValueQuotes2(v, quoteChar, escapeQuotes); const wrapAndEscape = (v) => quoteValue(escapeValue(v)); const wrapFieldName = (v) => getQuotedFieldName(v, { quoteFieldNamesWith, fieldIdentifierSeparator }); const t = translations ?? /* istanbul ignore next */ {}; const orTL = t.or ?? "or"; const trueTL = t.true ?? "true"; const falseTL = t.false ?? "false"; switch (operatorLowerCase) { case "null": case "notnull": { return ""; } case "between": case "notbetween": { if (!valueIsField) { return defaultValueProcessorByRule(rule, opts); } const valueAsArray = toArray(rule.value, { retainEmptyStrings: true }).slice(0, 2).map( (v) => wrapFieldName( getOption(fields ?? /* istanbul ignore next */ [], v)?.label ?? v ) ); if (valueAsArray.length < 2 || !isValidValue(valueAsArray[0]) || !isValidValue(valueAsArray[1])) { return ""; } return defaultValueProcessorByRule({ ...rule, value: valueAsArray }, opts); } case "in": case "notin": { const valueAsArray = toArray(rule.value); if (valueAsArray.length === 0) return ""; const valStringArray = valueAsArray.map( (v) => valueIsField ? wrapFieldName( getOption(fields ?? /* istanbul ignore next */ [], v)?.label ?? v ) : shouldRenderAsNumber(v, parseNumbers) ? `${trimIfString(v)}` : `${wrapAndEscape(v)}` ); return `${valStringArray.slice(0, -1).join(", ")}${valStringArray.length > 2 ? "," : ""} ${orTL} ${valStringArray.at(-1)}`; } } if (typeof rule.value === "boolean") { return rule.value ? trueTL : falseTL; } return valueIsField ? wrapFieldName( getOption(fields ?? /* istanbul ignore next */ [], rule.value)?.label ?? rule.value ) : shouldRenderAsNumber(rule.value, parseNumbers) ? `${trimIfString(rule.value)}` : `${wrapAndEscape(rule.value)}`; }; // src/utils/formatQuery/defaultRuleProcessorNL.ts var defaultExportOperatorMap = { "=": ["is", "is the same as the value in"], "!=": ["is not", "is not the same as the value in"], "<": ["is less than", "is less than the value in"], ">": ["is greater than", "is greater than the value in"], "<=": ["is less than or equal to", "is less than or equal to the value in"], ">=": ["is greater than or equal to", "is greater than or equal to the value in"], contains: ["contains", "contains the value in"], beginswith: ["starts with", "starts with the value in"], endswith: ["ends with", "ends with the value in"], doesnotcontain: ["does not contain", "does not contain the value in"], doesnotbeginwith: ["does not start with", "does not start with the value in"], doesnotendwith: ["does not end with", "does not end with the value in"], null: "is null", notnull: "is not null", in: ["is one of the values", "is the same as a value in"], notin: ["is not one of the values", "is not the same as any value in"], between: ["is between", "is between the values in"], notbetween: ["is not between", "is not between the values in"] }; var defaultGetOperators = () => []; var defaultOperatorProcessorNL = (rule, opts = {}) => { const { valueSource = "value" } = rule; const { getOperators = defaultGetOperators, operatorMap: operatorMapParam = defaultExportOperatorMap } = opts; const mapOperatorMap = new Map( Object.entries(defaultExportOperatorMap) ); for (const [key, value] of Object.entries(operatorMapParam)) { mapOperatorMap.set(key.toLowerCase(), value); } const operatorMap = Object.fromEntries(mapOperatorMap); const { value: operator, label } = getOption( toFullOptionList( getOperators(rule.field, { fieldData: opts.fieldData ?? { name: rule.field, value: rule.field, label: rule.field } }) ?? /* istanbul ignore next */ [] ), rule.operator ) ?? { name: rule.operator, value: rule.operator, label: rule.operator }; const operatorTL = operatorMap[operator] ?? operatorMap[operator.toLowerCase()] ?? [label, label]; return typeof operatorTL === "string" ? operatorTL : operatorTL[valueSource === "field" ? 1 : 0]; }; var defaultRuleProcessorNL = (rule, opts) => { const { fieldData, quoteFieldNamesWith = ["", ""], fieldIdentifierSeparator = "", quoteValuesWith = `'`, operatorProcessor = defaultOperatorProcessorNL, valueProcessor = defaultValueProcessorNL, concatOperator = "||", wordOrder = "SVO" } = opts ?? /* istanbul ignore next */ {}; const value = valueProcessor(rule, { ...opts, quoteFieldNamesWith, fieldIdentifierSeparator, quoteValuesWith, concatOperator }); const operatorLC = rule.operator.toLowerCase(); if ((operatorLC === "in" || operatorLC === "notin" || operatorLC === "between" || operatorLC === "notbetween") && !value) { return ""; } const processedField = getQuotedFieldName(fieldData?.label ?? rule.field, { quoteFieldNamesWith, fieldIdentifierSeparator }); const processedOperator = operatorProcessor(rule, opts); const wordOrderMap = { S: processedField, V: processedOperator, O: value }; return normalizeConstituentWordOrder(wordOrder).map((term) => `${wordOrderMap[term]}`).join(" ").trim(); }; // src/utils/formatQuery/defaultRuleProcessorSQL.ts var defaultOperatorProcessorSQL = (rule) => mapSQLOperator(rule.operator).toLowerCase(); var defaultRuleProcessorSQL = (rule, opts = {}) => { const { quoteFieldNamesWith = ["", ""], fieldIdentifierSeparator = "", quoteValuesWith = `'`, operatorProcessor = defaultOperatorProcessorSQL, valueProcessor = defaultValueProcessorByRule, concatOperator = "||" } = opts; const value = valueProcessor(rule, { ...opts, quoteFieldNamesWith, fieldIdentifierSeparator, quoteValuesWith, concatOperator }); const operator = operatorProcessor(rule, opts); const operatorLowerCase = operator.toLowerCase(); if ((operatorLowerCase === "in" || operatorLowerCase === "not in" || operatorLowerCase === "between" || operatorLowerCase === "not between") && !value) { return ""; } return `${getQuotedFieldName(rule.field, { quoteFieldNamesWith, fieldIdentifierSeparator })} ${operator} ${value}`.trim(); }; // src/utils/formatQuery/defaultRuleProcessorParameterized.ts var defaultRuleProcessorParameterized = (rule, opts, meta) => { const { fieldData, format, getNextNamedParam, parseNumbers, paramPrefix, paramsKeepPrefix, numberedParams, quoteFieldNamesWith = ["", ""], concatOperator, operatorProcessor = defaultOperatorProcessorSQL, valueProcessor = defaultValueProcessorByRule } = opts ?? {}; const { processedParams = [] } = meta ?? {}; const parameterized = format === "parameterized"; const params = []; const paramsNamed = {}; const finalize = (sql) => parameterized ? { sql, params } : { sql, params: paramsNamed }; const value = valueProcessor(rule, { parseNumbers, quoteFieldNamesWith, concatOperator, fieldData, format }); const sqlOperator = operatorProcessor(rule, opts); const sqlOperatorLowerCase = sqlOperator.toLowerCase(); const [qPre, qPost] = quoteFieldNamesWith; if ((sqlOperatorLowerCase === "in" || sqlOperatorLowerCase === "not in" || sqlOperatorLowerCase === "between" || sqlOperatorLowerCase === "not between") && !value) { return finalize(""); } else if (sqlOperatorLowerCase === "is null" || sqlOperatorLowerCase === "is not null") { return finalize(`${qPre}${rule.field}${qPost} ${sqlOperator}`); } else if (rule.valueSource === "field") { return finalize(`${qPre}${rule.field}${qPost} ${sqlOperator} ${value}`.trim()); } else if (sqlOperatorLowerCase === "in" || sqlOperatorLowerCase === "not in") { const splitValue = toArray(rule.value); if (parameterized) { for (const v of splitValue) { params.push(shouldRenderAsNumber(v, parseNumbers) ? parseNumber(v, { parseNumbers }) : v); } return finalize( `${qPre}${rule.field}${qPost} ${sqlOperator} (${splitValue.map( (_v, i) => numberedParams ? `${paramPrefix}${processedParams.length + 1 + splitValue.length - (splitValue.length - i)}` : "?" ).join(", ")})` ); } const inParams = []; for (const v of splitValue) { const thisParamName = getNextNamedParam(rule.field)