Skip to content

Commit

Permalink
Merge pull request #65 from strongloop/feature/change-hook
Browse files Browse the repository at this point in the history
Add change / delete events
  • Loading branch information
ritch committed Jan 30, 2014
2 parents 38e31b3 + e909749 commit 61a54da
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 3 deletions.
22 changes: 19 additions & 3 deletions lib/dao.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ DataAccessObject.create = function (data, callback) {
function modelCreated() {
if (--wait === 0) {
callback(gotError ? errors : null, instances);
if(!gotError) instances.forEach(Model.emit.bind('changed'));
}
}
}
Expand Down Expand Up @@ -168,6 +169,7 @@ DataAccessObject.create = function (data, callback) {
saveDone.call(obj, function () {
createDone.call(obj, function () {
callback(err, obj);
if(!err) Model.emit('changed', obj);
});
});
}, obj);
Expand Down Expand Up @@ -627,6 +629,7 @@ DataAccessObject.remove =
DataAccessObject.deleteAll =
DataAccessObject.destroyAll = function destroyAll(where, cb) {
if (stillConnecting(this.getDataSource(), this, arguments)) return;
var Model = this;

if (!cb && 'function' === typeof where) {
cb = where;
Expand All @@ -635,13 +638,15 @@ DataAccessObject.remove =
if (!where) {
this.getDataSource().connector.destroyAll(this.modelName, function (err, data) {
cb && cb(err, data);
if(!err) Model.emit('deletedAll');
}.bind(this));
} else {
// Support an optional where object
where = removeUndefined(where);
where = this._coerce(where);
this.getDataSource().connector.destroyAll(this.modelName, where, function (err, data) {
cb && cb(err, data);
if(!err) Model.emit('deletedAll', where);
}.bind(this));
}
};
Expand All @@ -655,11 +660,13 @@ DataAccessObject.removeById =
DataAccessObject.deleteById =
DataAccessObject.destroyById = function deleteById(id, cb) {
if (stillConnecting(this.getDataSource(), this, arguments)) return;
var Model = this;

this.getDataSource().connector.destroy(this.modelName, id, function (err) {
if ('function' === typeof cb) {
cb(err);
}
if(!err) Model.emit('deleted', id);
}.bind(this));
};

Expand Down Expand Up @@ -704,6 +711,7 @@ setRemoting(DataAccessObject.count, {
*/
DataAccessObject.prototype.save = function (options, callback) {
if (stillConnecting(this.getDataSource(), this, arguments)) return;
var Model = this.constructor;

if (typeof options == 'function') {
callback = options;
Expand Down Expand Up @@ -760,6 +768,9 @@ DataAccessObject.prototype.save = function (options, callback) {
updateDone.call(inst, function () {
saveDone.call(inst, function () {
callback(err, inst);
if(!err) {
Model.emit('changed', inst);
}
});
});
});
Expand Down Expand Up @@ -789,15 +800,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));
});
Expand Down Expand Up @@ -831,7 +845,8 @@ DataAccessObject.prototype.updateAttributes = function updateAttributes(data, cb
if (stillConnecting(this.getDataSource(), this, arguments)) return;

var inst = this;
var model = this.constructor.modelName;
var Model = this.constructor
var model = Model.modelName;

if (typeof data === 'function') {
cb = data;
Expand Down Expand Up @@ -870,7 +885,8 @@ 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);
});
});
});
Expand Down
81 changes: 81 additions & 0 deletions test/events.js
Original file line number Diff line number Diff line change
@@ -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;
}
2 changes: 2 additions & 0 deletions test/hooks.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down

0 comments on commit 61a54da

Please sign in to comment.