|
|
|
@ -12,9 +12,16 @@ var fs = require('fs') |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Create a new collection |
|
|
|
|
* If a filename is provided, persist it to disk |
|
|
|
|
* Otherwise keep it in memory (data will be lost when the application stops) |
|
|
|
|
*/ |
|
|
|
|
function Datastore (filename) { |
|
|
|
|
if (!filename || typeof filename !== 'string' || filename.length === 0) { |
|
|
|
|
this.filename = null; |
|
|
|
|
} else { |
|
|
|
|
this.filename = filename; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.executor = new Executor(); |
|
|
|
|
|
|
|
|
|
// We keep internally the number of lines in the datafile
|
|
|
|
@ -280,7 +287,32 @@ Datastore.prototype.persistCachedDatabase = function (cb) { |
|
|
|
|
if (toPersist.length === 0) { return callback(); } |
|
|
|
|
|
|
|
|
|
fs.writeFile(this.filename, toPersist, function (err) { return callback(err); }); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Persist new state for the given newDocs (can be insertion, update or removal) |
|
|
|
|
* Use an append-only format |
|
|
|
|
* @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 () {} |
|
|
|
|
; |
|
|
|
|
|
|
|
|
|
self.datafileSize += newDocs.length; |
|
|
|
|
|
|
|
|
|
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); |
|
|
|
|
}); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -293,27 +325,23 @@ Datastore.prototype.persistCachedDatabase = function (cb) { |
|
|
|
|
Datastore.prototype._insert = function (newDoc, cb) { |
|
|
|
|
var callback = cb || function () {} |
|
|
|
|
, self = this |
|
|
|
|
, persistableNewDoc |
|
|
|
|
, insertedDoc |
|
|
|
|
; |
|
|
|
|
|
|
|
|
|
// Ensure the document has the right format
|
|
|
|
|
try { |
|
|
|
|
newDoc._id = customUtils.uid(16); |
|
|
|
|
persistableNewDoc = model.serialize(newDoc); |
|
|
|
|
model.checkObject(newDoc); |
|
|
|
|
insertedDoc = model.deepCopy(newDoc); |
|
|
|
|
} catch (e) { |
|
|
|
|
return callback(e); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
insertedDoc = model.deserialize(persistableNewDoc); |
|
|
|
|
|
|
|
|
|
// Insert in all indexes (also serves to ensure uniqueness)
|
|
|
|
|
try { self.addToIndexes(insertedDoc); } catch (e) { return callback(e); } |
|
|
|
|
|
|
|
|
|
fs.appendFile(self.filename, persistableNewDoc + '\n', 'utf8', function (err) { |
|
|
|
|
this.persistNewState([newDoc], function (err) { |
|
|
|
|
if (err) { return callback(err); } |
|
|
|
|
|
|
|
|
|
self.datafileSize += 1; |
|
|
|
|
return callback(null, newDoc); |
|
|
|
|
}); |
|
|
|
|
}; |
|
|
|
@ -372,32 +400,6 @@ Datastore.prototype.findOne = function (query, callback) { |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Persist new state for the given newDocs (can be update or removal) |
|
|
|
|
* Use an append-only format |
|
|
|
|
* @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 () {} |
|
|
|
|
; |
|
|
|
|
|
|
|
|
|
self.datafileSize += newDocs.length; |
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
* For now, very naive implementation (recalculating the whole database) |
|
|
|
@ -508,7 +510,6 @@ Datastore.prototype._remove = function (query, options, cb) { |
|
|
|
|
|
|
|
|
|
self.persistNewState(removedDocs, function (err) { |
|
|
|
|
if (err) { return callback(err); } |
|
|
|
|
|
|
|
|
|
return callback(null, numRemoved); |
|
|
|
|
}); |
|
|
|
|
}; |
|
|
|
|