UNPKG

@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
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