UNPKG

mobdb

Version:

MarsDB is a lightweight client-side MongoDB-like database, Promise based, written in ES6

274 lines (221 loc) 7.94 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.IndexManager = undefined; var _createClass = 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, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _bind2 = require('fast.js/function/bind'); var _bind3 = _interopRequireDefault(_bind2); var _keys2 = require('fast.js/object/keys'); var _keys3 = _interopRequireDefault(_keys2); var _forEach = require('fast.js/forEach'); var _forEach2 = _interopRequireDefault(_forEach); var _map2 = require('fast.js/map'); var _map3 = _interopRequireDefault(_map2); var _invariant = require('invariant'); var _invariant2 = _interopRequireDefault(_invariant); var _PromiseQueue = require('./PromiseQueue'); var _PromiseQueue2 = _interopRequireDefault(_PromiseQueue); var _CollectionIndex = require('./CollectionIndex'); var _CollectionIndex2 = _interopRequireDefault(_CollectionIndex); var _DocumentRetriver = require('./DocumentRetriver'); var _DocumentRetriver2 = _interopRequireDefault(_DocumentRetriver); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /** * Manager for controlling a list of indexes * for some model. Building indexes is promise * based. * By default it creates an index for `_id` field. */ /* istanbul ignore next */ var IndexManager = exports.IndexManager = function () { function IndexManager(db) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; _classCallCheck(this, IndexManager); this.db = db; this.indexes = {}; this._queue = new _PromiseQueue2.default(options.concurrency || 2); // By default ensure index by _id field this.ensureIndex({ fieldName: '_id', unique: true }); } /** * Check index existance for given `options.fieldName` and * if index not exists it creates new one. * Always return a promise that resolved only when * index succesfully created, built and ready for working with. * If `options.forceRebuild` provided and equals to true then * existing index will be rebuilt, otherwise existing index * don't touched. * * @param {Object} options.fieldName name of the field for indexing * @param {Object} options.forceRebuild rebuild index if it exists * @return {Promise} */ _createClass(IndexManager, [{ key: 'ensureIndex', value: function ensureIndex(options) { (0, _invariant2.default)(options && options.fieldName, 'You must specify a fieldName in options object'); var key = options.fieldName; if (!this.indexes[key]) { this.indexes[key] = new _CollectionIndex2.default(options); return this.buildIndex(key); } else if (this.indexes[key].buildPromise) { return this.indexes[key].buildPromise; } else if (options && options.forceRebuild) { return this.buildIndex(key); } else { return Promise.resolve(); } } /** * Buld an existing index (ensured) and return a * promise that will be resolved only when index successfully * built for all documents in the storage. * @param {String} key * @return {Promise} */ }, { key: 'buildIndex', value: function buildIndex(key) { var _this = this; (0, _invariant2.default)(this.indexes[key], 'Index with key `%s` does not ensured yet', key); console.log("buildIndex", key); var cleanup = function cleanup() { _this.indexes[key].buildPromise = null; }; var buildPromise = this._queue.add((0, _bind3.default)(this._doBuildIndex, this, key)).then(cleanup, cleanup); this.indexes[key].buildPromise = buildPromise; return buildPromise; } /** * Schedule a task for each index in the * manager. Return promise that will be resolved * when all indexes is successfully built. * @return {Promise} */ }, { key: 'buildAllIndexes', value: function buildAllIndexes() { var _this2 = this; return Promise.all((0, _map3.default)(this.indexes, function (v, k) { return _this2.ensureIndex({ fieldName: k, forceRebuild: true }); })); } /** * Remove an index * @param {String} key * @return {Promise} */ }, { key: 'removeIndex', value: function removeIndex(key) { var _this3 = this; return this._queue.add(function () { delete _this3.indexes[key]; }); } /** * Add a document to all indexes * @param {Object} doc * @return {Promise} */ }, { key: 'indexDocument', value: function indexDocument(doc) { var _this4 = this; return this._queue.add(function () { var keys = (0, _keys3.default)(_this4.indexes); var failingIndex = null; try { (0, _forEach2.default)(keys, function (k, i) { failingIndex = i; _this4.indexes[k].insert(doc); }); } catch (e) { (0, _forEach2.default)(keys.slice(0, failingIndex), function (k) { _this4.indexes[k].remove(doc); }); throw e; } }); } /** * Update all indexes with new version of * the document * @param {Object} oldDoc * @param {Object} newDoc * @return {Promise} */ }, { key: 'reindexDocument', value: function reindexDocument(oldDoc, newDoc) { var _this5 = this; return this._queue.add(function () { var keys = (0, _keys3.default)(_this5.indexes); var failingIndex = null; try { (0, _forEach2.default)(keys, function (k, i) { failingIndex = i; _this5.indexes[k].update(oldDoc, newDoc); }); } catch (e) { (0, _forEach2.default)(keys.slice(0, failingIndex), function (k) { _this5.indexes[k].revertUpdate(oldDoc, newDoc); }); throw e; } }); } /** * Remove document from all indexes * @param {Object} doc * @return {Promise} */ }, { key: 'deindexDocument', value: function deindexDocument(doc) { var _this6 = this; return this._queue.add(function () { var keys = (0, _keys3.default)(_this6.indexes); (0, _forEach2.default)(keys, function (k) { _this6.indexes[k].remove(doc); }); }); } /** * Build an existing index with reseting first * @param {String} key * @return {Promise} */ }, { key: '_doBuildIndex', value: function _doBuildIndex(key) { // Get and reset index var index = this.indexes[key]; index.reset(); // Loop through all doucments in the storage var errors = []; return new _DocumentRetriver2.default(this.db).retriveAll().then(function (docs) { (0, _forEach2.default)(docs, function (doc) { try { index.insert(doc); } catch (e) { errors.push([e, doc]); } }); if (errors.length > 0) { throw new Error('Index build failed with errors: ', errors); } }); } }]); return IndexManager; }(); exports.default = IndexManager;