"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports._AST = exports.Operator = exports.Match = exports.AST = void 0; var _predicate = require("../../../services/predicate"); var _date_value = require("./date_value"); function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); } function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0 and the Server Side Public License, v 1; you may not use this file except * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ var Match = Object.freeze({ MUST: 'must', MUST_NOT: 'must_not', isMust: function isMust(match) { return match === Match.MUST; }, isMustClause: function isMustClause(clause) { return Match.isMust(clause.match); } }); exports.Match = Match; var Operator = Object.freeze({ EQ: 'eq', EXACT: 'exact', GT: 'gt', GTE: 'gte', LT: 'lt', LTE: 'lte', isEQ: function isEQ(match) { return match === Operator.EQ; }, isEQClause: function isEQClause(clause) { return Field.isInstance(clause) && Operator.isEQ(clause.operator); }, isEXACT: function isEXACT(match) { return match === Operator.EXACT; }, isEXACTClause: function isEXACTClause(clause) { return Field.isInstance(clause) && Operator.isEXACT(clause.operator); }, isRange: function isRange(match) { return Operator.isGT(match) || Operator.isGTE(match) || Operator.isLT(match) || Operator.isLTE(match); }, isRangeClause: function isRangeClause(clause) { return Field.isInstance(clause) && Operator.isRange(clause.operator); }, isGT: function isGT(match) { return match === Operator.GT; }, isGTClause: function isGTClause(clause) { return Field.isInstance(clause) && Operator.isGT(clause.operator); }, isGTE: function isGTE(match) { return match === Operator.GTE; }, isGTEClause: function isGTEClause(clause) { return Field.isInstance(clause) && Operator.isGTE(clause.operator); }, isLT: function isLT(match) { return match === Operator.LT; }, isLTClause: function isLTClause(clause) { return Field.isInstance(clause) && Operator.isLT(clause.operator); }, isLTE: function isLTE(match) { return match === Operator.LTE; }, isLTEClause: function isLTEClause(clause) { return Field.isInstance(clause) && Operator.isLTE(clause.operator); } }); exports.Operator = Operator; var Term = Object.freeze({ TYPE: 'term', isInstance: function isInstance(clause) { return clause.type === Term.TYPE; }, must: function must(value) { return { type: Term.TYPE, value: value, match: Match.MUST }; }, mustNot: function mustNot(value) { return { type: Term.TYPE, value: value, match: Match.MUST_NOT }; } }); var Group = Object.freeze({ TYPE: 'group', isInstance: function isInstance(clause) { return clause.type === Group.TYPE; }, must: function must(value) { return { type: Group.TYPE, value: value, match: Match.MUST }; }, mustNot: function mustNot(value) { return { type: Group.TYPE, value: value, match: Match.MUST_NOT }; } }); var Field = Object.freeze({ TYPE: 'field', isInstance: function isInstance(clause) { return clause.type === Field.TYPE; }, must: { eq: function eq(field, value) { return { type: Field.TYPE, field: field, value: value, match: Match.MUST, operator: Operator.EQ }; }, exact: function exact(field, value) { return { type: Field.TYPE, field: field, value: value, match: Match.MUST, operator: Operator.EXACT }; }, gt: function gt(field, value) { return { type: Field.TYPE, field: field, value: value, match: Match.MUST, operator: Operator.GT }; }, gte: function gte(field, value) { return { type: Field.TYPE, field: field, value: value, match: Match.MUST, operator: Operator.GTE }; }, lt: function lt(field, value) { return { type: Field.TYPE, field: field, value: value, match: Match.MUST, operator: Operator.LT }; }, lte: function lte(field, value) { return { type: Field.TYPE, field: field, value: value, match: Match.MUST, operator: Operator.LTE }; } }, mustNot: { eq: function eq(field, value) { return { type: Field.TYPE, field: field, value: value, match: Match.MUST_NOT, operator: Operator.EQ }; }, exact: function exact(field, value) { return { type: Field.TYPE, field: field, value: value, match: Match.MUST_NOT, operator: Operator.EXACT }; }, gt: function gt(field, value) { return { type: Field.TYPE, field: field, value: value, match: Match.MUST_NOT, operator: Operator.GT }; }, gte: function gte(field, value) { return { type: Field.TYPE, field: field, value: value, match: Match.MUST_NOT, operator: Operator.GTE }; }, lt: function lt(field, value) { return { type: Field.TYPE, field: field, value: value, match: Match.MUST_NOT, operator: Operator.LT }; }, lte: function lte(field, value) { return { type: Field.TYPE, field: field, value: value, match: Match.MUST_NOT, operator: Operator.LTE }; } } }); var Is = Object.freeze({ TYPE: 'is', isInstance: function isInstance(clause) { return clause.type === Is.TYPE; }, must: function must(flag) { return { type: Is.TYPE, flag: flag, match: Match.MUST }; }, mustNot: function mustNot(flag) { return { type: Is.TYPE, flag: flag, match: Match.MUST_NOT }; } }); var valuesEqual = function valuesEqual(v1, v2) { if ((0, _date_value.isDateValue)(v1)) { return (0, _date_value.dateValuesEqual)(v1, v2); } return v1 === v2; }; var arrayIncludesValue = function arrayIncludesValue(array, value) { return array.some(function (item) { return valuesEqual(item, value); }); }; var mustToMatch = function mustToMatch(must) { return must === true ? Match.MUST : Match.MUST_NOT; }; /** * The AST structure is an array of clauses. There are 3 types of clauses that are supported: * * :term: * Holds a VALUE and an OCCUR. The OCCUR indicates whether the value must match or must not match. Default * clauses are not associated with any specific field - when executing the search, one can specify what are * the default fields that the default clauses will be matched against. * * :field: * Like the `term` clause, holds a VALUE and an MATCH, but this clause also specifies the field that the * value will be matched against. * * :is: * Holds a FLAG and indicates whether this flag must be applied or must not be applied. Typically this clause * matches against boolean values of a record (e.g. "is:online", "is:internal", "is:on", etc..) * * This AST is immutable - every "mutating" operation returns a newly mutated AST. */ var _AST = /*#__PURE__*/function () { function _AST() { var _this = this; var clauses = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; _classCallCheck(this, _AST); _defineProperty(this, "_clauses", void 0); _defineProperty(this, "_indexedClauses", void 0); this._clauses = clauses; this._indexedClauses = { field: {}, is: {}, term: [], group: [] }; clauses.forEach(function (clause) { switch (clause.type) { case Field.TYPE: if (!_this._indexedClauses.field[clause.field]) { _this._indexedClauses.field[clause.field] = []; } _this._indexedClauses.field[clause.field].push(clause); break; case Is.TYPE: _this._indexedClauses.is[clause.flag] = clause; break; case Term.TYPE: _this._indexedClauses.term.push(clause); break; case Group.TYPE: _this._indexedClauses.group.push(clause); break; default: // @ts-ignore TS knows we have exhausted the match throw new Error("Unknown query clause type [".concat(clause.type, "]")); } }); } _createClass(_AST, [{ key: "clauses", get: function get() { return this._clauses; } }, { key: "getTermClauses", value: function getTermClauses() { return this._indexedClauses.term; } }, { key: "getTermClause", value: function getTermClause(value) { var clauses = this.getTermClauses(); return clauses.find(function (clause) { return valuesEqual(clause.value, value); }); } }, { key: "getFieldNames", value: function getFieldNames() { return Object.keys(this._indexedClauses.field); } }, { key: "getFieldClauses", value: function getFieldClauses(field) { return field ? this._indexedClauses.field[field] : this._clauses.filter(Field.isInstance); } }, { key: "getFieldClause", value: function getFieldClause(field, predicate) { var clauses = this.getFieldClauses(field); if (clauses) { return clauses.find(predicate); } } }, { key: "hasOrFieldClause", value: function hasOrFieldClause(field, value) { var clause = this.getFieldClause(field, function (clause) { return (0, _predicate.isArray)(clause.value); }); if (!clause) { return false; } // We can apply this type cast due to the `isArray` filter above return (0, _predicate.isNil)(value) || arrayIncludesValue(clause.value, value); } }, { key: "getOrFieldClause", value: function getOrFieldClause(field, value, must, operator) { return this.getFieldClause(field, function (clause) { if (!(0, _predicate.isArray)(clause.value)) { return false; } var matchValue = (0, _predicate.isNil)(value) || arrayIncludesValue(clause.value, value); var matchMust = (0, _predicate.isNil)(must) || mustToMatch(must) === clause.match; var matchOperator = (0, _predicate.isNil)(operator) || operator === clause.operator; return matchValue && matchMust && matchOperator; }); } }, { key: "addOrFieldValue", value: function addOrFieldValue(field, value) { var must = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; var operator = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : Operator.EQ; var existingClause = this.getOrFieldClause(field, undefined, must, operator); if (!existingClause) { var newClause = must ? Field.must[operator](field, [value]) : Field.mustNot[operator](field, [value]); return new _AST([].concat(_toConsumableArray(this._clauses), [newClause])); } var clauses = this._clauses.map(function (clause) { if (clause === existingClause) { clause.value.push(value); } return clause; }); return new _AST(clauses); } }, { key: "removeOrFieldValue", value: function removeOrFieldValue(field, value) { var existingClause = this.getOrFieldClause(field, value); if (!existingClause) { return new _AST(_toConsumableArray(this._clauses)); } var clauses = this._clauses.reduce(function (clauses, clause) { if (clause !== existingClause) { clauses.push(clause); return clauses; } var filteredValue = clause.value.filter(function (val) { return !valuesEqual(val, value); }); if (filteredValue.length === 0) { return clauses; } clauses.push(_objectSpread(_objectSpread({}, clause), {}, { value: filteredValue })); return clauses; }, []); return new _AST(clauses); } }, { key: "removeOrFieldClauses", value: function removeOrFieldClauses(field) { var clauses = this._clauses.filter(function (clause) { return !Field.isInstance(clause) || clause.field !== field || !(0, _predicate.isArray)(clause.value); }); return new _AST(clauses); } }, { key: "hasSimpleFieldClause", value: function hasSimpleFieldClause(field, value) { var clause = this.getFieldClause(field, function (clause) { return !(0, _predicate.isArray)(clause.value); }); if (!clause) { return false; } return (0, _predicate.isNil)(value) || valuesEqual(clause.value, value); } }, { key: "getSimpleFieldClause", value: function getSimpleFieldClause(field, value) { return this.getFieldClause(field, function (clause) { return !(0, _predicate.isArray)(clause.value) && ((0, _predicate.isNil)(value) || valuesEqual(clause.value, value)); }); } }, { key: "addSimpleFieldValue", value: function addSimpleFieldValue(field, value) { var must = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; var operator = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : Operator.EQ; var clause = must ? Field.must[operator](field, value) : Field.mustNot[operator](field, value); return this.addClause(clause); } }, { key: "removeSimpleFieldValue", value: function removeSimpleFieldValue(field, value) { var existingClause = this.getSimpleFieldClause(field, value); if (!existingClause) { return new _AST(_toConsumableArray(this._clauses)); } var clauses = this._clauses.filter(function (clause) { return clause !== existingClause; }); return new _AST(clauses); } }, { key: "removeSimpleFieldClauses", value: function removeSimpleFieldClauses(field) { var clauses = this._clauses.filter(function (clause) { return !Field.isInstance(clause) || clause.field !== field || (0, _predicate.isArray)(clause.value); }); return new _AST(clauses); } }, { key: "getIsClauses", value: function getIsClauses() { return Object.values(this._indexedClauses.is); } }, { key: "getIsClause", value: function getIsClause(flag) { return this._indexedClauses.is[flag]; } }, { key: "removeIsClause", value: function removeIsClause(flag) { return new _AST(this._clauses.filter(function (clause) { return !Is.isInstance(clause) || clause.flag !== flag; })); } }, { key: "removeIsClauses", value: function removeIsClauses() { return new _AST(this._clauses.filter(function (clause) { return !Is.isInstance(clause); })); } }, { key: "removeAllClauses", value: function removeAllClauses() { return new _AST(); } }, { key: "getGroupClauses", value: function getGroupClauses() { return Object.values(this._indexedClauses.group); } /** * Creates and returns a new AST with the given clause added to the current clauses. If * the current clauses already include a similar clause, it will be (in-place) replaced by * the given clause. Whether a clause is similar to the given one depends on the type of the clause. * Two clauses are similar if: * * - they are both of the same type * - if they are `default` clauses, they must have the same value * - if they are `term` clauses, they must have the same fields and values * - if they are `is` clauses, they must have the same flags * * The reasoning behind not including the `match` attributes of the clauses in the rules above, stems * in the fact that the AST clauses are ANDed, and having two similar clauses with two different * match attributes creates a logically contradicted AST (e.g. what does it mean to * "(must have x) AND (must not have x)"?) * * note: in-place replacement means the given clause will be placed in the same position as the one it * replaced */ }, { key: "addClause", value: function addClause(newClause) { var added = false; var newClauses = this._clauses.reduce(function (clauses, clause) { if (newClause.type !== clause.type) { clauses.push(clause); return clauses; } switch (newClause.type) { case Term.TYPE: if (newClause.value !== clause.value) { clauses.push(clause); return clauses; } break; case Field.TYPE: if (newClause.field !== clause.field || newClause.value !== clause.value) { clauses.push(clause); return clauses; } break; case Is.TYPE: if (newClause.flag !== clause.flag) { clauses.push(clause); return clauses; } break; default: throw new Error("unknown clause type [".concat(newClause.type, "]")); } added = true; clauses.push(newClause); return clauses; }, []); if (!added) { newClauses.push(newClause); } return new _AST(newClauses); } }], [{ key: "create", value: function create(clauses) { return new _AST(clauses); } }]); return _AST; }(); exports._AST = _AST; var AST = Object.freeze({ Match: Match, Operator: Operator, Term: Term, Group: Group, Field: Field, Is: Is, create: function create(clauses) { return new _AST(clauses); } }); exports.AST = AST;