diff --git a/lib/connectors/memory.js b/lib/connectors/memory.js index 62e02ac9..b545e968 100644 --- a/lib/connectors/memory.js +++ b/lib/connectors/memory.js @@ -189,7 +189,7 @@ Memory.prototype.define = function defineModel(definition) { if(!this.collection(m)) this.initCollection(m); }; -Memory.prototype.create = function create(model, data, options, callback) { +Memory.prototype._createSync = function(model, data, fn) { // FIXME: [rfeng] We need to generate unique ids based on the id type // FIXME: [rfeng] We don't support composite ids yet var currentId = this.collectionSeq(model); @@ -207,18 +207,27 @@ Memory.prototype.create = function create(model, data, options, callback) { var idName = this.idName(model); id = (props[idName] && props[idName].type && props[idName].type(id)) || id; this.setIdValue(model, data, id); - if(!this.collection(model)) { + if (!this.collection(model)) { this.collection(model, {}); } - if (this.collection(model)[id]) { - return process.nextTick(function() { - callback(new Error('Duplicate entry for ' + model + '.' + idName)); - }); - } + if (this.collection(model)[id]) + return fn(new Error('Duplicate entry for ' + model + '.' + idName)); this.collection(model)[id] = serialize(data); - this.saveToFile(id, callback); + fn(null, id); +}; + +Memory.prototype.create = function create(model, data, options, callback) { + var self = this; + this._createSync(model, data, function(err, id) { + if (err) { + return process.nextTick(function() { + callback(err); + }); + }; + self.saveToFile(id, callback); + }); }; Memory.prototype.updateOrCreate = function (model, data, options, callback) { @@ -237,6 +246,36 @@ Memory.prototype.updateOrCreate = function (model, data, options, callback) { }); }; +Memory.prototype.findOrCreate = function(model, filter, data, callback) { + var self = this; + var nodes = self._findAllSkippingIncludes(model, filter); + var found = nodes[0]; + + if(!found) { + // Calling _createSync to update the collection in a sync way and to guarantee to create it in the same turn of even loop + return self._createSync(model, data, function(err, id) { + if (err) return callback(err); + self.saveToFile(id, function(err, id) { + self.setIdValue(model, data, id); + callback(err, data, true); + }); + }); + } + + if (!filter || !filter.include) { + return process.nextTick(function() { + callback(null, found, false); + }); + } + + self._models[model].model.include(nodes[0], filter.include, {}, function(err, nodes) { + process.nextTick(function() { + if (err) return callback(err); + callback(null, nodes[0], false); + }); + }); +}; + Memory.prototype.save = function save(model, data, options, callback) { var self = this; var id = this.getIdValue(model, data); @@ -312,8 +351,7 @@ function getValue(obj, path) { return val; } -Memory.prototype.all = function all(model, filter, options, callback) { - var self = this; +Memory.prototype._findAllSkippingIncludes = function(model, filter) { var nodes = Object.keys(this.collection(model)).map(function (key) { return this.fromDb(model, this.collection(model)[key]); }.bind(this)); @@ -364,15 +402,8 @@ Memory.prototype.all = function all(model, filter, options, callback) { var limit = filter.limit || nodes.length; nodes = nodes.slice(skip, skip + limit); } - - process.nextTick(function () { - if (filter && filter.include) { - self._models[model].model.include(nodes, filter.include, options, callback); - } else { - callback(null, nodes); - } - }); - + return nodes; + function sorting(a, b) { var undefinedA, undefinedB; @@ -393,6 +424,19 @@ Memory.prototype.all = function all(model, filter, options, callback) { } }; +Memory.prototype.all = function all(model, filter, options, callback) { + var self = this; + var nodes = self._findAllSkippingIncludes(model, filter); + + process.nextTick(function() { + if (filter && filter.include) { + self._models[model].model.include(nodes, filter.include, options, callback); + } else { + callback(null, nodes); + } + }); +}; + function applyFilter(filter) { var where = filter.where; if (typeof where === 'function') { diff --git a/test/memory.test.js b/test/memory.test.js index e8244392..8cd8fa3a 100644 --- a/test/memory.test.js +++ b/test/memory.test.js @@ -345,7 +345,6 @@ describe('Memory connector', function() { } }, function (err, users) { should.not.exist(err); - console.log(users); users.length.should.be.equal(5); done(); }); @@ -695,6 +694,38 @@ describe('Memory connector', function() { }); + describe('findOrCreate', function() { + var ds, Cars; + before(function() { + ds = new DataSource({connector: 'memory'}); + Cars = ds.define('Cars', { + color: String + }); + }); + + it('should create a specific object once and in the subsequent calls it should find it', function(done) { + var creationNum = 0; + async.times(100, function(n, next) { + var initialData = {color: 'white'}; + var query = {'where': initialData}; + Cars.findOrCreate(query, initialData, function(err, car, created) { + if (created) creationNum++; + next(err, car); + }); + }, function(err, cars) { + if (err) done(err); + Cars.find(function(err, data) { + if (err) done(err); + data.length.should.equal(1); + data[0].color.should.equal('white'); + creationNum.should.equal(1); + done(); + }); + }); + }); + }); + + describe('automigrate when NO models are attached', function() { var ds; beforeEach(function() {