UNPKG

minimongo

Version:

Client-side mongo database with server sync over http

251 lines (250 loc) 9.68 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const lodash_1 = __importDefault(require("lodash")); const utils = __importStar(require("./utils")); const selector_1 = require("./selector"); /** Replicates data into a both a master and a replica db. Assumes both are identical at start * and then only uses master for finds and does all changes to both * Warning: removing a collection removes it from the underlying master and replica! */ class ReplicatingDb { constructor(masterDb, replicaDb) { this.collections = {}; this.masterDb = masterDb; this.replicaDb = replicaDb; } addCollection(name, success, error) { const collection = new Collection(name, this.masterDb[name], this.replicaDb[name]); this[name] = collection; this.collections[name] = collection; if (success != null) { return success(); } } removeCollection(name, success, error) { delete this[name]; delete this.collections[name]; if (success != null) { return success(); } } getCollectionNames() { return lodash_1.default.keys(this.collections); } } exports.default = ReplicatingDb; // Replicated collection. class Collection { constructor(name, masterCol, replicaCol) { this.name = name; this.masterCol = masterCol; this.replicaCol = replicaCol; } find(selector, options) { return this.masterCol.find(selector, options); } findOne(selector, options, success, error) { if (lodash_1.default.isFunction(options)) { ; [options, success, error] = [{}, options, success]; } options = options || {}; // If promise case if (success == null) { return new Promise((resolve, reject) => { this.findOne(selector, options, resolve, reject); }); } return this.masterCol.findOne(selector, options, success, error); } upsert(docs, bases, success, error) { // If promise case if (!success && !lodash_1.default.isFunction(bases)) { return new Promise((resolve, reject) => { this.upsert(docs, bases, resolve, reject); }); } let items; [items, success, error] = utils.regularizeUpsert(docs, bases, success, error); // Upsert does to both this.masterCol.upsert(lodash_1.default.map(items, "doc"), lodash_1.default.map(items, "base"), () => { return this.replicaCol.upsert(lodash_1.default.map(items, "doc"), lodash_1.default.map(items, "base"), (results) => { return success(docs); }, error); }, error); } remove(id, success, error) { if (!success) { return new Promise((resolve, reject) => { this.remove(id, resolve, reject); }); } // Do to both this.masterCol.remove(id, () => { this.replicaCol.remove(id, success, error); }, error); } cache(docs, selector, options, success, error) { // Calculate what has to be done for cache using the master database which is faster (usually MemoryDb) // then do minimum to both databases // Index docs let sort; const docsMap = lodash_1.default.keyBy(docs, "_id"); // Compile sort if (options.sort) { sort = (0, selector_1.compileSort)(options.sort); } // Perform query return this.masterCol.find(selector, options).fetch((results) => { let result; const resultsMap = lodash_1.default.keyBy(results, "_id"); // Determine if each result needs to be cached const toCache = []; for (let doc of docs) { result = resultsMap[doc._id]; // Exclude any excluded _ids from being cached/uncached if (options && options.exclude && options.exclude.includes(doc._id)) { continue; } // If not present locally, cache it if (!result) { toCache.push(doc); continue; } // If both have revisions (_rev) and new one is same or lower, do not cache if (doc._rev && result._rev && doc._rev <= result._rev) { continue; } // Only cache if different if (JSON.stringify(doc) != JSON.stringify(result)) { toCache.push(doc); } } const toUncache = []; for (result of results) { // If at limit if (options.limit && docs.length === options.limit) { // If past end on sorted limited, ignore if (options.sort && sort(result, lodash_1.default.last(docs)) >= 0) { continue; } // If no sort, ignore if (!options.sort) { continue; } } // Exclude any excluded _ids from being cached/uncached if (options && options.exclude && options.exclude.includes(result._id)) { continue; } // Determine which ones to uncache if (!docsMap[result._id]) { toUncache.push(result._id); } } // Cache ones needing caching const performCaches = (next) => { if (toCache.length > 0) { return this.masterCol.cacheList(toCache, () => { return this.replicaCol.cacheList(toCache, () => { return next(); }, error); }, error); } else { return next(); } }; // Uncache list const performUncaches = (next) => { if (toUncache.length > 0) { return this.masterCol.uncacheList(toUncache, () => { return this.replicaCol.uncacheList(toUncache, () => { return next(); }, error); }, error); } else { return next(); } }; return performCaches(() => { return performUncaches(() => { if (success != null) { success(); } }); }); }, error); } pendingUpserts(success, error) { return this.masterCol.pendingUpserts(success, error); } pendingRemoves(success, error) { return this.masterCol.pendingRemoves(success, error); } resolveUpserts(upserts, success, error) { return this.masterCol.resolveUpserts(upserts, () => { return this.replicaCol.resolveUpserts(upserts, success, error); }, error); } resolveRemove(id, success, error) { return this.masterCol.resolveRemove(id, () => { return this.replicaCol.resolveRemove(id, success, error); }, error); } // Add but do not overwrite or record as upsert seed(docs, success, error) { return this.masterCol.seed(docs, () => { return this.replicaCol.seed(docs, success, error); }, error); } // Add but do not overwrite upserts or removes cacheOne(doc, success, error) { return this.masterCol.cacheOne(doc, () => { return this.replicaCol.cacheOne(doc, success, error); }, error); } // Add but do not overwrite upserts or removes cacheList(docs, success, error) { return this.masterCol.cacheList(docs, () => { return this.replicaCol.cacheList(docs, success, error); }, error); } uncache(selector, success, error) { return this.masterCol.uncache(selector, () => { return this.replicaCol.uncache(selector, success, error); }, error); } uncacheList(ids, success, error) { return this.masterCol.uncacheList(ids, () => { return this.replicaCol.uncacheList(ids, success, error); }, error); } }