'use strict';
const utils = require('./utils');
/**
* @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.useContext=false] When true, the handler expects a context object
* @param {Array|Object} [options.params] Defines params that the handler accepts
*/
const Method = function(handler, options) {
if(!(this instanceof Method)) {
return new Method(handler, options);
}
// only got passed options
if(utils.isPlainObject(handler)) {
options = handler;
handler = null;
}
const defaults = {
useContext: false,
};
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) {
const options = this.options;
const isObjectParams = !Array.isArray(params) && utils.isPlainObject(params) && params;
const isArrayParams = Array.isArray(params);
switch(true) {
// handler always gets an array
case options.params === Array:
return isArrayParams ? params : utils.toArray(params);
// handler always gets an object
case options.params === Object:
return isObjectParams ? params : utils.toPlainObject(params);
// handler gets a list of defined properties that should always be set
case Array.isArray(options.params): {
const undefinedParams = Object.keys(options.params).reduce(function (out, index) {
const key = options.params[index];
out[key] = undefined;
return out;
}, {});
return {...undefinedParams, ...utils.pick(params, Object.keys(params))};
}
// handler gets a map of defined properties and their default values
case utils.isPlainObject(options.params):
return {...options.params, ...utils.pick(params, Object.keys(params))};
// give params as is
default:
return params;
}
};
/**
* @summary Executes this method in the context of a server
* @param {Server} server
* @param {Array|Object} requestParams
* @param {Object} [context]
* @param {Function} callback
*/
Method.prototype.execute = function(server, requestParams, context, callback) {
if(typeof(context) === 'function') {
callback = context;
context = {};
}
if(!context) {
context = {};
}
// when useContext is true, the handler gets a context object every time
const useContext = Boolean(this.options.useContext);
const handler = this.getHandler();
const params = this._getHandlerParams(requestParams);
const args = useContext ? [params, context, callback] : [params, callback];
return handler.call(server, ...args);
};