Fixed side effect bug

pull/2/head
Louis Chatriot 9 years ago
parent ef8905adf0
commit 7b3f3c2868
  1. 27
      lib/datastore.js
  2. 40
      test/db.test.js

@ -34,6 +34,7 @@ function Datastore (options) {
filename = options.filename; filename = options.filename;
this.inMemoryOnly = options.inMemoryOnly || false; this.inMemoryOnly = options.inMemoryOnly || false;
this.autoload = options.autoload || false; this.autoload = options.autoload || false;
this.timestampData = options.timestampData || false;
} }
// Determine whether in memory or persistent // Determine whether in memory or persistent
@ -283,17 +284,19 @@ Datastore.prototype.getCandidates = function (query) {
*/ */
Datastore.prototype._insert = function (newDoc, cb) { Datastore.prototype._insert = function (newDoc, cb) {
var callback = cb || function () {} var callback = cb || function () {}
, preparedDoc
; ;
try { try {
this._insertInCache(newDoc); preparedDoc = this.prepareDocumentForInsertion(newDoc)
this._insertInCache(preparedDoc);
} catch (e) { } catch (e) {
return callback(e); return callback(e);
} }
this.persistence.persistNewState(util.isArray(newDoc) ? newDoc : [newDoc], function (err) { this.persistence.persistNewState(util.isArray(preparedDoc) ? preparedDoc : [preparedDoc], function (err) {
if (err) { return callback(err); } if (err) { return callback(err); }
return callback(null, newDoc); return callback(null, model.deepCopy(preparedDoc));
}); });
}; };
@ -311,6 +314,7 @@ Datastore.prototype.createNewId = function () {
/** /**
* Prepare a document (or array of documents) to be inserted in a database * Prepare a document (or array of documents) to be inserted in a database
* Meaning adds _id and createdAt if necessary on a copy of newDoc to avoid any side effect on user input
* @api private * @api private
*/ */
Datastore.prototype.prepareDocumentForInsertion = function (newDoc) { Datastore.prototype.prepareDocumentForInsertion = function (newDoc) {
@ -320,9 +324,8 @@ Datastore.prototype.prepareDocumentForInsertion = function (newDoc) {
preparedDoc = []; preparedDoc = [];
newDoc.forEach(function (doc) { preparedDoc.push(self.prepareDocumentForInsertion(doc)); }); newDoc.forEach(function (doc) { preparedDoc.push(self.prepareDocumentForInsertion(doc)); });
} else { } else {
if (newDoc._id === undefined) { newDoc._id = this.createNewId(); }
preparedDoc = model.deepCopy(newDoc); preparedDoc = model.deepCopy(newDoc);
//if (preparedDoc._id === undefined) { preparedDoc._id = this.createNewId(); } if (preparedDoc._id === undefined) { preparedDoc._id = this.createNewId(); }
if (this.timestampData && preparedDoc.createdAt === undefined) { preparedDoc.createdAt = new Date(); } if (this.timestampData && preparedDoc.createdAt === undefined) { preparedDoc.createdAt = new Date(); }
model.checkObject(preparedDoc); model.checkObject(preparedDoc);
} }
@ -334,11 +337,11 @@ Datastore.prototype.prepareDocumentForInsertion = function (newDoc) {
* If newDoc is an array of documents, this will insert all documents in the cache * If newDoc is an array of documents, this will insert all documents in the cache
* @api private * @api private
*/ */
Datastore.prototype._insertInCache = function (newDoc) { Datastore.prototype._insertInCache = function (preparedDoc) {
if (util.isArray(newDoc)) { if (util.isArray(preparedDoc)) {
this._insertMultipleDocsInCache(newDoc); this._insertMultipleDocsInCache(preparedDoc);
} else { } else {
this.addToIndexes(this.prepareDocumentForInsertion(newDoc)); this.addToIndexes(preparedDoc);
} }
}; };
@ -347,10 +350,8 @@ Datastore.prototype._insertInCache = function (newDoc) {
* inserts and throws the error * inserts and throws the error
* @api private * @api private
*/ */
Datastore.prototype._insertMultipleDocsInCache = function (newDocs) { Datastore.prototype._insertMultipleDocsInCache = function (preparedDocs) {
var i, failingI, error var i, failingI, error;
, preparedDocs = this.prepareDocumentForInsertion(newDocs)
;
for (i = 0; i < preparedDocs.length; i += 1) { for (i = 0; i < preparedDocs.length; i += 1) {
try { try {

@ -265,10 +265,48 @@ describe('Database', function () {
done(); done();
}); });
}); });
});
});
it("If timestampData option is set, a createdAt field is added and persisted", function (done) {
var newDoc = { hello: 'world' }, beginning = Date.now();
d = new Datastore({ filename: testDb, timestampData: true, autoload: true });
d.find({}, function (err, docs) {
assert.isNull(err);
docs.length.should.equal(0);
d.insert(newDoc, function (err, insertedDoc) {
// No side effect on given input
assert.deepEqual(newDoc, { hello: 'world' });
// Insert doc has two new fields, _id and createdAt
insertedDoc.hello.should.equal('world');
assert.isDefined(insertedDoc.createdAt);
assert.isDefined(insertedDoc._id);
Object.keys(insertedDoc).length.should.equal(3);
assert.isBelow(Math.abs(insertedDoc.createdAt.getTime() - beginning), 15); // No more than 15ms should have elapsed
}); // Modifying results of insert doesn't change the cache
insertedDoc.bloup = "another";
Object.keys(insertedDoc).length.should.equal(4);
d.find({}, function (err, docs) {
docs.length.should.equal(1);
assert.deepEqual(newDoc, { hello: 'world' });
assert.deepEqual({ hello: 'world', _id: insertedDoc._id, createdAt: insertedDoc.createdAt }, docs[0]);
// All data correctly persisted on disk
d.loadDatabase(function () {
d.find({}, function (err, docs) {
docs.length.should.equal(1);
assert.deepEqual(newDoc, { hello: 'world' });
assert.deepEqual({ hello: 'world', _id: insertedDoc._id, createdAt: insertedDoc.createdAt }, docs[0]);
done();
});
});
});
});
});
}); });
it('Can insert a doc with id 0', function (done) { it('Can insert a doc with id 0', function (done) {

Loading…
Cancel
Save