@react-querybuilder/core
Version:
React Query Builder component for constructing queries and filters, with utilities for executing them in various database and evaluation contexts
153 lines (147 loc) • 6.52 kB
JavaScript
import { a as toFullOption, i as toFlatOptionArray, n as isFlexibleOptionArray, o as toFullOptionList, r as isFlexibleOptionGroupArray } from "./optGroupUtils-VeZ3k7-1.mjs";
import { a as lc, t as isRuleGroup } from "./isRuleGroup-CYcfPgbg.mjs";
import { produce } from "immer";
//#region src/utils/filterFieldsByComparator.ts
const filterByComparator = (field, operator, fieldToCompare) => {
const fullField = toFullOption(field);
const fullFieldToCompare = toFullOption(fieldToCompare);
if (fullField.value === fullFieldToCompare.value) return false;
if (typeof fullField.comparator === "string") return fullField[fullField.comparator] === fullFieldToCompare[fullField.comparator];
return fullField.comparator?.(fullFieldToCompare, operator) ?? false;
};
/**
* For a given {@link FullField}, returns the `fields` list filtered for
* other fields that match by `comparator`. Only fields *other than the
* one in question* will ever be included, even if `comparator` is `null`
* or `undefined`. If `comparator` is a string, fields with the same value
* for that property will be included. If `comparator` is a function, each
* field will be passed to the function along with the `operator` and fields
* for which the function returns `true` will be included.
*
* @group Option Lists
*/
const filterFieldsByComparator = (field, fields, operator) => {
if (!field.comparator) {
const filterOutSameField = (f) => (f.value ?? f.name) !== (field.value ?? field.name);
if (isFlexibleOptionGroupArray(fields)) return fields.map((og) => ({
...og,
options: og.options.filter((v) => filterOutSameField(v))
}));
return fields.filter((v) => filterOutSameField(v));
}
if (isFlexibleOptionGroupArray(fields)) return fields.map((og) => ({
...og,
options: og.options.filter((f) => filterByComparator(field, operator, f))
})).filter((og) => og.options.length > 0);
return fields.filter((f) => filterByComparator(field, operator, f));
};
//#endregion
//#region src/utils/getValueSourcesUtil.ts
const defaultValueSourcesArray = [{
name: "value",
value: "value",
label: "value"
}];
const dummyFD = {
name: "name",
value: "name",
valueSources: null,
label: "label"
};
/**
* Utility function to get the value sources array for the given
* field and operator. If the field definition does not define a
* `valueSources` property, the `getValueSources` prop is used.
* Returns `[FullOption<"value">]` by default.
*/
const getValueSourcesUtil = (fieldData, operator, getValueSources) => {
const fd = fieldData ? toFullOption(fieldData) : dummyFD;
let valueSourcesNEW = fd.valueSources ?? false;
if (typeof valueSourcesNEW === "function") valueSourcesNEW = valueSourcesNEW(operator);
if (!valueSourcesNEW && getValueSources) valueSourcesNEW = getValueSources(fd.value, operator, { fieldData: fd });
if (!valueSourcesNEW) return defaultValueSourcesArray;
if (isFlexibleOptionArray(valueSourcesNEW)) return toFullOptionList(valueSourcesNEW);
return valueSourcesNEW.map((vs) => defaultValueSourcesArray.find((dmm) => dmm.value === lc(vs)) ?? {
name: vs,
value: vs,
label: vs
});
};
//#endregion
//#region src/utils/parserUtils.ts
const getFieldsArray = (fields) => {
return toFlatOptionArray(fields ? Array.isArray(fields) ? fields : Object.keys(fields).map((fld) => ({
...fields[fld],
name: fld
})).sort((a, b) => a.label.localeCompare(b.label)) : []);
};
function fieldIsValidUtil(params) {
const { fieldsFlat, fieldName, operator, subordinateFieldName, getValueSources } = params;
const vsIncludes = (vs) => {
const vss = getValueSourcesUtil(primaryField, operator, getValueSources);
return isFlexibleOptionArray(vss) && vss.some((vso) => vso.value === vs || vso.name === vs);
};
if (fieldsFlat.length === 0) return true;
let valid = false;
const primaryField = toFullOption(fieldsFlat.find((ff) => ff.name === fieldName));
if (primaryField) {
valid = !(!subordinateFieldName && operator !== "notNull" && operator !== "null" && !vsIncludes("value"));
if (valid && !!subordinateFieldName) if (vsIncludes("field") && fieldName !== subordinateFieldName) {
if (!filterFieldsByComparator(primaryField, fieldsFlat, operator).some((vsf) => vsf.name === subordinateFieldName)) valid = false;
} else valid = false;
}
return valid;
}
//#endregion
//#region src/utils/generateID.ts
const cryptoModule = globalThis.crypto;
/**
* Default `id` generator. Generates a valid v4 UUID. Uses `crypto.randomUUID()`
* when available, otherwise uses an alternate method based on `getRandomValues`.
* The returned string is guaranteed to match this regex:
* ```
* /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
* ```
* @returns Valid v4 UUID
*/
// istanbul ignore next
let generateID = () => "00-0-4-2-000".replaceAll(/[^-]/g, (s) => ((Math.random() + Math.trunc(s)) * 65536 >> Number.parseInt(s)).toString(16).padStart(4, "0"));
// istanbul ignore else
if (cryptoModule) {
// istanbul ignore else
if (typeof cryptoModule.randomUUID === "function") generateID = () => cryptoModule.randomUUID();
else if (typeof cryptoModule.getRandomValues === "function") {
const position19vals = "89ab";
const container = new Uint32Array(32);
generateID = () => {
cryptoModule.getRandomValues(container);
let id = (container[0] % 16).toString(16);
for (let i = 1; i < 32; i++) {
if (i === 12) id = `${id}4`;
else if (i === 16) id = `${id}${position19vals[container[17] % 4]}`;
else id = `${id}${(container[i] % 16).toString(16)}`;
if (i === 7 || i === 11 || i === 15 || i === 19) id = `${id}-`;
}
return id;
};
}
}
//#endregion
//#region src/utils/prepareQueryObjects.ts
/**
* Ensures that a rule is valid by adding an `id` property if it does not already exist.
*/
const prepareRule = (rule, { idGenerator = generateID } = {}) => produce(rule, (draft) => {
if (!draft.id) draft.id = idGenerator();
});
/**
* Ensures that a rule group is valid by recursively adding an `id` property to the group itself
* and all its rules and subgroups where one does not already exist.
*/
const prepareRuleGroup = (queryObject, { idGenerator = generateID } = {}) => produce(queryObject, (draft) => {
if (!draft.id) draft.id = idGenerator();
draft.rules = draft.rules.map((r) => typeof r === "string" ? r : isRuleGroup(r) ? prepareRuleGroup(r, { idGenerator }) : prepareRule(r, { idGenerator }));
});
//#endregion
export { fieldIsValidUtil as n, getFieldsArray as r, prepareRuleGroup as t };
//# sourceMappingURL=prepareQueryObjects-DPCC-iHp.mjs.map