dexie-batch
Version:
Fetch DB entries in batches to improve performance while respecting IPC size constraints
168 lines (140 loc) • 5.68 kB
JavaScript
/*! 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