UNPKG

kibana-with-account

Version:

kibana-with-account is develop based kibana project

161 lines (136 loc) 5.41 kB
define(function (require) { var _ = require('lodash'); var inflector = require('ui/IndexedArray/inflector'); var pathGetter = _(_.get).rearg(1, 0).ary(2); var inflectIndex = inflector('by'); var inflectOrder = inflector('in', 'Order'); var CLEAR_CACHE = {}; var OPT_NAMES = IndexedArray.OPT_NAMES = ['index', 'group', 'order', 'initialSet', 'immutable']; /** * Generic extension of Array class, which will index (and reindex) the * objects it contains based on their properties. * * @class IndexedArray * @module utils * @constructor * @param {object} [config] - describes the properties of this registry object * @param {string[]} [config.index] - a list of props/paths that should be used to index the docs. * @param {string[]} [config.group] - a list of keys/paths to group docs by. * @param {string[]} [config.order] - a list of keys/paths to order the keys by. * @param {object[]} [config.initialSet] - the initial dataset the IndexedArray should contain. * @param {boolean} [config.immutable] - a flag that hints to people reading the implementation * that this IndexedArray should not be modified. It's modification * methods are also removed */ _.class(IndexedArray).inherits(Array); function IndexedArray(config) { IndexedArray.Super.call(this); // just to remind future us that this list is important config = _.pick(config || {}, OPT_NAMES); this.raw = []; // setup indices this._indexNames = _.union( this._setupIndices(config.group, inflectIndex, _.organizeBy), this._setupIndices(config.index, inflectIndex, _.indexBy), this._setupIndices(config.order, inflectOrder, _.sortBy) ); if (config.initialSet) { this.push.apply(this, config.initialSet); } if (config.immutable) { // just a hint, bugs caused by updates not propogating would be very // very very hard to track down this.push = this.splice = undefined; } } /** * Create indices for a group of object properties. getters and setters are used to * read and control the indices. * * @param {string[]} props - the properties that should be used to index docs * @param {function} inflect - a function that will be called with a property name, and * creates the public property at which the index will be exposed * @param {function} op - the function that will be used to create the indices, it is passed * the raw representaion of the registry, and a getter for reading the * right prop * * @returns {string[]} - the public keys of all indices created */ IndexedArray.prototype._setupIndices = function (props, inflect, op) { // shortcut for empty props if (!props || props.length === 0) return; var self = this; return props.map(function (prop) { var from = pathGetter.partial(prop).value(); var to = inflect(prop); var cache; Object.defineProperty(self, to, { enumerable: false, configurable: false, set: function (val) { // can't set any value other than the CLEAR_CACHE constant if (val === CLEAR_CACHE) { cache = false; } else { throw new TypeError(to + ' can not be set, it is a computed index of values'); } }, get: function () { return cache || (cache = op(self.raw, from)); } }); return to; }); }; /** * (Re)run index/group/order procedures to create indices of * sub-objects. * * @return {undefined} */ IndexedArray.prototype._clearIndices = function () { var self = this; self._indexNames.forEach(function (name) { self[name] = CLEAR_CACHE; }); }; /** * Copy all array methods which have side-effects, and wrap them * in a function that will reindex after each call, as well * as duplex the operation to the .raw version of the IndexedArray. * * @param {[type]} method [description] * @return {[type]} [description] */ 'pop push shift splice unshift reverse'.split(' ').forEach(function (method) { var orig = Array.prototype[method]; IndexedArray.prototype[method] = function (/* args... */) { // call the original method with this context orig.apply(this, arguments); // run the indexers this._clearIndices(); // call the original method on our "raw" array, and return the result(s) return orig.apply(this.raw, arguments); }; }); /** * Remove items from this based on a predicate * @param {function|object|string} predicate - the predicate used to decide what is removed * @param {object} context - this binding for predicate * @return {array} - the removed data */ IndexedArray.prototype.remove = function (predicate, context) { var out = _.remove(this, predicate, context); _.remove(this.raw, predicate, context); this._clearIndices(); return out; }; /** * provide a hook for the JSON serializer * @return {array} - a plain, vanilla array with our same data */ IndexedArray.prototype.toJSON = function () { return this.raw; }; return IndexedArray; });