-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmethod-factory.js
102 lines (89 loc) · 3.83 KB
/
method-factory.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import { Meteor } from 'meteor/meteor'
import { check, Match } from 'meteor/check'
import { ValidatedMethod } from 'meteor/mdg:validated-method'
const isMaybeValidatedMethod = Match.Where(v => !v || v instanceof ValidatedMethod || (v.prototype && v.prototype instanceof ValidatedMethod))
const isMaybeApplyOptions = Match.Maybe({
wait: Match.Maybe(Boolean),
onResultReceived: Match.Maybe(Function),
noRetry: Match.Maybe(Boolean),
throwStubExceptions: Match.Maybe(Boolean),
returnStubValue: Match.Maybe(Boolean)
})
/**
* Creates a new method factory for a fixed set of mixins and a schema factory
* @param custom
* @param mixins
* @param schemaFactory
* @return {function} a function to create a new ValidatedMethod
*/
export const createMethodFactory = ({ custom, mixins, schemaFactory } = {}) => {
check(custom, isMaybeValidatedMethod)
check(schemaFactory, Match.Maybe(Function))
check(mixins, Match.Maybe([Function]))
const ProductConstructor = custom || ValidatedMethod
const isRequiredSchema = schemaFactory ? Match.OneOf(Object, null) : Match.Maybe(Object)
const isRequiredValidate = schemaFactory ? Match.Maybe(Function) : Function
const abstractFactoryLevelMixins = (mixins && mixins.length > 0) ? mixins : []
/**
*
* @param name required, see https://github.com/meteor/validated-method
* @param schema a schema definition (not an instance!) for input validation
* @param validate overrides validation with a custom function, required if no schemaFactory is defined
* @param run see https://github.com/meteor/validated-method
* @param args your object can have any more arguments, that are internally defined as {args}
* @return {ValidatedMethod}
*/
return options => {
check(options, Match.ObjectIncluding({
name: String,
schema: options.validate ? Match.Maybe(isRequiredSchema) : isRequiredSchema,
schemaOptions: Match.Maybe(isRequiredSchema),
validate: options.schema ? Match.Maybe(isRequiredValidate) : isRequiredValidate,
run: Function,
applyOptions: isMaybeApplyOptions,
mixins: Match.Maybe([Function])
}))
const { name, schema, validate, run, mixins, applyOptions, ...args } = options
let validateFn
const hasValidate = typeof validate === 'function'
if (hasValidate) {
// We wrap the validate function to allow for a return value of Boolean type,
// which SimpleSchema does not support.
validateFn = function (...args) {
const isValid = validate.apply(this, args)
if (isValid === true) return
if (isValid === false) {
throw new Meteor.Error('422', 'validationFailed', {
userId: this.userId,
method: name
})
}
}
}
if (!hasValidate && schemaFactory) {
// for short-hand definition of pass-all schema
// we allow schema to be null, which then
// prevents any check in validate
const validationSchema = schema === null
? null
: schemaFactory(schema, options.schemaOptions)
// We fall back to a plain object to support Meteor.call(name, callback)
// for schemas that contain no property: { schema: {} }
validateFn = function validate (document = {}) {
if (validationSchema !== null) {
validationSchema.validate(document, options.schemaOptions)
}
}
}
const methodArgs = Object.assign({ name, validate: validateFn, run }, args)
if (applyOptions) methodArgs.applyOptions = applyOptions
const localMixins = (mixins && mixins.length > 0) ? mixins : []
const allMixins = [].concat(abstractFactoryLevelMixins, localMixins)
if (allMixins.length > 0) methodArgs.mixins = allMixins
const product = new ProductConstructor(methodArgs)
check(product.name, name)
check(product.validate, Function)
check(product.run, Function)
return product
}
}