diff --git a/lib/dao.js b/lib/dao.js index 4e868279..81c542f3 100644 --- a/lib/dao.js +++ b/lib/dao.js @@ -160,39 +160,38 @@ DataAccessObject.create = function (data, callback) { } if (Array.isArray(data)) { - var instances = []; - var errors = Array(data.length); - var gotError = false; - var wait = data.length; - if (wait === 0) { - callback(null, []); - } - - for (var i = 0; i < data.length; i += 1) { - (function (d, i) { - Model = self.lookupModel(d); // data-specific - instances.push(Model.create(d, function (err, inst) { - if (err) { - errors[i] = err; - gotError = true; - } - modelCreated(); - })); - })(data[i], i); - } - - return instances; - - function modelCreated() { - if (--wait === 0) { - callback(gotError ? errors : null, instances); - if(!gotError) { - instances.forEach(function(inst) { - inst.constructor.emit('changed'); - }); - } + // Undefined item will be skipped by async.map() which internally uses + // Array.prototype.map(). The following loop makes sure all items are + // iterated + for (var i = 0, n = data.length; i < n; i++) { + if (data[i] === undefined) { + data[i] = {}; } } + async.map(data, function(item, done) { + self.create(item, function(err, result) { + // Collect all errors and results + done(null, {err: err, result: result || item}); + }); + }, function(err, results) { + if (err) { + return callback && callback(err, results); + } + // Convert the results into two arrays + var errors = null; + var data = []; + for (var i = 0, n = results.length; i < n; i++) { + if (results[i].err) { + if (!errors) { + errors = []; + } + errors[i] = results[i].err; + } + data[i] = results[i].result; + } + callback && callback(errors, data); + }); + return data; } var enforced = {}; diff --git a/test/manipulation.test.js b/test/manipulation.test.js index 3f3dbed1..727e286a 100644 --- a/test/manipulation.test.js +++ b/test/manipulation.test.js @@ -153,6 +153,29 @@ describe('manipulation', function () { }).should.be.instanceOf(Array); }).should.have.lengthOf(3); }); + + it('should create batch of objects with beforeCreate', function(done) { + Person.beforeCreate = function(next, data) { + if (data && data.name === 'A') { + return next(null, {id: 'a', name: 'A'}); + } else { + return next(); + } + }; + var batch = [ + {name: 'A'}, + {name: 'B'}, + undefined + ]; + Person.create(batch, function(e, ps) { + should.not.exist(e); + should.exist(ps); + ps.should.be.instanceOf(Array); + ps.should.have.lengthOf(batch.length); + ps[0].should.be.eql({id: 'a', name: 'A'}); + done(); + }); + }); }); describe('save', function () {