Append-only format used for updates

pull/2/head
Louis Chatriot 12 years ago
parent c716261271
commit a394a6c431
  1. 35
      lib/datastore.js
  2. 67
      test/db.test.js

@ -200,6 +200,29 @@ Datastore.prototype.persistWholeDatabase = function (data, cb) {
}; };
/**
* Persist new state for the given newDocs (can be update or removal)
* @param {Array} newDocs Can be empty if no doc was updated/removed
* @param {Function} cb Optional, signature: err
*/
Datastore.prototype.persistNewState = function (newDocs, cb) {
var self = this
, toPersist = ''
, callback = cb || function () {}
;
newDocs.forEach(function (doc) {
toPersist += model.serialize(doc) + '\n';
});
if (toPersist.length === 0) { return callback(); }
fs.appendFile(self.filename, toPersist, 'utf8', function (err) {
return callback(err);
});
};
/** /**
* Update all docs matching query * Update all docs matching query
* For now, very naive implementation (recalculating the whole database) * For now, very naive implementation (recalculating the whole database)
@ -217,7 +240,10 @@ Datastore.prototype._update = function (query, updateQuery, options, cb) {
, self = this , self = this
, numReplaced = 0 , numReplaced = 0
, multi, upsert , multi, upsert
, newData = []; , modifiedDoc
, newData = []
, updatedData = []
;
if (typeof options === 'function') { cb = options; options = {}; } if (typeof options === 'function') { cb = options; options = {}; }
callback = cb || function () {}; callback = cb || function () {};
@ -247,7 +273,10 @@ Datastore.prototype._update = function (query, updateQuery, options, cb) {
self.data.forEach(function (d) { self.data.forEach(function (d) {
if (model.match(d, query) && (multi || numReplaced === 0)) { if (model.match(d, query) && (multi || numReplaced === 0)) {
numReplaced += 1; numReplaced += 1;
newData.push(model.modify(d, updateQuery)); modifiedDoc = model.modify(d, updateQuery);
newData.push(modifiedDoc);
updatedData.push(modifiedDoc);
} else { } else {
newData.push(d); newData.push(d);
} }
@ -256,7 +285,7 @@ Datastore.prototype._update = function (query, updateQuery, options, cb) {
return callback(err); return callback(err);
} }
self.persistWholeDatabase(newData, function (err) { self.persistNewState(updatedData, function (err) {
if (err) { return callback(err); } if (err) { return callback(err); }
self.data = newData; self.data = newData;
return callback(null, numReplaced); return callback(null, numReplaced);

@ -151,7 +151,6 @@ describe('Database', function () {
docs[0].somedata.should.equal('ok'); docs[0].somedata.should.equal('ok');
assert.isDefined(docs[0]._id); assert.isDefined(docs[0]._id);
done(); done();
}); });
}); });
@ -724,6 +723,72 @@ describe('Database', function () {
}); });
}); });
it('Non-multi updates are persistent', function (done) {
d.insert({ a:1, hello: 'world' }, function (err, doc1) {
d.insert({ a:2, hello: 'earth' }, function (err, doc2) {
d.update({ a: 2 }, { $set: { hello: 'changed' } }, {}, function (err) {
assert.isNull(err);
d.find({}, function (err, docs) {
docs.sort(function (a, b) { return a.a - b.a; });
docs.length.should.equal(2);
_.isEqual(docs[0], { _id: doc1._id, a:1, hello: 'world' }).should.equal(true);
_.isEqual(docs[1], { _id: doc2._id, a:2, hello: 'changed' }).should.equal(true);
// Even after a reload the database state hasn't changed
d.loadDatabase(function (err) {
assert.isUndefined(err);
d.find({}, function (err, docs) {
docs.sort(function (a, b) { return a.a - b.a; });
docs.length.should.equal(2);
_.isEqual(docs[0], { _id: doc1._id, a:1, hello: 'world' }).should.equal(true);
_.isEqual(docs[1], { _id: doc2._id, a:2, hello: 'changed' }).should.equal(true);
done();
});
});
});
});
});
});
});
it('Multi updates are persistent', function (done) {
d.insert({ a:1, hello: 'world' }, function (err, doc1) {
d.insert({ a:2, hello: 'earth' }, function (err, doc2) {
d.insert({ a:5, hello: 'pluton' }, function (err, doc3) {
d.update({ a: { $in: [1, 2] } }, { $set: { hello: 'changed' } }, { multi: true }, function (err) {
assert.isNull(err);
d.find({}, function (err, docs) {
docs.sort(function (a, b) { return a.a - b.a; });
docs.length.should.equal(3);
_.isEqual(docs[0], { _id: doc1._id, a:1, hello: 'changed' }).should.equal(true);
_.isEqual(docs[1], { _id: doc2._id, a:2, hello: 'changed' }).should.equal(true);
_.isEqual(docs[2], { _id: doc3._id, a:5, hello: 'pluton' }).should.equal(true);
// Even after a reload the database state hasn't changed
d.loadDatabase(function (err) {
assert.isUndefined(err);
d.find({}, function (err, docs) {
docs.sort(function (a, b) { return a.a - b.a; });
docs.length.should.equal(3);
_.isEqual(docs[0], { _id: doc1._id, a:1, hello: 'changed' }).should.equal(true);
_.isEqual(docs[1], { _id: doc2._id, a:2, hello: 'changed' }).should.equal(true);
_.isEqual(docs[2], { _id: doc3._id, a:5, hello: 'pluton' }).should.equal(true);
done();
});
});
});
});
});
});
});
});
}); // ==== End of 'Update' ==== // }); // ==== End of 'Update' ==== //

Loading…
Cancel
Save