Allow before hooks to pass arguments to next()

This commit is contained in:
Raymond Feng 2014-07-08 10:54:13 -07:00
parent bf17304558
commit 9325ce316b
4 changed files with 52 additions and 14 deletions

View File

@ -178,8 +178,8 @@ DataAccessObject.create = function (data, callback) {
}); });
}); });
}, obj); }, obj);
}, obj); }, obj, callback);
}, obj); }, obj, callback);
} }
// for chaining // for chaining
@ -1032,8 +1032,8 @@ DataAccessObject.prototype.save = function (options, callback) {
}); });
}); });
}); });
}, data); }, data, callback);
}, data); }, data, callback);
} }
}; };
@ -1136,7 +1136,7 @@ DataAccessObject.prototype.remove =
Model.emit('deleted', id); Model.emit('deleted', id);
}); });
}.bind(this)); }.bind(this));
}); }, null, cb);
}; };
/** /**
@ -1198,7 +1198,8 @@ DataAccessObject.prototype.updateAttributes = function updateAttributes(data, cb
typedData[key] = inst[key]; typedData[key] = inst[key];
} }
inst._adapter().updateAttributes(model, getIdValue(inst.constructor, inst), inst.constructor._forDB(typedData), function (err) { inst._adapter().updateAttributes(model, getIdValue(inst.constructor, inst),
inst.constructor._forDB(typedData), function (err) {
done.call(inst, function () { done.call(inst, function () {
saveDone.call(inst, function () { saveDone.call(inst, function () {
if(cb) cb(err, inst); if(cb) cb(err, inst);
@ -1206,8 +1207,8 @@ DataAccessObject.prototype.updateAttributes = function updateAttributes(data, cb
}); });
}); });
}); });
}, data); }, data, cb);
}, data); }, data, cb);
} }
}, data); }, data);
}; };

View File

@ -27,7 +27,7 @@ Hookable.beforeDestroy = null;
Hookable.afterDestroy = null; Hookable.afterDestroy = null;
// TODO: Evaluate https://github.com/bnoguchi/hooks-js/ // TODO: Evaluate https://github.com/bnoguchi/hooks-js/
Hookable.prototype.trigger = function trigger(actionName, work, data) { Hookable.prototype.trigger = function trigger(actionName, work, data, callback) {
var capitalizedName = capitalize(actionName); var capitalizedName = capitalize(actionName);
var beforeHook = this.constructor["before" + capitalizedName] var beforeHook = this.constructor["before" + capitalizedName]
|| this.constructor["pre" + capitalizedName]; || this.constructor["pre" + capitalizedName];
@ -42,8 +42,13 @@ Hookable.prototype.trigger = function trigger(actionName, work, data) {
// we only call "before" hook when we have actual action (work) to perform // we only call "before" hook when we have actual action (work) to perform
if (work) { if (work) {
if (beforeHook) { if (beforeHook) {
// before hook should be called on instance with one param: callback // before hook should be called on instance with two parameters: next and data
beforeHook.call(inst, function () { beforeHook.call(inst, function () {
// Check arguments to next(err, result)
if (arguments.length) {
return callback && callback.apply(null, arguments);
}
// No err & result is present, proceed with the real work
// actual action also have one param: callback // actual action also have one param: callback
work.call(inst, next); work.call(inst, next);
}, data); }, data);

View File

@ -389,7 +389,7 @@ Validatable.prototype.isValid = function (callback, data) {
validationsDone.call(inst, function () { validationsDone.call(inst, function () {
callback(valid); callback(valid);
}); });
}); }, data, callback);
} }
return valid; return valid;
} }
@ -440,7 +440,7 @@ Validatable.prototype.isValid = function (callback, data) {
} }
} }
}, data); }, data, callback);
if (async) { if (async) {
// in case of async validation we should return undefined here, // in case of async validation we should return undefined here,

View File

@ -81,7 +81,27 @@ describe('hooks', function () {
} }
User.afterCreate = function () { User.afterCreate = function () {
throw new Error('shouldn\'t be called') throw new Error('shouldn\'t be called');
};
User.create(function (err, user) {
User.dataSource.connector.create = old;
done();
});
});
it('afterCreate should not be triggered on failed beforeCreate', function (done) {
User.beforeCreate = function (next, data) {
// Skip next()
next(new Error('fail in beforeCreate'));
};
var old = User.dataSource.connector.create;
User.dataSource.connector.create = function (modelName, id, cb) {
throw new Error('shouldn\'t be called');
}
User.afterCreate = function () {
throw new Error('shouldn\'t be called');
}; };
User.create(function (err, user) { User.create(function (err, user) {
User.dataSource.connector.create = old; User.dataSource.connector.create = old;
@ -173,6 +193,18 @@ describe('hooks', function () {
}); });
}); });
it('beforeSave should be able to skip next', function (done) {
User.create(function (err, user) {
User.beforeSave = function (next, data) {
next(null, 'XYZ');
};
user.save(function(err, result) {
result.should.be.eql('XYZ');
done();
});
});
});
}); });
describe('update', function () { describe('update', function () {
@ -221,7 +253,7 @@ describe('hooks', function () {
it('should not trigger after-hook on failed save', function (done) { it('should not trigger after-hook on failed save', function (done) {
User.afterUpdate = function () { User.afterUpdate = function () {
should.fail('afterUpdate shouldn\'t be called') should.fail('afterUpdate shouldn\'t be called');
}; };
User.create(function (err, user) { User.create(function (err, user) {
var save = User.dataSource.connector.save; var save = User.dataSource.connector.save;