diff --git a/lib/mixins/index.js b/lib/mixins/index.js index 1e3eff11a6..acc65f178e 100644 --- a/lib/mixins/index.js +++ b/lib/mixins/index.js @@ -1,8 +1,20 @@ 'use strict'; +var _ = require('lodash'); + module.exports = function() { - return [ + var mixins = [ require('./promise'), - require('./event') + require('./event'), + require('./normalizer') ]; + + // Override push to make sure that normalize is always the last + mixins.push = function() { + var args = [ this.length - 1, 0].concat(_.toArray(arguments)); + this.splice.apply(this, args); + return this.length; + }; + + return mixins; }; diff --git a/lib/mixins/normalizer.js b/lib/mixins/normalizer.js new file mode 100644 index 0000000000..aaa6b01c7a --- /dev/null +++ b/lib/mixins/normalizer.js @@ -0,0 +1,19 @@ +var _ = require('lodash'); +var getArguments = require('feathers-commons').getArguments; + +module.exports = function (service) { + if (typeof service.mixin === 'function') { + var mixin = {}; + + _.each(this.methods, function(method) { + if(typeof service[method] === 'function') { + mixin[method] = function() { + var args = getArguments(method, arguments); + return this._super.apply(this, args); + }; + } + }); + + service.mixin(mixin); + } +}; diff --git a/lib/mixins/promise.js b/lib/mixins/promise.js index 4449250614..71a2551763 100644 --- a/lib/mixins/promise.js +++ b/lib/mixins/promise.js @@ -1,27 +1,28 @@ 'use strict'; var _ = require('lodash'); -var makeWrapper = function() { - return function() { - var result = this._super.apply(this, arguments); - var callback = arguments[arguments.length - 1]; - if(typeof result !== 'undefined' && _.isFunction(result.then) && _.isFunction(callback)) { - result.then(function(data) { - callback(null, data); - }, function(error) { - callback(error); - }); - } - return result; - }; +var wrapper = function () { + var result = this._super.apply(this, arguments); + var callback = arguments[arguments.length - 1]; + + if(typeof result !== 'undefined' && _.isFunction(result.then) && _.isFunction(callback)) { + result.then(function(data) { + callback(null, data); + }, function(error) { + callback(error); + }); + } + return result; }; module.exports = function (service) { if (typeof service.mixin === 'function') { - var mixin = _.transform(_.pick(service, this.methods), function(result, value, key) { - if(typeof value === 'function') { - result[key] = makeWrapper(); + var mixin = {}; + + _.each(this.methods, function(method) { + if(typeof service[method] === 'function') { + mixin[method] = wrapper; } }); diff --git a/test/application.test.js b/test/application.test.js index 0dff4714ed..6ac603bb77 100644 --- a/test/application.test.js +++ b/test/application.test.js @@ -296,10 +296,10 @@ describe('Feathers application', function () { it('mixins are unique to one application', function() { var app = feathers(); app.mixins.push(function() {}); - assert.equal(app.mixins.length, 3); + assert.equal(app.mixins.length, 4); var otherApp = feathers(); otherApp.mixins.push(function() {}); - assert.equal(otherApp.mixins.length, 3); + assert.equal(otherApp.mixins.length, 4); }); }); diff --git a/test/mixins/normalizer.test.js b/test/mixins/normalizer.test.js new file mode 100644 index 0000000000..e4a6c37c4d --- /dev/null +++ b/test/mixins/normalizer.test.js @@ -0,0 +1,63 @@ +'use strict'; + +var assert = require('assert'); +var Proto = require('uberproto'); +var normalizer = require('../../lib/mixins/normalizer'); +var mixins = require('../../lib/mixins'); + +describe('Argument normalizer mixin', function () { + it('normalizer mixin is always the last to run', function() { + var arr = mixins(); + var dummy = function() { }; + + assert.equal(arr.length, 3); + + arr.push(dummy); + + assert.equal(arr[arr.length - 1], normalizer, 'Last mixin is still the normalizer'); + assert.equal(arr[arr.length - 2], dummy, 'Dummy got added before last'); + }); + + // The normalization is already tests in all variations in `getArguments` + // so we just so we only test two random samples + + it('normalizes .find without a callback', function (done) { + var context = { + methods: ['find'] + }; + var FixtureService = Proto.extend({ + find: function(params, callback) { + assert.ok(typeof callback === 'function'); + assert.equal(params.test, 'Here'); + done(); + } + }); + + normalizer.call(context, FixtureService); + + var instance = Proto.create.call(FixtureService); + + instance.find({ test: 'Here' }); + }); + + it('normalizes .update without params and callback', function (done) { + var context = { + methods: ['update'] + }; + var FixtureService = Proto.extend({ + update: function(id, data, params, callback) { + assert.equal(id, 1); + assert.ok(typeof callback === 'function'); + assert.deepEqual(data, { test: 'Here' }); + assert.deepEqual(params, {}); + done(); + } + }); + + normalizer.call(context, FixtureService); + + var instance = Proto.create.call(FixtureService); + + instance.update(1, { test: 'Here' }); + }); +});