var jayson = require(__dirname);
var utils = require('./utils');
var _ = require('lodash');
/**
* @summary Constructor for a Jayson Method
* @class Method
* @param {Function} [handler] - Function to set as handler
* @param {Object} [options]
* @param {Function} [options.handler] - Same as separate handler
* @param {Boolean} [options.collect=true] - Params to the handler are collected in one object
* @param {Array|Object} [options.params] - Defines params that the handler accepts
*/
var Method = function(handler, options) {
if(!(this instanceof Method)) {
return new Method(handler, options);
}
// only got passed options
if(_.isPlainObject(handler)) {
options = handler;
handler = null;
}
var defaults = {
collect: true
};
options = options || {};
this.options = utils.merge(defaults, options);
this.handler = handler || options.handler;
};
module.exports = Method;
/**
* @summary Returns the handler function associated with this method
* @return {Function}
*/
Method.prototype.getHandler = function() {
return this.handler;
};
/**
* @summary Sets the handler function associated with this method
* @param {Function} handler
*/
Method.prototype.setHandler = function(handler) {
this.handler = handler;
};
/**
* @summary Prepare parameters for the method handler
* @private
*/
Method.prototype._getHandlerParams = function(params) {
var options = this.options;
var handler = this.getHandler();
var isObjectParams = !_.isArray(params) && _.isObject(params) && params;
var isArrayParams = _.isArray(params);
if(options.collect) {
// collect parameters in one argument to handler
switch(true) {
// handler always gets an array
case options.params === Array:
return isArrayParams ? params : _.toArray(params);
// handler always gets an object
case options.params === Object:
return isObjectParams ? params : _.toPlainObject(params);
// handler gets a list of defined properties that should always be set
case _.isArray(options.params):
var undefinedParams = _.object(_.zip(options.params, _.range(options.params.length).map(_.constant(undefined))));
return _.extend(undefinedParams, _.pick(params, _.keys(params)));
// handler gets a map of defined properties and their default values
case _.isPlainObject(options.params):
return _.extend({}, options.params, _.pick(params, _.keys(params)));
// give params as is
default:
return params;
}
} else {
// let the arguments pass to the handler as given
if(isObjectParams) {
// named parameters passed, take all parameters for handler except last (the callback)
return _.initial(utils.getParameterNames(handler)).map(function(name) {
return params[name];
});
}
// regular parameters array passed
return params;
}
};
/**
* @summary Executes this method in the context of a server
* @param {Server} server
* @param {Array|Object} requestParams
* @param {Function} callback
*/
Method.prototype.execute = function(server, requestParams, callback) {
var options = this.options;
var handler = this.getHandler();
var params = this._getHandlerParams(requestParams);
if(options.collect) {
return handler.call(server, params, callback);
}
// compare without the callback
if(handler.length !== (params.length + 1)) {
callback(server.error(jayson.Server.errors.INVALID_PARAMS));
return;
}
return handler.apply(server, _.flatten([params, callback]));
};