-
Notifications
You must be signed in to change notification settings - Fork 1.8k
/
ResolverFragments.js
121 lines (108 loc) · 3.59 KB
/
ResolverFragments.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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
// flowlint ambiguous-object-type:error
'use strict';
import type {GraphQLTaggedNode} from '../query/GraphQLTag';
import type {FragmentType, SingularReaderSelector} from './RelayStoreTypes';
const {getFragment} = require('../query/GraphQLTag');
const {getSelector} = require('./RelayModernSelector');
const invariant = require('invariant');
// When we call the user-supplied resolver function, it will in turn call
// `readFragment`, but that's a global function -- it needs information
// about what resolver is being executed, which is supplied by putting the
// info on this stack before we call the resolver function.
type ResolverContext = {|
getDataForResolverFragment: (SingularReaderSelector, FragmentType) => mixed,
|};
const contextStack: Array<ResolverContext> = [];
function withResolverContext<T>(context: ResolverContext, cb: () => T): T {
contextStack.push(context);
try {
return cb();
} finally {
contextStack.pop();
}
}
// NOTE: these declarations are copied from 'useFragment'; it would be good
// to figure out how to share the same type signature between the two functions.
// The declarations ensure that the type of the returned data is:
// - non-nullable if the provided ref type is non-nullable
// - nullable if the provided ref type is nullable
// - array of non-nullable if the privoided ref type is an array of
// non-nullable refs
// - array of nullable if the privoided ref type is an array of nullable refs
declare function readFragment<
TKey: {+$data?: mixed, +$fragmentSpreads: FragmentType, ...},
>(
fragmentInput: GraphQLTaggedNode,
fragmentKey: TKey,
): $Call<<TFragmentData>({+$data?: TFragmentData, ...}) => TFragmentData, TKey>;
declare function readFragment<
TKey: ?{+$data?: mixed, +$fragmentSpreads: FragmentType, ...},
>(
fragmentInput: GraphQLTaggedNode,
fragmentKey: TKey,
): $Call<
<TFragmentData>(?{+$data?: TFragmentData, ...}) => ?TFragmentData,
TKey,
>;
declare function readFragment<
TKey: $ReadOnlyArray<{
+$data?: mixed,
+$fragmentSpreads: FragmentType,
...
}>,
>(
fragmentInput: GraphQLTaggedNode,
fragmentKey: TKey,
): $Call<
<TFragmentData>(
$ReadOnlyArray<{+$data?: TFragmentData, ...}>,
) => TFragmentData,
TKey,
>;
declare function readFragment<
TKey: ?$ReadOnlyArray<{
+$data?: mixed,
+$fragmentSpreads: FragmentType,
...
}>,
>(
fragmentInput: GraphQLTaggedNode,
fragmentKey: TKey,
): $Call<
<TFragmentData>(
?$ReadOnlyArray<{+$data?: TFragmentData, ...}>,
) => ?TFragmentData,
TKey,
>;
function readFragment(
fragmentInput: GraphQLTaggedNode,
fragmentKey: FragmentType,
): mixed {
if (!contextStack.length) {
throw new Error(
'readFragment should be called only from within a Relay Resolver function.',
);
}
const context = contextStack[contextStack.length - 1];
const fragmentNode = getFragment(fragmentInput);
const fragmentSelector = getSelector(fragmentNode, fragmentKey);
invariant(
fragmentSelector != null,
`Expected a selector for the fragment of the resolver ${fragmentNode.name}, but got null.`,
);
invariant(
fragmentSelector.kind === 'SingularReaderSelector',
`Expected a singular reader selector for the fragment of the resolver ${fragmentNode.name}, but it was plural.`,
);
return context.getDataForResolverFragment(fragmentSelector, fragmentKey);
}
module.exports = {readFragment, withResolverContext};