diff --git a/lib/dao.js b/lib/dao.js index 954f3052..d63dedbd 100644 --- a/lib/dao.js +++ b/lib/dao.js @@ -780,15 +780,18 @@ DataAccessObject.prototype.remove = DataAccessObject.prototype.delete = DataAccessObject.prototype.destroy = function (cb) { if (stillConnecting(this.getDataSource(), this, arguments)) return; + var Model = this.constructor; + var id = getIdValue(this.constructor, this); this.trigger('destroy', function (destroyed) { - this._adapter().destroy(this.constructor.modelName, getIdValue(this.constructor, this), function (err) { + this._adapter().destroy(this.constructor.modelName, id, function (err) { if (err) { return cb(err); } destroyed(function () { if (cb) cb(); + Model.emit('deleted', id); }); }.bind(this)); }); @@ -862,7 +865,7 @@ DataAccessObject.prototype.updateAttributes = function updateAttributes(data, cb } done.call(inst, function () { saveDone.call(inst, function () { - cb(err, inst); + if(cb) cb(err, inst); if(!err) Model.emit('changed', inst); }); }); diff --git a/test/events.js b/test/events.js new file mode 100644 index 00000000..b2867591 --- /dev/null +++ b/test/events.js @@ -0,0 +1,81 @@ +var should = require('./init.js'); + +describe('events', function() { + beforeEach(function(done) { + var test = this; + this.db = getSchema(); + this.TestModel = this.db.define('TestModel'); + this.db.automigrate(function(err) { + if(err) return done(err); + test.TestModel.create(function(err, inst) { + if(err) return done(err); + test.inst = inst; + done(); + }); + }); + this.shouldEmitEvent = function(eventName, listener, done) { + var timeout = setTimeout(function() { + done(new Error('did not emit ' + eventName)); + }, 100); + this.TestModel.on(eventName, function() { + clearTimeout(timeout); + listener.apply(this, arguments); + done(); + }); + } + }); + + describe('changed', function() { + it('should be emitted after save', function(done) { + var model = new this.TestModel({name: 'foobar'}); + this.shouldEmitEvent('changed', assertValidChangedArgs, done); + model.save(); + }); + it('should be emitted after upsert', function(done) { + this.shouldEmitEvent('changed', assertValidChangedArgs, done); + this.TestModel.upsert({name: 'batbaz'}); + }); + it('should be emitted after create', function(done) { + this.shouldEmitEvent('changed', assertValidChangedArgs, done); + this.TestModel.create({name: '...'}); + }); + it('should be emitted after updateAttributes', function(done) { + var test = this; + this.TestModel.create({name: 'bazzy'}, function(err, model) { + // prevent getting the changed event from "create" + process.nextTick(function() { + test.shouldEmitEvent('changed', assertValidChangedArgs, done); + model.updateAttributes({name: 'foo'}); + }); + }); + }); + }); + + describe('deleted', function() { + it('should be emitted after destroy', function(done) { + this.shouldEmitEvent('deleted', assertValidDeletedArgs, done); + this.inst.destroy(); + }); + it('should be emitted after deleteById', function(done) { + this.shouldEmitEvent('deleted', assertValidDeletedArgs, done); + this.TestModel.deleteById(this.inst.id); + }); + }); + + describe('deletedAll', function() { + it('should be emitted after destroyAll', function(done) { + this.shouldEmitEvent('deletedAll', function(where) { + where.name.should.equal('foo'); + }, done); + this.TestModel.destroyAll({name: 'foo'}); + }); + }); +}); + +function assertValidChangedArgs(obj) { + obj.should.have.property('id'); +} + +function assertValidDeletedArgs(id) { + id.should.be.ok; +} \ No newline at end of file diff --git a/test/hooks.test.js b/test/hooks.test.js index 2610f1b3..f613122b 100644 --- a/test/hooks.test.js +++ b/test/hooks.test.js @@ -402,6 +402,8 @@ describe('hooks', function () { }); }); + + function addHooks(name, done) { var called = false, random = String(Math.floor(Math.random() * 1000)); User['before' + name] = function (next, data) {