@elastic/eui
Version:
Elastic UI Component Library
604 lines (600 loc) • 20.8 kB
JavaScript
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
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 _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _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(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 _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
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; }
function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
/*
* 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.
*/
import { isArray, isNil } from '../../../services/predicate';
import { dateValuesEqual, isDateValue } from './date_value';
export 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);
}
});
export 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);
}
});
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 (isDateValue(v1)) {
return 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.
*/
export 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, "]"));
}
});
}
return _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 isArray(clause.value);
});
if (!clause) {
return false;
}
// We can apply this type cast due to the `isArray` filter above
return isNil(value) || arrayIncludesValue(clause.value, value);
}
}, {
key: "getOrFieldClause",
value: function getOrFieldClause(field, value, must, operator) {
return this.getFieldClause(field, function (clause) {
if (!isArray(clause.value)) {
return false;
}
var matchValue = isNil(value) || arrayIncludesValue(clause.value, value);
var matchMust = isNil(must) || mustToMatch(must) === clause.match;
var matchOperator = 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 || !isArray(clause.value);
});
return new _AST(clauses);
}
}, {
key: "hasSimpleFieldClause",
value: function hasSimpleFieldClause(field, value) {
var clause = this.getFieldClause(field, function (clause) {
return !isArray(clause.value);
});
if (!clause) {
return false;
}
return isNil(value) || valuesEqual(clause.value, value);
}
}, {
key: "getSimpleFieldClause",
value: function getSimpleFieldClause(field, value) {
return this.getFieldClause(field, function (clause) {
return !isArray(clause.value) && (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 || 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);
}
}]);
}();
export var AST = Object.freeze({
Match: Match,
Operator: Operator,
Term: Term,
Group: Group,
Field: Field,
Is: Is,
create: function create(clauses) {
return new _AST(clauses);
}
});