UNPKG

nqm-minimongo

Version:

Client-side mongo database with server sync over http

331 lines (297 loc) 10.2 kB
var Collection, LocalStorageDb, async, compileSort, processFind, utils, _; _ = require('lodash'); async = require('async'); utils = require('./utils'); processFind = require('./utils').processFind; compileSort = require('./selector').compileSort; module.exports = LocalStorageDb = (function() { function LocalStorageDb(options, success) { this.collections = {}; if (options && options.namespace && window.localStorage) { this.namespace = options.namespace; } if (success) { success(this); } } LocalStorageDb.prototype.addCollection = function(name, success, error) { var collection, namespace; if (this.namespace) { namespace = this.namespace + "." + name; } collection = new Collection(name, namespace); this[name] = collection; this.collections[name] = collection; if (success != null) { return success(); } }; LocalStorageDb.prototype.removeCollection = function(name, success, error) { var i, key, keyToMatch, keys, _i, _j, _len, _ref; if (this.namespace && window.localStorage) { keys = []; for (i = _i = 0, _ref = window.localStorage.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) { keys.push(window.localStorage.key(i)); } for (_j = 0, _len = keys.length; _j < _len; _j++) { key = keys[_j]; keyToMatch = this.namespace + '.' + name; if (key.substring(0, keyToMatch.length) === keyToMatch) { window.localStorage.removeItem(key); } } } delete this[name]; delete this.collections[name]; if (success != null) { return success(); } }; return LocalStorageDb; })(); Collection = (function() { function Collection(name, namespace) { this.name = name; this.namespace = namespace; this.items = {}; this.upserts = {}; this.removes = {}; if (window.localStorage && (namespace != null)) { this.loadStorage(); } } Collection.prototype.loadStorage = function() { var base, i, item, key, removeItems, upsertKeys, _i, _j, _len, _ref; this.itemNamespace = this.namespace + "_"; for (i = _i = 0, _ref = window.localStorage.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) { key = window.localStorage.key(i); if (key.substring(0, this.itemNamespace.length) === this.itemNamespace) { item = JSON.parse(window.localStorage[key]); this.items[item._id] = item; } } upsertKeys = window.localStorage[this.namespace + "upserts"] ? JSON.parse(window.localStorage[this.namespace + "upserts"]) : []; for (_j = 0, _len = upsertKeys.length; _j < _len; _j++) { key = upsertKeys[_j]; this.upserts[key] = { doc: this.items[key] }; base = window.localStorage[this.namespace + "upsertbase_" + key] ? JSON.parse(window.localStorage[this.namespace + "upsertbase_" + key]) : null; this.upserts[key].base = base; } removeItems = window.localStorage[this.namespace + "removes"] ? JSON.parse(window.localStorage[this.namespace + "removes"]) : []; return this.removes = _.object(_.pluck(removeItems, "_id"), removeItems); }; Collection.prototype.find = function(selector, options) { return { fetch: (function(_this) { return function(success, error) { return _this._findFetch(selector, options, success, error); }; })(this) }; }; Collection.prototype.findOne = function(selector, options, success, error) { var _ref; if (_.isFunction(options)) { _ref = [{}, options, success], options = _ref[0], success = _ref[1], error = _ref[2]; } return this.find(selector, options).fetch(function(results) { if (success != null) { return success(results.length > 0 ? results[0] : null); } }, error); }; Collection.prototype._findFetch = function(selector, options, success, error) { if (success != null) { return success(processFind(_.cloneDeep(_.values(this.items)), selector, options)); } }; Collection.prototype.upsert = function(docs, bases, success, error) { var item, items, _i, _len, _ref; _ref = utils.regularizeUpsert(docs, bases, success, error), items = _ref[0], success = _ref[1], error = _ref[2]; items = JSON.parse(JSON.stringify(items)); for (_i = 0, _len = items.length; _i < _len; _i++) { item = items[_i]; if (item.base === void 0) { if (this.upserts[item.doc._id]) { item.base = this.upserts[item.doc._id].base; } else { item.base = this.items[item.doc._id] || null; } } item = _.cloneDeep(item); this._putItem(item.doc); this._putUpsert(item); } if (success) { return success(docs); } }; Collection.prototype.remove = function(id, success, error) { if (_.isObject(id)) { this.find(id).fetch((function(_this) { return function(rows) { return async.each(rows, function(row, cb) { return _this.remove(row._id, (function() { return cb(); }), cb); }, function() { return success(); }); }; })(this), error); return; } if (_.has(this.items, id)) { this._putRemove(this.items[id]); this._deleteItem(id); this._deleteUpsert(id); } else { this._putRemove({ _id: id }); } if (success != null) { return success(); } }; Collection.prototype._putItem = function(doc) { this.items[doc._id] = doc; if (this.namespace) { return window.localStorage[this.itemNamespace + doc._id] = JSON.stringify(doc); } }; Collection.prototype._deleteItem = function(id) { delete this.items[id]; if (this.namespace) { return window.localStorage.removeItem(this.itemNamespace + id); } }; Collection.prototype._putUpsert = function(upsert) { this.upserts[upsert.doc._id] = upsert; if (this.namespace) { window.localStorage[this.namespace + "upserts"] = JSON.stringify(_.keys(this.upserts)); return window.localStorage[this.namespace + "upsertbase_" + upsert.doc._id] = JSON.stringify(upsert.base); } }; Collection.prototype._deleteUpsert = function(id) { delete this.upserts[id]; if (this.namespace) { return window.localStorage[this.namespace + "upserts"] = JSON.stringify(_.keys(this.upserts)); } }; Collection.prototype._putRemove = function(doc) { this.removes[doc._id] = doc; if (this.namespace) { return window.localStorage[this.namespace + "removes"] = JSON.stringify(_.values(this.removes)); } }; Collection.prototype._deleteRemove = function(id) { delete this.removes[id]; if (this.namespace) { return window.localStorage[this.namespace + "removes"] = JSON.stringify(_.values(this.removes)); } }; Collection.prototype.cache = function(docs, selector, options, success, error) { var doc, docsMap, sort, _i, _len; for (_i = 0, _len = docs.length; _i < _len; _i++) { doc = docs[_i]; this.cacheOne(doc); } docsMap = _.object(_.pluck(docs, "_id"), docs); if (options.sort) { sort = compileSort(options.sort); } return this.find(selector, options).fetch((function(_this) { return function(results) { var result, _j, _len1; for (_j = 0, _len1 = results.length; _j < _len1; _j++) { result = results[_j]; if (!docsMap[result._id] && !_.has(_this.upserts, result._id)) { if (options.sort && options.limit && docs.length === options.limit) { if (sort(result, _.last(docs)) >= 0) { continue; } } _this._deleteItem(result._id); } } if (success != null) { return success(); } }; })(this), error); }; Collection.prototype.pendingUpserts = function(success) { return success(_.values(this.upserts)); }; Collection.prototype.pendingRemoves = function(success) { return success(_.pluck(this.removes, "_id")); }; Collection.prototype.resolveUpserts = function(upserts, success) { var upsert, _i, _len; for (_i = 0, _len = upserts.length; _i < _len; _i++) { upsert = upserts[_i]; if (this.upserts[upsert.doc._id]) { if (_.isEqual(upsert.doc, this.upserts[upsert.doc._id].doc)) { this._deleteUpsert(upsert.doc._id); } else { this.upserts[upsert.doc._id].base = upsert.doc; this._putUpsert(this.upserts[upsert.doc._id]); } } } if (success != null) { return success(); } }; Collection.prototype.resolveRemove = function(id, success) { this._deleteRemove(id); if (success != null) { return success(); } }; Collection.prototype.seed = function(docs, success) { var doc, _i, _len; if (!_.isArray(docs)) { docs = [docs]; } for (_i = 0, _len = docs.length; _i < _len; _i++) { doc = docs[_i]; if (!_.has(this.items, doc._id) && !_.has(this.removes, doc._id)) { this._putItem(doc); } } if (success != null) { return success(); } }; Collection.prototype.cacheOne = function(doc, success) { var existing; if (!_.has(this.upserts, doc._id) && !_.has(this.removes, doc._id)) { existing = this.items[doc._id]; if (!existing || !doc._rev || !existing._rev || doc._rev >= existing._rev) { this._putItem(doc); } } if (success != null) { return success(); } }; Collection.prototype.uncache = function(selector, success, error) { var compiledSelector, item, _i, _len, _ref; compiledSelector = utils.compileDocumentSelector(selector); _ref = _.values(this.items); for (_i = 0, _len = _ref.length; _i < _len; _i++) { item = _ref[_i]; if ((this.upserts[item._id] == null) && compiledSelector(item)) { this._deleteItem(item._id); } } if (success != null) { return success(); } }; return Collection; })();