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.
|
* Invoke all async observers for the given operation(s).
|
||||||
* @param {String} operation The operation name.
|
* @param {String|String[]} operation The operation name(s).
|
||||||
* @param {Object} context Operation-specific context.
|
* @param {Object} context Operation-specific context.
|
||||||
* @param {function(Error=)} callback The callback to call when all observers
|
* @param {function(Error=)} callback The callback to call when all observers
|
||||||
* has finished.
|
* has finished.
|
||||||
*/
|
*/
|
||||||
ObserverMixin.notifyObserversOf = function(operation, context, callback) {
|
ObserverMixin.notifyObserversOf = function(operation, context, callback) {
|
||||||
var observers = this._observers && this._observers[operation];
|
var self = this;
|
||||||
|
|
||||||
if (!callback) callback = utils.createPromiseCallback();
|
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) {
|
this._notifyBaseObservers(operation, context, function doNotify(err) {
|
||||||
if (err) return callback(err, context);
|
if (err) return callback(err, context);
|
||||||
if (!observers || !observers.length) return callback(null, 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) {
|
ObserverMixin.notifyObserversAround = function(operation, context, fn, callback) {
|
||||||
var self = this;
|
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,
|
return self.notifyObserversOf('before ' + operation, context,
|
||||||
function(err, context) {
|
function(err, context) {
|
||||||
if (err) return callback(err, context);
|
if (err) return callback(err);
|
||||||
|
|
||||||
function cbForWork(err) {
|
function cbForWork(err) {
|
||||||
if (err) return callback(err, context);
|
var args = [].slice.call(arguments, 0);
|
||||||
var returnedArgs = [].slice.call(arguments, 1);
|
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;
|
context.results = returnedArgs;
|
||||||
|
// Notify after observers
|
||||||
self.notifyObserversOf('after ' + operation, context,
|
self.notifyObserversOf('after ' + operation, context,
|
||||||
function(err, context) {
|
function(err, context) {
|
||||||
if (err) return callback(err, context);
|
if (err) return callback(err, context);
|
||||||
var results = returnedArgs;
|
var results = returnedArgs;
|
||||||
if (context) {
|
if (context && Array.isArray(context.results)) {
|
||||||
|
// Pickup the results from context
|
||||||
results = context.results;
|
results = context.results;
|
||||||
}
|
}
|
||||||
|
// Build the list of params for final callback
|
||||||
var args = [err].concat(results);
|
var args = [err].concat(results);
|
||||||
callback.apply(null, args);
|
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) {
|
it('inherits observers from base model', function(done) {
|
||||||
var notifications = [];
|
var notifications = [];
|
||||||
TestModel.observe('event', pushAndNext(notifications, 'base'));
|
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) {
|
it('does not modify observers in the base model', function(done) {
|
||||||
var notifications = [];
|
var notifications = [];
|
||||||
TestModel.observe('event', pushAndNext(notifications, 'base'));
|
TestModel.observe('event', pushAndNext(notifications, 'base'));
|
||||||
|
@ -194,6 +222,57 @@ describe('async observer', function() {
|
||||||
done();
|
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) {
|
it('resolves promises returned by observers', function(done) {
|
||||||
|
|
Loading…
Reference in New Issue