UNPKG

dexie-batch

Version:

Fetch DB entries in batches to improve performance while respecting IPC size constraints

168 lines (140 loc) 5.68 kB
/*! dexie-batch v0.4.3 | github.com/raphinesse/dexie-batch | MIT License */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('dexie')) : typeof define === 'function' && define.amd ? define(['dexie'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.DexieBatch = factory(global.Dexie)); }(this, (function (require$$0) { 'use strict'; function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var require$$0__default = /*#__PURE__*/_interopDefaultLegacy(require$$0); 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, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } var Promise$1 = require$$0__default['default'].Promise; var dexieBatch = /*#__PURE__*/function () { function DexieBatch(opts) { _classCallCheck(this, DexieBatch); assertValidOptions(opts); this.opts = opts; } _createClass(DexieBatch, [{ key: "isParallel", value: function isParallel() { return Boolean(this.opts.limit); } }, { key: "each", value: function each(collection, callback) { var _this = this; assertValidMethodArgs.apply(void 0, arguments); return this.eachBatch(collection, function (batch, batchIdx) { var baseIdx = batchIdx * _this.opts.batchSize; return Promise$1.all(batch.map(function (item, i) { return callback(item, baseIdx + i); })); }); } }, { key: "eachBatch", value: function eachBatch(collection, callback) { assertValidMethodArgs.apply(void 0, arguments); var delegate = this.isParallel() ? 'eachBatchParallel' : 'eachBatchSerial'; return this[delegate](collection, callback); } }, { key: "eachBatchParallel", value: function eachBatchParallel(collection, callback) { assertValidMethodArgs.apply(void 0, arguments); var _this$opts = this.opts, batchSize = _this$opts.batchSize, limit = _this$opts.limit; if (!limit) { throw new Error('Option "limit" must be set for parallel operation'); } var nextBatch = batchIterator(collection, batchSize); var numBatches = Math.ceil(limit / batchSize); var batchPromises = Array.from({ length: numBatches }, function (_, idx) { return nextBatch().then(function (batch) { return callback(batch, idx); }); }); return Promise$1.all(batchPromises).then(function (batches) { return batches.length; }); } }, { key: "eachBatchSerial", value: function eachBatchSerial(collection, callback) { assertValidMethodArgs.apply(void 0, arguments); var userPromises = []; var nextBatch = batchIterator(collection, this.opts.batchSize); var nextUnlessEmpty = function nextUnlessEmpty(batch) { if (batch.length === 0) return; userPromises.push(callback(batch, userPromises.length)); return nextBatch().then(nextUnlessEmpty); }; return nextBatch().then(nextUnlessEmpty).then(function () { return Promise$1.all(userPromises); }).then(function () { return userPromises.length; }); } }]); return DexieBatch; }(); // Does not conform to JS iterator requirements function batchIterator(collection, batchSize) { var it = collection.clone(); return function () { var batchPromise = it.clone().limit(batchSize).toArray(); it.offset(batchSize); return batchPromise; }; } function assertValidOptions(opts) { var batchSize = opts && opts.batchSize; if (!(batchSize && Number.isInteger(batchSize) && batchSize > 0)) { throw new Error('Mandatory option "batchSize" must be a positive integer'); } if ('limit' in opts && !(Number.isInteger(opts.limit) && opts.limit >= 0)) { throw new Error('Option "limit" must be a non-negative integer'); } } function assertValidMethodArgs(collection, callback) { if (arguments.length < 2) { throw new Error('Arguments "collection" and "callback" are mandatory'); } if (!isCollectionInstance(collection)) { throw new Error('"collection" must be of type Collection'); } if (!(typeof callback === 'function')) { throw new TypeError('"callback" must be a function'); } } // We would need the Dexie instance that created the collection to get the // Collection constructor and do some proper type checking. // So for now we resort to duck typing function isCollectionInstance(obj) { if (!obj) return false; return ['clone', 'offset', 'limit', 'toArray'].every(function (name) { return typeof obj[name] === 'function'; }); } return dexieBatch; }))); //# sourceMappingURL=dexie-batch.js.map