diff --git a/src/knapsack.js b/src/knapsack.js index 9206115..abd593e 100644 --- a/src/knapsack.js +++ b/src/knapsack.js @@ -30,12 +30,55 @@ KS.Database.prototype.init = function(){ ids: [] }) + this.ops = [] + this.reactorRunning = false; + _.each(this.collectionNames, function(indexes, collection){ this.collections[collection] = new KS.Collection(collection, this, indexes) }, this) return this } + +KS.Database.prototype.execute = function(collection, resolve, reject, action, args){ + console.log("registered", action, "on", collection.name) + this.ops.push({ + collection: collection, + resolve: resolve, + reject: reject, + action: action, + args: args + }) + this.runReactor() +} + +KS.Database.prototype.runReactor = function(){ + if (this.reactorRunning === true) return; + if (this.ops.length === 0) return; + console.log('run reactor') + this.reactorRunning = true; + var self = this; + + var op = this.ops.shift() + + console.log('starting to execute', op.action, 'on', op.collection.name) + op.collection[op.action](op.args[0], op.args[1], op.args[2], op.args[3], op.args[4]) + .then(function(value){ + console.log('excuted', op.action, 'on', op.collection.name, value) + op.resolve(value) + self.reactorRunning = false; + self.runReactor() + }).catch(function(e){ + self.reactorRunning = false; + console.log('ERROR', e, e.stack) + op.reject(e) + throw new Error(e) + self.runReactor() + }) +} + + + // remove database KS.Database.prototype.remove = function(opts){ } @@ -54,23 +97,96 @@ KS.Collection = function(name, db, indexes){ this.addIndexes(indexes) } -KS.Collection.prototype.addIndexes = function(indexes){ +KS.Collection.prototype.addIndexes = function(indexNames){ - this.indexNames = indexes + this.indexNames = indexNames localforage.setItem(this.brainName, { - indexNames: indexes, + indexNames: indexNames, ids: [] }) - _.each(indexes, function(index){ - localforage.setItem(this.indexBaseName + index, {name: index, values: {}}) + + var self = this; + _.each(indexNames, function(indexName){ + self.addIndex(indexName).catch(function(e){console.log(e)}) }, this) +} + +KS.Collection.prototype.addIndex = function(newDoc, cb){ + var self = this; + var args = arguments + return new Promise(function(resolve, reject){ + self.db.execute(self, resolve, reject, '_addIndex', args) + }) +} + +KS.Collection.prototype.add = function(newDoc, cb){ + var self = this; + var args = arguments + return new Promise(function(resolve, reject){ + self.db.execute(self, resolve, reject, '_add', args) + }) +} + + +KS.Collection.prototype.find = function(newDoc, cb){ + var self = this; + var args = arguments + return new Promise(function(resolve, reject){ + self.db.execute(self, resolve, reject, '_find', args) + }) } -KS.Collection.prototype.add = function(doc, cb){ + + +KS.Collection.prototype.all = function(newDoc, cb){ + var self = this; + var args = arguments + return new Promise(function(resolve, reject){ + self.db.execute(self, resolve, reject, '_all', args) + }) +} + + +KS.Collection.prototype.remove = function(newDoc, cb){ var self = this; + var args = arguments return new Promise(function(resolve, reject){ - if (doc.id == undefined){ + self.db.execute(self, resolve, reject, '_remove', args) + }) +} + +KS.Collection.prototype.update = function(newDoc, cb){ + var self = this; + var args = arguments + return new Promise(function(resolve, reject){ + self.db.execute(self, resolve, reject, '_update', args) + }) +} + + +KS.Collection.prototype._addIndex = function(indexName, cb){ + var self = this; + return new Promise(function(resolve, reject){ + localforage.setItem(self.indexBaseName + indexName, { + name: indexName, + values: {} + }) + .then(function(index){ + resolve(index) + }) + .catch(function(e){ + reject(e) + }) + }) +} + + + +KS.Collection.prototype._add = function(doc, cb){ + var self = this; + return new Promise(function(resolve, reject){ + if (doc.id == undefined || doc.id == null){ var message = "All objects need an id" if (cb){ cb(null, message) } reject(message) @@ -105,6 +221,7 @@ KS.Collection.prototype.add = function(doc, cb){ })) }) .then(function(indexes){ + indexes = _.compact(indexes) return self._addToIndexes(indexes, doc) }) .then(function(){ @@ -113,12 +230,13 @@ KS.Collection.prototype.add = function(doc, cb){ }) .catch(function(e){ if (cb){ cb(null, e) } - reject() + reject(e) }) }) } KS.Collection.prototype._addToIndexes = function(indexes, doc){ + console.log('add to these indexes', indexes) var self = this; return Promise.all(_.map(indexes, function(index){ return self._addToIndex(index, doc) @@ -135,10 +253,10 @@ KS.Collection.prototype._addToIndex = function(index, doc){ return localforage.setItem(self.indexBaseName + index.name, index) } -KS.Collection.prototype.find = function(){ +KS.Collection.prototype._find = function(){ var self = this; var cb; - var args = Array.prototype.slice.call(arguments); + var args = _.compact(Array.prototype.slice.call(arguments)); if (typeof _.last(args) == "function"){ cb = args.pop() } @@ -154,7 +272,7 @@ KS.Collection.prototype.find = function(){ } } -KS.Collection.prototype.all = function(cb){ +KS.Collection.prototype._all = function(cb){ var self = this; return new Promise(function(resolve, reject){ localforage.getItem(self.brainName) @@ -163,6 +281,8 @@ KS.Collection.prototype.all = function(cb){ return localforage.getItem(self.docBaseName + id) })) }).then(function(docs){ + if (docs == null){console.log("THE DOCS ARE NULL")} + docs = _.compact(docs) if (cb){ cb(docs) } resolve(docs) }).catch(function(error){ @@ -181,6 +301,7 @@ KS.Collection.prototype._findById = function(id, cb){ resolve(doc) }) .catch(function(error){ + console.log(error, error.stack) if (cb) {cb(null, error)} reject(error) }) @@ -190,40 +311,60 @@ KS.Collection.prototype._findById = function(id, cb){ KS.Collection.prototype._findByIndex = function(index, value, cb){ var self = this; - // this method is a bit messy with how the promises and mixed with callbacks return new Promise(function(resolve, reject){ + console.log('looking at the index', index, 'on', self.name, self.indexBaseName + index) localforage.getItem(self.indexBaseName + index) - .then(function(index, error){ - var ids = index.values[JSON.stringify(value)] + //self.find('by_' + index) + .then(function(index){ + if (index == null || index == undefined) debugger; + var ids = index.values[JSON.stringify(value)] || [] if (ids.length == 0){ - if (cb) {cb([], error)} - if (error){reject(error)} + console.log('not in index') + if (cb){cb([])} resolve([]) - } else if (ids.length > 1){ - localforage.getItem(self.docBaseName + ids[0], function(item, error){ - if (cb) {cb(item, error)} - if (error){reject(error)} - resolve(item) + } else if (ids.length == 1){ + console.log('find an id in the index', ids[0]) + return localforage.getItem(self.docBaseName + ids[0]) + .then(function(item){ + // it was deleted since we searched for it + if (item == null){ + if (cb) {cb([])} + resolve([]) + } else { + if (cb) {cb([item])} + resolve([item]) + } + }) + .catch(function(error){ + console.log(error, error.stack) + if (cb) { cb(null, error) }; + reject( error ) }) } else { - Promise.all(ids.map(function(id){ + return Promise.all(ids.map(function(id){ return localforage.getItem(self.docBaseName + id) })) - .then(function(values, error){ - if (cb) {cb(values, error)} - if (error){reject(error)} + .then(function(values){ + console.log(values) + values = _.compact(values) + console.log('values after find by index', values) + if (cb) { cb(values) } resolve(values) + }).catch(function(error){ + console.log(error, error.stack); + reject(error); }) } - }).catch(function(error){ reject(error) }) + }).catch(function(error){ console.log(error, error.stack); reject(error) }) }) } -KS.Collection.prototype.remove = function(id, cb){ +KS.Collection.prototype._remove = function(id, cb){ + console.log('remove a document with id', id) var self = this; return new Promise(function(resolve, reject){ // remove from localforage @@ -232,38 +373,42 @@ KS.Collection.prototype.remove = function(id, cb){ // remove from all other indexes localforage.getItem(self.docBaseName + id) .then(function(docToRemove){ - localforage.removeItem(self.docBaseName + id) - .then(function(){ - return localforage.getItem(self.db.brainName) - }) - .then(function(dbBrain){ - // remove from the databae index - dbBrain.ids = _.without(dbBrain.ids, id) - return localforage.setItem(self.db.brainName, dbBrain) - }) - .then(function(){ - return localforage.getItem(self.brainName) - }) - .then(function(collectionBrain){ - collectionBrain.ids = _.without(collectionBrain.ids, id) - return localforage.setItem(self.brainName, collectionBrain) - }) - .then(function(){ - return Promise.all(_.map(self.indexNames, function(indexName){ - return localforage.getItem(self.indexBaseName + indexName) - })) - }) - .then(function(indexes){ - self._removeFromIndexes(indexes, docToRemove) - }) - .then(function(){ - if (cb) { cb() } + if (docToRemove){ + return localforage.removeItem(self.docBaseName + id) + .then(function(){ + return localforage.getItem(self.db.brainName) + }) + .then(function(dbBrain){ + // remove from the databae index + dbBrain.ids = _.without(dbBrain.ids, id) + return localforage.setItem(self.db.brainName, dbBrain) + }) + .then(function(){ + return localforage.getItem(self.brainName) + }) + .then(function(collectionBrain){ + collectionBrain.ids = _.without(collectionBrain.ids, id) + return localforage.setItem(self.brainName, collectionBrain) + }) + .then(function(){ + return Promise.all(_.map(self.indexNames, function(indexName){ + return localforage.getItem(self.indexBaseName + indexName) + })) + }) + .then(function(indexes){ + return self._removeFromIndexes(indexes, docToRemove) + }) + .then(function(){ + if (cb) { cb() } + resolve() + }) + .catch(function(error){ + if (cb) { cb(error) } + reject(error) + }) + } else { resolve() - }) - .catch(function(error){ - if (cb) { cb(error) } - reject(error) - }) + } }) }) } @@ -277,17 +422,19 @@ KS.Collection.prototype._removeFromIndexes = function(indexes, docToRemove){ KS.Collection.prototype._removeFromIndex = function(index, docToRemove){ var indexedValue = JSON.stringify(docToRemove[index.name]) - var ids = index.values[indexedValue] + var ids = index.values[indexedValue] || [] var self = this; + if (ids.length > 1){ - index.values[indexedValue] = _.without(index.values[indexedValue], id) + index.values[indexedValue] = _.without(index.values[indexedValue], docToRemove.id) } else { delete index.values[indexedValue] } return localforage.setItem(self.indexBaseName + index.name, index) } -KS.Collection.prototype.update = function(newDoc, cb){ +KS.Collection.prototype._update = function(newDoc, cb){ + var self = this; return new Promise(function(resolve, reject){ @@ -298,10 +445,16 @@ KS.Collection.prototype.update = function(newDoc, cb){ localforage.getItem(self.docBaseName + newDoc.id) .then(function(value){ oldDoc = value + if (value == null){ + console.log('doc wasnt found', newDoc) + if (cb){ cb(null, new Error("Document has already been deleted")) } + reject(new Error("Document has already been deleted")) + } return localforage.setItem(self.docBaseName + newDoc.id, newDoc) }) .then(function(newDoc){ indexNamesToUpdate = _.compact(_.map(self.indexNames, function(indexName){ + console.log('oldDoc', oldDoc, index) if (oldDoc[indexName] !== newDoc[indexName]){ return indexName }