From 7425a5aed3269eb229893caa40790199ada6e4d7 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Mon, 16 Sep 2013 23:59:04 +0100 Subject: [PATCH] Adds hasMany hooks.beforeSave (#324) --- lib/Associations/Many.js | 58 +++++--- test/integration/association-hasmany-hooks.js | 125 ++++++++++++++++++ 2 files changed, 161 insertions(+), 22 deletions(-) create mode 100644 test/integration/association-hasmany-hooks.js diff --git a/lib/Associations/Many.js b/lib/Associations/Many.js index e0f35fb6..53b46a55 100644 --- a/lib/Associations/Many.js +++ b/lib/Associations/Many.js @@ -1,5 +1,6 @@ var _ = require("lodash"); var InstanceConstructor = require("../Instance").Instance; +var Hook = require("../Hook"); var Settings = require("../Settings"); var Property = require("../Property"); var ErrorCodes = require("../ErrorCodes"); @@ -29,6 +30,7 @@ exports.prepare = function (Model, associations) { break; } } + if (props === null) { props = {}; } else { @@ -43,6 +45,7 @@ exports.prepare = function (Model, associations) { name : name, model : OtherModel || Model, props : props, + hooks : opts.hooks || {}, autoFetch : opts.autoFetch || false, autoFetchLimit : opts.autoFetchLimit || 2, // I'm not sure the next key is used.. @@ -321,20 +324,38 @@ function extendInstance(Model, Instance, Driver, association, opts, createInstan } var Association = Associations.pop(); - - Association.save(function (err) { + var saveAssociation = function (err) { if (err) { return cb(err); } - var data = {}; + Association.save(function (err) { + if (err) { + return cb(err); + } - for (var k in opts) { - data[k] = opts[k]; - } + var data = {}; + + for (var k in opts) { + data[k] = opts[k]; + } + + if (Driver.hasMany) { + return Driver.hasMany(Model, association).add(Instance, Association, data, function (err) { + if (err) { + return cb(err); + } + + savedAssociations.push(Association); + + return saveNextAssociation(); + }); + } - if (Driver.hasMany) { - return Driver.hasMany(Model, association).add(Instance, Association, data, function (err) { + util.populateConditions(Model, Object.keys(association.mergeId), Instance, data); + util.populateConditions(association.model, Object.keys(association.mergeAssocId), Association, data); + + Driver.insert(association.mergeTable, data, null, function (err) { if (err) { return cb(err); } @@ -343,21 +364,14 @@ function extendInstance(Model, Instance, Driver, association, opts, createInstan return saveNextAssociation(); }); - } - - util.populateConditions(Model, Object.keys(association.mergeId), Instance, data); - util.populateConditions(association.model, Object.keys(association.mergeAssocId), Association, data); - - Driver.insert(association.mergeTable, data, null, function (err) { - if (err) { - return cb(err); - } - - savedAssociations.push(Association); - - return saveNextAssociation(); }); - }); + }; + + if (Object.keys(association.props).length) { + Hook.wait(Association, association.hooks.beforeSave, saveAssociation, opts); + } else { + Hook.wait(Association, association.hooks.beforeSave, saveAssociation); + } }; return saveNextAssociation(); diff --git a/test/integration/association-hasmany-hooks.js b/test/integration/association-hasmany-hooks.js new file mode 100644 index 00000000..50b07e06 --- /dev/null +++ b/test/integration/association-hasmany-hooks.js @@ -0,0 +1,125 @@ +var should = require('should'); +var helper = require('../support/spec_helper'); +var ORM = require('../../'); + +describe("hasMany hooks", function() { + var db = null; + var Person = null; + var Pet = null; + + var setup = function (props, opts) { + return function (done) { + db.settings.set('instance.cache', false); + + Person = db.define('person', { + name : String, + }); + Pet = db.define('pet', { + name : String + }); + Person.hasMany('pets', Pet, props || {}, opts || {}); + + return helper.dropSync([ Person, Pet ], done); + }; + }; + + before(function(done) { + helper.connect(function (connection) { + db = connection; + done(); + }); + }); + + describe("beforeSave", function () { + var had_extra = false; + + before(setup({ + born : Date + }, { + hooks : { + beforeSave: function (extra, next) { + had_extra = (typeof extra == "object"); + return next(); + } + } + })); + + it("should pass extra data to hook if extra defined", function (done) { + Person.create({ + name : "John" + }, function (err, John) { + Pet.create({ + name : "Deco" + }, function (err, Deco) { + John.addPets(Deco, function (err) { + should.not.exist(err); + + had_extra.should.be.true; + + return done(); + }); + }); + }); + }); + }); + + describe("beforeSave", function () { + var had_extra = false; + + before(setup({}, { + hooks : { + beforeSave: function (next) { + next.should.be.a("function"); + return next(); + } + } + })); + + it("should not pass extra data to hook if extra defined", function (done) { + Person.create({ + name : "John" + }, function (err, John) { + Pet.create({ + name : "Deco" + }, function (err, Deco) { + John.addPets(Deco, function (err) { + should.not.exist(err); + + return done(); + }); + }); + }); + }); + }); + + describe("beforeSave", function () { + var had_extra = false; + + before(setup({}, { + hooks : { + beforeSave: function (next) { + setTimeout(function () { + return next(new Error('blocked')); + }, 100); + } + } + })); + + it("should block if error returned", function (done) { + Person.create({ + name : "John" + }, function (err, John) { + Pet.create({ + name : "Deco" + }, function (err, Deco) { + John.addPets(Deco, function (err) { + should.exist(err); + err.message.should.equal('blocked'); + + return done(); + }); + }); + }); + }); + }); +});