UNPKG

@kineticdata/react

Version:
369 lines (367 loc) 15.8 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault")["default"]; Object.defineProperty(exports, "__esModule", { value: true }); exports.defineKqlQuery = exports.defineFilter = void 0; var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/esm/toConsumableArray")); var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/esm/objectSpread2")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/esm/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/esm/createClass")); var _immutable = require("immutable"); var _lodashEs = require("lodash-es"); var defineKqlQuery = exports.defineKqlQuery = function defineKqlQuery() { return new SearchBuilder('kql'); }; var defineFilter = exports.defineFilter = function defineFilter(caseInsensitive, rootOperator) { return new SearchBuilder('filter', caseInsensitive, rootOperator); }; var SearchBuilder = /*#__PURE__*/function () { function SearchBuilder(type) { var caseInsensitive = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; var rootOperator = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'and'; (0, _classCallCheck2["default"])(this, SearchBuilder); this.caseInsensitive = caseInsensitive; this.type = type; this.rootExpression = { operator: rootOperator, operands: [] }; this.expressionStack = [this.rootExpression]; } (0, _createClass2["default"])(SearchBuilder, [{ key: "and", value: function and() { return pushExpression(this, {}, 'and'); } }, { key: "between", value: function between(field, minValue, maxValue, strict) { return pushExpression(this, { strict: strict }, 'bt', field, minValue, maxValue); } }, { key: "equals", value: function equals(field, value, strict) { return pushExpression(this, { strict: strict }, 'eq', field, value); } }, { key: "greaterThan", value: function greaterThan(field, value, strict) { return pushExpression(this, { strict: strict }, 'gt', field, value); } }, { key: "greaterThanOrEquals", value: function greaterThanOrEquals(field, value, strict) { return pushExpression(this, { strict: strict }, 'gte', field, value); } }, { key: "in", value: function _in(field, values, strict) { return pushExpression(this, { strict: strict }, 'in', field, values); } }, { key: "lessThan", value: function lessThan(field, value, strict) { return pushExpression(this, { strict: strict }, 'lt', field, value); } }, { key: "lessThanOrEquals", value: function lessThanOrEquals(field, value, strict) { return pushExpression(this, { strict: strict }, 'lte', field, value); } }, { key: "or", value: function or() { return pushExpression(this, {}, 'or'); } }, { key: "startsWith", value: function startsWith(field, value) { return pushExpression(this, {}, 'sw', field, value); } }, { key: "matches", value: function matches(field, value) { return pushExpression(this, {}, 'mt', field, value); } }, { key: "end", value: function end() { var _this = this; if (this.expressionStack.length === 1) { return this.type === 'kql' ? function (values) { return compileKqlQuery(_this.rootExpression, values).replace(/^\s*\(\s*/, '').replace(/\s*\)\s*$/, ''); } : compileExpression(this.rootExpression); } else { this.expressionStack.pop(); return this; } } }]); return SearchBuilder; }(); // This could be a method of SearchBuilder but we don't have a way to make it // private so its here... // The last entry in expressionStack will always be an 'and' / 'or' operation, // so we push the given expression to the end of that one. Then if the given // expression is another 'and' / 'or' operation we push the new expression // to the expression stack and subsequent expressions will be added to that one. var pushExpression = function pushExpression(self, options, operator) { var currentExpression = (0, _lodashEs.last)(self.expressionStack); for (var _len = arguments.length, operands = new Array(_len > 3 ? _len - 3 : 0), _key = 3; _key < _len; _key++) { operands[_key - 3] = arguments[_key]; } currentExpression.operands.push({ operator: operator, operands: operands, options: (0, _objectSpread2["default"])({ caseInsensitive: self.caseInsensitive }, options) }); if (['and', 'or'].includes(operator)) { self.expressionStack.push((0, _lodashEs.last)(currentExpression.operands)); } return self; }; var nullFix = function nullFix(val) { return val === null || typeof val === 'undefined' ? '""' : "\"".concat(val, "\""); }; var compileKqlQuery = function compileKqlQuery(_ref, values) { var operator = _ref.operator, operands = _ref.operands, options = _ref.options; switch (operator) { case 'or': case 'and': var andContents = operands.map(function (operand) { return compileKqlQuery(operand, values); }).filter(function (op) { return op !== ''; }); var combinator = operator === 'and' ? 'AND' : 'OR'; return andContents.length > 0 ? "( ".concat(andContents.join(" ".concat(combinator, " ")), " )") : ''; case 'eq': return options.strict || values[operands[1]] ? "".concat(operands[0], " = ").concat(nullFix(values[operands[1]])) : ''; case 'sw': return options.strict || values[operands[1]] ? "".concat(operands[0], " =* ").concat(nullFix(values[operands[1]])) : ''; case 'mt': return values[operands[1]] ? "".concat(operands[0], " *=* ").concat(nullFix(values[operands[1]])) : ''; case 'in': { var rval = values[operands[1]]; var inList = rval ? rval.filter(function (val) { return options.strict ? true : val; }).map(function (val) { return nullFix(val); }).join(', ') : ''; return inList ? "".concat(operands[0], " IN (").concat(inList, ")") : ''; } case 'bt': { var lval = operands[0]; var rval1 = values[operands[1]]; var rval2 = values[operands[2]]; return options.strict || rval1 && rval2 ? "".concat(lval, " BETWEEN (").concat(nullFix(rval1), ", ").concat(nullFix(rval2), ")") : ''; } case 'gt': return options.strict || values[operands[1]] ? "".concat(operands[0], " > ").concat(nullFix(values[operands[1]])) : ''; case 'gte': return options.strict || values[operands[1]] ? "".concat(operands[0], " >= ").concat(nullFix(values[operands[1]])) : ''; case 'lt': return options.strict || values[operands[1]] ? "".concat(operands[0], " < ").concat(nullFix(values[operands[1]])) : ''; case 'lte': return options.strict || values[operands[1]] ? "".concat(operands[0], " <= ").concat(nullFix(values[operands[1]])) : ''; default: return ''; } }; var compileExpression = function compileExpression(_ref2) { var operator = _ref2.operator, operands = _ref2.operands, options = _ref2.options; switch (operator) { case 'and': return andOperation(operands); case 'bt': return betweenOperation.apply(void 0, [options].concat((0, _toConsumableArray2["default"])(operands))); case 'eq': return equalsOperation.apply(void 0, [options].concat((0, _toConsumableArray2["default"])(operands))); case 'gt': return greaterThanOperation.apply(void 0, [options].concat((0, _toConsumableArray2["default"])(operands))); case 'gte': return greaterThanOrEqualsOperation.apply(void 0, [options].concat((0, _toConsumableArray2["default"])(operands))); case 'in': return inOperation.apply(void 0, [options].concat((0, _toConsumableArray2["default"])(operands))); case 'lt': return lessThanOperation.apply(void 0, [options].concat((0, _toConsumableArray2["default"])(operands))); case 'lte': return lessThanOrEqualsOperation.apply(void 0, [options].concat((0, _toConsumableArray2["default"])(operands))); case 'or': return orOperation(operands); case 'sw': return startsWithOperation.apply(void 0, [options].concat((0, _toConsumableArray2["default"])(operands))); case 'mt': return matchesOperation.apply(void 0, [options].concat((0, _toConsumableArray2["default"])(operands))); default: return (0, _lodashEs.constant)(true); } }; var andOperation = function andOperation(expressions) { var fns = (0, _lodashEs.map)(expressions, compileExpression); return function (object, filters) { return (0, _lodashEs.every)(fns, function (fn) { return fn(object, filters); }); }; }; var orOperation = function orOperation(expressions) { var fns = (0, _lodashEs.map)(expressions, compileExpression); return function (object, filters) { return (0, _lodashEs.some)(fns, function (fn) { return fn(object, filters); }); }; }; var betweenOperation = function betweenOperation(options, lvalue, rvalueMin, rvalueMax) { return function (object, filters) { var left = object[lvalue]; var right1 = (0, _immutable.get)(filters, rvalueMin); var right2 = (0, _immutable.get)(filters, rvalueMax); // If the filter value is empty and strict is not enabled we skip the filter // by returning true. if ((isNullOrEmpty(right1) || isNullOrEmpty(right2)) && !options.strict) { return true; } if (compare(right1, right2, options, typeof left) <= 0) { throw new Error("Invalid filter values for between operation of ".concat(rvalueMin, " and ") + "".concat(rvalueMax, ". Min ").concat(JSON.stringify(right1), " not less than max ") + JSON.stringify(right2) + (options.caseInsensitive ? ' (caseInsensitive)' : '')); } return compare(left, right1, options) <= 0 && compare(left, right2, options) > 0; }; }; var equalsOperation = function equalsOperation(options, lvalue, rvalue) { return function (object, filters) { return skip((0, _immutable.get)(filters, rvalue), options) || compare(object[lvalue], (0, _immutable.get)(filters, rvalue), options) === 0; }; }; var greaterThanOperation = function greaterThanOperation(options, lvalue, rvalue) { return function (object, filters) { return skip((0, _immutable.get)(filters, rvalue), options) || compare(object[lvalue], (0, _immutable.get)(filters, rvalue), options) < 0; }; }; var greaterThanOrEqualsOperation = function greaterThanOrEqualsOperation(options, lvalue, rvalue) { return function (object, filters) { return skip((0, _immutable.get)(filters, rvalue), options) || compare(object[lvalue], (0, _immutable.get)(filters, rvalue), options) <= 0; }; }; var inOperation = function inOperation(options, lvalue, rvalue) { return function (object, filters) { // If the filter value is [], null, undefined then we check for the strict // option, if strict always return false and if not strict always return // true (because we are effectively skipping this filter operation). if (isNullOrEmpty((0, _immutable.get)(filters, rvalue)) && !(0, _lodashEs.isString)((0, _immutable.get)(filters, rvalue))) { return !options.strict; } // If we got a non-empty filter value that isn't an array (like a string) // we throw an error. if (!(0, _lodashEs.isArray)((0, _immutable.get)(filters, rvalue)) && !(0, _immutable.isImmutable)((0, _immutable.get)(filters, rvalue))) { throw new Error("Invalid filter value for in operation of ".concat(rvalue, " filter. Got ").concat(JSON.stringify((0, _immutable.get)(filters, rvalue)), ". Require an array.")); } // Finally perform the operation by checking the filter value for membership // of the object value. return (0, _immutable.Seq)((0, _immutable.get)(filters, rvalue)).some(function (v) { return compare((0, _immutable.get)(object, lvalue), v, options) === 0; }); }; }; var lessThanOperation = function lessThanOperation(options, lvalue, rvalue) { return function (object, filters) { return skip((0, _immutable.get)(filters, rvalue), options) || compare(object[lvalue], (0, _immutable.get)(filters, rvalue), options) > 0; }; }; var lessThanOrEqualsOperation = function lessThanOrEqualsOperation(options, lvalue, rvalue) { return function (object, filters) { return skip((0, _immutable.get)(filters, rvalue), options) || compare(object[lvalue], (0, _immutable.get)(filters, rvalue), options) >= 0; }; }; var startsWithOperation = function startsWithOperation(options, lvalue, rvalue) { var normalize = normalization(options); return function (object, filters) { return isNullOrEmpty((0, _immutable.get)(filters, rvalue)) || object[lvalue] && normalize(object[lvalue]).startsWith(normalize((0, _immutable.get)(filters, rvalue))); }; }; var matchesOperation = function matchesOperation(options, lvalue, rvalue) { var normalize = normalization(options); return function (object, filters) { return isNullOrEmpty((0, _immutable.get)(filters, rvalue)) || object[lvalue] && normalize(object[lvalue]).includes(normalize((0, _immutable.get)(filters, rvalue))); }; }; var skip = function skip(filterValue, options) { return isNullOrEmpty(filterValue) && !options.strict; }; // Helper that normalizes comparing values when one or both of the values is // falsy. Our convention is (any truthy) > '' > null > undefined. var compare = function compare(left, right, options) { var type = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : typeof left; var normalize = normalization(options); if (nonNull(left) && nonNull(right)) { return normalize(right, type) > normalize(left, type) ? 1 : normalize(right, type) === normalize(left, type) ? 0 : -1; } else { var falsyRanks = [undefined, null, '']; var leftRank = nonNull(left) ? 3 : falsyRanks.indexOf(left); var rightRank = nonNull(right) ? 3 : falsyRanks.indexOf(right); return rightRank > leftRank ? 1 : rightRank === leftRank ? 0 : -1; } }; var nonNull = function nonNull(v) { return v || v === 0 || v === false; }; var normalization = function normalization(options) { return function (value, coerceType) { return options.caseInsensitive ? toLower(coerce(value, coerceType)) : coerce(value, coerceType); }; }; var isNullOrEmpty = function isNullOrEmpty(value) { return (0, _lodashEs.isString)(value) && (0, _lodashEs.isEmpty)(value) || (0, _lodashEs.isArray)(value) && (0, _lodashEs.isEmpty)(value) || value === null || value === undefined; }; var coerce = function coerce(value, type) { if ( // no-op if a type is not specified !type || // return value if it is already the correct type typeof value === type || // do not attempt to coerce null / undefined value === null || typeof value === 'undefined' || // do not attempt to coerce to undefined or object (which type null returns) type === 'undefined' || type === 'object') { return value; } var valueType = typeof value; // if-else conditions below perform the actual type coercion, if a value is // not returned if (type === 'number' && valueType === 'string') { return parseInt(value); } else if (type === 'boolean' && valueType === 'string') { if (value === 'true') { return true; } else if (value === 'false') { return false; } } throw new Error("Cannot coerce value ".concat(JSON.stringify(value), " to ").concat(type, ".")); }; var toLower = function toLower(value) { return (0, _lodashEs.isString)(value) ? value.toLocaleLowerCase() : value; };