From 0776c519946d908f3650951ebc1a74403b37759d Mon Sep 17 00:00:00 2001 From: Anatoliy Chakkaev Date: Sun, 31 Mar 2013 13:40:37 +0400 Subject: [PATCH] Batch create --- docs/model.md | 9 +++++++++ lib/model.js | 34 +++++++++++++++++++++++++++++++--- test/manipulation.test.js | 27 ++++++++++++++++++++++++++- 3 files changed, 66 insertions(+), 4 deletions(-) diff --git a/docs/model.md b/docs/model.md index 595bb826..bfe08a70 100644 --- a/docs/model.md +++ b/docs/model.md @@ -22,6 +22,15 @@ instance. console.log(user instanceof User); }); +When called with array of objects as first argument `Model.create` creates bunch +of records. Both `err` and `model instance` arguments passed to callback will be +arrays then. When no errors happened `err` argument will be null. + +The value returned from `Model.create` depends on second argument too. In case +of Array it will return an array of instances, otherwise single instance. But be +away, this instance(s) aren't save to database yet and you have to wait until +callback called to be able to do id-sensitive stuff. + ### Model.prototype.save([options[, callback]]); Save instance to database, options is an object {validate: true, throws: false}, diff --git a/lib/model.js b/lib/model.js index aeb57e16..3c023f98 100644 --- a/lib/model.js +++ b/lib/model.js @@ -160,7 +160,8 @@ AbstractClass.prototype.whatTypeName = function (propName) { AbstractClass.create = function (data, callback) { if (stillConnecting(this.schema, this, arguments)) return; - var modelName = this.modelName; + var Model = this; + var modelName = Model.modelName; if (typeof data === 'function') { callback = data; @@ -171,12 +172,39 @@ AbstractClass.create = function (data, callback) { callback = function () {}; } + if (data instanceof Array) { + var instances = []; + var errors = new Array(data.length); + var gotError = false; + var wait = data.length; + if (wait === 0) callback(null, []); + + var instances = data.map(function(d, i) { + return Model.create(d, function(err, inst) { + // console.log('got', i, err, inst, inst.errors); + if (err) { + errors[i] = err; + gotError = true; + } + modelCreated(); + }); + }); + + return instances; + + function modelCreated() { + if (--wait === 0) { + callback(gotError ? errors : null, instances); + } + } + } + var obj; // if we come from save - if (data instanceof this && !data.id) { + if (data instanceof Model && !data.id) { obj = data; } else { - obj = new this(data); + obj = new Model(data); } data = obj.toObject(true); diff --git a/test/manipulation.test.js b/test/manipulation.test.js index f8754719..170d9af5 100644 --- a/test/manipulation.test.js +++ b/test/manipulation.test.js @@ -79,10 +79,35 @@ describe('manipulation', function() { should.exist(this.id); Person.afterCreate = null; next(); - setTimeout(done, 10); + setTimeout(done, 30); }; Person.create(); }); + + it('should create batch of objects', function(done) { + var batch = [{name: 'Shaltay'}, {name: 'Boltay'}, {}]; + Person.create(batch, function(e, ps) { + should.not.exist(e); + should.exist(ps); + ps.should.be.instanceOf(Array); + ps.should.have.lengthOf(batch.length); + + Person.validatesPresenceOf('name'); + Person.create(batch, function(errors, persons) { + delete Person._validations; + should.exist(errors); + errors.should.have.lengthOf(batch.length); + should.not.exist(errors[0]); + should.not.exist(errors[1]); + should.exist(errors[2]); + + should.exist(persons); + persons.should.have.lengthOf(batch.length); + persons[0].errors.should.be.false; + done(); + }).should.be.instanceOf(Array); + }).should.have.lengthOf(3); + }); }); describe('save', function() {