@react-querybuilder/core
Version:
React Query Builder component for constructing queries and filters, with utilities for executing them in various database and evaluation contexts
1,066 lines (1,049 loc) • 120 kB
JavaScript
const require_isRuleGroup = require('./isRuleGroup-DqAs2x4E.js');
const require_optGroupUtils = require('./optGroupUtils-B0hTpodo.js');
const require_arrayUtils = require('./arrayUtils-QxZOZTf6.js');
const require_parseNumber = require('./parseNumber-D4iQDxK-.js');
const require_transformQuery = require('./transformQuery-CWDPogO5.js');
const require_convertQuery = require('./convertQuery-DAqoID3O.js');
let immer = require("immer");
immer = require_isRuleGroup.__toESM(immer);
//#region src/utils/isRuleOrGroupValid.ts
/**
* Determines if an object is useful as a validation result.
*/
const isValidationResult = (vr) => require_isRuleGroup.isPojo(vr) && typeof vr.valid === "boolean";
/**
* Determines if a rule or group is valid based on a validation result (if defined)
* or a validator function. Returns `true` if neither are defined and the `muted`
* property is not `true`.
*/
const isRuleOrGroupValid = (rg, validationResult, validator) => {
if (rg.muted) return false;
if (typeof validationResult === "boolean") return validationResult;
if (isValidationResult(validationResult)) return validationResult.valid;
if (typeof validator === "function" && !require_isRuleGroup.isRuleGroup(rg)) {
const vr = validator(rg);
if (typeof vr === "boolean") return vr;
// istanbul ignore else
if (isValidationResult(vr)) return vr.valid;
}
return true;
};
//#endregion
//#region src/utils/getParseNumberMethod.ts
const 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;
};
//#endregion
//#region src/utils/formatQuery/utils.ts
/**
* Maps a {@link DefaultOperatorName} to a SQL operator.
*
* @group Export
*/
const mapSQLOperator = (rqbOperator) => {
switch (require_isRuleGroup.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;
}
};
/**
* Maps a (lowercase) {@link DefaultOperatorName} to a MongoDB operator.
*
* @group Export
*/
const mongoOperators = {
"=": "$eq",
"!=": "$ne",
"<": "$lt",
"<=": "$lte",
">": "$gt",
">=": "$gte",
in: "$in",
notin: "$nin",
notIn: "$nin"
};
/**
* Maps a (lowercase) {@link DefaultOperatorName} to a Prisma ORM operator.
*
* @group Export
*/
const prismaOperators = {
"=": "equals",
"!=": "not",
"<": "lt",
"<=": "lte",
">": "gt",
">=": "gte",
in: "in",
notin: "notIn"
};
/**
* Maps a {@link DefaultCombinatorName} to a CEL combinator.
*
* @group Export
*/
const celCombinatorMap = {
and: "&&",
or: "||"
};
/**
* Register these operators with `jsonLogic` before applying the result
* of `formatQuery(query, 'jsonlogic')`.
*
* @example
* ```
* for (const [op, func] of Object.entries(jsonLogicAdditionalOperators)) {
* jsonLogic.add_operation(op, func);
* }
* jsonLogic.apply({ "startsWith": [{ "var": "firstName" }, "Stev"] }, data);
* ```
*
* @group Export
*/
const jsonLogicAdditionalOperators = {
startsWith: (a, b) => typeof a === "string" && a.startsWith(b),
endsWith: (a, b) => typeof a === "string" && a.endsWith(b)
};
/**
* Converts all `string`-type `value` properties of a query object into `number` where appropriate.
*
* Used by {@link formatQuery} for the `json*` formats when `parseNumbers` is `true`.
*
* @group Export
*/
const numerifyValues = (rg, options) => ({
...rg,
rules: rg.rules.map((r) => {
if (typeof r === "string") return r;
if (require_isRuleGroup.isRuleGroup(r)) return numerifyValues(r, options);
const fieldData = require_optGroupUtils.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) => require_parseNumber.parseNumber(v, { parseNumbers }))
};
const valAsArray = require_arrayUtils.toArray(r.value, { retainEmptyStrings: true }).map((v) => require_parseNumber.parseNumber(v, { parseNumbers }));
if (valAsArray.every((v) => typeof v === "number")) {
// istanbul ignore else
if (valAsArray.length > 1) return {
...r,
value: valAsArray
};
else if (valAsArray.length === 1) return {
...r,
value: valAsArray[0]
};
}
return r;
})
});
/**
* Determines whether a value is _anything_ except an empty `string` or `NaN`.
*
* @group Export
*/
const isValidValue = (value) => typeof value === "string" && value.length > 0 || typeof value === "number" && !Number.isNaN(value) || typeof value !== "string" && typeof value !== "number";
/**
* Determines whether {@link formatQuery} should render the given value as a number.
* As long as `parseNumbers` is `true`, `number` and `bigint` values will return `true` and
* `string` values will return `true` if they test positive against {@link numericRegex}.
*
* @group Export
*/
const shouldRenderAsNumber = (value, parseNumbers) => !!parseNumbers && (typeof value === "number" || typeof value === "bigint" || typeof value === "string" && require_isRuleGroup.numericRegex.test(value));
/**
* Used by {@link formatQuery} to determine whether the given value processor is a
* "legacy" value processor by counting the number of arguments. Legacy value
* processors take 3 arguments (not counting any arguments with default values), while
* rule-based value processors take no more than 2 arguments.
*
* @group Export
*/
const isValueProcessorLegacy = (valueProcessor) => valueProcessor.length >= 3;
/**
* Converts the `quoteFieldNamesWith` option into an array of two strings.
* If the option is a string, the array elements are both that string.
*
* @default
* ['', '']
*
* @group Export
*/
const getQuoteFieldNamesWithArray = (quoteFieldNamesWith = ["", ""]) => Array.isArray(quoteFieldNamesWith) ? quoteFieldNamesWith : typeof quoteFieldNamesWith === "string" ? [quoteFieldNamesWith, quoteFieldNamesWith] : quoteFieldNamesWith ?? ["", ""];
/**
* Given a field name and relevant {@link ValueProcessorOptions}, returns the field name
* wrapped in the configured quote character(s).
*
* @group Export
*/
const getQuotedFieldName = (fieldName, { quoteFieldNamesWith, fieldIdentifierSeparator }) => {
const [qPre, qPost] = getQuoteFieldNamesWithArray(quoteFieldNamesWith);
return typeof fieldIdentifierSeparator === "string" && fieldIdentifierSeparator.length > 0 ? require_arrayUtils.joinWith(require_arrayUtils.splitBy(fieldName, fieldIdentifierSeparator).map((part) => `${qPre}${part}${qPost}`), fieldIdentifierSeparator) : `${qPre}${fieldName}${qPost}`;
};
const defaultWordOrder = [
"S",
"V",
"O"
];
/**
* Given a [Constituent word order](https://en.wikipedia.org/wiki/Word_order#Constituent_word_orders)
* like "svo" or "sov", returns a permutation of `["S", "V", "O"]` based on the first occurrence of
* each letter in the input string (case insensitive). This widens the valid input from abbreviations
* like "svo" to more expressive strings like "subject-verb-object" or "sub ver obj". Any missing
* letters are appended in the default order "SVO" (e.g., "object" would yield `["O", "S", "V"]`).
*
* @group Export
*/
const 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;
};
/**
* Default translations used by {@link formatQuery} for "natural_language" format.
*
* @group Export
*/
const defaultNLTranslations = {
groupPrefix: "",
groupPrefix_not_xor: "either zero or more than one of",
groupPrefix_xor: "exactly one of",
groupSuffix: "is true",
groupSuffix_not: "is not true"
};
/**
* Note: This function assumes `conditions.length > 0`
*/
const translationMatchFilter = (key, keyToTest, conditions) => keyToTest.startsWith(key) && conditions.every((c) => keyToTest.includes(`_${c}`) && keyToTest.match(/_/g)?.length === conditions.length);
/**
* Used by {@link formatQuery} to get a translation based on certain conditions
* for the "natural_language" format.
*
* @group Export
*/
const getNLTranslataion = (key, translations, conditions = []) => conditions.length === 0 ? translations[key] ?? defaultNLTranslations[key] ?? "" : Object.entries(translations).find(([keyToTest]) => translationMatchFilter(key, keyToTest, conditions))?.[1] ?? Object.entries(defaultNLTranslations).find(([keyToTest]) => translationMatchFilter(key, keyToTest, conditions))?.[1] ?? defaultNLTranslations[key] ?? "";
const processMatchMode = (rule) => {
const { mode, threshold } = rule.match ?? {};
if (mode) {
if (!require_isRuleGroup.isRuleGroup(rule.value)) return false;
const matchModeLC = require_isRuleGroup.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
};
}
};
/**
* "Replacer" method for JSON.stringify's second argument. Converts `bigint` values to
* objects with a `$bigint` property having a value of a string representation of
* the actual `bigint`-type value.
*
* Inverse of {@link bigIntJsonParseReviver}.
*
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#use_within_json
*/
const bigIntJsonStringifyReplacer = (_key, value) => typeof value === "bigint" ? { $bigint: value.toString() } : value;
/**
* "Reviver" method for JSON.parse's second argument. Converts objects having a single
* `$bigint: string` property to an actual `bigint` value.
*
* Inverse of {@link bigIntJsonStringifyReplacer}.
*
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#use_within_json
*/
const bigIntJsonParseReviver = (_key, value) => require_isRuleGroup.isPojo(value) && Object.keys(value).length === 1 && typeof value.$bigint === "string" ? BigInt(value.$bigint) : value;
//#endregion
//#region src/utils/formatQuery/defaultRuleGroupProcessorCEL.ts
/**
* Rule group processor used by {@link formatQuery} for "cel" format.
*
* @group Export
*/
const defaultRuleGroupProcessorCEL = (ruleGroup, options) => {
const { fields, fallbackExpression, getParseNumberBoolean, placeholderFieldName, placeholderOperatorName, placeholderValueName, ruleProcessor, validateRule, validationMap } = options;
const processRuleGroup = (rg, outermost) => {
if (!isRuleOrGroupValid(rg, validationMap[rg.id ?? ""])) return outermost ? fallbackExpression : "";
const processedRules = [];
let precedingCombinator = "";
let firstRule = true;
for (const rule of rg.rules) {
if (typeof rule === "string") {
precedingCombinator = celCombinatorMap[rule];
continue;
}
if (require_isRuleGroup.isRuleGroup(rule)) {
const processedGroup = processRuleGroup(rule);
if (processedGroup) {
if (!firstRule && precedingCombinator) {
processedRules.push(precedingCombinator);
precedingCombinator = "";
}
firstRule = false;
processedRules.push(processedGroup);
}
continue;
}
const [validationResult, fieldValidator] = validateRule(rule);
if (!isRuleOrGroupValid(rule, validationResult, fieldValidator) || rule.field === placeholderFieldName || rule.operator === placeholderOperatorName || placeholderValueName !== void 0 && rule.value === placeholderValueName) continue;
const fieldData = require_optGroupUtils.getOption(fields, rule.field);
const processedRule = ruleProcessor(rule, {
...options,
parseNumbers: getParseNumberBoolean(fieldData?.inputType),
escapeQuotes: (rule.valueSource ?? "value") === "value",
fieldData
});
if (processedRule) {
if (!firstRule && precedingCombinator) {
processedRules.push(precedingCombinator);
precedingCombinator = "";
}
firstRule = false;
processedRules.push(processedRule);
}
}
const expression = processedRules.join(require_isRuleGroup.isRuleGroupType(rg) ? ` ${celCombinatorMap[rg.combinator]} ` : " ");
const [prefix, suffix] = rg.not || !outermost ? [`${rg.not ? "!" : ""}(`, ")"] : ["", ""];
return expression ? `${prefix}${expression}${suffix}` : fallbackExpression;
};
return processRuleGroup(ruleGroup, true);
};
//#endregion
//#region src/utils/formatQuery/defaultRuleProcessorCEL.ts
const shouldNegate$2 = (op) => op.startsWith("not") || op.startsWith("doesnot");
const escapeDoubleQuotes = (v, escapeQuotes) => typeof v !== "string" || !escapeQuotes ? `${v}` : v.replaceAll(`"`, `\\"`);
/**
* Default rule processor used by {@link formatQuery} for "cel" format.
*
* @group Export
*/
const defaultRuleProcessorCEL = (rule, opts = {}) => {
const { escapeQuotes, parseNumbers, preserveValueOrder } = opts;
const { field, operator, value, valueSource } = rule;
const valueIsField = valueSource === "field";
const operatorTL = require_isRuleGroup.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 nestedArrayFilter = defaultRuleGroupProcessorCEL(require_transformQuery.transformQuery(rule.value, { ruleProcessor: (r) => ({
...r,
field: `${arrayElementAlias}${r.field ? `.${r.field}` : ""}`
}) }), 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 ? require_arrayUtils.trimIfString(value) : `"${escapeDoubleQuotes(value, escapeQuotes)}"`}`;
case "contains":
case "doesnotcontain": return `${shouldNegate$2(operatorTL) ? "!" : ""}${field}.contains(${valueIsField ? require_arrayUtils.trimIfString(value) : `"${escapeDoubleQuotes(value, escapeQuotes)}"`})`;
case "beginswith":
case "doesnotbeginwith": return `${shouldNegate$2(operatorTL) ? "!" : ""}${field}.startsWith(${valueIsField ? require_arrayUtils.trimIfString(value) : `"${escapeDoubleQuotes(value, escapeQuotes)}"`})`;
case "endswith":
case "doesnotendwith": return `${shouldNegate$2(operatorTL) ? "!" : ""}${field}.endsWith(${valueIsField ? require_arrayUtils.trimIfString(value) : `"${escapeDoubleQuotes(value, escapeQuotes)}"`})`;
case "null": return `${field} == null`;
case "notnull": return `${field} != null`;
case "in":
case "notin": {
const [prefix, suffix] = shouldNegate$2(operatorTL) ? ["!(", ")"] : ["", ""];
return `${prefix}${field} in [${require_arrayUtils.toArray(value).map((val) => valueIsField || shouldRenderAsNumber(val, parseNumbers) ? `${require_arrayUtils.trimIfString(val)}` : `"${escapeDoubleQuotes(val, escapeQuotes)}"`).join(", ")}]${suffix}`;
}
case "between":
case "notbetween": {
const valueAsArray = require_arrayUtils.toArray(value);
if (valueAsArray.length >= 2 && !require_isRuleGroup.nullOrUndefinedOrEmpty(valueAsArray[0]) && !require_isRuleGroup.nullOrUndefinedOrEmpty(valueAsArray[1])) {
const [first, second] = valueAsArray;
const shouldParseNumbers = !(parseNumbers === false);
const firstNum = shouldRenderAsNumber(first, shouldParseNumbers) ? require_parseNumber.parseNumber(first, { parseNumbers: shouldParseNumbers }) : NaN;
const secondNum = shouldRenderAsNumber(second, shouldParseNumbers) ? require_parseNumber.parseNumber(second, { parseNumbers: shouldParseNumbers }) : 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 "";
};
//#endregion
//#region src/utils/formatQuery/defaultRuleGroupProcessorMongoDBQuery.ts
/**
* Default fallback object used by {@link formatQuery} for "mongodb_query" format.
*
* @group Export
*/
const mongoDbFallback = { $and: [{ $expr: true }] };
/**
* Rule group processor used by {@link formatQuery} for "mongodb_query" format.
*
* @group Export
*/
const defaultRuleGroupProcessorMongoDBQuery = (ruleGroup, options, meta) => {
const { fields, getParseNumberBoolean, placeholderFieldName, placeholderOperatorName, placeholderValueName, ruleProcessor, validateRule, validationMap } = options;
const processRuleGroup = (rg, outermost) => {
if (!isRuleOrGroupValid(rg, validationMap[rg.id ?? ""])) return outermost ? mongoDbFallback : false;
const combinator = `$${require_isRuleGroup.lc(rg.combinator)}`;
let hasChildRules = false;
const expressions = rg.rules.map((rule) => {
if (require_isRuleGroup.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 || placeholderValueName !== void 0 && rule.value === placeholderValueName) return false;
const fieldData = require_optGroupUtils.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(require_convertQuery.convertFromIC(ruleGroup), true);
};
//#endregion
//#region src/utils/formatQuery/defaultRuleProcessorMongoDBQuery.ts
const processNumber$1 = (value, fallback, parseNumbers = false) => shouldRenderAsNumber(value, parseNumbers || typeof value === "bigint") ? Number(require_parseNumber.parseNumber(value, { parseNumbers: "strict" })) : fallback;
/**
* Default rule processor used by {@link formatQuery} for "mongodb_query" format.
*
* @group Export
*/
const 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(require_transformQuery.transformQuery(value, { ruleProcessor: (r) => ({
...r,
field: r.field ? `${field}.${r.field}` : field
}) }), {
...options,
ruleProcessor: defaultRuleProcessorMongoDBQuery,
context: {
...options.context,
avoidFieldsAsKeys: false
}
});
const subQueryWithAggCtx = defaultRuleGroupProcessorMongoDBQuery(require_transformQuery.transformQuery(value, { ruleProcessor: (r) => ({
...r,
field: r.field ? `$item.${r.field}` : "$item"
}) }), {
...options,
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$1(value, value, parseNumbers)] } : { [field]: processNumber$1(value, value, parseNumbers) };
const operatorLC = require_isRuleGroup.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$1(value, value, parseNumbers)] }] } : { [field]: { [mongoOperator]: processNumber$1(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 = require_arrayUtils.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$1(val, val, parseNumbers))] } } : { [mongoOperators[operatorLC]]: [`$${field}`, valueAsArray.map((val) => processNumber$1(val, val, parseNumbers))] } : { [field]: { [mongoOperators[operatorLC]]: valueAsArray.map((val) => processNumber$1(val, val, parseNumbers)) } };
}
case "between":
case "notbetween": {
const valueAsArray = require_arrayUtils.toArray(value);
if (valueAsArray.length >= 2 && isValidValue(valueAsArray[0]) && isValidValue(valueAsArray[1])) {
const [first, second] = valueAsArray;
const firstNum = processNumber$1(first, NaN, true);
const secondNum = processNumber$1(second, 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 "";
};
//#endregion
//#region src/utils/formatQuery/defaultRuleProcessorMongoDB.ts
/**
* Default rule processor used by {@link formatQuery} for "mongodb" format.
*
* Note that the "mongodb" format is deprecated in favor of the "mongodb_query" format.
*
* @group Export
*/
const defaultRuleProcessorMongoDB = (rule, options) => {
const queryObj = defaultRuleProcessorMongoDBQuery(rule, options);
return queryObj ? JSON.stringify(queryObj) : "";
};
//#endregion
//#region src/utils/formatQuery/defaultRuleGroupProcessorSpEL.ts
/**
* Default rule processor used by {@link formatQuery} for "spel" format.
*
* @group Export
*/
const defaultRuleGroupProcessorSpEL = (ruleGroup, options) => {
const { fields, fallbackExpression, getParseNumberBoolean, placeholderFieldName, placeholderOperatorName, placeholderValueName, ruleProcessor, validateRule, validationMap } = options;
const processRuleGroup = (rg, outermost) => {
if (!isRuleOrGroupValid(rg, validationMap[rg.id ?? ""])) return outermost ? fallbackExpression : "";
const processedRules = [];
let precedingCombinator = "";
let firstRule = true;
for (const rule of rg.rules) {
if (typeof rule === "string") {
precedingCombinator = rule;
continue;
}
if (require_isRuleGroup.isRuleGroup(rule)) {
const processedGroup = processRuleGroup(rule);
if (processedGroup) {
if (!firstRule && precedingCombinator) {
processedRules.push(precedingCombinator);
precedingCombinator = "";
}
firstRule = false;
processedRules.push(processedGroup);
}
continue;
}
const [validationResult, fieldValidator] = validateRule(rule);
if (!isRuleOrGroupValid(rule, validationResult, fieldValidator) || rule.field === placeholderFieldName || rule.operator === placeholderOperatorName || placeholderValueName !== void 0 && rule.value === placeholderValueName) continue;
const fieldData = require_optGroupUtils.getOption(fields, rule.field);
const processedRule = ruleProcessor(rule, {
...options,
parseNumbers: getParseNumberBoolean(fieldData?.inputType),
escapeQuotes: (rule.valueSource ?? "value") === "value",
fieldData
});
if (processedRule) {
if (!firstRule && precedingCombinator) {
processedRules.push(precedingCombinator);
precedingCombinator = "";
}
firstRule = false;
processedRules.push(processedRule);
}
}
const expression = processedRules.join(require_isRuleGroup.isRuleGroupType(rg) ? ` ${rg.combinator} ` : " ");
const [prefix, suffix] = rg.not || !outermost ? [`${rg.not ? "!" : ""}(`, ")"] : ["", ""];
return expression ? `${prefix}${expression}${suffix}` : fallbackExpression;
};
return processRuleGroup(ruleGroup, true);
};
//#endregion
//#region src/utils/formatQuery/defaultRuleProcessorSpEL.ts
const shouldNegate$1 = (op) => op.startsWith("not") || op.startsWith("doesnot");
const wrapInNegation = (clause, negate$1) => negate$1 ? `!(${clause})` : clause;
const escapeSingleQuotes = (v, escapeQuotes) => typeof v !== "string" || !escapeQuotes ? `${v}` : v.replaceAll(`'`, `\\'`);
/**
* Default rule processor used by {@link formatQuery} for "spel" format.
*
* @group Export
*/
const defaultRuleProcessorSpEL = (rule, opts = {}) => {
const { field, operator, value, valueSource } = rule;
const { escapeQuotes, parseNumbers, preserveValueOrder } = opts;
const valueIsField = valueSource === "field";
const operatorTL = require_isRuleGroup.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(require_transformQuery.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 ? require_arrayUtils.trimIfString(value) : `'${escapeSingleQuotes(value, escapeQuotes)}'`}`;
case "contains":
case "doesnotcontain": return wrapInNegation(`${field} matches ${valueIsField || useBareValue ? require_arrayUtils.trimIfString(value) : `'${escapeSingleQuotes(value, escapeQuotes)}'`}`, shouldNegate$1(operatorTL));
case "beginswith":
case "doesnotbeginwith": return wrapInNegation(`${field} matches ${valueIsField ? `'^'.concat(${require_arrayUtils.trimIfString(value)})` : `'${typeof value === "string" && !value.startsWith("^") || useBareValue ? "^" : ""}${escapeSingleQuotes(value, escapeQuotes)}'`}`, shouldNegate$1(operatorTL));
case "endswith":
case "doesnotendwith": return wrapInNegation(`${field} matches ${valueIsField ? `${require_arrayUtils.trimIfString(value)}.concat('$')` : `'${escapeSingleQuotes(value, escapeQuotes)}${typeof value === "string" && !value.endsWith("$") || useBareValue ? "$" : ""}'`}`, shouldNegate$1(operatorTL));
case "null": return `${field} == null`;
case "notnull": return `${field} != null`;
case "in":
case "notin": {
const negate$1 = shouldNegate$1(operatorTL) ? "!" : "";
const valueAsArray = require_arrayUtils.toArray(value);
return valueAsArray.length > 0 ? `${negate$1}(${valueAsArray.map((val) => `${field} == ${valueIsField || shouldRenderAsNumber(val, parseNumbers) ? `${require_arrayUtils.trimIfString(val)}` : `'${escapeSingleQuotes(val, escapeQuotes)}'`}`).join(" or ")})` : "";
}
case "between":
case "notbetween": {
const valueAsArray = require_arrayUtils.toArray(value);
if (valueAsArray.length >= 2 && !require_isRuleGroup.nullOrUndefinedOrEmpty(valueAsArray[0]) && !require_isRuleGroup.nullOrUndefinedOrEmpty(valueAsArray[1])) {
const [first, second] = valueAsArray;
const shouldParseNumbers = !(parseNumbers === false);
const firstNum = shouldRenderAsNumber(first, shouldParseNumbers) ? require_parseNumber.parseNumber(first, { parseNumbers: shouldParseNumbers }) : NaN;
const secondNum = shouldRenderAsNumber(second, shouldParseNumbers) ? require_parseNumber.parseNumber(second, { parseNumbers: shouldParseNumbers }) : 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 "";
};
//#endregion
//#region src/utils/formatQuery/defaultValueProcessorByRule.ts
const escapeStringValueQuotes$1 = (v, quoteChar, escapeQuotes) => escapeQuotes && typeof v === "string" ? v.replaceAll(`${quoteChar}`, `${quoteChar}${quoteChar}`) : v;
/**
* Default value processor used by {@link formatQuery} for "sql" format.
*
* @group Export
*/
const defaultValueProcessorByRule = ({ operator, value, valueSource }, { escapeQuotes, parseNumbers, preserveValueOrder, quoteFieldNamesWith, quoteValuesWith, concatOperator = "||", fieldIdentifierSeparator, wrapValueWith = ["", ""], translations } = {}) => {
const valueIsField = valueSource === "field";
const operatorLowerCase = require_isRuleGroup.lc(operator);
const quoteChar = quoteValuesWith || "'";
const quoteValue = (v) => `${wrapValueWith[0]}${quoteChar}${v}${quoteChar}${wrapValueWith[1]}`;
const escapeValue = (v) => escapeStringValueQuotes$1(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 = require_arrayUtils.toArray(value);
if (valueAsArray.length > 0) return `(${valueAsArray.map((v) => valueIsField ? wrapFieldName(v) : shouldRenderAsNumber(v, parseNumbers) ? `${require_arrayUtils.trimIfString(v)}` : `${wrapAndEscape(v)}`).join(", ")})`;
return "";
}
case "between":
case "notbetween": {
const valueAsArray = require_arrayUtils.toArray(value, { retainEmptyStrings: true });
if (valueAsArray.length < 2 || !isValidValue(valueAsArray[0]) || !isValidValue(valueAsArray[1])) return "";
const [first, second] = valueAsArray;
const firstNum = shouldRenderAsNumber(first, parseNumbers) ? require_parseNumber.parseNumber(first, { parseNumbers: "strict" }) : NaN;
const secondNum = shouldRenderAsNumber(second, parseNumbers) ? require_parseNumber.parseNumber(second, { parseNumbers: "strict" }) : 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) => require_parseNumber.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) ? `${require_arrayUtils.trimIfString(value)}` : `${wrapAndEscape(value)}`;
};
//#endregion
//#region src/utils/formatQuery/defaultRuleProcessorDrizzle.ts
/**
* Default rule processor used by {@link formatQuery} for the "drizzle" format.
*
* @group Export
*/
const defaultRuleProcessorDrizzle = (rule, _options) => {
const opts = _options ?? ( /* istanbul ignore next */ {});
// 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 = require_isRuleGroup.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 nestedArrayFilter = defaultRuleGroupProcessorDrizzle(require_transformQuery.transformQuery(rule.value, { ruleProcessor: (r) => ({
...r,
field: arrayElementAlias
}) }), {
...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));
case "<": return lt(column, asFieldOrValue(value));
case ">=": return gte(column, asFieldOrValue(value));
case "<=": return lte(column, asFieldOrValue(value));
case "beginswith":
case "doesnotbeginwith": return (operatorLC === "doesnotbeginwith" ? notLike : like)(column, valueIsField ? sql`${asFieldOrValue(value)} || '%'` : `${value}%`);
case "contains":
case "doesnotcontain": return (operatorLC === "doesnotcontain" ? notLike : like)(column, valueIsField ? sql`'%' || ${asFieldOrValue(value)} || '%'` : `%${value}%`);
case "endswith":
case "doesnotendwith": return (operatorLC === "doesnotendwith" ? notLike : like)(column, valueIsField ? sql`'%' || ${asFieldOrValue(value)}` : `%${value}`);
case "null": return isNull(column);
case "notnull": return isNotNull(column);
case "in":
case "notin": {
const valueAsArray = require_arrayUtils.toArray(value).map((v) => asFieldOrValue(v));
return operatorLC === "notin" ? notInArray(column, valueAsArray) : inArray(column, valueAsArray);
}
case "between":
case "notbetween": {
const valueAsArray = require_arrayUtils.toArray(value);
if (valueAsArray.length >= 2 && isValidValue(valueAsArray[0]) && isValidValue(valueAsArray[1])) {
let [first, second] = valueAsArray;
const shouldParseNumbers = !(parseNumbers === false);
if (!valueIsField && shouldRenderAsNumber(first, shouldParseNumbers) && shouldRenderAsNumber(second, shouldParseNumbers)) {
const firstNum = require_parseNumber.parseNumber(first, { parseNumbers: shouldParseNumbers });
const secondNum = require_parseNumber.parseNumber(second, { parseNumbers: shouldParseNumbers });
if (!preserveValueOrder && secondNum < firstNum) {
const tempNum = secondNum;
second = firstNum;
first = tempNum;
} else {
first = firstNum;
second = secondNum;
}
} else if (valueIsField) {
first = asFieldOrValue(first);
second = asFieldOrValue(second);
}
return operatorLC === "notbetween" ? notBetween(column, first, second) : between(column, first, second);
}
return;
}
default: return;
}
};
//#endregion
//#region src/utils/formatQuery/defaultRuleGroupProcessorDrizzle.ts
/**
* Default rule group processor used by {@link formatQuery} for the "drizzle" format. The returned
* function can be assigned to the `where` property in the Drizzle relational queries API.
*
* @example
* const where = formatQuery(query, 'drizzle');
* const results = db.query.users.findMany({ where });
*
* @returns Function that takes a Drizzle table config and an object of Drizzle operators.
*
* @group Export
*/
const defaultRuleGroupProcessorDrizzle = (ruleGroup, options, _meta) => (columns, drizzleOperators) => {
const { fields, getParseNumberBoolean, placeholderFieldName, placeholderOperatorName, placeholderValueName, validateRule, validationMap } = options;
if (!columns || !drizzleOperators) return;
const { and, not, or } = drizzleOperators;
const ruleProcessor = defaultRuleProcessorDrizzle;
const processRuleGroup = (rg, _outermost) => {
if (!isRuleOrGroupValid(rg, validationMap[rg.id ?? ""])) return;
const processedRules = rg.rules.map((rule) => {
if (require_isRuleGroup.isRuleGroup(rule)) return processRuleGroup(rule);
const [validationResult, fieldValidator] = validateRule(rule);
if (!isRuleOrGroupValid(rule, validationResult, fieldValidator) || rule.field === placeholderFieldName || rule.operator === placeholderOperatorName || placeholderValueName !== void 0 && rule.value === placeholderValueName) return;
const fieldData = require_optGroupUtils.getOption(fields, rule.field);
return ruleProcessor(rule, {
...options,
parseNumbers: getParseNumberBoolean(fieldData?.inputType),
fieldData,
context: {
...options.context,
columns,
drizzleOperators
}
});
}).filter(Boolean);
if (processedRules.length === 0) return;
const ruleGroupSQL = rg.combinator === "or" ? or(...processedRules) : and(...processedRules);
return rg.not ? not(ruleGroupSQL) : ruleGroupSQL;
};
return processRuleGroup(require_convertQuery.convertFromIC(ruleGroup), true);
};
//#endregion
//#region src/utils/formatQuery/defaultRuleGroupProcessorElasticSearch.ts
/**
* Rule group processor used by {@link formatQuery} for "elasticsearch" format.
*
* @group Export
*/
const defaultRuleGroupProcessorElasticSearch = (ruleGroup, options) => {
const { fields, getParseNumberBoolean, placeholderFieldName, placeholderOperatorName, placeholderValueName, ruleProcessor, validateRule, validationMap } = options;
const processRuleGroup = (rg) => {
if (!isRuleOrGroupValid(rg, validationMap[rg.id ?? ""])) return false;
const processedRules = rg.rules.map((rule) => {
if (require_isRuleGroup.isRuleGroup(rule)) return processRuleGroup(rule);
const [validationResult, fieldValidator] = validateRule(rule);
if (!isRuleOrGroupValid(rule, validationResult, fieldValidator) || rule.field === placeholderFieldName || rule.operator === placeholderOperatorName || placeholderValueName !== void 0 && rule.value === placeholderValueName) return false;
const fieldData = require_optGroupUtils.getOption(fields, rule.field);
return ruleProcessor(rule, {
...options,
parseNumbers: getParseNumberBoolean(fieldData?.inputType),
fieldData
});
}).filter(Boolean);
if (processedRules.length === 0) return false;
return { bool: rg.not ? { must_not: /^or$/i.test(rg.combinator) ? { bool: { should: processedRules } } : processedRules } : { [/^or$/i.test(rg.combinator) ? "should" : "must"]: processedRules } };
};
const processedRuleGroup = processRuleGroup(require_convertQuery.convertFromIC(ruleGroup));
return processedRuleGroup === false ? {} : processedRuleGroup;
};
//#endregion
//#region src/utils/formatQuery/defaultRuleGroupProcessorJSONata.ts
/**
* Rule group processor used by {@link formatQuery} for "jsonata" format.
*
* @group Export
*/
const defaultRuleGroupProcessorJSONata = (ruleGroup, options) => {
const { fields, fallbackExpression, getParseNumberBoolean, placeholderFieldName, placeholderOperatorName, placeholderValueName, ruleProcessor, validateRule, validationMap } = options;
const processRuleGroup = (rg, outermost) => {
if (!isRuleOrGroupValid(rg, validationMap[rg.id ?? ""])) return outermost ? fallbackExpression : "";
const processedRules = [];
let precedingCombinator = "";
let firstRule = true;
for (const rule of rg.rules) {
if (typeof rule === "string") {
precedingCombinator = rule;
continue;
}
if (require_isRuleGroup.isRuleGroup(rule)) {
const processedGroup = processRuleGroup(rule);
if (processedGroup) {
if (!firstRule && precedingCombinator) {
processedRules.push(precedingCombinator);
precedingCombinator = "";
}
firstRule = false;
processedRules.push(processedGroup);
}
continue;
}
const [validationResult, fieldValidator] = validateRule(rule);
if (!isRuleOrGroupValid(rule, validationResult, fieldValidator) || rule.field === placeholderFieldName || rule.operator === placeholderOperatorName || placeholderValueName !== void 0 && rule.value === placeholderValueName) continue;
const fieldData = require_optGroupUtils.getOption(fields, rule.field);
const processedRule = ruleProcessor(rule, {
...options,
parseNumbers: getParseNumberBoolean(fieldData?.inputType),
escapeQuotes: (rule.valueSource ?? "value") === "value",
fieldData
});
if (processedRule) {
if (!firstRule && precedingCombinator) {
processedRules.push(precedingCombinator);
precedingCombinator = "";
}
firstRule = false;
processedRules.push(processedRule);
}
}
const expression = processedRules.join(require_isRuleGroup.isRuleGroupType(rg) ? ` ${rg.combinator} ` : " ");
const [prefix, suffix] = rg.not || !outermost ? [`${rg.not ? "$not" : ""}(`, ")"] : ["", ""];
return expression ? `${prefix}${expression}${suffix}` : fallbackExpression;
};
return processRuleGroup(ruleGroup, true);
};
//#endregion
//#region src/utils/formatQuery/defaultRuleGroupProcessorJsonLogic.ts
/**
* Rule group processor used by {@link formatQuery} for "jsonlogic" format.
*
* @group Export
*/
const defaultRuleGroupProcessorJsonLogic = (ruleGroup, options) => {
const { fields, getParseNumberBoolean, placeholderFieldName, placeholderOperatorName, placeholderValueName, ruleProcessor, validateRule, validationMap } = options;
const query = require_convertQuery.convertFromIC(ruleGroup);
const processRuleGroup = (rg, _outermost) => {
if (!isRuleOrGroupValid(rg, validationMap[rg.id ?? ""])) return false;
const processedRules = rg.rules.map((rule) => {
if (require_isRuleGroup.isRuleGroup(rule)) return processRuleGroup(rule);
const [validationResult, fieldValidator] = validateRule(rule);
if (!isRuleOrGroupValid(rule, validationResult, fieldValidator) || rule.field === placeholderFieldName || rule.operator === placeholderOperatorName || placeholderValueName !== void 0 && rule.value === placeholderValueName) return false;
const fieldData = require_optGroupUtils.getOption(fields, rule.field);
return ruleProcessor(rule, {
...options,
parseNumbers: getParseNumberBoolean(fieldData?.inputType),
fieldData
});
}).filter(Boolean);
if (processedRules.length === 0) return false;
const jsonRuleGroup = { [rg.combinator]: processedRules };
return rg.not ? { "!": jsonRuleGroup } : jsonRuleGroup;
};
return processRuleGroup(query, true);
};
//#endregion
//#region src/utils/formatQuery/defaultRuleGroupProcessorLDAP.ts
/**
* Rule group processor used by {@link formatQuery} for "ldap" format.
*
* @group Export
*/
const defaultRuleGroupProcessorLDAP = (ruleGroup, options) => {
const { fields, fallbackExpression, getParseNumberBoolean, placeholderFieldName, placeholderOperatorName, placeholderValueName, ruleProcessor, validateRule, validationMap } = options;
const processRuleGroup = (rg, outermost) => {
if (!isRuleOrGroupValid(