-
Notifications
You must be signed in to change notification settings - Fork 154
/
resolvers.ts
77 lines (68 loc) · 2.43 KB
/
resolvers.ts
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
import { Resolver, ResolverConfig } from '@urql/exchange-graphcache';
import {
IntrospectionInterfaceType,
IntrospectionOutputTypeRef,
IntrospectionType,
} from 'graphql';
// Load the types and convert them into a map of name to type
import schema from 'app/graphql/schema';
import * as scalars from './scalars';
const types = schema.__schema.types;
const keyedTypes: { [key: string]: IntrospectionType } = types.reduce(
(out, type) => ({ ...out, [type.name]: type }),
{}
);
// Load the resolvers and create a map of scalar name to resolver function
type ScalarResolver = (value: unknown) => ReturnType<Resolver>;
function resolverFor(type: IntrospectionOutputTypeRef): ScalarResolver | null {
const scalarResolver =
'ofType' in type && type.ofType ? resolverFor(type.ofType) : null;
switch (type.kind) {
case 'SCALAR':
return scalars[type.name] as ScalarResolver;
case 'NON_NULL':
return scalarResolver;
case 'LIST':
return scalarResolver
? (list) => {
return (list as unknown[]).map((v) => scalarResolver(v));
}
: null;
default:
return null;
}
}
/*
* Create a resolver map for rehydrating scalars on all our object types. Typescript is more than a
* little confused by our introspection JSON so we create a simple schema type to help it out.
*/
const resolvers: ResolverConfig = {};
for (const name of Object.keys(keyedTypes)) {
const type = keyedTypes[name];
// If we're an object with fields, find any which are scalars and add them to our resolver map.
if (type.kind === 'OBJECT') {
const { fields: baseFields, interfaces: baseInterfaces } = type;
const fields = baseFields ? [...baseFields] : [];
const interfaces = baseInterfaces ? [...baseInterfaces] : [];
// Flatten our interfaces into the fields list
while (interfaces?.length) {
const interfaceRef = interfaces.shift();
const intf =
interfaceRef &&
(keyedTypes[interfaceRef.name] as IntrospectionInterfaceType);
if (intf?.fields) fields.push(...intf.fields);
if (intf?.interfaces) interfaces.push(...intf.interfaces);
}
for (const field of fields) {
const resolver = resolverFor(field.type);
if (resolver) {
resolvers[name] ??= {};
resolvers[name][field.name] = (parent) => {
const result = resolver(parent[field.name]);
return result;
};
}
}
}
}
export default resolvers;