From 1f0d19ac1894fc858fd45505e9cea5bc01230a12 Mon Sep 17 00:00:00 2001 From: Louis Chatriot Date: Thu, 30 May 2013 14:19:17 +0200 Subject: [PATCH] No side effect when using multiple indexes --- lib/datastore.js | 26 ++++++++++++++++++++++---- test/db.test.js | 30 +++++++++++++++++++++++++++--- 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/lib/datastore.js b/lib/datastore.js index 0b6b4d4..d536fa8 100644 --- a/lib/datastore.js +++ b/lib/datastore.js @@ -65,11 +65,29 @@ Datastore.prototype.ensureIndex = function (options) { * Add one or several document(s) to all indexes */ Datastore.prototype.addToIndexes = function (doc) { - var self = this; + var self = this + , i, failingIndex, error + , keys = Object.keys(this.indexes) + ; - Object.keys(this.indexes).forEach(function (i) { - self.indexes[i].insert(doc); - }); + for (i = 0; i < keys.length; i += 1) { + try { + this.indexes[keys[i]].insert(doc); + } catch (e) { + failingIndex = i; + error = e; + break; + } + } + + // If an error happened, we need to rollback the insert on all other indexes + if (error) { + for (i = 0; i < failingIndex; i += 1) { + this.indexes[keys[i]].remove(doc); + } + + throw error; + } }; diff --git a/test/db.test.js b/test/db.test.js index 9d357f1..073549d 100644 --- a/test/db.test.js +++ b/test/db.test.js @@ -1288,7 +1288,7 @@ describe('Database', function () { }); }); - it('If the index has a unique constraint, an error is thrown if it is violated', function (done) { + it('If the index has a unique constraint, an error is thrown if it is violated and the data didnt change', function (done) { d.ensureIndex({ fieldName: 'z', unique: true }); d.indexes.z.tree.getNumberOfKeys().should.equal(0); @@ -1316,8 +1316,32 @@ describe('Database', function () { }); }); - it.skip('If the index has a unique constraint, others cannot be modified when it raises an error', function (done) { - done(); + it('If the index has a unique constraint, others cannot be modified when it raises an error', function (done) { + d.ensureIndex({ fieldName: 'nonu1' }); + d.ensureIndex({ fieldName: 'uni', unique: true }); + d.ensureIndex({ fieldName: 'nonu2' }); + + d.insert({ nonu1: 'yes', nonu2: 'yes2', uni: 'willfail' }, function (err, newDoc) { + assert.isNull(err); + d.indexes.nonu1.tree.getNumberOfKeys().should.equal(1); + d.indexes.uni.tree.getNumberOfKeys().should.equal(1); + d.indexes.nonu2.tree.getNumberOfKeys().should.equal(1); + + d.insert({ nonu1: 'no', nonu2: 'no2', uni: 'willfail' }, function (err) { + err.errorType.should.equal('uniqueViolated'); + + // No index was modified + d.indexes.nonu1.tree.getNumberOfKeys().should.equal(1); + d.indexes.uni.tree.getNumberOfKeys().should.equal(1); + d.indexes.nonu2.tree.getNumberOfKeys().should.equal(1); + + assert.deepEqual(d.indexes.nonu1.getMatching('yes'), [newDoc]); + assert.deepEqual(d.indexes.uni.getMatching('willfail'), [newDoc]); + assert.deepEqual(d.indexes.nonu2.getMatching('yes2'), [newDoc]); + + done(); + }); + }); }); }); // ==== End of 'Indexing newly inserted documents' ==== //