react-relay 14.0.0 → 15.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ReactRelayContainerUtils.js.flow +1 -2
- package/ReactRelayContext.js +1 -1
- package/ReactRelayContext.js.flow +1 -2
- package/ReactRelayFragmentContainer.js.flow +6 -4
- package/ReactRelayFragmentMockRenderer.js.flow +1 -2
- package/ReactRelayLocalQueryRenderer.js.flow +5 -5
- package/ReactRelayPaginationContainer.js.flow +21 -14
- package/ReactRelayQueryFetcher.js.flow +28 -16
- package/ReactRelayQueryRenderer.js.flow +42 -13
- package/ReactRelayQueryRendererContext.js.flow +2 -3
- package/ReactRelayRefetchContainer.js.flow +9 -9
- package/ReactRelayTestMocker.js.flow +3 -3
- package/ReactRelayTypes.js.flow +7 -8
- package/RelayContext.js.flow +1 -2
- package/__flowtests__/ReactRelayFragmentContainer-flowtest.js.flow +4 -5
- package/__flowtests__/ReactRelayPaginationContainer-flowtest.js.flow +4 -5
- package/__flowtests__/ReactRelayRefetchContainer-flowtest.js.flow +4 -5
- package/__flowtests__/RelayModern-flowtest.js.flow +3 -4
- package/__flowtests__/RelayModernFlowtest_badref.graphql.js.flow +3 -4
- package/__flowtests__/RelayModernFlowtest_notref.graphql.js.flow +3 -4
- package/__flowtests__/RelayModernFlowtest_user.graphql.js.flow +3 -4
- package/__flowtests__/RelayModernFlowtest_users.graphql.js.flow +3 -4
- package/__flowtests__/__generated__/ReactRelayFragmentContainerFlowtest_viewer.graphql.js.flow +3 -1
- package/__flowtests__/__generated__/ReactRelayFragmentContainerFlowtest_viewer2.graphql.js.flow +3 -1
- package/__flowtests__/__generated__/ReactRelayPaginationContainerFlowtestQuery.graphql.js.flow +4 -2
- package/__flowtests__/__generated__/ReactRelayPaginationContainerFlowtest_viewer.graphql.js.flow +3 -1
- package/__flowtests__/__generated__/ReactRelayRefetchContainerFlowtestQuery.graphql.js.flow +4 -2
- package/__flowtests__/__generated__/ReactRelayRefetchContainerFlowtest_viewer.graphql.js.flow +3 -1
- package/__flowtests__/__generated__/RelayModernFlowtest_badref.graphql.js.flow +4 -2
- package/__flowtests__/__generated__/RelayModernFlowtest_notref.graphql.js.flow +4 -2
- package/__flowtests__/__generated__/RelayModernFlowtest_user.graphql.js.flow +3 -1
- package/__flowtests__/__generated__/RelayModernFlowtest_users.graphql.js.flow +3 -1
- package/assertFragmentMap.js.flow +1 -2
- package/buildReactRelayContainer.js.flow +7 -7
- package/getRootVariablesForFragments.js.flow +1 -3
- package/hooks.js +1 -1
- package/hooks.js.flow +4 -2
- package/index.js +1 -1
- package/index.js.flow +6 -2
- package/isRelayEnvironment.js.flow +1 -2
- package/jest-react/enqueueTask.js.flow +1 -1
- package/jest-react/index.js.flow +1 -1
- package/jest-react/internalAct.js.flow +1 -1
- package/legacy.js +1 -1
- package/legacy.js.flow +1 -2
- package/lib/ReactRelayContainerUtils.js +2 -3
- package/lib/ReactRelayContext.js +3 -4
- package/lib/ReactRelayFragmentContainer.js +47 -73
- package/lib/ReactRelayFragmentMockRenderer.js +2 -4
- package/lib/ReactRelayLocalQueryRenderer.js +18 -31
- package/lib/ReactRelayPaginationContainer.js +74 -164
- package/lib/ReactRelayQueryFetcher.js +49 -76
- package/lib/ReactRelayQueryRenderer.js +63 -84
- package/lib/ReactRelayQueryRendererContext.js +2 -2
- package/lib/ReactRelayRefetchContainer.js +58 -108
- package/lib/ReactRelayTestMocker.js +33 -68
- package/lib/ReactRelayTypes.js +2 -1
- package/lib/RelayContext.js +4 -7
- package/lib/assertFragmentMap.js +3 -5
- package/lib/buildReactRelayContainer.js +11 -27
- package/lib/getRootVariablesForFragments.js +6 -10
- package/lib/hooks.js +5 -18
- package/lib/index.js +7 -24
- package/lib/isRelayEnvironment.js +5 -4
- package/lib/jest-react/enqueueTask.js +5 -9
- package/lib/jest-react/index.js +0 -1
- package/lib/jest-react/internalAct.js +9 -20
- package/lib/legacy.js +2 -8
- package/lib/multi-actor/ActorChange.js +2 -5
- package/lib/multi-actor/index.js +2 -1
- package/lib/multi-actor/useRelayActorEnvironment.js +4 -8
- package/lib/relay-hooks/EntryPointContainer.react.js +9 -15
- package/lib/relay-hooks/EntryPointTypes.flow.js +5 -3
- package/lib/relay-hooks/FragmentResource.js +109 -203
- package/lib/relay-hooks/HooksImplementation.js +3 -6
- package/lib/relay-hooks/InternalLogger.js +2 -3
- package/lib/relay-hooks/LRUCache.js +2 -20
- package/lib/relay-hooks/LazyLoadEntryPointContainer_DEPRECATED.react.js +33 -54
- package/lib/relay-hooks/MatchContainer.js +15 -24
- package/lib/relay-hooks/ProfilerContext.js +3 -3
- package/lib/relay-hooks/QueryResource.js +31 -101
- package/lib/relay-hooks/RelayEnvironmentProvider.js +5 -9
- package/lib/relay-hooks/SuspenseResource.js +9 -33
- package/lib/relay-hooks/loadEntryPoint.js +19 -31
- package/lib/relay-hooks/loadQuery.js +42 -78
- package/lib/relay-hooks/preloadQuery_DEPRECATED.js +11 -37
- package/lib/relay-hooks/prepareEntryPoint_DEPRECATED.js +9 -15
- package/lib/relay-hooks/react-cache/RelayReactCache.js +7 -12
- package/lib/relay-hooks/react-cache/getQueryResultOrFetchQuery_REACT_CACHE.js +27 -81
- package/lib/relay-hooks/react-cache/readFragmentInternal_REACT_CACHE.js +206 -0
- package/lib/relay-hooks/react-cache/useFragmentInternal_REACT_CACHE.js +195 -215
- package/lib/relay-hooks/react-cache/useFragment_REACT_CACHE.js +5 -15
- package/lib/relay-hooks/react-cache/useLazyLoadQuery_REACT_CACHE.js +17 -24
- package/lib/relay-hooks/react-cache/usePaginationFragment_REACT_CACHE.js +149 -0
- package/lib/relay-hooks/react-cache/usePreloadedQuery_REACT_CACHE.js +24 -39
- package/lib/relay-hooks/react-cache/useRefetchableFragmentInternal_REACT_CACHE.js +325 -0
- package/lib/relay-hooks/react-cache/useRefetchableFragment_REACT_CACHE.js +37 -0
- package/lib/relay-hooks/useBlockingPaginationFragment.js +73 -93
- package/lib/relay-hooks/useClientQuery.js +30 -0
- package/lib/relay-hooks/useEntryPointLoader.js +18 -38
- package/lib/relay-hooks/useFetchTrackingRef.js +10 -12
- package/lib/relay-hooks/useFragment.js +8 -19
- package/lib/relay-hooks/useFragmentNode.js +20 -32
- package/lib/relay-hooks/useIsMountedRef.js +4 -6
- package/lib/relay-hooks/useIsOperationNodeActive.js +8 -20
- package/lib/relay-hooks/useIsParentQueryActive.js +3 -6
- package/lib/relay-hooks/useLazyLoadQuery.js +7 -24
- package/lib/relay-hooks/useLazyLoadQueryNode.js +23 -34
- package/lib/relay-hooks/useLoadMoreFunction.js +46 -78
- package/lib/relay-hooks/useMemoOperationDescriptor.js +6 -15
- package/lib/relay-hooks/useMemoVariables.js +15 -34
- package/lib/relay-hooks/useMutation.js +9 -27
- package/lib/relay-hooks/usePaginationFragment.js +73 -76
- package/lib/relay-hooks/usePreloadedQuery.js +13 -44
- package/lib/relay-hooks/useQueryLoader.js +24 -49
- package/lib/relay-hooks/useRefetchableFragment.js +19 -17
- package/lib/relay-hooks/useRefetchableFragmentNode.js +65 -109
- package/lib/relay-hooks/useRelayEnvironment.js +4 -8
- package/lib/relay-hooks/useStaticFragmentNodeWarning.js +4 -8
- package/lib/relay-hooks/useSubscribeToInvalidationState.js +8 -9
- package/lib/relay-hooks/useSubscription.js +5 -10
- package/lib/relay-hooks/useUnsafeRef_DEPRECATED.js +29 -0
- package/multi-actor/ActorChange.js.flow +1 -1
- package/multi-actor/index.js.flow +1 -1
- package/multi-actor/useRelayActorEnvironment.js.flow +2 -4
- package/package.json +2 -2
- package/react-relay-hooks.js +2 -2
- package/react-relay-hooks.min.js +2 -2
- package/react-relay-legacy.js +2 -2
- package/react-relay-legacy.min.js +2 -2
- package/react-relay.js +2 -2
- package/react-relay.min.js +2 -2
- package/relay-hooks/EntryPointContainer.react.js.flow +3 -5
- package/relay-hooks/EntryPointTypes.flow.js.flow +37 -37
- package/relay-hooks/FragmentResource.js.flow +43 -19
- package/relay-hooks/HooksImplementation.js.flow +7 -9
- package/relay-hooks/InternalLogger.js.flow +1 -3
- package/relay-hooks/LRUCache.js.flow +1 -3
- package/relay-hooks/LazyLoadEntryPointContainer_DEPRECATED.react.js.flow +19 -14
- package/relay-hooks/MatchContainer.js.flow +6 -8
- package/relay-hooks/ProfilerContext.js.flow +1 -3
- package/relay-hooks/QueryResource.js.flow +29 -11
- package/relay-hooks/RelayEnvironmentProvider.js.flow +4 -6
- package/relay-hooks/SuspenseResource.js.flow +1 -3
- package/relay-hooks/__flowtests__/EntryPointTypes/EntryPointElementConfig-flowtest.js.flow +6 -4
- package/relay-hooks/__flowtests__/EntryPointTypes/NestedEntrypoints-flowtest.js.flow +4 -4
- package/relay-hooks/__flowtests__/__generated__/useFragmentFlowtest_user.graphql.js.flow +3 -1
- package/relay-hooks/__flowtests__/__generated__/useFragmentFlowtest_users.graphql.js.flow +3 -1
- package/relay-hooks/__flowtests__/useBlockingPaginationFragment-flowtest.js.flow +39 -39
- package/relay-hooks/__flowtests__/useFragment-flowtest.js.flow +1 -3
- package/relay-hooks/__flowtests__/usePaginationFragment-flowtest.js.flow +37 -38
- package/relay-hooks/__flowtests__/useRefetchableFragment-flowtest.js.flow +18 -20
- package/relay-hooks/__flowtests__/utils.js.flow +21 -12
- package/relay-hooks/loadEntryPoint.js.flow +11 -6
- package/relay-hooks/loadQuery.js.flow +11 -7
- package/relay-hooks/preloadQuery_DEPRECATED.js.flow +9 -12
- package/relay-hooks/prepareEntryPoint_DEPRECATED.js.flow +13 -10
- package/relay-hooks/react-cache/RelayReactCache.js.flow +1 -3
- package/relay-hooks/react-cache/getQueryResultOrFetchQuery_REACT_CACHE.js.flow +26 -20
- package/relay-hooks/react-cache/readFragmentInternal_REACT_CACHE.js.flow +297 -0
- package/relay-hooks/react-cache/useFragmentInternal_REACT_CACHE.js.flow +136 -96
- package/relay-hooks/react-cache/useFragment_REACT_CACHE.js.flow +1 -3
- package/relay-hooks/react-cache/useLazyLoadQuery_REACT_CACHE.js.flow +3 -5
- package/relay-hooks/react-cache/usePaginationFragment_REACT_CACHE.js.flow +190 -0
- package/relay-hooks/react-cache/usePreloadedQuery_REACT_CACHE.js.flow +3 -6
- package/relay-hooks/react-cache/useRefetchableFragmentInternal_REACT_CACHE.js.flow +601 -0
- package/relay-hooks/react-cache/useRefetchableFragment_REACT_CACHE.js.flow +65 -0
- package/relay-hooks/useBlockingPaginationFragment.js.flow +86 -59
- package/relay-hooks/useClientQuery.js.flow +39 -0
- package/relay-hooks/useEntryPointLoader.js.flow +16 -14
- package/relay-hooks/useFetchTrackingRef.js.flow +7 -8
- package/relay-hooks/useFragment.js.flow +2 -4
- package/relay-hooks/useFragmentNode.js.flow +7 -8
- package/relay-hooks/useIsMountedRef.js.flow +2 -4
- package/relay-hooks/useIsOperationNodeActive.js.flow +1 -1
- package/relay-hooks/useIsParentQueryActive.js.flow +1 -1
- package/relay-hooks/useLazyLoadQuery.js.flow +9 -32
- package/relay-hooks/useLazyLoadQueryNode.js.flow +4 -6
- package/relay-hooks/useLoadMoreFunction.js.flow +20 -17
- package/relay-hooks/useMemoOperationDescriptor.js.flow +3 -5
- package/relay-hooks/useMemoVariables.js.flow +13 -31
- package/relay-hooks/useMutation.js.flow +6 -8
- package/relay-hooks/usePaginationFragment.js.flow +75 -43
- package/relay-hooks/usePreloadedQuery.js.flow +49 -43
- package/relay-hooks/useQueryLoader.js.flow +89 -28
- package/relay-hooks/useRefetchableFragment.js.flow +83 -23
- package/relay-hooks/useRefetchableFragmentNode.js.flow +26 -22
- package/relay-hooks/useRelayEnvironment.js.flow +2 -4
- package/relay-hooks/useStaticFragmentNodeWarning.js.flow +3 -5
- package/relay-hooks/useSubscribeToInvalidationState.js.flow +2 -4
- package/relay-hooks/useSubscription.js.flow +1 -3
- package/relay-hooks/useUnsafeRef_DEPRECATED.js.flow +25 -0
- package/lib/readContext.js +0 -28
- package/readContext.js.flow +0 -31
|
@@ -4,15 +4,13 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*
|
|
7
|
-
* @emails oncall+relay
|
|
8
7
|
* @flow strict-local
|
|
9
8
|
* @format
|
|
9
|
+
* @oncall relay
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
// flowlint ambiguous-object-type:error
|
|
13
|
-
|
|
14
12
|
'use strict';
|
|
15
|
-
|
|
13
|
+
import type {OperationType} from '../../relay-runtime/util/RelayRuntimeTypes';
|
|
16
14
|
import type {
|
|
17
15
|
EntryPoint,
|
|
18
16
|
EntryPointComponent,
|
|
@@ -42,6 +40,7 @@ function prepareEntryPoint<
|
|
|
42
40
|
): void {
|
|
43
41
|
// Start loading the code for the entrypoint
|
|
44
42
|
if (entryPoint.root.getModuleIfRequired() == null) {
|
|
43
|
+
// $FlowFixMe[unused-promise]
|
|
45
44
|
entryPoint.root.load();
|
|
46
45
|
}
|
|
47
46
|
const preloadProps = entryPoint.getPreloadProps(entryPointParams);
|
|
@@ -58,7 +57,7 @@ function prepareEntryPoint<
|
|
|
58
57
|
environmentProviderOptions,
|
|
59
58
|
);
|
|
60
59
|
|
|
61
|
-
preloadedQueries[queryPropName] = preloadQuery(
|
|
60
|
+
preloadedQueries[queryPropName] = preloadQuery<OperationType, mixed>(
|
|
62
61
|
environment,
|
|
63
62
|
parameters,
|
|
64
63
|
variables,
|
|
@@ -77,11 +76,15 @@ function prepareEntryPoint<
|
|
|
77
76
|
}
|
|
78
77
|
const {entryPoint: nestedEntryPoint, entryPointParams: nestedParams} =
|
|
79
78
|
entryPointDescription;
|
|
80
|
-
preloadedEntryPoints[entryPointPropName] = prepareEntryPoint
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
79
|
+
preloadedEntryPoints[entryPointPropName] = prepareEntryPoint<
|
|
80
|
+
TEntryPointParams,
|
|
81
|
+
TPreloadedQueries,
|
|
82
|
+
TPreloadedEntryPoints,
|
|
83
|
+
TRuntimeProps,
|
|
84
|
+
TExtraProps,
|
|
85
|
+
TEntryPointComponent,
|
|
86
|
+
TEntryPoint,
|
|
87
|
+
>(environmentProvider, nestedEntryPoint, nestedParams);
|
|
85
88
|
});
|
|
86
89
|
}
|
|
87
90
|
}
|
|
@@ -5,12 +5,10 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*
|
|
7
7
|
* @flow strict-local
|
|
8
|
-
* @emails oncall+relay
|
|
9
8
|
* @format
|
|
9
|
+
* @oncall relay
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
// flowlint ambiguous-object-type:error
|
|
13
|
-
|
|
14
12
|
'use strict';
|
|
15
13
|
|
|
16
14
|
const invariant = require('invariant');
|
|
@@ -5,12 +5,10 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*
|
|
7
7
|
* @flow strict-local
|
|
8
|
-
* @emails oncall+relay
|
|
9
8
|
* @format
|
|
9
|
+
* @oncall relay
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
// flowlint ambiguous-object-type:error
|
|
13
|
-
|
|
14
12
|
'use strict';
|
|
15
13
|
|
|
16
14
|
import type {
|
|
@@ -27,17 +25,17 @@ const SuspenseResource = require('../SuspenseResource');
|
|
|
27
25
|
const {getCacheForType, getCacheSignal} = require('./RelayReactCache');
|
|
28
26
|
const invariant = require('invariant');
|
|
29
27
|
const {
|
|
30
|
-
RelayFeatureFlags,
|
|
31
28
|
__internal: {fetchQuery: fetchQueryInternal},
|
|
29
|
+
RelayFeatureFlags,
|
|
32
30
|
} = require('relay-runtime');
|
|
33
31
|
const warning = require('warning');
|
|
34
32
|
|
|
35
33
|
type QueryCacheCommitable = () => () => void;
|
|
36
34
|
|
|
37
|
-
type QueryResult = {
|
|
35
|
+
type QueryResult = {
|
|
38
36
|
fragmentNode: ReaderFragment,
|
|
39
37
|
fragmentRef: mixed,
|
|
40
|
-
|
|
38
|
+
};
|
|
41
39
|
|
|
42
40
|
// Note that the status of a cache entry will be 'resolved' when partial
|
|
43
41
|
// rendering is allowed, even if a fetch is ongoing. The pending status
|
|
@@ -49,34 +47,42 @@ type QueryResult = {|
|
|
|
49
47
|
// before any components have mounted. It is unused when Legacy Timeouts
|
|
50
48
|
// mode is off.
|
|
51
49
|
type QueryCacheEntryStatus =
|
|
52
|
-
| {
|
|
50
|
+
| {
|
|
53
51
|
status: 'resolved',
|
|
54
52
|
result: QueryResult,
|
|
55
|
-
|
|
56
|
-
| {
|
|
53
|
+
}
|
|
54
|
+
| {
|
|
57
55
|
status: 'pending',
|
|
58
56
|
promise: Promise<void>,
|
|
59
|
-
|
|
60
|
-
| {
|
|
57
|
+
}
|
|
58
|
+
| {
|
|
61
59
|
status: 'rejected',
|
|
62
60
|
error: Error,
|
|
63
|
-
|
|
61
|
+
};
|
|
64
62
|
|
|
65
|
-
type QueryCacheEntry = {
|
|
63
|
+
type QueryCacheEntry = {
|
|
66
64
|
...QueryCacheEntryStatus,
|
|
67
65
|
onCommit: QueryCacheCommitable,
|
|
68
66
|
suspenseResource: SuspenseResource | null,
|
|
69
|
-
|
|
67
|
+
};
|
|
70
68
|
|
|
71
69
|
const DEFAULT_FETCH_POLICY = 'store-or-network';
|
|
72
70
|
|
|
71
|
+
const WEAKMAP_SUPPORTED = typeof WeakMap === 'function';
|
|
72
|
+
|
|
73
|
+
interface IMap<K, V> {
|
|
74
|
+
delete(key: K): boolean;
|
|
75
|
+
get(key: K): V | void;
|
|
76
|
+
set(key: K, value: V): IMap<K, V>;
|
|
77
|
+
}
|
|
78
|
+
|
|
73
79
|
type QueryCacheKey = string;
|
|
74
80
|
|
|
75
81
|
class QueryCache {
|
|
76
|
-
_map:
|
|
82
|
+
_map: IMap<IEnvironment, Map<QueryCacheKey, QueryCacheEntry>>;
|
|
77
83
|
|
|
78
84
|
constructor() {
|
|
79
|
-
this._map = new Map();
|
|
85
|
+
this._map = WEAKMAP_SUPPORTED ? new WeakMap() : new Map();
|
|
80
86
|
}
|
|
81
87
|
|
|
82
88
|
get(environment: IEnvironment, key: QueryCacheKey): QueryCacheEntry | void {
|
|
@@ -121,7 +127,7 @@ const noopOnCommit = () => {
|
|
|
121
127
|
return () => undefined;
|
|
122
128
|
};
|
|
123
129
|
|
|
124
|
-
const noopPromise = new Promise(() => {});
|
|
130
|
+
const noopPromise = new Promise<void>(() => {});
|
|
125
131
|
|
|
126
132
|
function getQueryCacheKey(
|
|
127
133
|
operation: OperationDescriptor,
|
|
@@ -160,12 +166,12 @@ function makeInitialCacheEntry() {
|
|
|
160
166
|
function getQueryResultOrFetchQuery_REACT_CACHE(
|
|
161
167
|
environment: IEnvironment,
|
|
162
168
|
queryOperationDescriptor: OperationDescriptor,
|
|
163
|
-
options?: {
|
|
169
|
+
options?: {
|
|
164
170
|
fetchPolicy?: FetchPolicy,
|
|
165
171
|
renderPolicy?: RenderPolicy,
|
|
166
172
|
fetchKey?: ?string | ?number,
|
|
167
173
|
fetchObservable?: Observable<GraphQLResponse>,
|
|
168
|
-
|
|
174
|
+
},
|
|
169
175
|
): [QueryResult, QueryCacheCommitable] {
|
|
170
176
|
const fetchPolicy = options?.fetchPolicy ?? DEFAULT_FETCH_POLICY;
|
|
171
177
|
const renderPolicy =
|
|
@@ -369,7 +375,7 @@ function executeOperationAndKeepUpToDate(
|
|
|
369
375
|
customFetchObservable?: Observable<GraphQLResponse>,
|
|
370
376
|
) {
|
|
371
377
|
let resolvePromise;
|
|
372
|
-
const promise = new Promise(r => {
|
|
378
|
+
const promise = new Promise<void>(r => {
|
|
373
379
|
resolvePromise = r;
|
|
374
380
|
});
|
|
375
381
|
// $FlowExpectedError[prop-missing] Expando to annotate Promises.
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @flow strict-local
|
|
8
|
+
* @format
|
|
9
|
+
* @oncall relay
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
'use strict';
|
|
13
|
+
|
|
14
|
+
import type {QueryResult} from '../QueryResource';
|
|
15
|
+
import type {
|
|
16
|
+
CacheConfig,
|
|
17
|
+
FetchPolicy,
|
|
18
|
+
IEnvironment,
|
|
19
|
+
ReaderFragment,
|
|
20
|
+
ReaderSelector,
|
|
21
|
+
SelectorData,
|
|
22
|
+
Snapshot,
|
|
23
|
+
} from 'relay-runtime';
|
|
24
|
+
import type {MissingClientEdgeRequestInfo} from 'relay-runtime/store/RelayStoreTypes';
|
|
25
|
+
|
|
26
|
+
const {getQueryResourceForEnvironment} = require('../QueryResource');
|
|
27
|
+
const invariant = require('invariant');
|
|
28
|
+
const {
|
|
29
|
+
__internal: {fetchQuery: fetchQueryInternal},
|
|
30
|
+
createOperationDescriptor,
|
|
31
|
+
getPendingOperationsForFragment,
|
|
32
|
+
getSelector,
|
|
33
|
+
getVariablesFromFragment,
|
|
34
|
+
handlePotentialSnapshotErrors,
|
|
35
|
+
} = require('relay-runtime');
|
|
36
|
+
const warning = require('warning');
|
|
37
|
+
|
|
38
|
+
type FragmentQueryOptions = {
|
|
39
|
+
fetchPolicy?: FetchPolicy,
|
|
40
|
+
networkCacheConfig?: ?CacheConfig,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
type FragmentState = $ReadOnly<
|
|
44
|
+
| {kind: 'bailout'}
|
|
45
|
+
| {kind: 'singular', snapshot: Snapshot, epoch: number}
|
|
46
|
+
| {kind: 'plural', snapshots: $ReadOnlyArray<Snapshot>, epoch: number},
|
|
47
|
+
>;
|
|
48
|
+
|
|
49
|
+
function isMissingData(state: FragmentState): boolean {
|
|
50
|
+
if (state.kind === 'bailout') {
|
|
51
|
+
return false;
|
|
52
|
+
} else if (state.kind === 'singular') {
|
|
53
|
+
return state.snapshot.isMissingData;
|
|
54
|
+
} else {
|
|
55
|
+
return state.snapshots.some(s => s.isMissingData);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function getMissingClientEdges(
|
|
60
|
+
state: FragmentState,
|
|
61
|
+
): $ReadOnlyArray<MissingClientEdgeRequestInfo> | null {
|
|
62
|
+
if (state.kind === 'bailout') {
|
|
63
|
+
return null;
|
|
64
|
+
} else if (state.kind === 'singular') {
|
|
65
|
+
return state.snapshot.missingClientEdges ?? null;
|
|
66
|
+
} else {
|
|
67
|
+
let edges: null | Array<MissingClientEdgeRequestInfo> = null;
|
|
68
|
+
for (const snapshot of state.snapshots) {
|
|
69
|
+
if (snapshot.missingClientEdges) {
|
|
70
|
+
edges = edges ?? [];
|
|
71
|
+
for (const edge of snapshot.missingClientEdges) {
|
|
72
|
+
edges.push(edge);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return edges;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function handlePotentialSnapshotErrorsForState(
|
|
81
|
+
environment: IEnvironment,
|
|
82
|
+
state: FragmentState,
|
|
83
|
+
): void {
|
|
84
|
+
if (state.kind === 'singular') {
|
|
85
|
+
handlePotentialSnapshotErrors(
|
|
86
|
+
environment,
|
|
87
|
+
state.snapshot.missingRequiredFields,
|
|
88
|
+
state.snapshot.relayResolverErrors,
|
|
89
|
+
);
|
|
90
|
+
} else if (state.kind === 'plural') {
|
|
91
|
+
for (const snapshot of state.snapshots) {
|
|
92
|
+
handlePotentialSnapshotErrors(
|
|
93
|
+
environment,
|
|
94
|
+
snapshot.missingRequiredFields,
|
|
95
|
+
snapshot.relayResolverErrors,
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function handleMissingClientEdge(
|
|
102
|
+
environment: IEnvironment,
|
|
103
|
+
parentFragmentNode: ReaderFragment,
|
|
104
|
+
parentFragmentRef: mixed,
|
|
105
|
+
missingClientEdgeRequestInfo: MissingClientEdgeRequestInfo,
|
|
106
|
+
queryOptions?: FragmentQueryOptions,
|
|
107
|
+
): QueryResult {
|
|
108
|
+
const originalVariables = getVariablesFromFragment(
|
|
109
|
+
parentFragmentNode,
|
|
110
|
+
parentFragmentRef,
|
|
111
|
+
);
|
|
112
|
+
const variables = {
|
|
113
|
+
...originalVariables,
|
|
114
|
+
id: missingClientEdgeRequestInfo.clientEdgeDestinationID, // TODO should be a reserved name
|
|
115
|
+
};
|
|
116
|
+
const queryOperationDescriptor = createOperationDescriptor(
|
|
117
|
+
missingClientEdgeRequestInfo.request,
|
|
118
|
+
variables,
|
|
119
|
+
queryOptions?.networkCacheConfig,
|
|
120
|
+
);
|
|
121
|
+
// This may suspend. We don't need to do anything with the results; all we're
|
|
122
|
+
// doing here is started the query if needed and retaining and releasing it
|
|
123
|
+
// according to the component mount/suspense cycle; QueryResource
|
|
124
|
+
// already handles this by itself.
|
|
125
|
+
const QueryResource = getQueryResourceForEnvironment(environment);
|
|
126
|
+
return QueryResource.prepare(
|
|
127
|
+
queryOperationDescriptor,
|
|
128
|
+
fetchQueryInternal(environment, queryOperationDescriptor),
|
|
129
|
+
queryOptions?.fetchPolicy,
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function getFragmentState(
|
|
134
|
+
environment: IEnvironment,
|
|
135
|
+
fragmentSelector: ?ReaderSelector,
|
|
136
|
+
): FragmentState {
|
|
137
|
+
if (fragmentSelector == null) {
|
|
138
|
+
return {kind: 'bailout'};
|
|
139
|
+
} else if (fragmentSelector.kind === 'PluralReaderSelector') {
|
|
140
|
+
if (fragmentSelector.selectors.length === 0) {
|
|
141
|
+
return {kind: 'bailout'};
|
|
142
|
+
} else {
|
|
143
|
+
return {
|
|
144
|
+
kind: 'plural',
|
|
145
|
+
snapshots: fragmentSelector.selectors.map(s => environment.lookup(s)),
|
|
146
|
+
epoch: environment.getStore().getEpoch(),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
} else {
|
|
150
|
+
return {
|
|
151
|
+
kind: 'singular',
|
|
152
|
+
snapshot: environment.lookup(fragmentSelector),
|
|
153
|
+
epoch: environment.getStore().getEpoch(),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// fragmentNode cannot change during the lifetime of the component, though fragmentRef may change.
|
|
159
|
+
function readFragmentInternal_REACT_CACHE(
|
|
160
|
+
environment: IEnvironment,
|
|
161
|
+
fragmentNode: ReaderFragment,
|
|
162
|
+
fragmentRef: mixed,
|
|
163
|
+
hookDisplayName: string,
|
|
164
|
+
queryOptions?: FragmentQueryOptions,
|
|
165
|
+
fragmentKey?: string,
|
|
166
|
+
): {
|
|
167
|
+
+data: ?SelectorData | Array<?SelectorData>,
|
|
168
|
+
+clientEdgeQueries: ?Array<QueryResult>,
|
|
169
|
+
} {
|
|
170
|
+
const fragmentSelector = getSelector(fragmentNode, fragmentRef);
|
|
171
|
+
const isPlural = fragmentNode?.metadata?.plural === true;
|
|
172
|
+
|
|
173
|
+
if (isPlural) {
|
|
174
|
+
invariant(
|
|
175
|
+
fragmentRef == null || Array.isArray(fragmentRef),
|
|
176
|
+
'Relay: Expected fragment pointer%s for fragment `%s` to be ' +
|
|
177
|
+
'an array, instead got `%s`. Remove `@relay(plural: true)` ' +
|
|
178
|
+
'from fragment `%s` to allow the prop to be an object.',
|
|
179
|
+
fragmentKey != null ? ` for key \`${fragmentKey}\`` : '',
|
|
180
|
+
fragmentNode.name,
|
|
181
|
+
typeof fragmentRef,
|
|
182
|
+
fragmentNode.name,
|
|
183
|
+
);
|
|
184
|
+
} else {
|
|
185
|
+
invariant(
|
|
186
|
+
!Array.isArray(fragmentRef),
|
|
187
|
+
'Relay: Expected fragment pointer%s for fragment `%s` not to be ' +
|
|
188
|
+
'an array, instead got `%s`. Add `@relay(plural: true)` ' +
|
|
189
|
+
'to fragment `%s` to allow the prop to be an array.',
|
|
190
|
+
fragmentKey != null ? ` for key \`${fragmentKey}\`` : '',
|
|
191
|
+
fragmentNode.name,
|
|
192
|
+
typeof fragmentRef,
|
|
193
|
+
fragmentNode.name,
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
invariant(
|
|
197
|
+
fragmentRef == null ||
|
|
198
|
+
(isPlural && Array.isArray(fragmentRef) && fragmentRef.length === 0) ||
|
|
199
|
+
fragmentSelector != null,
|
|
200
|
+
'Relay: Expected to receive an object where `...%s` was spread, ' +
|
|
201
|
+
'but the fragment reference was not found`. This is most ' +
|
|
202
|
+
'likely the result of:\n' +
|
|
203
|
+
"- Forgetting to spread `%s` in `%s`'s parent's fragment.\n" +
|
|
204
|
+
'- Conditionally fetching `%s` but unconditionally passing %s prop ' +
|
|
205
|
+
'to `%s`. If the parent fragment only fetches the fragment conditionally ' +
|
|
206
|
+
'- with e.g. `@include`, `@skip`, or inside a `... on SomeType { }` ' +
|
|
207
|
+
'spread - then the fragment reference will not exist. ' +
|
|
208
|
+
'In this case, pass `null` if the conditions for evaluating the ' +
|
|
209
|
+
'fragment are not met (e.g. if the `@include(if)` value is false.)',
|
|
210
|
+
fragmentNode.name,
|
|
211
|
+
fragmentNode.name,
|
|
212
|
+
hookDisplayName,
|
|
213
|
+
fragmentNode.name,
|
|
214
|
+
fragmentKey == null ? 'a fragment reference' : `the \`${fragmentKey}\``,
|
|
215
|
+
hookDisplayName,
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
const state = getFragmentState(environment, fragmentSelector);
|
|
219
|
+
|
|
220
|
+
// Handle the queries for any missing client edges; this may suspend.
|
|
221
|
+
// FIXME handle client edges in parallel.
|
|
222
|
+
let clientEdgeQueries = null;
|
|
223
|
+
if (fragmentNode.metadata?.hasClientEdges === true) {
|
|
224
|
+
const missingClientEdges = getMissingClientEdges(state);
|
|
225
|
+
if (missingClientEdges?.length) {
|
|
226
|
+
clientEdgeQueries = ([]: Array<QueryResult>);
|
|
227
|
+
for (const edge of missingClientEdges) {
|
|
228
|
+
clientEdgeQueries.push(
|
|
229
|
+
handleMissingClientEdge(
|
|
230
|
+
environment,
|
|
231
|
+
fragmentNode,
|
|
232
|
+
fragmentRef,
|
|
233
|
+
edge,
|
|
234
|
+
queryOptions,
|
|
235
|
+
),
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (isMissingData(state)) {
|
|
242
|
+
// Suspend if an active operation bears on this fragment, either the
|
|
243
|
+
// fragment's owner or some other mutation etc. that could affect it:
|
|
244
|
+
invariant(fragmentSelector != null, 'refinement, see invariants above');
|
|
245
|
+
const fragmentOwner =
|
|
246
|
+
fragmentSelector.kind === 'PluralReaderSelector'
|
|
247
|
+
? fragmentSelector.selectors[0].owner
|
|
248
|
+
: fragmentSelector.owner;
|
|
249
|
+
const pendingOperationsResult = getPendingOperationsForFragment(
|
|
250
|
+
environment,
|
|
251
|
+
fragmentNode,
|
|
252
|
+
fragmentOwner,
|
|
253
|
+
);
|
|
254
|
+
if (pendingOperationsResult) {
|
|
255
|
+
throw pendingOperationsResult.promise;
|
|
256
|
+
}
|
|
257
|
+
// Report required fields only if we're not suspending, since that means
|
|
258
|
+
// they're missing even though we are out of options for possibly fetching them:
|
|
259
|
+
handlePotentialSnapshotErrorsForState(environment, state);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
let data: ?SelectorData | Array<?SelectorData>;
|
|
263
|
+
if (state.kind === 'bailout') {
|
|
264
|
+
data = isPlural ? [] : null;
|
|
265
|
+
} else if (state.kind === 'singular') {
|
|
266
|
+
data = state.snapshot.data;
|
|
267
|
+
} else {
|
|
268
|
+
data = state.snapshots.map(s => s.data);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (__DEV__) {
|
|
272
|
+
if (
|
|
273
|
+
fragmentRef != null &&
|
|
274
|
+
(data === undefined ||
|
|
275
|
+
(Array.isArray(data) &&
|
|
276
|
+
data.length > 0 &&
|
|
277
|
+
data.every(d => d === undefined)))
|
|
278
|
+
) {
|
|
279
|
+
warning(
|
|
280
|
+
false,
|
|
281
|
+
'Relay: Expected to have been able to read non-null data for ' +
|
|
282
|
+
'fragment `%s` declared in ' +
|
|
283
|
+
'`%s`, since fragment reference was non-null. ' +
|
|
284
|
+
"Make sure that that `%s`'s parent isn't " +
|
|
285
|
+
'holding on to and/or passing a fragment reference for data that ' +
|
|
286
|
+
'has been deleted.',
|
|
287
|
+
fragmentNode.name,
|
|
288
|
+
hookDisplayName,
|
|
289
|
+
hookDisplayName,
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return {data, clientEdgeQueries};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
module.exports = readFragmentInternal_REACT_CACHE;
|