@kineticdata/react
Version:
A React library for the Kinetic Platform
369 lines (367 loc) • 15.8 kB
JavaScript
"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;
};