UNPKG

3.55 kBJavaScriptView Raw
1'use strict';
2
3const isArray = require('lodash/isArray');
4const isPlainObject = require('lodash/isPlainObject');
5const isObject = require('lodash/isObject');
6const extend = require('lodash/extend');
7const keys = require('lodash/keys');
8const reduce = require('lodash/reduce');
9const pick = require('lodash/pick');
10const toArray = require('lodash/toArray');
11const toPlainObject = require('lodash/toPlainObject');
12const utils = require('./utils');
13
14/**
15 * @summary Constructor for a Jayson Method
16 * @class Method
17 * @param {Function} [handler] Function to set as handler
18 * @param {Object} [options]
19 * @param {Function} [options.handler] Same as separate handler
20 * @param {Boolean} [options.useContext=false] When true, the handler expects a context object
21 * @param {Array|Object} [options.params] Defines params that the handler accepts
22 */
23const Method = function(handler, options) {
24
25 if(!(this instanceof Method)) {
26 return new Method(handler, options);
27 }
28
29 // only got passed options
30 if(isPlainObject(handler)) {
31 options = handler;
32 handler = null;
33 }
34
35 const defaults = {
36 useContext: false,
37 };
38
39 options = options || {};
40
41 this.options = utils.merge(defaults, options);
42 this.handler = handler || options.handler;
43};
44
45module.exports = Method;
46
47/**
48 * @summary Returns the handler function associated with this method
49 * @return {Function}
50 */
51Method.prototype.getHandler = function() {
52 return this.handler;
53};
54
55/**
56 * @summary Sets the handler function associated with this method
57 * @param {Function} handler
58 */
59Method.prototype.setHandler = function(handler) {
60 this.handler = handler;
61};
62
63/**
64 * @summary Prepare parameters for the method handler
65 * @private
66 */
67Method.prototype._getHandlerParams = function(params) {
68 const options = this.options;
69
70 const isObjectParams = !isArray(params) && isObject(params) && params;
71 const isArrayParams = isArray(params);
72
73 switch(true) {
74
75 // handler always gets an array
76 case options.params === Array:
77 return isArrayParams ? params : toArray(params);
78
79 // handler always gets an object
80 case options.params === Object:
81 return isObjectParams ? params : toPlainObject(params);
82
83 // handler gets a list of defined properties that should always be set
84 case isArray(options.params): {
85 const undefinedParams = reduce(options.params, function(undefinedParams, key) {
86 undefinedParams[key] = undefined;
87 return undefinedParams;
88 }, {});
89 return extend(undefinedParams, pick(params, keys(params)));
90 }
91
92 // handler gets a map of defined properties and their default values
93 case isPlainObject(options.params):
94 return extend({}, options.params, pick(params, keys(params)));
95
96 // give params as is
97 default:
98 return params;
99
100 }
101
102};
103
104/**
105 * @summary Executes this method in the context of a server
106 * @param {Server} server
107 * @param {Array|Object} requestParams
108 * @param {Object} [context]
109 * @param {Function} callback
110 */
111Method.prototype.execute = function(server, requestParams, context, callback) {
112 if(typeof(context) === 'function') {
113 callback = context;
114 context = {};
115 }
116
117 if(!context) {
118 context = {};
119 }
120
121 // when useContext is true, the handler gets a context object every time
122 const useContext = Boolean(this.options.useContext);
123 const handler = this.getHandler();
124 const params = this._getHandlerParams(requestParams);
125
126 const args = useContext ? [params, context, callback] : [params, callback];
127 return handler.call(server, ...args);
128};