From 76ebdcb91bef7638d0f708c3b0bed72b06c17943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Tue, 17 Feb 2015 17:41:46 +0100 Subject: [PATCH] ModelBaseClass: promise mode for notifyObserversOf Support both promise and callback styles in ModelBaseClass.notifyObserversOf. When there is no callback supplied, the method returns a promise that is resolved (or rejected) with the result. --- lib/model.js | 3 +++ lib/utils.js | 28 ++++++++++++++++++++++++++++ test/async-observer.test.js | 23 ++++++++++++++++++++++- test/init.js | 6 +++++- 4 files changed, 58 insertions(+), 2 deletions(-) diff --git a/lib/model.js b/lib/model.js index 0a3ca8c0..0d8ca70a 100644 --- a/lib/model.js +++ b/lib/model.js @@ -561,6 +561,8 @@ 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); @@ -579,6 +581,7 @@ ModelBaseClass.notifyObserversOf = function(operation, context, callback) { function(err) { callback(err, context) } ); }); + return callback.promise; } ModelBaseClass._notifyBaseObservers = function(operation, context, callback) { diff --git a/lib/utils.js b/lib/utils.js index c3fbf841..6400e1ad 100644 --- a/lib/utils.js +++ b/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.'); +} diff --git a/test/async-observer.test.js b/test/async-observer.test.js index 47b32324..3cb2dbdb 100644 --- a/test/async-observer.test.js +++ b/test/async-observer.test.js @@ -1,6 +1,5 @@ var ModelBuilder = require('../').ModelBuilder; var should = require('./init'); -var Promise = global.Promise || require('bluebird'); describe('async observer', function() { var TestModel; @@ -115,6 +114,28 @@ describe('async observer', function() { 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) { diff --git a/test/init.js b/test/init.js index 200cabd0..0c63d304 100644 --- a/test/init.js +++ b/test/init.js @@ -25,4 +25,8 @@ if (!('getModelBuilder' in global)) { global.getModelBuilder = function () { return new ModelBuilder(); }; -} \ No newline at end of file +} + +if (!('Promise' in global)) { + global.Promise = require('bluebird'); +}