react-querybuilder
Version:
React Query Builder component for constructing queries and filters, with utilities for executing them in various database and evaluation contexts
1,191 lines (1,168 loc) • 127 kB
JavaScript
"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, {
bigIntJsonParseReviver: () => bigIntJsonParseReviver,
bigIntJsonStringifyReplacer: () => bigIntJsonStringifyReplacer,
celCombinatorMap: () => celCombinatorMap,
defaultCELValueProcessor: () => defaultCELValueProcessor,
defaultExportOperatorMap: () => defaultExportOperatorMap,
defaultMongoDBValueProcessor: () => defaultMongoDBValueProcessor,
defaultNLTranslations: () => defaultNLTranslations,
defaultOperatorProcessorNL: () => defaultOperatorProcessorNL,
defaultOperatorProcessorSQL: () => defaultOperatorProcessorSQL,
defaultRuleGroupProcessorCEL: () => defaultRuleGroupProcessorCEL,
defaultRuleGroupProcessorDrizzle: () => defaultRuleGroupProcessorDrizzle,
defaultRuleGroupProcessorElasticSearch: () => defaultRuleGroupProcessorElasticSearch,
defaultRuleGroupProcessorJSONata: () => defaultRuleGroupProcessorJSONata,
defaultRuleGroupProcessorJsonLogic: () => defaultRuleGroupProcessorJsonLogic,
defaultRuleGroupProcessorLDAP: () => defaultRuleGroupProcessorLDAP,
defaultRuleGroupProcessorMongoDB: () => defaultRuleGroupProcessorMongoDB,
defaultRuleGroupProcessorMongoDBQuery: () => defaultRuleGroupProcessorMongoDBQuery,
defaultRuleGroupProcessorNL: () => defaultRuleGroupProcessorNL,
defaultRuleGroupProcessorParameterized: () => defaultRuleGroupProcessorParameterized,
defaultRuleGroupProcessorPrisma: () => defaultRuleGroupProcessorPrisma,
defaultRuleGroupProcessorSQL: () => defaultRuleGroupProcessorSQL,
defaultRuleGroupProcessorSequelize: () => defaultRuleGroupProcessorSequelize,
defaultRuleGroupProcessorSpEL: () => defaultRuleGroupProcessorSpEL,
defaultRuleProcessorCEL: () => defaultRuleProcessorCEL,
defaultRuleProcessorDrizzle: () => defaultRuleProcessorDrizzle,
defaultRuleProcessorElasticSearch: () => defaultRuleProcessorElasticSearch,
defaultRuleProcessorJSONata: () => defaultRuleProcessorJSONata,
defaultRuleProcessorJsonLogic: () => defaultRuleProcessorJsonLogic,
defaultRuleProcessorLDAP: () => defaultRuleProcessorLDAP,
defaultRuleProcessorMongoDB: () => defaultRuleProcessorMongoDB,
defaultRuleProcessorMongoDBQuery: () => defaultRuleProcessorMongoDBQuery,
defaultRuleProcessorNL: () => defaultRuleProcessorNL,
defaultRuleProcessorParameterized: () => defaultRuleProcessorParameterized,
defaultRuleProcessorPrisma: () => defaultRuleProcessorPrisma,
defaultRuleProcessorSQL: () => defaultRuleProcessorSQL,
defaultRuleProcessorSequelize: () => defaultRuleProcessorSequelize,
defaultRuleProcessorSpEL: () => defaultRuleProcessorSpEL,
defaultSpELValueProcessor: () => defaultSpELValueProcessor,
defaultValueProcessor: () => defaultValueProcessor,
defaultValueProcessorByRule: () => defaultValueProcessorByRule,
defaultValueProcessorCELByRule: () => defaultValueProcessorCELByRule,
defaultValueProcessorMongoDBByRule: () => defaultValueProcessorMongoDBByRule,
defaultValueProcessorNL: () => defaultValueProcessorNL,
defaultValueProcessorSpELByRule: () => defaultValueProcessorSpELByRule,
formatQuery: () => formatQuery,
formatQueryOptionPresets: () => formatQueryOptionPresets,
getNLTranslataion: () => getNLTranslataion,
getQuoteFieldNamesWithArray: () => getQuoteFieldNamesWithArray,
getQuotedFieldName: () => getQuotedFieldName,
isValidValue: () => isValidValue,
isValueProcessorLegacy: () => isValueProcessorLegacy,
jsonLogicAdditionalOperators: () => jsonLogicAdditionalOperators,
mapSQLOperator: () => mapSQLOperator,
mongoDbFallback: () => mongoDbFallback,
mongoOperators: () => mongoOperators,
normalizeConstituentWordOrder: () => normalizeConstituentWordOrder,
numerifyValues: () => numerifyValues,
prismaFallback: () => prismaFallback,
prismaOperators: () => prismaOperators,
processMatchMode: () => processMatchMode,
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 lc = (v) => typeof v === "string" ? v.toLowerCase() : v;
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, bigIntOnOverflow } = {}) => {
if (!parseNumbers || typeof val === "bigint" || typeof val === "number") {
return val;
}
if (parseNumbers === "native") {
return Number.parseFloat(val);
}
const valAsNum = (
// TODO: Should these options be configurable?
(0, import_numeric_quantity2.numericQuantity)(val, {
allowTrailingInvalid: parseNumbers === "enhanced",
bigIntOnOverflow,
romanNumerals: false,
round: false
})
);
return typeof valAsNum === "bigint" || !Number.isNaN(valAsNum) ? valAsNum : val;
};
// src/utils/transformQuery.ts
var import_immer = require("immer");
// 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/transformQuery.ts
var remapProperties = (obj, propertyMap, deleteRemappedProperties) => (0, import_immer.produce)(obj, (draft) => {
for (const [k, v] of Object.entries(propertyMap)) {
if (v === false) {
delete draft[k];
} else if (!!v && k !== v && k in draft) {
draft[v] = draft[k];
if (deleteRemappedProperties) {
delete draft[k];
}
}
}
});
function transformQuery(query, options = {}) {
const {
ruleProcessor = (r) => r,
ruleGroupProcessor = (rg) => rg,
propertyMap = {},
combinatorMap = {},
operatorMap = {},
omitPath = false,
deleteRemappedProperties = true
} = options;
const processGroup = (rg) => ({
...ruleGroupProcessor(
remapProperties(
{
...rg,
...isRuleGroupType(rg) ? { combinator: combinatorMap[rg.combinator] ?? rg.combinator } : {}
},
propertyMap,
deleteRemappedProperties
)
),
...propertyMap["rules"] === false ? null : {
// oxlint-disable-next-line typescript/no-explicit-any
[propertyMap["rules"] ?? "rules"]: rg.rules.map((r, idx) => {
const pathObject = omitPath ? null : { path: [...rg.path, idx] };
if (typeof r === "string") {
return combinatorMap[r] ?? r;
} else if (isRuleGroup(r)) {
return processGroup({ ...r, ...pathObject });
}
return ruleProcessor(
remapProperties(
{
...r,
...pathObject,
..."operator" in r ? { operator: operatorMap[r.operator] ?? r.operator } : {}
},
propertyMap,
deleteRemappedProperties
)
);
})
}
});
return processGroup({ ...query, ...omitPath ? null : { path: [] } });
}
// src/utils/isRuleOrGroupValid.ts
var isValidationResult = (vr) => isPojo(vr) && typeof vr.valid === "boolean";
var isRuleOrGroupValid = (rg, validationResult, validator) => {
if (typeof validationResult === "boolean") {
return validationResult;
}
if (isValidationResult(validationResult)) {
return validationResult.valid;
}
if (typeof validator === "function" && !isRuleGroup(rg)) {
const vr = validator(rg);
if (typeof vr === "boolean") {
return vr;
}
if (isValidationResult(vr)) {
return vr.valid;
}
}
return true;
};
// src/utils/optGroupUtils.ts
var import_immer2 = 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, labelMap) {
const recipe = (0, import_immer2.produce)((draft) => {
const idObj = {};
let needsUpdating = !!baseProperties;
if (typeof draft === "string") {
return {
...baseProperties,
name: draft,
value: draft,
label: labelMap?.[draft] ?? draft
};
}
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, labelMap) {
if (!Array.isArray(optList)) {
return [];
}
const recipe = (0, import_immer2.produce)((draft) => {
if (isFlexibleOptionGroupArray(draft)) {
for (const optGroup of draft) {
for (const [idx, opt] of optGroup.options.entries())
optGroup.options[idx] = toFullOption(opt, baseProperties, labelMap);
}
} else {
for (const [idx, opt] of draft.entries())
draft[idx] = toFullOption(opt, baseProperties, labelMap);
}
});
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/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/formatQuery/utils.ts
var mapSQLOperator = (rqbOperator) => {
switch (lc(rqbOperator)) {
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 prismaOperators = {
"=": "equals",
"!=": "not",
"<": "lt",
"<=": "lte",
">": "gt",
">=": "gte",
in: "in",
notin: "notIn"
};
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" && !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 */
"";
var processMatchMode = (rule) => {
const { mode, threshold } = rule.match ?? {};
if (mode) {
if (!isRuleGroup(rule.value)) return false;
const matchModeLC = lc(mode);
const matchModeCoerced = matchModeLC === "atleast" && threshold === 1 ? "some" : matchModeLC === "atmost" && threshold === 0 ? "none" : matchModeLC;
if ((matchModeCoerced === "atleast" || matchModeCoerced === "atmost" || matchModeCoerced === "exactly") && (typeof threshold !== "number" || threshold < 0)) {
return false;
}
return { mode: matchModeCoerced, threshold };
}
};
var bigIntJsonStringifyReplacer = (_key, value) => typeof value === "bigint" ? { $bigint: value.toString() } : value;
var bigIntJsonParseReviver = (_key, value) => isPojo(value) && Object.keys(value).length === 1 && typeof value.$bigint === "string" ? BigInt(value.$bigint) : value;
// src/utils/formatQuery/defaultRuleGroupProcessorCEL.ts
var defaultRuleGroupProcessorCEL = (ruleGroup, options) => {
const {
fields,
fallbackExpression,
getParseNumberBoolean,
placeholderFieldName,
placeholderOperatorName,
placeholderValueName,
ruleProcessor,
validateRule,
validationMap
} = options;
const processRuleGroup = (rg, outermost) => {
if (!isRuleOrGroupValid(rg, validationMap[rg.id ?? /* istanbul ignore next */
""])) {
return outermost ? fallbackExpression : "";
}
const expression = rg.rules.map((rule) => {
if (typeof rule === "string") {
return celCombinatorMap[rule];
}
if (isRuleGroup(rule)) {
return processRuleGroup(rule);
}
const [validationResult, fieldValidator] = validateRule(rule);
if (!isRuleOrGroupValid(rule, validationResult, fieldValidator) || rule.field === placeholderFieldName || rule.operator === placeholderOperatorName || /* istanbul ignore next */
placeholderValueName !== void 0 && rule.value === placeholderValueName) {
return "";
}
const fieldData = getOption(fields, rule.field);
return ruleProcessor(rule, {
...options,
parseNumbers: getParseNumberBoolean(fieldData?.inputType),
escapeQuotes: (rule.valueSource ?? "value") === "value",
fieldData
});
}).filter(Boolean).join(
isRuleGroupType(rg) ? ` ${celCombinatorMap[rg.combinator]} ` : " "
);
const [prefix, suffix] = rg.not || !outermost ? [`${rg.not ? "!" : ""}(`, ")"] : ["", ""];
return expression ? `${prefix}${expression}${suffix}` : fallbackExpression;
};
return processRuleGroup(ruleGroup, true);
};
// 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 = (rule, opts = {}) => {
const { escapeQuotes, parseNumbers, preserveValueOrder } = opts;
const { field, operator, value, valueSource } = rule;
const valueIsField = valueSource === "field";
const operatorTL = lc(operator === "=" ? "==" : operator);
const useBareValue = typeof value === "number" || typeof value === "boolean" || typeof value === "bigint" || shouldRenderAsNumber(value, parseNumbers);
const matchEval = processMatchMode(rule);
if (matchEval === false) {
return "";
} else if (matchEval) {
const { mode, threshold } = matchEval;
const arrayElementAlias = "elem_alias";
const celQuery = transformQuery(rule.value, {
ruleProcessor: (r) => ({ ...r, field: `${arrayElementAlias}${r.field ? `.${r.field}` : ""}` })
});
const nestedArrayFilter = defaultRuleGroupProcessorCEL(
celQuery,
opts
);
switch (mode) {
case "all":
return `${field}.all(${arrayElementAlias}, ${nestedArrayFilter})`;
case "none":
case "some":
return `${mode === "none" ? "!" : ""}${field}.exists(${arrayElementAlias}, ${nestedArrayFilter})`;
case "atleast":
case "atmost":
case "exactly": {
const totalCount = `double(${field}.size())`;
const filteredCount = `${field}.filter(${arrayElementAlias}, ${nestedArrayFilter}).size()`;
const op = mode === "atleast" ? ">=" : mode === "atmost" ? "<=" : "==";
if (threshold > 0 && threshold < 1) {
return `${filteredCount} ${op} (${totalCount} * ${threshold})`;
}
return `${filteredCount} ${op} ${threshold}`;
}
}
}
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 shouldParseNumbers = !(parseNumbers === false);
const firstNum = shouldRenderAsNumber(first, shouldParseNumbers) ? parseNumber(first, { parseNumbers: shouldParseNumbers }) : Number.NaN;
const secondNum = shouldRenderAsNumber(second, shouldParseNumbers) ? parseNumber(second, { parseNumbers: shouldParseNumbers }) : Number.NaN;
let firstValue = Number.isNaN(firstNum) ? valueIsField ? `${first}` : `"${escapeDoubleQuotes(first, escapeQuotes)}"` : firstNum;
let secondValue = Number.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/convertQuery.ts
var import_immer3 = require("immer");
var combinatorLevels = ["or", "xor", "and"];
var isSameString = (a, b) => lc(a) === b;
var generateRuleGroupICWithConsistentCombinators = (rg, baseCombinatorLevel = 0) => {
const baseCombinator = combinatorLevels[baseCombinatorLevel];
if (!rg.rules.includes(baseCombinator)) {
return baseCombinatorLevel < combinatorLevels.length - 2 ? generateRuleGroupICWithConsistentCombinators(rg, baseCombinatorLevel + 1) : rg;
}
return (0, import_immer3.produce)(rg, (draft) => {
let cursor = 0;
while (cursor < draft.rules.length - 2) {
if (isSameString(draft.rules[cursor + 1], baseCombinator)) {
cursor += 2;
continue;
}
const nextBaseCombinatorIndex = draft.rules.findIndex(
(r, i) => i > cursor && typeof r === "string" && lc(r) === baseCombinator
);
if (nextBaseCombinatorIndex === -1) {
draft.rules.splice(
cursor,
draft.rules.length,
generateRuleGroupICWithConsistentCombinators(
// oxlint-disable-next-line typescript/no-explicit-any
{ rules: draft.rules.slice(cursor) },
baseCombinatorLevel + 1
)
);
break;
} else {
draft.rules.splice(
cursor,
nextBaseCombinatorIndex - cursor,
generateRuleGroupICWithConsistentCombinators(
// oxlint-disable-next-line typescript/no-explicit-any
{ rules: draft.rules.slice(cursor, nextBaseCombinatorIndex) },
baseCombinatorLevel + 1
)
);
}
}
});
};
var convertFromIC = (rg) => {
if (isRuleGroupType(rg)) {
return rg;
}
const processedRG = generateRuleGroupICWithConsistentCombinators(rg);
const rulesAsMixedList = processedRG.rules.map(
(r) => typeof r === "string" || !isRuleGroup(r) ? r : convertFromIC(r)
);
const combinator = rulesAsMixedList.length < 2 ? "and" : rulesAsMixedList[1];
const rules = rulesAsMixedList.filter((r) => typeof r !== "string");
return { ...processedRG, combinator, rules };
};
// src/utils/formatQuery/defaultRuleGroupProcessorMongoDBQuery.ts
var mongoDbFallback = { $and: [{ $expr: true }] };
var defaultRuleGroupProcessorMongoDBQuery = (ruleGroup, options, meta) => {
const {
fields,
getParseNumberBoolean,
placeholderFieldName,
placeholderOperatorName,
placeholderValueName,
ruleProcessor,
validateRule,
validationMap
} = options;
const processRuleGroup = (rg, outermost) => {
if (!isRuleOrGroupValid(rg, validationMap[rg.id ?? /* istanbul ignore next */
""])) {
return outermost ? mongoDbFallback : false;
}
const combinator = `$${lc(rg.combinator)}`;
let hasChildRules = false;
const expressions = rg.rules.map((rule) => {
if (isRuleGroup(rule)) {
const processedRuleGroup = processRuleGroup(rule);
if (processedRuleGroup) {
hasChildRules = true;
return processedRuleGroup;
}
return false;
}
const [validationResult, fieldValidator] = validateRule(rule);
if (!isRuleOrGroupValid(rule, validationResult, fieldValidator) || rule.field === placeholderFieldName || rule.operator === placeholderOperatorName || /* istanbul ignore next */
placeholderValueName !== void 0 && rule.value === placeholderValueName) {
return false;
}
const fieldData = getOption(fields, rule.field);
return ruleProcessor(
rule,
{
...options,
parseNumbers: getParseNumberBoolean(fieldData?.inputType),
fieldData
},
meta
);
}).filter(Boolean);
return expressions.length > 0 ? expressions.length === 1 && !hasChildRules ? expressions[0] : { [combinator]: expressions } : mongoDbFallback;
};
return processRuleGroup(convertFromIC(ruleGroup), true);
};
// src/utils/formatQuery/defaultRuleProcessorMongoDBQuery.ts
var processNumber = (value, fallback, parseNumbers = false) => shouldRenderAsNumber(value, parseNumbers || typeof value === "bigint") ? Number(parseNumber(value, { parseNumbers: "strict" })) : fallback;
var defaultRuleProcessorMongoDBQuery = (rule, options = {}) => {
const { field, operator, value, valueSource } = rule;
const { parseNumbers, preserveValueOrder, context } = options;
const valueIsField = valueSource === "field";
const { avoidFieldsAsKeys } = context ?? {};
const matchEval = processMatchMode(rule);
if (matchEval === false) {
return;
} else if (matchEval) {
const { mode, threshold } = matchEval;
const totalCount = { $size: { $ifNull: [`$${field}`, []] } };
const subQueryNoAggCtx = defaultRuleGroupProcessorMongoDBQuery(
transformQuery(value, {
ruleProcessor: (r) => ({ ...r, field: r.field ? `${field}.${r.field}` : field })
}),
{
...options,
// We have to override `ruleProcessor` in case original `format` is "mongodb"
ruleProcessor: defaultRuleProcessorMongoDBQuery,
context: { ...options.context, avoidFieldsAsKeys: false }
}
);
const subQueryWithAggCtx = defaultRuleGroupProcessorMongoDBQuery(
transformQuery(value, {
ruleProcessor: (r) => ({ ...r, field: r.field ? `$item.${r.field}` : "$item" })
}),
{
...options,
// We have to override `ruleProcessor` in case original `format` is "mongodb"
ruleProcessor: defaultRuleProcessorMongoDBQuery,
context: { ...options.context, avoidFieldsAsKeys: true }
}
);
const filteredCount = {
$size: {
$ifNull: [
{ $filter: { input: `$${field}`, as: "item", cond: { $and: [subQueryWithAggCtx] } } },
[]
]
}
};
switch (mode) {
case "all":
return { $expr: { $eq: [filteredCount, totalCount] } };
case "none":
return { $nor: [subQueryNoAggCtx] };
case "some":
return subQueryNoAggCtx;
case "atleast":
case "atmost":
case "exactly": {
const op = mode === "atleast" ? mongoOperators[">="] : mode === "atmost" ? mongoOperators["<="] : mongoOperators["="];
if (threshold > 0 && threshold < 1) {
return { $expr: { [op]: [filteredCount, { $multiply: [totalCount, threshold] }] } };
}
return { $expr: { [op]: [filteredCount, threshold] } };
}
}
}
if (operator === "=" && !valueIsField) {
return avoidFieldsAsKeys ? { $eq: [`$${field}`, processNumber(value, value, parseNumbers)] } : { [field]: processNumber(value, value, parseNumbers) };
}
const operatorLC = lc(operator);
switch (operatorLC) {
case "<":
case "<=":
case "=":
case "!=":
case ">":
case ">=": {
const mongoOperator = mongoOperators[operatorLC];
return valueIsField ? { [mongoOperator]: [`$${field}`, `$${value}`] } : avoidFieldsAsKeys ? {
$and: [
{ $ne: [`$${field}`, null] },
{ [mongoOperator]: [`$${field}`, processNumber(value, value, parseNumbers)] }
]
} : { [field]: { [mongoOperator]: processNumber(value, value, parseNumbers) } };
}
case "contains":
return valueIsField ? { $where: `this.${field}.includes(this.${value})` } : avoidFieldsAsKeys ? { $regexMatch: { input: `$${field}`, regex: value } } : { [field]: { $regex: value } };
case "beginswith":
return valueIsField ? { $where: `this.${field}.startsWith(this.${value})` } : avoidFieldsAsKeys ? { $regexMatch: { input: `$${field}`, regex: `^${value}` } } : { [field]: { $regex: `^${value}` } };
case "endswith":
return valueIsField ? { $where: `this.${field}.endsWith(this.${value})` } : avoidFieldsAsKeys ? { $regexMatch: { input: `$${field}`, regex: `${value}$` } } : { [field]: { $regex: `${value}$` } };
case "doesnotcontain":
return valueIsField ? { $where: `!this.${field}.includes(this.${value})` } : avoidFieldsAsKeys ? { $not: { $regexMatch: { input: `$${field}`, regex: value } } } : { [field]: { $not: { $regex: value } } };
case "doesnotbeginwith":
return valueIsField ? { $where: `!this.${field}.startsWith(this.${value})` } : avoidFieldsAsKeys ? { $not: { $regexMatch: { input: `$${field}`, regex: `^${value}` } } } : { [field]: { $not: { $regex: `^${value}` } } };
case "doesnotendwith":
return valueIsField ? { $where: `!this.${field}.endsWith(this.${value})` } : avoidFieldsAsKeys ? { $not: { $regexMatch: { input: `$${field}`, regex: `${value}$` } } } : { [field]: { $not: { $regex: `${value}$` } } };
case "null":
return avoidFieldsAsKeys ? { $eq: [`$${field}`, null] } : { [field]: null };
case "notnull":
return avoidFieldsAsKeys ? { $ne: [`$${field}`, null] } : { [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})`
} : avoidFieldsAsKeys ? operatorLC === "notin" ? {
$not: {
[mongoOperators.in]: [
`$${field}`,
valueAsArray.map((val) => processNumber(val, val, parseNumbers))
]
}
} : {
[mongoOperators[operatorLC]]: [
`$${field}`,
valueAsArray.map((val) => processNumber(val, val, parseNumbers))
]
} : {
[field]: {
[mongoOperators[operatorLC]]: valueAsArray.map(
(val) => processNumber(val, val, parseNumbers)
)
}
};
}
case "between":
case "notbetween": {
const valueAsArray = toArray(value);
if (valueAsArray.length >= 2 && isValidValue(valueAsArray[0]) && isValidValue(valueAsArray[1])) {
const [first, second] = valueAsArray;
const firstNum = processNumber(first, Number.NaN, true);
const secondNum = processNumber(second, Number.NaN, true);
let firstValue = valueIsField ? first : Number.isNaN(firstNum) ? first : firstNum;
let secondValue = valueIsField ? second : Number.isNaN(secondNum) ? second : secondNum;
if (!preserveValueOrder && firstValue === firstNum && secondValue === secondNum && secondNum < firstNum) {
const tempNum = secondNum;
secondValue = firstNum;
firstValue = tempNum;
}
if (operatorLC === "between") {
return valueIsField ? { $gte: [`$${field}`, `$${firstValue}`], $lte: [`$${field}`, `$${secondValue}`] } : avoidFieldsAsKeys ? {
$and: [{ $gte: [`$${field}`, firstValue] }, { $lte: [`$${field}`, secondValue] }]
} : { [field]: { $gte: firstValue, $lte: secondValue } };
} else {
return valueIsField ? {
$or: [
{ $lt: [`$${field}`, `$${firstValue}`] },
{ $gt: [`$${field}`, `$${secondValue}`] }
]
} : avoidFieldsAsKeys ? {
$or: [{ $lt: [`$${field}`, firstValue] }, { $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/defaultRuleGroupProcessorSpEL.ts
var defaultRuleGroupProcessorSpEL = (ruleGroup, options) => {
const {
fields,
fallbackExpression,
getParseNumberBoolean,
placeholderFieldName,
placeholderOperatorName,
placeholderValueName,
ruleProcessor,
validateRule,
validationMap
} = options;
const processRuleGroup = (rg, outermost) => {
if (!isRuleOrGroupValid(rg, validationMap[rg.id ?? /* istanbul ignore next */
""])) {
return outermost ? fallbackExpression : "";
}
const expression = rg.rules.map((rule) => {
if (typeof rule === "string") {
return rule;
}
if (isRuleGroup(rule)) {
return processRuleGroup(rule);
}
const [validationResult, fieldValidator] = validateRule(rule);
if (!isRuleOrGroupValid(rule, validationResult, fieldValidator) || rule.field === placeholderFieldName || rule.operator === placeholderOperatorName || /* istanbul ignore next */
placeholderValueName !== void 0 && rule.value === placeholderValueName) {
return "";
}
const fieldData = getOption(fields, rule.field);
return ruleProcessor(rule, {
...options,
parseNumbers: getParseNumberBoolean(fieldData?.inputType),
escapeQuotes: (rule.valueSource ?? "value") === "value",
fieldData
});
}).filter(Boolean).join(isRuleGroupType(rg) ? ` ${rg.combinator} ` : " ");
const [prefix, suffix] = rg.not || !outermost ? [`${rg.not ? "!" : ""}(`, ")"] : ["", ""];
return expression ? `${prefix}${expression}${suffix}` : fallbackExpression;
};
return processRuleGroup(ruleGroup, true);
};
// 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 = (rule, opts = {}) => {
const { field, operator, value, valueSource } = rule;
const { escapeQuotes, parseNumbers, preserveValueOrder } = opts;
const valueIsField = valueSource === "field";
const operatorTL = lc(operator === "=" ? "==" : operator);
const useBareValue = typeof value === "number" || typeof value === "boolean" || typeof value === "bigint" || shouldRenderAsNumber(value, parseNumbers);
const matchEval = processMatchMode(rule);
if (matchEval === false) {
return "";
} else if (matchEval) {
const { mode, threshold } = matchEval;
const nestedArrayFilter = defaultRuleGroupProcessorSpEL(
transformQuery(rule.value, {
ruleProcessor: (r) => ({ ...r, field: `${r.field || "#this"}` })
}),
opts
);
const totalCount = `${field}.size()`;
const filteredCount = `${field}.?[${nestedArrayFilter}].size()`;
switch (mode) {
case "all":
return `${filteredCount} == ${totalCount}`;
case "none":
return `${filteredCount} == 0`;
case "some":
return `${filteredCount} >= 1`;
case "atleast":
case "atmost":
case "exactly": {
const op = mode === "atleast" ? ">=" : mode === "atmost" ? "<=" : "==";
if (threshold > 0 && threshold < 1) {
return `${filteredCount} ${op} (${totalCount} * ${threshold})`;
}
return `${filteredCount} ${op} ${threshold}`;
}
}
}
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 shouldParseNumbers = !(parseNumbers === false);
const firstNum = shouldRenderAsNumber(first, shouldParseNumbers) ? parseNumber(first, { parseNumbers: shouldParseNumbers }) : Number.NaN;
const secondNum = shouldRenderAsNumber(second, shouldParseNumbers) ? parseNumber(second, { parseNumbers: shouldParseNumbers }) : Number.NaN;
let firstValue = Number.isNaN(firstNum) ? valueIsField ? `${first}` : `'${escapeSingleQuotes(first, escapeQuotes)}'` : firstNum;
let secondValue = Number.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 = lc(operator);
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" }) : Number.NaN;
const secondNum = shouldRenderAsNumber(second, parseNumbers) ? parseNumber(second, { parseNumbers: "strict" }) : Number.NaN;
const firstValue = Number.isNaN(firstNum) ? valueIsField ? `${first}` : first : firstNum;
const secondValue = Number.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/defaultRuleProcessorDrizzle.ts
var defaultRuleProcessorDrizzle = (rule, _options) => {
const opts = _options ?? /* istanbul ignore next */
{};
const { parseNumbers, preserveValueOrder, context = {} } = opts;
const { columns, drizzleOperators, useRawFields } = context;
if (!columns || !drizzleOperators) return;
const {
between,
eq,
gt,
gte,
inArray,
isNotNull,
isNull,
like,
lt,
lte,
ne,
notBetween,
notInArray,
notLike,
sql
} = drizzleOperators;
const { field, operator, value, valueSource } = rule;
const column = useRawFields && /[a-z][a-z0-9]*/i.test(field) ? sql.raw(field) : columns[field];
const operatorLC = lc(operator);
const valueIsField = valueSource === "field";
const asFieldOrValue = (v) => valueIsField ? columns[v] : v;
if (!column) return;
const matchEval = processMatchMode(rule);
if (matchEval === false) {
return;
} else if (matchEval) {
if (opts.preset !== "postgresql") return;
const { mode, threshold } = matchEval;
const arrayElementAlias = "elem_alias";
const sqlQuery = transformQuery(rule.value, {
ruleProcessor: (r) => ({ ...r, field: arrayElementAlias })
});
const nestedArrayFilter = defaultRuleGroupProcessorDrizzle(sqlQuery, {
...opts,
context: { ...opts.context, useRawFields: true }
});
switch (mode) {
case "all":
return sql`(select count(*) from unnest(${column}) as ${sql.raw(arrayElementAlias)} where ${nestedArrayFilter({}, drizzleOperators)}) = array_length(${column}, 1)`;
case "none":
return sql`not exists (select 1 from unnest(${column}) as ${sql.raw(arrayElementAlias)} where ${nestedArrayFilter({}, drizzleOperators)})`;
case "some":
return sql`exists (select 1 from unnest(${column}) as ${sql.raw(arrayElementAlias)} where ${nestedArrayFilter({}, drizzleOperators)})`;
case "atleast":
case "atmost":
case "exactly": {
const op = mode === "atleast" ? ">=" : mode === "atmost" ? "<=" : "=";
return threshold > 0 && threshold < 1 ? sql`(select count(*) / array_length(${column}, 1) from unnest(${column}) as ${sql.raw(arrayElementAlias)} where ${nestedArrayFilter({}, drizzleOperators)}) ${sql.raw(`${op} ${threshold}`)}` : sql`(select count(*) from unnest(${column}) as ${sql.raw(arrayElementAlias)} where ${nestedArrayFilter({}, drizzleOperators)}) ${sql.raw(`${op} ${threshold}`)}`;
}
}
}
switch (operatorLC) {
case "=":
return eq(column, asFieldOrValue(value));
case "!=":
return ne(column, asFieldOrValue(value));
case ">":
return gt(column, asFieldOrValue(value));