Merge pull request #449 from strongloop/feature/promises-for-operation-hooks
Promises for operation hooks
This commit is contained in:
commit
9e0a22141a
13
lib/model.js
13
lib/model.js
|
@ -561,16 +561,27 @@ ModelBaseClass.observe = function(operation, listener) {
|
|||
ModelBaseClass.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(fn, next) { fn(context, next); },
|
||||
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;
|
||||
}
|
||||
|
||||
ModelBaseClass._notifyBaseObservers = function(operation, context, callback) {
|
||||
|
|
28
lib/utils.js
28
lib/utils.js
|
@ -9,6 +9,7 @@ exports.defineCachedRelations = defineCachedRelations;
|
|||
exports.sortObjectsByIds = sortObjectsByIds;
|
||||
exports.setScopeValuesFromWhere = setScopeValuesFromWhere;
|
||||
exports.mergeQuery = mergeQuery;
|
||||
exports.createPromiseCallback = createPromiseCallback
|
||||
|
||||
var traverse = require('traverse');
|
||||
|
||||
|
@ -340,3 +341,30 @@ function sortObjectsByIds(idName, ids, objects, strict) {
|
|||
|
||||
return heading.concat(tailing);
|
||||
};
|
||||
|
||||
function createPromiseCallback() {
|
||||
var cb;
|
||||
|
||||
if (!global.Promise) {
|
||||
cb = function(){};
|
||||
cb.promise = {};
|
||||
Object.defineProperty(cb.promise, 'then', { get: throwPromiseNotDefined });
|
||||
Object.defineProperty(cb.promise, 'catch', { get: throwPromiseNotDefined });
|
||||
return cb;
|
||||
}
|
||||
|
||||
var promise = new Promise(function (resolve, reject) {
|
||||
cb = function (err, data) {
|
||||
if (err) return reject(err);
|
||||
return resolve(data);
|
||||
};
|
||||
});
|
||||
cb.promise = promise;
|
||||
return cb;
|
||||
}
|
||||
|
||||
function throwPromiseNotDefined() {
|
||||
throw new Error(
|
||||
'Your Node runtime does support ES6 Promises. ' +
|
||||
'Set "global.Promise" to your preferred implementation of promises.');
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
"node >= 0.6"
|
||||
],
|
||||
"devDependencies": {
|
||||
"bluebird": "^2.9.9",
|
||||
"mocha": "^2.1.0",
|
||||
"should": "^5.0.0"
|
||||
},
|
||||
|
|
|
@ -93,6 +93,49 @@ describe('async observer', function() {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('resolves promises returned by observers', function(done) {
|
||||
TestModel.observe('event', function(ctx) {
|
||||
return Promise.resolve('value-to-ignore');
|
||||
});
|
||||
TestModel.notifyObserversOf('event', {}, function(err, ctx) {
|
||||
// the test times out when the promises are not supported
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('handles rejected promise returned by an observer', function(done) {
|
||||
var testError = new Error('expected test error');
|
||||
TestModel.observe('event', function(ctx) {
|
||||
return Promise.reject(testError);
|
||||
});
|
||||
TestModel.notifyObserversOf('event', {}, function(err, ctx) {
|
||||
err.should.eql(testError);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('returns a promise when no callback is provided', function() {
|
||||
var context = { value: 'a-test-context' };
|
||||
var p = TestModel.notifyObserversOf('event', context);
|
||||
(p !== undefined).should.be.true;
|
||||
return p.then(function(result) {
|
||||
result.should.eql(context);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns a rejected promise when no callback is provided', function() {
|
||||
var testError = new Error('expected test error');
|
||||
TestModel.observe('event', function(ctx, next) { next(testError); });
|
||||
var p = TestModel.notifyObserversOf('event', context);
|
||||
return p.then(
|
||||
function(result) {
|
||||
throw new Error('The promise should have been rejected.');
|
||||
},
|
||||
function(err) {
|
||||
err.should.eql(testError);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function pushAndNext(array, value) {
|
||||
|
|
|
@ -25,4 +25,8 @@ if (!('getModelBuilder' in global)) {
|
|||
global.getModelBuilder = function () {
|
||||
return new ModelBuilder();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (!('Promise' in global)) {
|
||||
global.Promise = require('bluebird');
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue