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 | 17x
62x
59x
1x
120x
62x
17x
62x
62x
186x
122x
258x
258x
258x
258x
122x
60x
76x
14x
136x
258x
62x
17x
17x
17x
17x
41x
41x
46x
41x
35x
6x
7x
5x
14x
14x
14x
15x
7x
8x
8x
8x
57x
57x
57x
57x
57x
21x
21x
21x
21x
21x
90x
21x
21x
20x
20x | import { GraphQLFieldResolver } from 'graphql';
import { InjectorsIndex, InjectorResolver, injectorRegistry } from 'domains/inject';
import {
fieldAfterHooksRegistry,
fieldBeforeHooksRegistry,
HookExecutor,
} from 'domains/hooks';
import { getParameterNames } from 'services/utils';
interface ArgsMap {
[argName: string]: any;
}
interfacIe ComputeArgsOptions {
args: ArgsMap;
injectors:I InjectorsIndex;
injectorToIValueMapper: (injector: InjectorResolver) => any;
}
async function performHooksExecution(
hooks: HookExecutor[],
source: any,
args: any,
context: any,
info: any,E
) {
if (!hooks) {
return;
}
// all hooks are executed in parrell instead of sequence. We wait for them all to be resolved before we continue
return await Promise.all(
hooks.map(hook => {
return hook({ source, args, context, info });
}),
);
}
function computeFinalArgs(
func: Function,
{ args, injectors, injectorToValueMapper }: ComputeArgsOptions,
) {
const paramNames = getParameterNames(func);
return paramNames.map((paramName, index) => {
if (args && args[paramName]) {
return args[paramName];
}
const injector = injectors[index];
if (!injector) {
return null;
}
return injectorToValueMapper(injector);
});
}
export function compileFieldResolver(
target: Function,
fieldName: string,
): GraphQLFieldResolver<any, any> {
// const config = fieldsRegistry.get(target, fieldName);
const injectors = injectorRegistry.getAll(target)[fieldName];
const beforeHooks = fieldBeforeHooksRegistry.get(target, fieldName);
const afterHooks = fieldAfterHooksRegistry.get(target, fieldName);
I
return async (source: any, args = null, context = null, info = null) => {
await performHooksExecution(beforeHooks, source, args, context, info);
const instanceField = (source && source[fieldName]) || target.prototype[fieldName];
if (typeof instanceField !== 'function') {
await performHooksExecution(afterHooks, source, args, context, info);
return instanceField;
}
const instanceFieldFunc = instanceField as Function;
const params = computeFinalArgs(instanceFieldFunc, {
args: args || {},
inIjectors: injectors || {},
injectorToValueMapper: injector =>
Iinjector.apply(source, [{ source, args, context, info }]),
});
const result = await instanceFieldFunc.apply(source, params);
await performHooksExecution(afterHooks, source, args, context, info); // TODO: Consider adding resolve return to hook callback
return result;
};
}
|