When inserting multiple documents at once in an index, rollback all inserts if one fails

pull/2/head
Louis Chatriot 12 years ago
parent 9c42221f95
commit d223e4733d
  1. 15
      lib/datastore.js
  2. 30
      lib/indexes.js
  3. 19
      test/indexes.test.js

@ -42,22 +42,25 @@ Datastore.prototype.resetIndexes = function (newData) {
/** /**
* Ensure an index is kept for this field. Same parameters as lib/indexes * Ensure an index is kept for this field. Same parameters as lib/indexes
* For now this function is synchronous, we need to test how much time it takes * For now this function is synchronous, we need to test how much time it takes
* We use an async API for consistency with the rest of the code
* @param {String} options.fieldName * @param {String} options.fieldName
* @param {Boolean} options.unique * @param {Boolean} options.unique
* @param {Boolean} options.sparse * @param {Boolean} options.sparse
* @return {Boolean} true if index was created or already exists, false otherwise * @param {Function} cb Optional callback, signature: err
*/ */
Datastore.prototype.ensureIndex = function (options) { Datastore.prototype.ensureIndex = function (options, cb) {
var callback = cb || function () {};
options = options || {}; options = options || {};
if (!options.fieldName) { return false; } if (!options.fieldName) { return callback({ missingFieldName: true }); }
if (this.indexes[options.fieldName]) { return true; } if (this.indexes[options.fieldName]) { return callback(); }
options.datastore = this; options.datastore = this;
this.indexes[options.fieldName] = new Index(options); this.indexes[options.fieldName] = new Index(options);
this.indexes[options.fieldName].insert(this.data); this.indexes[options.fieldName].insert(this.data);
return true; return callback();
}; };
@ -106,7 +109,7 @@ Datastore.prototype.removeFromIndexes = function (doc) {
/** /**
* Update a document in all indexes * Update a document in all indexes
*/ */
Datastore.prototype.removeFromIndexes = function (doc, newDoc) { Datastore.prototype.updateIndexes = function (doc, newDoc) {
var self = this; var self = this;
Object.keys(this.indexes).forEach(function (i) { Object.keys(this.indexes).forEach(function (i) {

@ -56,7 +56,7 @@ Index.prototype.reset = function (newData) {
Index.prototype.insert = function (doc) { Index.prototype.insert = function (doc) {
var key, self = this; var key, self = this;
if (util.isArray(doc)) { doc.forEach(function (d) { self.insert(d); }); return; } if (util.isArray(doc)) { this.insertMultipleDocs(doc); return; }
key = model.getDotValue(doc, this.fieldName); key = model.getDotValue(doc, this.fieldName);
@ -70,8 +70,36 @@ Index.prototype.insert = function (doc) {
}; };
/**
* When inserting an array of documents, we need to rollback all insertions
* if an error is thrown
*/
Index.prototype.insertMultipleDocs = function (docs) {
var i, error, failingI;
for (i = 0; i < docs.length; i += 1) {
try {
this.insert(docs[i]);
} catch (e) {
error = e;
failingI = i;
break;
}
}
if (error) {
for (i = 0; i < failingI; i += 1) {
this.remove(docs[i]);
}
throw error;
}
};
/** /**
* Remove a document from the index * Remove a document from the index
* If an array is passed, we remove all its elements
* O(log(n)) * O(log(n))
*/ */
Index.prototype.remove = function (doc) { Index.prototype.remove = function (doc) {

@ -105,6 +105,25 @@ describe('Indexes', function () {
assert.deepEqual(idx.tree.search('bloup'), [doc3]); assert.deepEqual(idx.tree.search('bloup'), [doc3]);
}); });
it('When inserting an array of elements, if an error is thrown all inserts need to be rolled back', function () {
var idx = new Index({ fieldName: 'tf', unique: true })
, doc1 = { a: 5, tf: 'hello' }
, doc2 = { a: 8, tf: 'world' }
, doc2b = { a: 84, tf: 'world' }
, doc3 = { a: 2, tf: 'bloup' }
;
try {
idx.insert([doc1, doc2, doc2b, doc3]);
} catch (e) {
e.errorType.should.equal('uniqueViolated');
}
idx.tree.getNumberOfKeys().should.equal(0);
assert.deepEqual(idx.tree.search('hello'), []);
assert.deepEqual(idx.tree.search('world'), []);
assert.deepEqual(idx.tree.search('bloup'), []);
});
}); // ==== End of 'Insertion' ==== // }); // ==== End of 'Insertion' ==== //

Loading…
Cancel
Save