Enhance the apis and add more tests
This commit is contained in:
parent
12dea6e1cb
commit
621adf5435
|
@ -58,17 +58,36 @@ ObserverMixin.clearObservers = function(operation) {
|
|||
};
|
||||
|
||||
/**
|
||||
* Invoke all async observers for the given operation.
|
||||
* @param {String} operation The operation name.
|
||||
* Invoke all async observers for the given operation(s).
|
||||
* @param {String|String[]} operation The operation name(s).
|
||||
* @param {Object} context Operation-specific context.
|
||||
* @param {function(Error=)} callback The callback to call when all observers
|
||||
* has finished.
|
||||
*/
|
||||
ObserverMixin.notifyObserversOf = function(operation, context, callback) {
|
||||
var observers = this._observers && this._observers[operation];
|
||||
|
||||
var self = this;
|
||||
if (!callback) callback = utils.createPromiseCallback();
|
||||
|
||||
function createNotifier(op) {
|
||||
return function(ctx, done) {
|
||||
if (typeof ctx === 'function' && done === undefined) {
|
||||
done = ctx;
|
||||
ctx = context;
|
||||
}
|
||||
self.notifyObserversOf(op, context, done);
|
||||
};
|
||||
}
|
||||
|
||||
if (Array.isArray(operation)) {
|
||||
var tasks = [];
|
||||
for (var i = 0, n = operation.length; i < n; i++) {
|
||||
tasks.push(createNotifier(operation[i]));
|
||||
}
|
||||
return async.waterfall(tasks, callback);
|
||||
}
|
||||
|
||||
var observers = this._observers && this._observers[operation];
|
||||
|
||||
this._notifyBaseObservers(operation, context, function doNotify(err) {
|
||||
if (err) return callback(err, context);
|
||||
if (!observers || !observers.length) return callback(null, context);
|
||||
|
@ -115,21 +134,34 @@ ObserverMixin._notifyBaseObservers = function(operation, context, callback) {
|
|||
*/
|
||||
ObserverMixin.notifyObserversAround = function(operation, context, fn, callback) {
|
||||
var self = this;
|
||||
context = context || {};
|
||||
// Add callback to the context object so that an observer can skip other
|
||||
// ones by calling the callback function directly and not calling next
|
||||
if (context.end === undefined) {
|
||||
context.end = callback;
|
||||
}
|
||||
// First notify before observers
|
||||
return self.notifyObserversOf('before ' + operation, context,
|
||||
function(err, context) {
|
||||
if (err) return callback(err, context);
|
||||
if (err) return callback(err);
|
||||
|
||||
function cbForWork(err) {
|
||||
if (err) return callback(err, context);
|
||||
var returnedArgs = [].slice.call(arguments, 1);
|
||||
var args = [].slice.call(arguments, 0);
|
||||
if (err) return callback.apply(null, args);
|
||||
// Find the list of params from the callback in addition to err
|
||||
var returnedArgs = args.slice(1);
|
||||
// Set up the array of results
|
||||
context.results = returnedArgs;
|
||||
// Notify after observers
|
||||
self.notifyObserversOf('after ' + operation, context,
|
||||
function(err, context) {
|
||||
if (err) return callback(err, context);
|
||||
var results = returnedArgs;
|
||||
if (context) {
|
||||
if (context && Array.isArray(context.results)) {
|
||||
// Pickup the results from context
|
||||
results = context.results;
|
||||
}
|
||||
// Build the list of params for final callback
|
||||
var args = [err].concat(results);
|
||||
callback.apply(null, args);
|
||||
});
|
||||
|
|
|
@ -37,6 +37,18 @@ describe('async observer', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('allows multiple operations to be notified in one call', function(done) {
|
||||
var notifications = [];
|
||||
TestModel.observe('event1', pushAndNext(notifications, 'one'));
|
||||
TestModel.observe('event2', pushAndNext(notifications, 'two'));
|
||||
|
||||
TestModel.notifyObserversOf(['event1', 'event2'], {}, function(err) {
|
||||
if (err) return done(err);
|
||||
notifications.should.eql(['one', 'two']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('inherits observers from base model', function(done) {
|
||||
var notifications = [];
|
||||
TestModel.observe('event', pushAndNext(notifications, 'base'));
|
||||
|
@ -51,6 +63,22 @@ describe('async observer', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('allow multiple operations to be notified with base models', function(done) {
|
||||
var notifications = [];
|
||||
TestModel.observe('event1', pushAndNext(notifications, 'base1'));
|
||||
TestModel.observe('event2', pushAndNext(notifications, 'base2'));
|
||||
|
||||
var Child = TestModel.extend('Child');
|
||||
Child.observe('event1', pushAndNext(notifications, 'child1'));
|
||||
Child.observe('event2', pushAndNext(notifications, 'child2'));
|
||||
|
||||
Child.notifyObserversOf(['event1', 'event2'], {}, function(err) {
|
||||
if (err) return done(err);
|
||||
notifications.should.eql(['base1', 'child1', 'base2', 'child2']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('does not modify observers in the base model', function(done) {
|
||||
var notifications = [];
|
||||
TestModel.observe('event', pushAndNext(notifications, 'base'));
|
||||
|
@ -194,6 +222,57 @@ describe('async observer', function() {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow observers to skip other ones',
|
||||
function(done) {
|
||||
TestModel.observe('before invoke',
|
||||
function(context, next) {
|
||||
notifications.push('before invoke');
|
||||
context.end(null, 0);
|
||||
});
|
||||
TestModel.observe('after invoke',
|
||||
pushAndNext(notifications, 'after invoke'));
|
||||
|
||||
var context = {};
|
||||
|
||||
function work(done) {
|
||||
process.nextTick(function() {
|
||||
done(null, 1, 2);
|
||||
});
|
||||
}
|
||||
|
||||
TestModel.notifyObserversAround('invoke', context, work,
|
||||
function(err, r1) {
|
||||
r1.should.eql(0);
|
||||
notifications.should.eql(['before invoke']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow observers to tweak results',
|
||||
function(done) {
|
||||
TestModel.observe('after invoke',
|
||||
function(context, next) {
|
||||
notifications.push('after invoke');
|
||||
context.results = [3];
|
||||
next();
|
||||
});
|
||||
|
||||
var context = {};
|
||||
|
||||
function work(done) {
|
||||
process.nextTick(function() {
|
||||
done(null, 1, 2);
|
||||
});
|
||||
}
|
||||
|
||||
TestModel.notifyObserversAround('invoke', context, work,
|
||||
function(err, r1) {
|
||||
r1.should.eql(3);
|
||||
notifications.should.eql(['after invoke']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('resolves promises returned by observers', function(done) {
|
||||
|
|
Loading…
Reference in New Issue