@react-awesome-query-builder/core
Version:
User-friendly query builder for React. Core
362 lines (353 loc) • 19.3 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getNewValueForFieldOp = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _immutable = _interopRequireDefault(require("immutable"));
var _configUtils = require("./configUtils");
var _stuff = require("./stuff");
var _i18n = require("../i18n");
var _treeUtils = require("./treeUtils");
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) { (0, _defineProperty2["default"])(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; }
/**
* @param {Immutable.Map} current
* @param {string} changedProp
* @param {boolean} canFix (default: false) true - eg. set value to max if it > max or revert or drop
* @param {boolean} isEndValue (default: false) true - if value is in process of editing by user
* @param {boolean} canDropArgs (default: false)
* @return {{canReuseValue, newValue, newValueSrc, newValueType, fixedField, operatorCardinality, newValueError, newFieldError, validationErrors}}
*/
var getNewValueForFieldOp = exports.getNewValueForFieldOp = function getNewValueForFieldOp(_ref, config) {
var _currentField, _currentField$get, _newField, _newField$get;
var validateValue = _ref.validateValue,
validateRange = _ref.validateRange;
var oldConfig = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
var current = arguments.length > 3 ? arguments[3] : undefined;
var newField = arguments.length > 4 ? arguments[4] : undefined;
var newOperator = arguments.length > 5 ? arguments[5] : undefined;
var changedProp = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null;
var canFix = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : false;
var isEndValue = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : false;
var canDropArgs = arguments.length > 9 && arguments[9] !== undefined ? arguments[9] : false;
//const isValidatingTree = (changedProp === null);
if (!oldConfig) oldConfig = config;
var _config$settings = config.settings,
keepInputOnChangeFieldSrc = _config$settings.keepInputOnChangeFieldSrc,
convertableWidgets = _config$settings.convertableWidgets,
clearValueOnChangeField = _config$settings.clearValueOnChangeField,
clearValueOnChangeOp = _config$settings.clearValueOnChangeOp;
var isCase = newField == "!case_value";
var currentField = current.get("field");
if (!currentField && isCase) {
currentField = newField;
}
var currentFieldType = current.get("fieldType");
var currentFieldSrc = current.get("fieldSrc");
var currentOperator = current.get("operator");
var currentValue = current.get("value");
var currentValueSrc = current.get("valueSrc", new _immutable["default"].List());
var currentValueType = current.get("valueType", new _immutable["default"].List());
var currentValueError = current.get("valueError", new _immutable["default"].List());
var asyncListValues = current.get("asyncListValues");
var isOkWithoutOperator = isCase;
var currentOperatorConfig = (0, _configUtils.getOperatorConfig)(oldConfig, currentOperator);
var newOperatorConfig = (0, _configUtils.getOperatorConfig)(config, newOperator, newField);
var currentOperatorCardinality = isCase ? 1 : currentOperator ? (0, _stuff.getOpCardinality)(currentOperatorConfig) : null;
var operatorCardinality = isCase ? 1 : newOperator ? (0, _stuff.getOpCardinality)(newOperatorConfig) : null;
var currentFieldConfig = (0, _configUtils.getFieldConfig)(oldConfig, currentField);
var newFieldConfig = (0, _configUtils.getFieldConfig)(config, newField);
var isOkWithoutField = !currentField && currentFieldType && keepInputOnChangeFieldSrc;
var currentType = (currentFieldConfig === null || currentFieldConfig === void 0 ? void 0 : currentFieldConfig.type) || currentFieldType;
var newType = (newFieldConfig === null || newFieldConfig === void 0 ? void 0 : newFieldConfig.type) || !newField && isOkWithoutField && currentType;
var currentListValuesType = currentFieldConfig === null || currentFieldConfig === void 0 ? void 0 : currentFieldConfig.listValuesType;
var newListValuesType = newFieldConfig === null || newFieldConfig === void 0 ? void 0 : newFieldConfig.listValuesType;
var currentFieldSimpleValue = ((_currentField = currentField) === null || _currentField === void 0 || (_currentField$get = _currentField.get) === null || _currentField$get === void 0 ? void 0 : _currentField$get.call(_currentField, "func")) || currentField;
var newFieldSimpleValue = ((_newField = newField) === null || _newField === void 0 || (_newField$get = _newField.get) === null || _newField$get === void 0 ? void 0 : _newField$get.call(_newField, "func")) || newField;
var hasFieldChanged = newFieldSimpleValue != currentFieldSimpleValue;
var validationErrors = [];
var canReuseValue = (currentField || isOkWithoutField) && (currentOperator && newOperator || isOkWithoutOperator) && currentValue != undefined;
if (!(currentType && newType && currentType == newType) || changedProp === "field" && hasFieldChanged && clearValueOnChangeField || changedProp === "operator" && clearValueOnChangeOp) {
canReuseValue = false;
}
if (hasFieldChanged && _configUtils.selectTypes.includes(newType)) {
if (newListValuesType && newListValuesType === currentListValuesType) {
// ok
} else {
// different fields of select types has different listValues
canReuseValue = false;
}
}
if (!isOkWithoutOperator && (!(currentValue !== null && currentValue !== void 0 && currentValue.size) && operatorCardinality || currentValue !== null && currentValue !== void 0 && currentValue.size && !operatorCardinality)) {
canReuseValue = false;
}
// validate func LHS
var newFieldError;
if (currentFieldSrc === "func" && newField) {
var _validateValue = validateValue(config, null, null, newOperator, newField, newType, currentFieldSrc, asyncListValues, canFix, isEndValue, canDropArgs),
_validateValue2 = (0, _slicedToArray2["default"])(_validateValue, 2),
fixedField = _validateValue2[0],
fieldErrors = _validateValue2[1];
var isValid = !(fieldErrors !== null && fieldErrors !== void 0 && fieldErrors.length);
var willFix = fixedField !== newField;
var willFixAllErrors = !isValid && willFix && !fieldErrors.find(function (e) {
return !e.fixed;
});
var willRevert = canFix && !isValid && !willFixAllErrors && !!changedProp && newField !== currentField;
var willDrop = false; //canFix && !isValid && !willFixAllErrors && !willRevert && !changedProp;
if (willDrop) {
newField = null;
} else if (willRevert) {
newField = currentField;
} else if (willFix) {
newField = fixedField;
}
if (!isValid) {
var showError = !isValid && !willFixAllErrors && !willDrop && !willRevert;
var firstError = fieldErrors.find(function (e) {
return !e.fixed && !e.ignore;
});
if (showError && firstError) {
newFieldError = (0, _i18n.translateValidation)(firstError);
}
// tip: even if we don't show errors, but revert LHS, put the reason of revert
fieldErrors.map(function (e) {
return validationErrors.push(_objectSpread(_objectSpread({
side: "lhs"
}, e), {}, {
fixed: e.fixed || willRevert || willDrop
}));
});
}
}
// compare old & new widgets
for (var i = 0; i < operatorCardinality; i++) {
var vs = currentValueSrc.get(i) || null;
var currentWidget = (0, _configUtils.getWidgetForFieldOp)(oldConfig, currentField, currentOperator, vs);
var newWidget = (0, _configUtils.getWidgetForFieldOp)(config, newField, newOperator, vs);
// need to also check value widgets if we changed operator and current value source was 'field'
// cause for select type op '=' requires single value and op 'in' requires array value
var currentValueWidget = vs === "value" ? currentWidget : (0, _configUtils.getWidgetForFieldOp)(oldConfig, currentField, currentOperator, "value");
var newValueWidget = vs === "value" ? newWidget : (0, _configUtils.getWidgetForFieldOp)(config, newField, newOperator, "value");
var canReuseWidget = newValueWidget == currentValueWidget || (convertableWidgets[currentValueWidget] || []).includes(newValueWidget) || !currentValueWidget && isOkWithoutField;
if (!canReuseWidget) {
canReuseValue = false;
}
}
if (currentOperator != newOperator && [currentOperator, newOperator].includes("proximity")) {
canReuseValue = false;
}
var firstValueSrc = currentValueSrc.first();
var firstWidgetConfig = (0, _configUtils.getFieldWidgetConfig)(config, newField, newOperator, null, firstValueSrc);
var valueSources = (0, _configUtils.getValueSourcesForFieldOp)(config, newField, newOperator, null);
if (!newField && isOkWithoutField) {
valueSources = Object.keys(config.settings.valueSourcesInfo);
}
var defaultValueSrc = valueSources[0];
var defaultValueType;
if (operatorCardinality === 1 && firstWidgetConfig && firstWidgetConfig.type !== undefined) {
defaultValueType = firstWidgetConfig.type;
} else if (operatorCardinality === 1 && newFieldConfig && newFieldConfig.type !== undefined) {
defaultValueType = newFieldConfig.type === "!group" ? "number" : newFieldConfig.type;
}
// changed operator from '==' to 'between'
var canExtendValueToRange = canReuseValue && changedProp === "operator" && currentOperatorCardinality === 1 && operatorCardinality === 2;
var valueFixes = [];
var valueSrcFixes = [];
var valueTypeFixes = [];
var valueErrors = Array.from({
length: operatorCardinality
}, function () {
return null;
});
if (canReuseValue) {
var _loop = function _loop(_i) {
var v = currentValue.get(_i);
var vType = currentValueType.get(_i) || null;
var vSrc = currentValueSrc.get(_i) || null;
if (canExtendValueToRange && _i === 1) {
v = valueFixes[0] !== undefined ? valueFixes[0] : currentValue.get(0);
valueFixes[_i] = v;
vType = currentValueType.get(0) || null;
vSrc = currentValueSrc.get(0) || null;
}
var isValidSrc = vSrc ? valueSources.find(function (v) {
return v == vSrc;
}) !== undefined : true;
var _validateValue3 = validateValue(config, newField, newField, newOperator, v, vType, vSrc, asyncListValues, canFix, isEndValue, canDropArgs),
_validateValue4 = (0, _slicedToArray2["default"])(_validateValue3, 2),
fixedValue = _validateValue4[0],
allErrors = _validateValue4[1];
var isValid = !(allErrors !== null && allErrors !== void 0 && allErrors.length);
// Allow bad value with error message
// But not on field change - in that case just drop bad value that can't be reused
// ? Maybe we should also drop bad value on op change?
// For bad multiselect value we have both error message + fixed value.
// If we show error message, it will gone on next tree validation
var willFix = fixedValue !== v;
var willFixAllErrors = !isValid && willFix && !(allErrors !== null && allErrors !== void 0 && allErrors.find(function (e) {
return !e.fixed;
}));
var allErrorsHandled = !(allErrors !== null && allErrors !== void 0 && allErrors.find(function (e) {
return !e.fixed && !e.ignore;
}));
// tip: is value src is invalid, drop ANYWAY
// tip: Edge case in demo:
// Given "login = LOWER(?)", change config to not show errors -> "LOWER(?)" will be dropped
// We don't want to drop func completely, so need to add `allErrorsAheHandled` or `vSrc !== "func"`
// todo: `hasFieldChanged` is not needed ?
var willDrop = !isValidSrc || canFix && !isValid && !willFixAllErrors && (!allErrorsHandled || hasFieldChanged);
if (!isValid) {
// tip: even if we don't show errors, but drop bad values, put the reason of removal
allErrors === null || allErrors === void 0 || allErrors.map(function (e) {
return validationErrors.push(_objectSpread(_objectSpread({
side: "rhs",
delta: _i
}, e), {}, {
fixed: e.fixed || willDrop
}));
});
}
if (willDrop) {
valueFixes[_i] = null;
if (_i === 0) {
delete valueFixes[1];
}
}
var showError = !isValid && !willFix;
var firstError = allErrors === null || allErrors === void 0 ? void 0 : allErrors.find(function (e) {
return !e.fixed && !e.ignore;
});
if (showError && firstError) {
valueErrors[_i] = (0, _i18n.translateValidation)(firstError);
}
if (willFix) {
valueFixes[_i] = fixedValue;
}
if (canExtendValueToRange && _i === 0 && !isValid && !willFix) {
// don't extend bad value to range
canExtendValueToRange = false;
}
if (canExtendValueToRange && _i === 0 && ["func", "field"].includes(vSrc)) {
// don't extend func/field value, only primitive value
canExtendValueToRange = false;
}
};
for (var _i = 0; _i < operatorCardinality; _i++) {
_loop(_i);
}
}
// if can't reuse, get defaultValue
if (!canReuseValue) {
for (var _i2 = 0; _i2 < operatorCardinality; _i2++) {
if (operatorCardinality === 1) {
var _newFieldConfig$field, _dv$get;
// tip: default range values (for cardinality > 1) are not supported yet, todo
var dv = (0, _stuff.getFirstDefined)([newFieldConfig === null || newFieldConfig === void 0 ? void 0 : newFieldConfig.defaultValue, newFieldConfig === null || newFieldConfig === void 0 || (_newFieldConfig$field = newFieldConfig.fieldSettings) === null || _newFieldConfig$field === void 0 ? void 0 : _newFieldConfig$field.defaultValue, firstWidgetConfig === null || firstWidgetConfig === void 0 ? void 0 : firstWidgetConfig.defaultValue]);
valueFixes[_i2] = dv;
if (dv !== null && dv !== void 0 && dv.func || dv !== null && dv !== void 0 && (_dv$get = dv.get) !== null && _dv$get !== void 0 && _dv$get.call(dv, "func")) {
valueSrcFixes[_i2] = "func";
//tip: defaultValue of src "field" is not supported, todo
}
}
}
}
// set default valueSrc and valueType
for (var _i3 = 0; _i3 < operatorCardinality; _i3++) {
var _vs = canReuseValue && currentValueSrc.get(_i3) || null;
var vt = canReuseValue && currentValueType.get(_i3) || null;
var v = valueFixes[_i3] !== undefined ? valueFixes[_i3] : canReuseValue ? currentValue.get(_i3) : undefined;
if (canReuseValue && canExtendValueToRange && _i3 === 1) {
var _valueSrcFixes$_i, _valueTypeFixes$_i;
_vs = (_valueSrcFixes$_i = valueSrcFixes[_i3]) !== null && _valueSrcFixes$_i !== void 0 ? _valueSrcFixes$_i : currentValueSrc.get(0);
vt = (_valueTypeFixes$_i = valueTypeFixes[_i3]) !== null && _valueTypeFixes$_i !== void 0 ? _valueTypeFixes$_i : currentValueType.get(0);
valueSrcFixes[_i3] = _vs;
valueTypeFixes[_i3] = vt;
}
var isValidSrc = valueSources.includes(_vs);
if (!isValidSrc) {
valueSrcFixes[_i3] = defaultValueSrc;
}
if (!vt) {
valueTypeFixes[_i3] = defaultValueType;
}
// Fix if func in LHS has `defaultValue: { func: ..., args: {...} }`
if (v !== null && v !== void 0 && v.func) {
valueFixes[_i3] = (0, _treeUtils.jsToImmutable)(v);
valueSrcFixes[_i3] = "func";
}
}
// build new values
var newValue = currentValue;
if (valueFixes.length > 0 || !canReuseValue || operatorCardinality < currentOperatorCardinality) {
newValue = new _immutable["default"].List(Array.from({
length: operatorCardinality
}, function (_ignore, i) {
return valueFixes[i] !== undefined ? valueFixes[i] : canReuseValue ? currentValue.get(i) : undefined;
}));
}
var newValueSrc = currentValueSrc;
if (valueSrcFixes.length > 0 || !canReuseValue || operatorCardinality < currentOperatorCardinality) {
newValueSrc = new _immutable["default"].List(Array.from({
length: operatorCardinality
}, function (_ignore, i) {
var _valueSrcFixes$i;
return (_valueSrcFixes$i = valueSrcFixes[i]) !== null && _valueSrcFixes$i !== void 0 ? _valueSrcFixes$i : canReuseValue && currentValueSrc.get(i) || null;
}));
}
var newValueType = currentValueType;
if (valueTypeFixes.length > 0 || !canReuseValue || operatorCardinality < currentOperatorCardinality) {
newValueType = new _immutable["default"].List(Array.from({
length: operatorCardinality
}, function (_ignore, i) {
var _valueTypeFixes$i;
return (_valueTypeFixes$i = valueTypeFixes[i]) !== null && _valueTypeFixes$i !== void 0 ? _valueTypeFixes$i : canReuseValue && currentValueType.get(i) || null;
}));
}
// Validate range
var rangeErrorObj = validateRange(config, newField, newOperator, newValue, newValueSrc);
if (rangeErrorObj) {
// last element in `valueError` list is for range validation error
var rangeValidationError = (0, _i18n.translateValidation)(rangeErrorObj);
var _willFix = canFix && operatorCardinality >= 2;
var badValue = newValue;
if (_willFix) {
valueFixes[1] = newValue.get(0);
newValue = newValue.set(1, valueFixes[1]);
valueErrors[1] = valueErrors[0];
}
var _showError = !_willFix;
if (_showError) {
valueErrors.push(rangeValidationError);
}
validationErrors.push(_objectSpread(_objectSpread({
side: "rhs",
delta: -1
}, rangeErrorObj), {}, {
fixed: _willFix,
fixedFrom: _willFix ? [badValue.get(0), badValue.get(1)] : undefined,
fixedTo: _willFix ? [newValue.get(0), newValue.get(1)] : undefined
}));
}
var newValueError = currentValueError;
var hasValueErrorChanged = (currentValueError === null || currentValueError === void 0 ? void 0 : currentValueError.size) !== valueErrors.length || valueErrors.filter(function (v, i) {
return v != currentValueError.get(i);
}).length > 0;
if (hasValueErrorChanged) {
newValueError = new _immutable["default"].List(valueErrors);
}
return {
canReuseValue: canReuseValue,
newValue: newValue,
newValueSrc: newValueSrc,
newValueType: newValueType,
operatorCardinality: operatorCardinality,
fixedField: newField,
newValueError: newValueError,
newFieldError: newFieldError,
validationErrors: validationErrors
};
};