@react-awesome-query-builder/core
Version:
User-friendly query builder for React. Core
1,105 lines (1,067 loc) • 51.5 kB
JavaScript
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
import _defineProperty from "@babel/runtime/helpers/defineProperty";
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
import Immutable, { fromJS } from "immutable";
import { expandTreePath, expandTreeSubpath, getItemByPath, getAncestorRuleGroups, fixPathsInTree, getTotalRulesCountInTree, fixEmptyGroupsInTree, isEmptyTree, hasChildren, removeIsLockedInTree } from "../utils/treeUtils";
import { defaultRuleProperties, defaultGroupProperties, getDefaultOperator, defaultOperatorOptions, defaultItemProperties } from "../utils/defaultRuleUtils";
import * as constants from "./constants";
import uuid from "../utils/uuid";
import { getFuncConfig, getFieldConfig, getOperatorConfig, selectTypes, getOperatorsForType, getOperatorsForField, getFirstOperator } from "../utils/configUtils";
import { isEmptyItem, calculateValueType } from "../utils/ruleUtils";
import { deepEqual, getOpCardinality, applyToJS } from "../utils/stuff";
import { validateValue, validateRange } from "../utils/validation";
import { getNewValueForFieldOp } from "../utils/getNewValueForFieldOp";
import { translateValidation } from "../i18n";
import omit from "lodash/omit";
import mapValues from "lodash/mapValues";
import { setFunc, setArgValue, setArgValueSrc, setArgValueAsyncListValues } from "../utils/funcUtils";
/**
* @param {object} config
* @param {Immutable.List} path
* @param {Immutable.Map} properties
*/
var addNewGroup = function addNewGroup(state, path, type, generatedId, properties, config) {
var _properties$get;
var children = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null;
var meta = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : {};
var targetItem = state.getIn(expandTreePath(path));
if (!targetItem) {
// incorrect path
return state;
}
var groupUuid = (properties === null || properties === void 0 || (_properties$get = properties.get) === null || _properties$get === void 0 ? void 0 : _properties$get.call(properties, "id")) || generatedId;
var shouldCreateEmptyGroup = config.settings.shouldCreateEmptyGroup;
var groupPath = path.push(groupUuid);
var canAddNewRule = !shouldCreateEmptyGroup;
var isDefaultCase = !!(meta !== null && meta !== void 0 && meta.isDefaultCase);
var origState = state;
state = addItem(state, path, type, groupUuid, defaultGroupProperties(config).merge(fromJS(properties) || {}), config, children);
if (state !== origState) {
if (!children && !isDefaultCase) {
state = state.setIn(expandTreePath(groupPath, "children1"), new Immutable.OrderedMap());
// Add one empty rule into new group
if (canAddNewRule) {
state = addItem(state, groupPath, "rule", uuid(), defaultRuleProperties(config, meta === null || meta === void 0 ? void 0 : meta.parentRuleGroupField), config);
}
}
state = fixPathsInTree(state);
}
return state;
};
/**
* @param {object} config
* @param {Immutable.List} path
* @param {Immutable.Map} properties
*/
var removeGroup = function removeGroup(state, path, config) {
var targetItem = state.getIn(expandTreePath(path));
if (!targetItem) {
// incorrect path
return state;
}
state = removeItem(state, path);
var canLeaveEmptyGroup = config.settings.canLeaveEmptyGroup;
var parentPath = path.slice(0, -1);
var isEmptyParentGroup = !hasChildren(state, parentPath);
if (isEmptyParentGroup && !canLeaveEmptyGroup) {
// check ancestors for emptiness (and delete 'em if empty)
state = fixEmptyGroupsInTree(state);
if (isEmptyTree(state) && !canLeaveEmptyGroup) {
// if whole query is empty, add one empty(!) rule to root
var canUseDefaultFieldAndOp = false;
var canGetFirst = false;
state = addItem(state, new Immutable.List(), "rule", uuid(), defaultRuleProperties(config, undefined, undefined, canUseDefaultFieldAndOp, canGetFirst), config);
}
}
state = fixPathsInTree(state);
return state;
};
/**
* @param {object} config
* @param {Immutable.List} path
* @param {Immutable.Map} properties
*/
var removeGroupChildren = function removeGroupChildren(state, path, config) {
var targetItem = state.getIn(expandTreePath(path));
if (!targetItem) {
// incorrect path
return state;
}
state = removeChildren(state, path);
state = fixPathsInTree(state);
return state;
};
/**
* @param {object} config
* @param {Immutable.List} path
*/
var removeRule = function removeRule(state, path, config) {
var targetItem = state.getIn(expandTreePath(path));
if (!targetItem) {
// incorrect path
return state;
}
state = removeItem(state, path);
var canLeaveEmptyGroup = config.settings.canLeaveEmptyGroup;
var parentPath = path.pop();
var parent = state.getIn(expandTreePath(parentPath));
var parentField = parent.getIn(["properties", "field"]);
var parentOperator = parent.getIn(["properties", "operator"]);
// const parentValue = parent.getIn(["properties", "value", 0]);
var parentFieldConfig = parentField ? getFieldConfig(config, parentField) : null;
var parentOperatorConfig = parentOperator ? getOperatorConfig(config, parentOperator, parentField) : null;
var hasGroupCountRule = parentField && parentOperator && parentOperatorConfig.cardinality != 0; // && parentValue != undefined;
var isParentRuleGroup = parent.get("type") == "rule_group";
var isEmptyParentGroup = !hasChildren(state, parentPath);
var canLeaveEmpty = isParentRuleGroup ? hasGroupCountRule && parentFieldConfig.initialEmptyWhere : canLeaveEmptyGroup;
if (isEmptyParentGroup && !canLeaveEmpty) {
if (isParentRuleGroup) {
// deleted last rule from rule_group, so delete whole rule_group
state = state.deleteIn(expandTreePath(parentPath));
}
// check ancestors for emptiness (and delete 'em if empty)
state = fixEmptyGroupsInTree(state);
if (isEmptyTree(state) && !canLeaveEmptyGroup) {
// if whole query is empty, add one empty(!) rule to root
var canUseDefaultFieldAndOp = false;
var canGetFirst = false;
state = addItem(state, new Immutable.List(), "rule", uuid(), defaultRuleProperties(config, undefined, undefined, canUseDefaultFieldAndOp, canGetFirst), config);
}
}
state = fixPathsInTree(state);
return state;
};
/**
* @param {Immutable.Map} state
* @param {Immutable.List} path
* @param {bool} not
*/
var setNot = function setNot(state, path, not) {
var targetItem = state.getIn(expandTreePath(path));
if (!targetItem) {
// incorrect path
return state;
}
state = state.setIn(expandTreePath(path, "properties", "not"), not);
return state;
};
/**
* @param {Immutable.Map} state
* @param {Immutable.List} path
* @param {bool} lock
*/
var setLock = function setLock(state, path, lock) {
var targetItem = state.getIn(expandTreePath(path));
if (!targetItem) {
// incorrect path
return state;
}
state = removeIsLockedInTree(state.setIn(expandTreePath(path, "properties", "isLocked"), lock));
return state;
};
/**
* @param {Immutable.Map} state
* @param {Immutable.List} path
* @param {string} conjunction
*/
var setConjunction = function setConjunction(state, path, conjunction) {
var targetItem = state.getIn(expandTreePath(path));
if (!targetItem) {
// incorrect path
return state;
}
state = state.setIn(expandTreePath(path, "properties", "conjunction"), conjunction);
return state;
};
/**
* @param {Immutable.Map} state
* @param {Immutable.List} path
* @param {string} type
* @param {string} id
* @param {Immutable.OrderedMap} properties
* @param {object} config
*/
var addItem = function addItem(state, path, type, generatedId, properties, config) {
var _properties$get2;
var children = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null;
if (type === "switch_group") throw new Error("Can't add switch_group programmatically");
var targetItem = state.getIn(expandTreePath(path));
if (!targetItem) {
// incorrect path
return state;
}
var id = (properties === null || properties === void 0 || (_properties$get2 = properties.get) === null || _properties$get2 === void 0 ? void 0 : _properties$get2.call(properties, "id")) || generatedId;
var _config$settings = config.settings,
maxNumberOfCases = _config$settings.maxNumberOfCases,
maxNumberOfRules = _config$settings.maxNumberOfRules,
maxNesting = _config$settings.maxNesting;
var rootType = state.get("type");
var isTernary = rootType === "switch_group";
var caseGroup = isTernary ? state.getIn(expandTreePath(path.take(2))) : null;
var childrenPath = expandTreePath(path, "children1");
var targetChildren = state.getIn(childrenPath);
var hasChildren = !!targetChildren && targetChildren.size;
var targetChildrenSize = hasChildren ? targetChildren.size : null;
var currentNumber, maxNumber;
if (type === "case_group") {
currentNumber = targetChildrenSize;
maxNumber = maxNumberOfCases;
} else if (type === "group") {
var ruleGroups = getAncestorRuleGroups(state, path);
if (ruleGroups.length) {
// closest rule-group
var _ruleGroups$ = ruleGroups[0],
ruleGroupPath = _ruleGroups$.path,
ruleGroupField = _ruleGroups$.field;
var ruleGroupFieldConfig = getFieldConfig(config, ruleGroupField);
currentNumber = path.size - ruleGroupPath.length;
maxNumber = ruleGroupFieldConfig === null || ruleGroupFieldConfig === void 0 ? void 0 : ruleGroupFieldConfig.maxNesting;
} else {
currentNumber = path.size;
maxNumber = maxNesting;
}
} else {
// rule or rule_group
var _ruleGroups = getAncestorRuleGroups(state, path);
if (_ruleGroups.length) {
// closest rule-group
var _ruleGroups$2 = _ruleGroups[0],
_ruleGroupPath = _ruleGroups$2.path,
_ruleGroupField = _ruleGroups$2.field;
var _ruleGroupFieldConfig = getFieldConfig(config, _ruleGroupField);
var ruleGroupItem = getItemByPath(state, _ruleGroupPath);
maxNumber = _ruleGroupFieldConfig === null || _ruleGroupFieldConfig === void 0 ? void 0 : _ruleGroupFieldConfig.maxNumberOfRules;
currentNumber = getTotalRulesCountInTree(ruleGroupItem);
} else {
currentNumber = isTernary ? getTotalRulesCountInTree(caseGroup) : getTotalRulesCountInTree(state);
maxNumber = maxNumberOfRules;
}
}
var canAdd = maxNumber && currentNumber ? currentNumber < maxNumber : true;
var item = {
type: type,
id: id,
properties: properties
};
_addChildren(config, item, children);
var isLastDefaultCase = type === "case_group" && hasChildren && targetChildren.last().get("children1") == null;
if (canAdd) {
var newChildren = new Immutable.OrderedMap(_defineProperty({}, id, new Immutable.Map(item)));
if (!hasChildren) {
state = state.setIn(childrenPath, newChildren);
} else if (isLastDefaultCase) {
var last = targetChildren.last();
var newChildrenWithLast = new Immutable.OrderedMap(_defineProperty(_defineProperty({}, id, new Immutable.Map(item)), last.get("id"), last));
state = state.deleteIn(expandTreePath(childrenPath, "children1", last.get("id")));
state = state.mergeIn(childrenPath, newChildrenWithLast);
} else {
state = state.mergeIn(childrenPath, newChildren);
}
state = fixPathsInTree(state);
}
return state;
};
/**
* @param {Immutable.Map} state
* @param {Immutable.List} path
*/
var removeItem = function removeItem(state, path) {
state = state.deleteIn(expandTreePath(path));
state = fixPathsInTree(state);
return state;
};
/**
* @param {Immutable.Map} state
* @param {Immutable.List} path
*/
var removeChildren = function removeChildren(state, path) {
state = state.deleteIn(expandTreePath(path, "children1"));
state = fixPathsInTree(state);
return state;
};
/**
* @param {Immutable.Map} state
* @param {Immutable.List} fromPath
* @param {Immutable.List} toPath
* @param {string} placement, see constants PLACEMENT_*: PLACEMENT_AFTER, PLACEMENT_BEFORE, PLACEMENT_APPEND, PLACEMENT_PREPEND
* @param {object} config
*/
var moveItem = function moveItem(state, fromPath, toPath, placement, config) {
var from = getItemByPath(state, fromPath);
var sourcePath = fromPath.pop();
var source = fromPath.size > 1 ? getItemByPath(state, sourcePath) : null;
var sourceChildren = source ? source.get("children1") : null;
var to = getItemByPath(state, toPath);
var targetPath = placement == constants.PLACEMENT_APPEND || placement == constants.PLACEMENT_PREPEND ? toPath : toPath.pop();
var target = placement == constants.PLACEMENT_APPEND || placement == constants.PLACEMENT_PREPEND ? to : toPath.size > 1 ? getItemByPath(state, targetPath) : null;
var targetChildren = target ? target.get("children1") : null;
if (!source || !target || !from) {
// incorrect path
return state;
}
var isSameParent = source.get("id") == target.get("id");
var isSourceInsideTarget = targetPath.size < sourcePath.size && deepEqual(targetPath.toArray(), sourcePath.toArray().slice(0, targetPath.size));
var isTargetInsideSource = targetPath.size > sourcePath.size && deepEqual(sourcePath.toArray(), targetPath.toArray().slice(0, sourcePath.size));
var sourceSubpathFromTarget = null;
var targetSubpathFromSource = null;
if (isSourceInsideTarget) {
sourceSubpathFromTarget = Immutable.List(sourcePath.toArray().slice(targetPath.size));
} else if (isTargetInsideSource) {
targetSubpathFromSource = Immutable.List(targetPath.toArray().slice(sourcePath.size));
}
var newTargetChildren = targetChildren,
newSourceChildren = sourceChildren;
if (!isTargetInsideSource) newSourceChildren = newSourceChildren["delete"](from.get("id"));
if (isSameParent) {
newTargetChildren = newSourceChildren;
} else if (isSourceInsideTarget) {
newTargetChildren = newTargetChildren.updateIn(expandTreeSubpath(sourceSubpathFromTarget, "children1"), function (_oldChildren) {
return newSourceChildren;
});
}
if (placement == constants.PLACEMENT_BEFORE || placement == constants.PLACEMENT_AFTER) {
newTargetChildren = Immutable.OrderedMap().withMutations(function (r) {
var _iterator = _createForOfIteratorHelper(newTargetChildren.entries()),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var _step$value = _slicedToArray(_step.value, 2),
itemId = _step$value[0],
item = _step$value[1];
if (itemId == (to === null || to === void 0 ? void 0 : to.get("id")) && placement == constants.PLACEMENT_BEFORE) {
r.set(from.get("id"), from);
}
r.set(itemId, item);
if (itemId == (to === null || to === void 0 ? void 0 : to.get("id")) && placement == constants.PLACEMENT_AFTER) {
r.set(from.get("id"), from);
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
});
} else if (placement == constants.PLACEMENT_APPEND) {
newTargetChildren = newTargetChildren.merge(Immutable.OrderedMap(_defineProperty({}, from.get("id"), from)));
} else if (placement == constants.PLACEMENT_PREPEND) {
newTargetChildren = Immutable.OrderedMap(_defineProperty({}, from.get("id"), from)).merge(newTargetChildren);
}
if (isTargetInsideSource) {
newSourceChildren = newSourceChildren.updateIn(expandTreeSubpath(targetSubpathFromSource, "children1"), function (_oldChildren) {
return newTargetChildren;
});
newSourceChildren = newSourceChildren["delete"](from.get("id"));
}
if (!isSameParent && !isSourceInsideTarget) state = state.updateIn(expandTreePath(sourcePath, "children1"), function (_oldChildren) {
return newSourceChildren;
});
if (!isTargetInsideSource) state = state.updateIn(expandTreePath(targetPath, "children1"), function (_oldChildren) {
return newTargetChildren;
});
state = fixPathsInTree(state);
return state;
};
/**
* @param {Immutable.Map} state
* @param {Immutable.List} path
* @param {integer} delta
* @param {string} srcKey
*/
var setFieldSrc = function setFieldSrc(state, path, srcKey, config) {
var currentRule = state.getIn(expandTreePath(path));
if (!currentRule) {
// incorrect path
return state;
}
var keepInputOnChangeFieldSrc = config.settings.keepInputOnChangeFieldSrc;
var currentProperties = currentRule.get("properties");
var currentField = currentProperties === null || currentProperties === void 0 ? void 0 : currentProperties.get("field");
var currentFielType = currentProperties === null || currentProperties === void 0 ? void 0 : currentProperties.get("fieldType");
var currentFieldConfig = getFieldConfig(config, currentField);
// const currentType = currentRule.get("type");
// const currentFieldSrc = currentProperties?.get("fieldSrc");
// get fieldType for "memory effect"
var fieldType = (currentFieldConfig === null || currentFieldConfig === void 0 ? void 0 : currentFieldConfig.type) || currentFielType;
if (!fieldType || fieldType === "!group" || fieldType === "!struct") {
fieldType = null;
}
var canReuseValue = !selectTypes.includes(fieldType);
var keepInput = keepInputOnChangeFieldSrc && !isEmptyItem(currentRule, config) && canReuseValue;
if (!keepInput) {
// clear ALL properties
state = state.setIn(expandTreePath(path, "properties"), defaultRuleProperties(config, null, null, false));
} else {
// clear non-relevant properties
state = state.setIn(expandTreePath(path, "properties", "field"), null);
state = state.deleteIn(expandTreePath(path, "properties", "fieldError"));
// set fieldType for "memory effect"
state = state.setIn(expandTreePath(path, "properties", "fieldType"), fieldType);
}
// set fieldSrc
state = state.setIn(expandTreePath(path, "properties", "fieldSrc"), srcKey);
return state;
};
/**
* @param {Immutable.Map} state
* @param {Immutable.List} path
* @param {integer} delta
* @param {Array} parentFuncs
* @param {string | null} argKey
* @param {*} argValue if argKey is null, it's new func key
* @param {string | "!valueSrc"} valueType
* @param {*} asyncListValues
*/
var setFuncValue = function setFuncValue(config, state, path, delta, parentFuncs, argKey, argValue, valueType, asyncListValues) {
var _meta = arguments.length > 9 && arguments[9] !== undefined ? arguments[9] : {};
var currentRule = state.getIn(expandTreePath(path));
if (!currentRule) {
// incorrect path
return state;
}
var isLHS = delta === -1;
var currentProperties = currentRule.get("properties");
var currentField = currentProperties.get("field");
var currentValue = currentProperties.get("value");
var currentV = isLHS ? currentField : currentValue.getIn([delta]);
// go inwards
var funcsPath = [];
var targetFV = currentV;
var _iterator2 = _createForOfIteratorHelper(parentFuncs || []),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var _step2$value = _slicedToArray(_step2.value, 2),
_funcK = _step2$value[0],
_argK = _step2$value[1];
funcsPath.push([_funcK, _argK, targetFV]);
if (_funcK !== targetFV.get("func")) {
var funcPath = funcsPath.map(function (_ref) {
var _ref2 = _slicedToArray(_ref, 2),
f = _ref2[0],
a = _ref2[1];
return "".concat(f, "(").concat(a, ")");
}).join("/") || "root";
throw new Error("In ".concat(isLHS ? "LHS" : "RHS", " for path ").concat(funcPath, " expected func key ").concat(_funcK, " but got ").concat(targetFV.get("func")));
}
targetFV = targetFV.getIn(["args", _argK, "value"]);
}
// modify
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
if (!argKey) {
var newFuncKey = argValue;
var canFixArgs = true; // try to fix args to fit new func validations, otherwise - drop invalid args
targetFV = setFunc(targetFV, newFuncKey, config, canFixArgs);
// allow drop invalid args / reset to default, but don't trigger error if some arg is required
// (not same as setting isEndValue = true)
_meta.canDropArgs = true;
} else {
var funcKey = targetFV.get("func");
var funcDefinition = getFuncConfig(config, funcKey);
var args = funcDefinition.args;
var argDefinition = args[argKey];
if (valueType === "!valueSrc") {
targetFV = setArgValueSrc(targetFV, argKey, argValue, argDefinition, config);
} else {
targetFV = setArgValue(targetFV, argKey, argValue, argDefinition, config);
if (asyncListValues) {
targetFV = setArgValueAsyncListValues(targetFV, argKey, asyncListValues, argDefinition, config);
}
}
}
// go outwards
var newV = targetFV;
while (funcsPath.length) {
var _funcsPath$pop = funcsPath.pop(),
_funcsPath$pop2 = _slicedToArray(_funcsPath$pop, 3),
funcK = _funcsPath$pop2[0],
argK = _funcsPath$pop2[1],
parentFV = _funcsPath$pop2[2];
var _funcDefinition = getFuncConfig(config, funcK);
var _args = _funcDefinition.args;
var _argDefinition = _args[argK];
newV = setArgValue(parentFV, argK, newV, _argDefinition, config);
}
if (isLHS) {
return setField(state, path, newV, config, undefined, _meta);
} else {
return setValue(state, path, delta, newV, undefined, config, undefined, _meta);
}
};
/**
* @param {Immutable.Map} state
* @param {Immutable.List} path
* @param {string | Immutable.OrderedMap} newField
*/
var setField = function setField(state, path, newField, config, asyncListValues) {
var _newFieldConfig$opera, _currentField$get, _newField, _newField$get;
var _meta = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {};
var currentRule = state.getIn(expandTreePath(path));
if (!currentRule) {
// incorrect path
return {
state: state
};
}
var isEndValue = _meta.isEndValue,
canDropArgs = _meta.canDropArgs;
if (!newField) {
state = removeItem(state, path);
return {
state: state
};
}
var _config$settings2 = config.settings,
fieldSeparator = _config$settings2.fieldSeparator,
setOpOnChangeField = _config$settings2.setOpOnChangeField,
showErrorMessage = _config$settings2.showErrorMessage;
if (Array.isArray(newField)) newField = newField.join(fieldSeparator);
var currentType = currentRule.get("type");
var currentProperties = currentRule.get("properties");
var wasRuleGroup = currentType == "rule_group";
var currentFieldSrc = currentProperties === null || currentProperties === void 0 ? void 0 : currentProperties.get("fieldSrc");
// const currentFieldError = currentProperties?.get("fieldError");
var newFieldConfig = getFieldConfig(config, newField);
if (!newFieldConfig) {
console.warn("No config for LHS ".concat(newField));
return {
state: state
};
}
var fieldType = newFieldConfig.type;
if (fieldType === "!group" || fieldType === "!struct") {
fieldType = null;
}
var currentOperator = currentProperties === null || currentProperties === void 0 ? void 0 : currentProperties.get("operator");
var currentOperatorOptions = currentProperties === null || currentProperties === void 0 ? void 0 : currentProperties.get("operatorOptions");
var currentField = currentProperties === null || currentProperties === void 0 ? void 0 : currentProperties.get("field");
// const currentValue = currentProperties?.get("value");
// const currentValueErrorStr = currentProperties?.get("valueError")?.join?.("|");
// const _currentValueSrc = currentProperties?.get("valueSrc", new Immutable.List());
// const _currentValueType = currentProperties?.get("valueType", new Immutable.List());
var isRuleGroup = newFieldConfig.type == "!group";
var isRuleGroupExt = isRuleGroup && newFieldConfig.mode == "array";
var isChangeToAnotherType = wasRuleGroup != isRuleGroup;
// const wasOkWithoutField = !currentField && currentFieldSrc && currentOperator;
// If the newly selected field supports the same operator the rule currently
// uses, keep it selected.
var lastOp = newFieldConfig && ((_newFieldConfig$opera = newFieldConfig.operators) === null || _newFieldConfig$opera === void 0 ? void 0 : _newFieldConfig$opera.indexOf(currentOperator)) !== -1 ? currentOperator : null;
var isSameFunc = currentFieldSrc === "func" && (currentField === null || currentField === void 0 || (_currentField$get = currentField.get) === null || _currentField$get === void 0 ? void 0 : _currentField$get.call(currentField, "func")) === ((_newField = newField) === null || _newField === void 0 || (_newField$get = _newField.get) === null || _newField$get === void 0 ? void 0 : _newField$get.call(_newField, "func"));
var forceKeepOp = isSameFunc && !!lastOp;
var newOperator = null;
var availOps = currentFieldSrc === "func" ? getOperatorsForType(config, fieldType) : getOperatorsForField(config, newField);
if (availOps && availOps.length == 1) newOperator = availOps[0];else if (forceKeepOp) newOperator = lastOp;else if (availOps && availOps.length > 1) {
var _iterator3 = _createForOfIteratorHelper(setOpOnChangeField),
_step3;
try {
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
var strategy = _step3.value;
if (strategy == "keep" && !isChangeToAnotherType) newOperator = lastOp;else if (strategy == "default") newOperator = getDefaultOperator(config, newField, false);else if (strategy == "first") newOperator = getFirstOperator(config, newField);
if (newOperator)
//found op for strategy
break;
}
} catch (err) {
_iterator3.e(err);
} finally {
_iterator3.f();
}
}
if (!isRuleGroup && !newFieldConfig.operators) {
console.warn("Type ".concat(newFieldConfig.type, " is not supported"));
return {
state: state
};
}
if (wasRuleGroup && !isRuleGroup) {
state = state.setIn(expandTreePath(path, "type"), "rule");
state = state.deleteIn(expandTreePath(path, "children1"));
state = state.setIn(expandTreePath(path, "properties"), new Immutable.OrderedMap());
}
if (!currentProperties) {
state = state.setIn(expandTreePath(path, "properties"), new Immutable.OrderedMap());
}
var canFix = !showErrorMessage;
if (isRuleGroup) {
state = state.setIn(expandTreePath(path, "type"), "rule_group");
var _getNewValueForFieldO = getNewValueForFieldOp({
validateValue: validateValue,
validateRange: validateRange
}, config, config, currentProperties, newField, newOperator, "field", canFix, isEndValue, canDropArgs),
canReuseValue = _getNewValueForFieldO.canReuseValue,
newValue = _getNewValueForFieldO.newValue,
newValueSrc = _getNewValueForFieldO.newValueSrc,
newValueType = _getNewValueForFieldO.newValueType,
operatorCardinality = _getNewValueForFieldO.operatorCardinality;
var groupProperties = defaultGroupProperties(config, newFieldConfig, newField).merge({
field: newField,
fieldSrc: "field",
mode: newFieldConfig.mode
});
if (isRuleGroupExt) {
groupProperties = groupProperties.merge({
operator: newOperator,
value: newValue,
valueSrc: newValueSrc,
valueType: newValueType
});
}
state = state.setIn(expandTreePath(path, "children1"), new Immutable.OrderedMap());
state = state.setIn(expandTreePath(path, "properties"), groupProperties);
if (newFieldConfig.initialEmptyWhere && operatorCardinality == 1) {// just `COUNT(grp) > 1` without `HAVING ..`
// no children
} else {
state = addItem(state, path, "rule", uuid(), defaultRuleProperties(config, newField), config);
}
state = fixPathsInTree(state);
} else {
state = state.updateIn(expandTreePath(path, "properties"), function (map) {
return map.withMutations(function (current) {
var _getNewValueForFieldO2 = getNewValueForFieldOp({
validateValue: validateValue,
validateRange: validateRange
}, config, config, current, newField, newOperator, "field", canFix, isEndValue, canDropArgs),
canReuseValue = _getNewValueForFieldO2.canReuseValue,
newValue = _getNewValueForFieldO2.newValue,
newValueSrc = _getNewValueForFieldO2.newValueSrc,
newValueType = _getNewValueForFieldO2.newValueType,
newValueError = _getNewValueForFieldO2.newValueError,
newFieldError = _getNewValueForFieldO2.newFieldError,
fixedField = _getNewValueForFieldO2.fixedField;
// const newValueErrorStr = newValueError?.join?.("|");
var newCorrectField = newField;
var willFixField = fixedField !== newField;
if (willFixField) {
newCorrectField = fixedField;
}
// tip: `newCorrectField` is SAFE to set: even if it can't be fixed, it is reverted to previous good field.
// Unlike logic in `setValue()` action where we need to calc `canUpdValue`
// const didFieldErrorChanged = showErrorMessage ? currentFieldError != newFieldError : !!currentFieldError != !!newFieldError;
// const didValueErrorChanged = showErrorMessage ? currentValueErrorStr != newValueErrorStr : !!currentValueErrorStr != !!newValueErrorStr;
// const didErrorChanged = didFieldErrorChanged || didValueErrorChanged;
// isInternalValueChange = !didErrorChanged && !willFixField;
if (showErrorMessage) {
current = current.set("fieldError", newFieldError);
current = current.set("valueError", newValueError);
}
var newOperatorOptions = canReuseValue ? currentOperatorOptions : defaultOperatorOptions(config, newOperator, newCorrectField);
current = current.set("field", newCorrectField)["delete"]("fieldType") // remove "memory effect"
.set("fieldSrc", currentFieldSrc).set("operator", newOperator).set("operatorOptions", newOperatorOptions).set("value", newValue).set("valueSrc", newValueSrc).set("valueType", newValueType);
if (!canReuseValue) {
current = current["delete"]("asyncListValues");
}
return current;
});
});
}
return {
state: state
};
};
/**
* @param {Immutable.Map} state
* @param {Immutable.List} path
* @param {string} operator
*/
var setOperator = function setOperator(state, path, newOperator, config) {
var currentRule = state.getIn(expandTreePath(path));
if (!currentRule) {
// incorrect path
return state;
}
var showErrorMessage = config.settings.showErrorMessage;
var properties = currentRule.get("properties");
var children = currentRule.get("children1");
var currentField = properties.get("field");
var currentFieldSrc = properties.get("fieldSrc");
var fieldConfig = getFieldConfig(config, currentField);
var isRuleGroup = (fieldConfig === null || fieldConfig === void 0 ? void 0 : fieldConfig.type) == "!group";
var operatorConfig = getOperatorConfig(config, newOperator, currentField);
var operatorCardinality = operatorConfig ? getOpCardinality(operatorConfig) : null;
var canFix = true;
state = state.updateIn(expandTreePath(path, "properties"), function (map) {
return map.withMutations(function (current) {
var currentField = current.get("field");
var currentOperatorOptions = current.get("operatorOptions");
var _currentValue = current.get("value", new Immutable.List());
var _currentValueSrc = current.get("valueSrc", new Immutable.List());
var _currentOperator = current.get("operator");
var _getNewValueForFieldO3 = getNewValueForFieldOp({
validateValue: validateValue,
validateRange: validateRange
}, config, config, current, currentField, newOperator, "operator", canFix),
canReuseValue = _getNewValueForFieldO3.canReuseValue,
newValue = _getNewValueForFieldO3.newValue,
newValueSrc = _getNewValueForFieldO3.newValueSrc,
newValueType = _getNewValueForFieldO3.newValueType,
newValueError = _getNewValueForFieldO3.newValueError;
if (showErrorMessage) {
current = current.set("valueError", newValueError);
}
var newOperatorOptions = canReuseValue ? currentOperatorOptions : defaultOperatorOptions(config, newOperator, currentField);
if (!canReuseValue) {
current = current["delete"]("asyncListValues");
}
return current.set("operator", newOperator).set("operatorOptions", newOperatorOptions).set("value", newValue).set("valueSrc", newValueSrc).set("valueType", newValueType);
});
});
if (isRuleGroup) {
if (operatorCardinality == 0 && (children === null || children === void 0 ? void 0 : children.size) == 0) {
state = addItem(state, path, "rule", uuid(), defaultRuleProperties(config, currentField), config);
}
}
return state;
};
/**
* @param {Immutable.Map} state
* @param {Immutable.List} path
* @param {integer} delta
* @param {*} value
* @param {string} valueType
* @param {*} asyncListValues
*/
var setValue = function setValue(state, path, delta, value, valueType, config, asyncListValues) {
var _meta = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : {};
var currentRule = state.getIn(expandTreePath(path));
if (!currentRule) {
// incorrect path
return {
state: state
};
}
var canDropArgs = _meta.canDropArgs,
isEndValue = _meta.isEndValue;
var _config$settings3 = config.settings,
fieldSeparator = _config$settings3.fieldSeparator,
showErrorMessage = _config$settings3.showErrorMessage;
var valueSrc = state.getIn(expandTreePath(path, "properties", "valueSrc", delta + "")) || null;
if (valueSrc === "field" && Array.isArray(value)) value = value.join(fieldSeparator);
var field = state.getIn(expandTreePath(path, "properties", "field")) || null;
//const fieldSrc = state.getIn(expandTreePath(path, "properties", "fieldSrc")) || null;
var operator = state.getIn(expandTreePath(path, "properties", "operator")) || null;
var operatorConfig = getOperatorConfig(config, operator, field);
var operatorCardinality = operator ? getOpCardinality(operatorConfig) : null;
var calculatedValueType = valueType || calculateValueType(value, valueSrc, config);
var canFix = !showErrorMessage;
var _validateValue = validateValue(config, field, field, operator, value, calculatedValueType, valueSrc, asyncListValues, canFix, isEndValue, canDropArgs),
_validateValue2 = _slicedToArray(_validateValue, 2),
fixedValue = _validateValue2[0],
allErrors = _validateValue2[1];
var firstError = allErrors === null || allErrors === void 0 ? void 0 : allErrors.find(function (e) {
return !e.fixed && !e.ignore;
});
var validationError = firstError ? translateValidation(firstError) : null;
// tip: even if canFix == false, use fixedValue, it can SAFELY fix value of select
// (get exact value from listValues, not string)
var willFix = fixedValue !== value;
if (willFix) {
value = fixedValue;
}
// init lists
state = initEmptyValueLists(state, path, config, operatorCardinality);
// Additional validation for range values
var values = Array.from({
length: operatorCardinality
}, function (_, i) {
return i == delta ? value : state.getIn(expandTreePath(path, "properties", "value", i + "")) || null;
});
var valueSrcs = Array.from({
length: operatorCardinality
}, function (_, i) {
return state.getIn(expandTreePath(path, "properties", "valueSrc", i + "")) || null;
});
var rangeErrorObj = validateRange(config, field, operator, values, valueSrcs);
var rangeValidationError = rangeErrorObj ? translateValidation(rangeErrorObj) : null;
var isValid = !validationError && !rangeValidationError;
var canUpdValue = showErrorMessage ? true : isValid || willFix; // set only good value
// const lastValue = state.getIn(expandTreePath(path, "properties", "value", delta));
// const lastError = state.getIn(expandTreePath(path, "properties", "valueError", delta));
// const lastRangeError = state.getIn(expandTreePath(path, "properties", "valueError", operatorCardinality));
// const didDeltaErrorChanged = showErrorMessage ? lastError != validationError : !!lastError != !!validationError;
// const didRangeErrorChanged = showErrorMessage ? lastRangeError != rangeValidationError : !!lastRangeError != !!rangeValidationError;
// const didErrorChanged = didDeltaErrorChanged || didRangeErrorChanged;
// const didEmptinessChanged = !!lastValue != !!value;
// isInternalValueChange = !didEmptinessChanged && !didErrorChanged && !willFix;
if (canUpdValue) {
state = state.deleteIn(expandTreePath(path, "properties", "asyncListValues"));
if (typeof value === "undefined") {
state = state.setIn(expandTreePath(path, "properties", "value", delta), undefined);
state = state.setIn(expandTreePath(path, "properties", "valueType", delta), null);
} else {
if (asyncListValues) {
state = state.setIn(expandTreePath(path, "properties", "asyncListValues"), asyncListValues);
}
state = state.setIn(expandTreePath(path, "properties", "value", delta), value);
state = state.setIn(expandTreePath(path, "properties", "valueType", delta), calculatedValueType);
}
}
if (showErrorMessage) {
// check list
var lastValueErrorArr = state.getIn(expandTreePath(path, "properties", "valueError"));
if (!lastValueErrorArr) {
state = state.setIn(expandTreePath(path, "properties", "valueError"), new Immutable.List(new Array(operatorCardinality)));
}
// set error at delta
state = state.setIn(expandTreePath(path, "properties", "valueError", delta), validationError);
// set range error
if (operatorCardinality >= 2) {
state = state.setIn(expandTreePath(path, "properties", "valueError", operatorCardinality), rangeValidationError);
}
}
return {
state: state
};
};
/**
* @param {Immutable.Map} state
* @param {Immutable.List} path
* @param {integer} delta
* @param {*} srcKey
*/
var setValueSrc = function setValueSrc(state, path, delta, srcKey, config) {
var _meta = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {};
var currentRule = state.getIn(expandTreePath(path));
if (!currentRule) {
// incorrect path
return state;
}
var showErrorMessage = config.settings.showErrorMessage;
var field = state.getIn(expandTreePath(path, "properties", "field")) || null;
//const fieldSrc = state.getIn(expandTreePath(path, "properties", "fieldSrc")) || null;
var operator = state.getIn(expandTreePath(path, "properties", "operator")) || null;
var operatorConfig = getOperatorConfig(config, operator, field);
var operatorCardinality = operator ? getOpCardinality(operatorConfig) : null;
// init lists
state = initEmptyValueLists(state, path, config, operatorCardinality);
state = state.setIn(expandTreePath(path, "properties", "value", delta + ""), undefined);
state = state.setIn(expandTreePath(path, "properties", "valueType", delta + ""), null);
state = state.deleteIn(expandTreePath(path, "properties", "asyncListValues"));
if (showErrorMessage) {
// clear value error
state = state.setIn(expandTreePath(path, "properties", "valueError", delta), null);
// if current operator is range, clear possible range error
if (operatorConfig !== null && operatorConfig !== void 0 && operatorConfig.validateValues) {
state = state.setIn(expandTreePath(path, "properties", "valueError", operatorCardinality), null);
}
}
// set valueSrc
if (typeof srcKey === "undefined") {
state = state.setIn(expandTreePath(path, "properties", "valueSrc", delta + ""), null);
} else {
state = state.setIn(expandTreePath(path, "properties", "valueSrc", delta + ""), srcKey);
}
// maybe set default value
if (srcKey) {
var properties = state.getIn(expandTreePath(path, "properties"));
// this call should return canReuseValue = false and provide default value
var canFix = true;
var _getNewValueForFieldO4 = getNewValueForFieldOp({
validateValue: validateValue,
validateRange: validateRange
}, config, config, properties, field, operator, "valueSrc", canFix),
canReuseValue = _getNewValueForFieldO4.canReuseValue,
newValue = _getNewValueForFieldO4.newValue,
newValueSrc = _getNewValueForFieldO4.newValueSrc,
newValueType = _getNewValueForFieldO4.newValueType,
newValueError = _getNewValueForFieldO4.newValueError;
if (!canReuseValue && newValueSrc.get(delta) == srcKey) {
state = state.setIn(expandTreePath(path, "properties", "value", delta + ""), newValue.get(delta));
state = state.setIn(expandTreePath(path, "properties", "valueType", delta + ""), newValueType.get(delta));
}
}
return state;
};
/**
* @param {Immutable.Map} state
* @param {Immutable.List} path
* @param {string} name
* @param {*} value
*/
var setOperatorOption = function setOperatorOption(state, path, name, value) {
var currentRule = state.getIn(expandTreePath(path));
if (!currentRule) {
// incorrect path
return state;
}
return state.setIn(expandTreePath(path, "properties", "operatorOptions", name), value);
};
/**
* @param {Immutable.Map} state
*/
var checkEmptyGroups = function checkEmptyGroups(state, config) {
var canLeaveEmptyGroup = config.settings.canLeaveEmptyGroup;
if (!canLeaveEmptyGroup) {
state = fixEmptyGroupsInTree(state);
}
return state;
};
var initEmptyValueLists = function initEmptyValueLists(state, path, config, operatorCardinality) {
if (!operatorCardinality) {
var field = state.getIn(expandTreePath(path, "properties", "field")) || null;
var operator = state.getIn(expandTreePath(path, "properties", "operator")) || null;
var operatorConfig = getOperatorConfig(config, operator, field);
operatorCardinality = operator ? getOpCardinality(operatorConfig) : null;
}
for (var _i = 0, _arr = ["value", "valueType", "valueError", "valueSrc"]; _i < _arr.length; _i++) {
var k = _arr[_i];
if (!state.getIn(expandTreePath(path, "properties", k))) {
state = state.setIn(expandTreePath(path, "properties", k), new Immutable.List(operatorCardinality ? Array.from({
length: operatorCardinality
}) : []));
}
}
return state;
};
// convert children deeply from JS to Immutable
var _addChildren = function _addChildren1(config, item, children) {
if (children && Array.isArray(children)) {
item.children1 = new Immutable.OrderedMap(children.reduce(function (map, it) {
var _it$id;
var id1 = (_it$id = it.id) !== null && _it$id !== void 0 ? _it$id : uuid();
var it1 = _objectSpread(_objectSpread({}, it), {}, {
properties: defaultItemProperties(config, it).merge(fromJS(it.properties) || {}),
id: id1
});
_addChildren(config, it1, it1.children1);
//todo: guarantee order
return _objectSpread(_objectSpread({}, map), {}, _defineProperty({}, id1, new Immutable.Map(it1)));
}, {}));
}
};
var getField = function getField(state, path) {
var field = state.getIn(expandTreePath(path, "properties", "field")) || null;
return field;
};
var emptyDrag = {
dragging: {
id: null,
x: null,
y: null,
w: null,
h: null
},
mousePos: {},
dragStart: {
id: null
}
};
var getActionMeta = function getActionMeta(action, state) {
if (!action || !action.type) return null;
var actionKeysToOmit = ["config", "asyncListValues"];
var actionTypesToIgnore = [constants.SET_TREE, constants.SET_DRAG_START, constants.SET_DRAG_PROGRESS, constants.SET_DRAG_END];
var meta = mapValues(omit(action, actionKeysToOmit), applyToJS);
var affectedField = action.path && getField(state.tree, action.path) || action.field;
if (affectedField) {
var _affectedField;
if ((_affectedField = affectedField) !== null && _affectedField !== void 0 && _affectedField.toJS) affectedField = affectedField.toJS();
meta.affectedField = affectedField;
}
if (actionTypesToIgnore.includes(action.type) || action.type.indexOf("@@redux") == 0) meta = null;
return meta;
};
/**
* @param {Immutable.Map} state
* @param {object} action
*/
export default (function (initialConfig, tree, getMemoizedTree, setLastTree, getLastConfig) {
var initTree = tree;
var emptyState = _objectSpread({
tree: initTree
}, emptyDrag);
return function () {
var _ref3, _getLastConfig;
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : emptyState;
var action = arguments.length > 1 ? arguments[1] : undefined;
var config = (_ref3 = (_getLastConfig = getLastConfig === null || getLastConfig === void 0 ? void 0 : getLastConfig()) !== null && _getLastConfig !== void 0 ? _getLastConfig : action === null || action === void 0 ? void 0 : action.config) !== null && _ref3 !== void 0 ? _ref3 : initialConfig;
var unset = {
__lastAction: undefined
};
var set = {};
var actionMeta = getActionMeta(action, state);
switch (action === null || action === void 0 ? void 0 : action.type) {
case constants.SET_TREE:
{
var validatedTree = getMemoizedTree(config, action.tree);
set.tree = validatedTree;
break;
}
case constants.ADD_CASE_GROUP:
{
set.tree = addNewGroup(state.tree, action.path, "case_group", action.id, action.properties, config, action.children, action.meta);
break;
}
case constants.ADD_GROUP:
{
set.tree = addNewGroup(state.tree, action.path, "group", action.id, action.properties, config, action.children, action.meta);
break;
}
case constants.REMOVE_GROUP:
{
set.tree = removeGroup(state.tree, action.path, config);
break;
}
case constants.REMOVE_GROUP_CHILDREN:
{
set.tree = removeGroupChildren(state.tree, action.path, config);
break;
}
case constants.ADD_RULE:
{
set.tree = addItem(state.tree, action.path, action.ruleType, action.id, action.properties, config, action.children);
break;
}
case constants.REMOVE_RULE:
{
set.tree = removeRule(state.tree, action.path, config);
break;
}
case constants.SET_CONJUNCTION:
{
set.tree = setConjunction(state.tree, action.path, action.conjunction);
break;
}
case constants.SET_NOT:
{
set.tree = setNot(state.tree, action.path, action.not);
break;
}
case constants.SET_FIELD:
{
var _setField = setField(state.tree, action.path, action.field, config, action.asyncListValues, action._meta),
newTree = _setField.state;
set.tree = newTree;
break;
}
case constants.SET_FIELD_SRC:
{
set.tree = setFieldSrc(state.tree, action.path, action.srcKey, config);
break;
}
case constants.SET_LOCK:
{
set.tree = setLock(state.tree, action.path, action.lock);
break;
}
case constants.SET_OPERATOR:
{
set.tree = setOperator(state.tree, action.path, action.operator, config);
break;
}
case constants.SET_VALUE:
{
var _setValue = setValue(state.tree, action.path, action.delta, action.value, action.valueType, config, action.asyncListValues, action._meta),
_newTree = _setValue.state;
set.tree = _newTree;
break;
}
case constants.SET_FUNC_VALUE:
{
var _setFuncValue = setFuncValue(config, state.tree, action.path, action.delta, action.parentFuncs, action.argKey, action.value, action.v