loopback-datasource-juggler/lib/observer.js

99 lines
2.9 KiB
JavaScript

var async = require('async');
var utils = require('./utils');
module.exports = ObserverMixin;
/**
* ObserverMixin class. Use to add observe/notifyObserversOf APIs to other
* classes.
*
* @class ObserverMixin
*/
function ObserverMixin() {
}
/**
* Register an asynchronous observer for the given operation (event).
* @param {String} operation The operation name.
* @callback {function} listener The listener function. It will be invoked with
* `this` set to the model constructor, e.g. `User`.
* @param {Object} context Operation-specific context.
* @param {function(Error=)} next The callback to call when the observer
* has finished.
* @end
*/
ObserverMixin.observe = function(operation, listener) {
this._observers = this._observers || {};
if (!this._observers[operation]) {
this._observers[operation] = [];
}
this._observers[operation].push(listener);
};
/**
* Unregister an asynchronous observer for the given operation (event).
* @param {String} operation The operation name.
* @callback {function} listener The listener function.
* @end
*/
ObserverMixin.removeObserver = function(operation, listener) {
if (!(this._observers && this._observers[operation])) return;
var index = this._observers[operation].indexOf(listener);
if (index !== -1) {
return this._observers[operation].splice(index, 1);
}
};
/**
* Unregister all asynchronous observers for the given operation (event).
* @param {String} operation The operation name.
* @end
*/
ObserverMixin.clearObservers = function(operation) {
if (!(this._observers && this._observers[operation])) return;
this._observers[operation].length = 0;
};
/**
* Invoke all async observers for the given operation.
* @param {String} operation The operation name.
* @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];
if (!callback) callback = utils.createPromiseCallback();
this._notifyBaseObservers(operation, context, function doNotify(err) {
if (err) return callback(err, context);
if (!observers || !observers.length) return callback(null, context);
async.eachSeries(
observers,
function notifySingleObserver(fn, next) {
var retval = fn(context, next);
if (retval && typeof retval.then === 'function') {
retval.then(
function() { next(); },
next // error handler
);
}
},
function(err) { callback(err, context) }
);
});
return callback.promise;
}
ObserverMixin._notifyBaseObservers = function(operation, context, callback) {
if (this.base && this.base.notifyObserversOf)
this.base.notifyObserversOf(operation, context, callback);
else
callback();
}