@react-awesome-query-builder/core
Version:
User-friendly query builder for React. Core
249 lines (225 loc) • 7.03 kB
JavaScript
import * as Utils from "../../utils";
const { isObject, uuid } = Utils.OtherUtils;
const { defaultConjunction, defaultGroupConjunction } = Utils.DefaultUtils;
const { getFieldConfig, getWidgetForFieldOp } = Utils.ConfigUtils;
// export const wrapInDefaultConjRuleGroup = (rule, parentField, parentFieldConfig, config, conj) => {
// if (!rule) return undefined;
// return {
// type: "rule_group",
// id: uuid(),
// children1: { [rule.id]: rule },
// properties: {
// conjunction: conj || defaultGroupConjunction(config, parentFieldConfig),
// not: false,
// field: parentField,
// }
// };
// };
export const wrapInDefaultConj = (rule, config, not = false) => {
return {
type: "group",
id: uuid(),
children1: { [rule.id]: rule },
properties: {
conjunction: defaultConjunction(config),
not: not || false
}
};
};
export const buildCase = (convCond, convVal, conv, config, meta, spel = null) => {
const valProperties = buildCaseValProperties(config, meta, conv, convVal, spel);
let caseI;
if (convCond) {
caseI = convCond;
if (caseI.type) {
if (caseI.type != "group" && caseI.type != "case_group") {
caseI = wrapInDefaultConj(caseI, config);
}
caseI.type = "case_group";
} else {
meta.errors.push(`Unexpected case: ${JSON.stringify(caseI)}`);
caseI = undefined;
}
} else {
caseI = {
id: uuid(),
type: "case_group",
properties: {}
};
}
if (caseI) {
caseI.properties = {
...caseI.properties,
...valProperties
};
}
return caseI;
};
export const buildSimpleSwitch = (convVal, conv, config, meta) => {
let children1 = {};
const caseI = buildCase(null, convVal, conv, config, meta);
if (caseI) {
children1[caseI.id] = caseI;
}
let res = {
type: "switch_group",
id: uuid(),
children1,
properties: {}
};
return res;
};
export const buildRuleGroup = ({groupFilter, groupFieldValue}, opKey, convertedArgs, config, meta) => {
if (groupFieldValue.valueSrc != "field")
throw `Bad groupFieldValue: ${JSON.stringify(groupFieldValue)}`;
const groupField = groupFieldValue.value;
let groupOpRule = buildRule(config, meta, groupField, opKey, convertedArgs);
if (!groupOpRule)
return undefined;
const fieldConfig = getFieldConfig(config, groupField);
const mode = fieldConfig?.mode;
let res;
if (groupFilter?.type === "group") {
res = {
...(groupFilter || {}),
type: "rule_group",
properties: {
...groupOpRule.properties,
...(groupFilter?.properties || {}),
mode
}
};
} else if (groupFilter) {
// rule_group in rule_group
res = {
...(groupOpRule || {}),
type: "rule_group",
children1: [ groupFilter ],
properties: {
...groupOpRule.properties,
mode
}
};
} else {
res = {
...(groupOpRule || {}),
type: "rule_group",
properties: {
...groupOpRule.properties,
mode
}
};
}
if (!res.id)
res.id = uuid();
return res;
};
export const buildCaseValProperties = (config, meta, conv, convVal, spel = null) => {
let valProperties = {};
let widget;
let widgetConfig;
const caseValueFieldConfig = getFieldConfig(config, "!case_value");
if (convVal?.valueType === "case_value") {
/**
* @deprecated
*/
widget = "case_value";
} else {
widget = caseValueFieldConfig?.mainWidget;
widgetConfig = config.widgets[widget];
if (convVal && convVal.valueSrc === "value") {
convVal.valueType = widgetConfig?.type || caseValueFieldConfig?.type || convVal.valueType;
}
}
const widgetDef = config.widgets[widget];
if (widget === "case_value") {
/**
* @deprecated
*/
const importCaseValue = widgetDef?.spelImportValue;
if (importCaseValue) {
const [normVal, normErrors] = importCaseValue.call(config.ctx, convVal);
normErrors.map(e => meta.errors.push(e));
if (normVal != undefined) {
valProperties = {
value: [normVal],
valueSrc: ["value"],
valueType: [widgetDef?.type ?? "case_value"],
field: "!case_value",
};
}
}
} else if (convVal != undefined && convVal?.value != undefined) {
valProperties = {
value: [convVal.value],
valueSrc: [convVal.valueSrc],
valueType: [convVal.valueType],
field: "!case_value",
};
}
return valProperties;
};
export const buildRule = (config, meta, field, opKey, convertedArgs, spel) => {
if (convertedArgs.filter(v => v === undefined).length) {
return undefined;
}
let fieldSrc = field?.func ? "func" : "field";
if (isObject(field) && field.valueSrc) {
// if comed from convertFuncToOp()
fieldSrc = field.valueSrc;
field = field.value;
}
const fieldConfig = getFieldConfig(config, field);
if (!fieldConfig) {
meta.errors.push(`No config for field ${field}`);
return undefined;
}
const parentFieldConfig = getFieldConfig(config, spel?._groupField);
const isRuleGroup = fieldConfig.type == "!group";
const isGroupArray = isRuleGroup && fieldConfig.mode == "array";
const isInRuleGroup = parentFieldConfig?.type == "!group";
let opConfig = config.operators[opKey];
const reversedOpConfig = config.operators[opConfig?.reversedOp];
const opNeedsReverse = spel?.not && ["between"].includes(opKey);
const opCanReverse = !!reversedOpConfig;
const canRev = opCanReverse && (
!!config.settings.reverseOperatorsForNot
|| opNeedsReverse
|| !isRuleGroup && isInRuleGroup // 2+ rules in rule-group should be flat. see inits.with_not_and_in_some in test
);
const needRev = spel?.not && canRev || opNeedsReverse;
if (needRev) {
// todo: should be already handled at convertOp ? or there are special cases to handle here, like rule-group ?
opKey = opConfig.reversedOp;
opConfig = config.operators[opKey];
spel.not = !spel.not;
}
const needWrapWithNot = !!spel?.not;
const widget = getWidgetForFieldOp(config, field, opKey);
const widgetConfig = config.widgets[widget || fieldConfig.mainWidget];
const asyncListValuesArr = convertedArgs.map(v => v.asyncListValues).filter(v => v != undefined);
const asyncListValues = asyncListValuesArr.length ? asyncListValuesArr[0] : undefined;
let res = {
type: "rule",
id: uuid(),
properties: {
field,
fieldSrc,
operator: opKey,
value: convertedArgs.map(v => v.value),
valueSrc: convertedArgs.map(v => v.valueSrc),
valueType: convertedArgs.map(v => {
if (v.valueSrc == "value") {
return widgetConfig?.type || fieldConfig?.type || v.valueType;
}
return v.valueType;
}),
...(asyncListValues ? {asyncListValues} : {}),
}
};
if (needWrapWithNot) {
res = wrapInDefaultConj(res, config, spel.not);
// spel.not = !spel.not; // why I added this line?
}
return res;
};