relay-runtime 11.0.1 → 13.0.0-rc.1
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/handlers/RelayDefaultHandlerProvider.js.flow +2 -2
- package/handlers/connection/ConnectionHandler.js.flow +8 -17
- package/handlers/connection/MutationHandlers.js.flow +7 -11
- package/index.js +1 -1
- package/index.js.flow +60 -36
- package/lib/handlers/RelayDefaultHandlerProvider.js +1 -1
- package/lib/handlers/connection/ConnectionHandler.js +13 -19
- package/lib/handlers/connection/MutationHandlers.js +4 -7
- package/lib/index.js +58 -43
- package/lib/multi-actor-environment/ActorIdentifier.js +33 -0
- package/lib/multi-actor-environment/ActorSpecificEnvironment.js +152 -0
- package/lib/multi-actor-environment/ActorUtils.js +27 -0
- package/lib/multi-actor-environment/MultiActorEnvironment.js +419 -0
- package/lib/multi-actor-environment/MultiActorEnvironmentTypes.js +11 -0
- package/lib/multi-actor-environment/index.js +21 -0
- package/lib/mutations/RelayDeclarativeMutationConfig.js +4 -1
- package/lib/mutations/RelayRecordProxy.js +3 -2
- package/lib/mutations/RelayRecordSourceMutator.js +3 -2
- package/lib/mutations/RelayRecordSourceProxy.js +12 -4
- package/lib/mutations/RelayRecordSourceSelectorProxy.js +18 -5
- package/lib/mutations/applyOptimisticMutation.js +6 -6
- package/lib/mutations/commitMutation.js +14 -10
- package/lib/mutations/readUpdatableQuery_EXPERIMENTAL.js +238 -0
- package/lib/mutations/validateMutation.js +10 -5
- package/lib/network/ConvertToExecuteFunction.js +2 -1
- package/lib/network/RelayNetwork.js +3 -2
- package/lib/network/RelayQueryResponseCache.js +21 -5
- package/lib/network/wrapNetworkWithLogObserver.js +79 -0
- package/lib/query/GraphQLTag.js +3 -2
- package/lib/query/fetchQuery.js +6 -5
- package/lib/query/fetchQueryInternal.js +1 -1
- package/lib/query/fetchQuery_DEPRECATED.js +2 -1
- package/lib/store/ClientID.js +7 -1
- package/lib/store/DataChecker.js +123 -54
- package/lib/store/{RelayModernQueryExecutor.js → OperationExecutor.js} +518 -200
- package/lib/store/RelayConcreteVariables.js +26 -8
- package/lib/store/RelayExperimentalGraphResponseHandler.js +153 -0
- package/lib/store/RelayExperimentalGraphResponseTransform.js +391 -0
- package/lib/store/RelayModernEnvironment.js +175 -240
- package/lib/store/RelayModernFragmentSpecResolver.js +52 -26
- package/lib/store/RelayModernOperationDescriptor.js +2 -1
- package/lib/store/RelayModernRecord.js +47 -12
- package/lib/store/RelayModernSelector.js +14 -8
- package/lib/store/RelayModernStore.js +56 -28
- package/lib/store/RelayOperationTracker.js +34 -24
- package/lib/store/RelayPublishQueue.js +41 -13
- package/lib/store/RelayReader.js +288 -48
- package/lib/store/RelayRecordSource.js +87 -3
- package/lib/store/RelayReferenceMarker.js +34 -22
- package/lib/store/RelayResponseNormalizer.js +211 -110
- package/lib/store/RelayStoreReactFlightUtils.js +4 -10
- package/lib/store/RelayStoreSubscriptions.js +14 -9
- package/lib/store/RelayStoreUtils.js +12 -7
- package/lib/store/ResolverCache.js +213 -0
- package/lib/store/ResolverFragments.js +61 -0
- package/lib/store/cloneRelayHandleSourceField.js +5 -4
- package/lib/store/cloneRelayScalarHandleSourceField.js +5 -4
- package/lib/store/createRelayContext.js +4 -2
- package/lib/store/readInlineData.js +6 -2
- package/lib/subscription/requestSubscription.js +34 -25
- package/lib/util/RelayConcreteNode.js +3 -0
- package/lib/util/RelayFeatureFlags.js +10 -4
- package/lib/util/RelayProfiler.js +17 -187
- package/lib/util/RelayReplaySubject.js +22 -7
- package/lib/util/RelayRuntimeTypes.js +0 -6
- package/lib/util/StringInterner.js +71 -0
- package/lib/util/getFragmentIdentifier.js +15 -7
- package/lib/util/getOperation.js +2 -1
- package/lib/util/getPaginationMetadata.js +41 -0
- package/lib/util/getPaginationVariables.js +66 -0
- package/lib/util/getPendingOperationsForFragment.js +55 -0
- package/lib/util/getRefetchMetadata.js +36 -0
- package/lib/util/getRelayHandleKey.js +2 -2
- package/lib/util/getRequestIdentifier.js +2 -2
- package/lib/util/getValueAtPath.js +51 -0
- package/lib/util/isEmptyObject.js +1 -1
- package/lib/util/registerEnvironmentWithDevTools.js +26 -0
- package/lib/util/withDuration.js +31 -0
- package/multi-actor-environment/ActorIdentifier.js.flow +43 -0
- package/multi-actor-environment/ActorSpecificEnvironment.js.flow +225 -0
- package/multi-actor-environment/ActorUtils.js.flow +33 -0
- package/multi-actor-environment/MultiActorEnvironment.js.flow +506 -0
- package/multi-actor-environment/MultiActorEnvironmentTypes.js.flow +261 -0
- package/multi-actor-environment/index.js.flow +26 -0
- package/mutations/RelayDeclarativeMutationConfig.js.flow +32 -26
- package/mutations/RelayRecordProxy.js.flow +4 -5
- package/mutations/RelayRecordSourceMutator.js.flow +4 -6
- package/mutations/RelayRecordSourceProxy.js.flow +19 -10
- package/mutations/RelayRecordSourceSelectorProxy.js.flow +22 -7
- package/mutations/applyOptimisticMutation.js.flow +13 -14
- package/mutations/commitLocalUpdate.js.flow +1 -1
- package/mutations/commitMutation.js.flow +35 -46
- package/mutations/readUpdatableQuery_EXPERIMENTAL.js.flow +309 -0
- package/mutations/validateMutation.js.flow +26 -16
- package/network/ConvertToExecuteFunction.js.flow +2 -2
- package/network/RelayNetwork.js.flow +4 -5
- package/network/RelayNetworkTypes.js.flow +5 -4
- package/network/RelayObservable.js.flow +1 -1
- package/network/RelayQueryResponseCache.js.flow +34 -21
- package/network/wrapNetworkWithLogObserver.js.flow +100 -0
- package/package.json +3 -2
- package/query/GraphQLTag.js.flow +9 -9
- package/query/PreloadableQueryRegistry.js.flow +2 -1
- package/query/fetchQuery.js.flow +11 -13
- package/query/fetchQueryInternal.js.flow +6 -9
- package/query/fetchQuery_DEPRECATED.js.flow +6 -6
- package/relay-runtime.js +2 -2
- package/relay-runtime.min.js +2 -2
- package/store/ClientID.js.flow +14 -3
- package/store/DataChecker.js.flow +141 -59
- package/store/{RelayModernQueryExecutor.js.flow → OperationExecutor.js.flow} +605 -303
- package/store/RelayConcreteVariables.js.flow +27 -8
- package/store/RelayExperimentalGraphResponseHandler.js.flow +124 -0
- package/store/RelayExperimentalGraphResponseTransform.js.flow +475 -0
- package/store/RelayModernEnvironment.js.flow +173 -240
- package/store/RelayModernFragmentSpecResolver.js.flow +55 -31
- package/store/RelayModernOperationDescriptor.js.flow +12 -7
- package/store/RelayModernRecord.js.flow +67 -11
- package/store/RelayModernSelector.js.flow +24 -14
- package/store/RelayModernStore.js.flow +66 -36
- package/store/RelayOperationTracker.js.flow +59 -43
- package/store/RelayOptimisticRecordSource.js.flow +2 -2
- package/store/RelayPublishQueue.js.flow +79 -34
- package/store/RelayReader.js.flow +351 -73
- package/store/RelayRecordSource.js.flow +72 -6
- package/store/RelayReferenceMarker.js.flow +40 -26
- package/store/RelayResponseNormalizer.js.flow +258 -99
- package/store/RelayStoreReactFlightUtils.js.flow +4 -11
- package/store/RelayStoreSubscriptions.js.flow +19 -11
- package/store/RelayStoreTypes.js.flow +209 -43
- package/store/RelayStoreUtils.js.flow +24 -11
- package/store/ResolverCache.js.flow +249 -0
- package/store/ResolverFragments.js.flow +121 -0
- package/store/StoreInspector.js.flow +2 -2
- package/store/TypeID.js.flow +1 -1
- package/store/ViewerPattern.js.flow +2 -2
- package/store/cloneRelayHandleSourceField.js.flow +5 -6
- package/store/cloneRelayScalarHandleSourceField.js.flow +5 -6
- package/store/createFragmentSpecResolver.js.flow +3 -4
- package/store/createRelayContext.js.flow +3 -3
- package/store/normalizeRelayPayload.js.flow +6 -7
- package/store/readInlineData.js.flow +7 -8
- package/subscription/requestSubscription.js.flow +53 -41
- package/util/NormalizationNode.js.flow +10 -3
- package/util/ReaderNode.js.flow +38 -2
- package/util/RelayConcreteNode.js.flow +5 -0
- package/util/RelayFeatureFlags.js.flow +24 -10
- package/util/RelayProfiler.js.flow +22 -194
- package/util/RelayReplaySubject.js.flow +9 -9
- package/util/RelayRuntimeTypes.js.flow +72 -3
- package/util/StringInterner.js.flow +69 -0
- package/util/createPayloadFor3DField.js.flow +3 -3
- package/util/getFragmentIdentifier.js.flow +27 -15
- package/util/getOperation.js.flow +2 -2
- package/util/getPaginationMetadata.js.flow +72 -0
- package/util/getPaginationVariables.js.flow +108 -0
- package/util/getPendingOperationsForFragment.js.flow +62 -0
- package/util/getRefetchMetadata.js.flow +79 -0
- package/util/getRelayHandleKey.js.flow +1 -2
- package/util/getRequestIdentifier.js.flow +3 -3
- package/util/getValueAtPath.js.flow +46 -0
- package/util/isEmptyObject.js.flow +1 -0
- package/util/registerEnvironmentWithDevTools.js.flow +33 -0
- package/util/resolveImmediate.js.flow +1 -1
- package/util/withDuration.js.flow +32 -0
- package/lib/store/RelayRecordSourceMapImpl.js +0 -107
- package/lib/store/RelayStoreSubscriptionsUsingMapByID.js +0 -318
- package/store/RelayRecordSourceMapImpl.js.flow +0 -91
- package/store/RelayStoreSubscriptionsUsingMapByID.js.flow +0 -283
|
@@ -12,12 +12,39 @@
|
|
|
12
12
|
|
|
13
13
|
'use strict';
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
import type {
|
|
16
|
+
ReaderActorChange,
|
|
17
|
+
ReaderClientEdge,
|
|
18
|
+
ReaderFlightField,
|
|
19
|
+
ReaderFragment,
|
|
20
|
+
ReaderFragmentSpread,
|
|
21
|
+
ReaderInlineDataFragmentSpread,
|
|
22
|
+
ReaderLinkedField,
|
|
23
|
+
ReaderModuleImport,
|
|
24
|
+
ReaderNode,
|
|
25
|
+
ReaderRelayResolver,
|
|
26
|
+
ReaderRequiredField,
|
|
27
|
+
ReaderScalarField,
|
|
28
|
+
ReaderSelection,
|
|
29
|
+
} from '../util/ReaderNode';
|
|
30
|
+
import type {DataID, Variables} from '../util/RelayRuntimeTypes';
|
|
31
|
+
import type {
|
|
32
|
+
ClientEdgeTraversalInfo,
|
|
33
|
+
DataIDSet,
|
|
34
|
+
MissingClientEdgeRequestInfo,
|
|
35
|
+
MissingRequiredFields,
|
|
36
|
+
Record,
|
|
37
|
+
RecordSource,
|
|
38
|
+
RequestDescriptor,
|
|
39
|
+
SelectorData,
|
|
40
|
+
SingularReaderSelector,
|
|
41
|
+
Snapshot,
|
|
42
|
+
} from './RelayStoreTypes';
|
|
43
|
+
import type {ResolverCache} from './ResolverCache';
|
|
19
44
|
|
|
20
45
|
const {
|
|
46
|
+
ACTOR_CHANGE,
|
|
47
|
+
CLIENT_EDGE,
|
|
21
48
|
CLIENT_EXTENSION,
|
|
22
49
|
CONDITION,
|
|
23
50
|
DEFER,
|
|
@@ -27,53 +54,43 @@ const {
|
|
|
27
54
|
INLINE_FRAGMENT,
|
|
28
55
|
LINKED_FIELD,
|
|
29
56
|
MODULE_IMPORT,
|
|
57
|
+
RELAY_RESOLVER,
|
|
30
58
|
REQUIRED_FIELD,
|
|
31
59
|
SCALAR_FIELD,
|
|
32
60
|
STREAM,
|
|
33
61
|
} = require('../util/RelayConcreteNode');
|
|
62
|
+
const RelayFeatureFlags = require('../util/RelayFeatureFlags');
|
|
63
|
+
const ClientID = require('./ClientID');
|
|
64
|
+
const RelayModernRecord = require('./RelayModernRecord');
|
|
34
65
|
const {getReactFlightClientResponse} = require('./RelayStoreReactFlightUtils');
|
|
35
66
|
const {
|
|
36
|
-
|
|
67
|
+
CLIENT_EDGE_TRAVERSAL_PATH,
|
|
37
68
|
FRAGMENT_OWNER_KEY,
|
|
38
69
|
FRAGMENT_PROP_NAME_KEY,
|
|
70
|
+
FRAGMENTS_KEY,
|
|
39
71
|
ID_KEY,
|
|
40
72
|
IS_WITHIN_UNMATCHED_TYPE_REFINEMENT,
|
|
41
73
|
MODULE_COMPONENT_KEY,
|
|
42
74
|
ROOT_ID,
|
|
43
75
|
getArgumentValues,
|
|
44
|
-
getStorageKey,
|
|
45
76
|
getModuleComponentKey,
|
|
77
|
+
getStorageKey,
|
|
46
78
|
} = require('./RelayStoreUtils');
|
|
79
|
+
const {NoopResolverCache} = require('./ResolverCache');
|
|
80
|
+
const {withResolverContext} = require('./ResolverFragments');
|
|
47
81
|
const {generateTypeID} = require('./TypeID');
|
|
48
|
-
|
|
49
|
-
import type {
|
|
50
|
-
ReaderFlightField,
|
|
51
|
-
ReaderFragmentSpread,
|
|
52
|
-
ReaderInlineDataFragmentSpread,
|
|
53
|
-
ReaderLinkedField,
|
|
54
|
-
ReaderModuleImport,
|
|
55
|
-
ReaderNode,
|
|
56
|
-
ReaderRequiredField,
|
|
57
|
-
ReaderScalarField,
|
|
58
|
-
ReaderSelection,
|
|
59
|
-
} from '../util/ReaderNode';
|
|
60
|
-
import type {DataID, Variables} from '../util/RelayRuntimeTypes';
|
|
61
|
-
import type {
|
|
62
|
-
Record,
|
|
63
|
-
RecordSource,
|
|
64
|
-
RequestDescriptor,
|
|
65
|
-
SelectorData,
|
|
66
|
-
SingularReaderSelector,
|
|
67
|
-
Snapshot,
|
|
68
|
-
MissingRequiredFields,
|
|
69
|
-
DataIDSet,
|
|
70
|
-
} from './RelayStoreTypes';
|
|
82
|
+
const invariant = require('invariant');
|
|
71
83
|
|
|
72
84
|
function read(
|
|
73
85
|
recordSource: RecordSource,
|
|
74
86
|
selector: SingularReaderSelector,
|
|
87
|
+
resolverCache?: ResolverCache,
|
|
75
88
|
): Snapshot {
|
|
76
|
-
const reader = new RelayReader(
|
|
89
|
+
const reader = new RelayReader(
|
|
90
|
+
recordSource,
|
|
91
|
+
selector,
|
|
92
|
+
resolverCache ?? new NoopResolverCache(),
|
|
93
|
+
);
|
|
77
94
|
return reader.read();
|
|
78
95
|
}
|
|
79
96
|
|
|
@@ -81,7 +98,9 @@ function read(
|
|
|
81
98
|
* @private
|
|
82
99
|
*/
|
|
83
100
|
class RelayReader {
|
|
101
|
+
_clientEdgeTraversalPath: Array<ClientEdgeTraversalInfo | null>;
|
|
84
102
|
_isMissingData: boolean;
|
|
103
|
+
_missingClientEdges: Array<MissingClientEdgeRequestInfo>;
|
|
85
104
|
_isWithinUnmatchedTypeRefinement: boolean;
|
|
86
105
|
_missingRequiredFields: ?MissingRequiredFields;
|
|
87
106
|
_owner: RequestDescriptor;
|
|
@@ -89,8 +108,19 @@ class RelayReader {
|
|
|
89
108
|
_seenRecords: DataIDSet;
|
|
90
109
|
_selector: SingularReaderSelector;
|
|
91
110
|
_variables: Variables;
|
|
111
|
+
_resolverCache: ResolverCache;
|
|
92
112
|
|
|
93
|
-
constructor(
|
|
113
|
+
constructor(
|
|
114
|
+
recordSource: RecordSource,
|
|
115
|
+
selector: SingularReaderSelector,
|
|
116
|
+
resolverCache: ResolverCache,
|
|
117
|
+
) {
|
|
118
|
+
this._clientEdgeTraversalPath =
|
|
119
|
+
RelayFeatureFlags.ENABLE_CLIENT_EDGES &&
|
|
120
|
+
selector.clientEdgeTraversalPath?.length
|
|
121
|
+
? [...selector.clientEdgeTraversalPath]
|
|
122
|
+
: [];
|
|
123
|
+
this._missingClientEdges = [];
|
|
94
124
|
this._isMissingData = false;
|
|
95
125
|
this._isWithinUnmatchedTypeRefinement = false;
|
|
96
126
|
this._missingRequiredFields = null;
|
|
@@ -99,6 +129,7 @@ class RelayReader {
|
|
|
99
129
|
this._seenRecords = new Set();
|
|
100
130
|
this._selector = selector;
|
|
101
131
|
this._variables = selector.variables;
|
|
132
|
+
this._resolverCache = resolverCache;
|
|
102
133
|
}
|
|
103
134
|
|
|
104
135
|
read(): Snapshot {
|
|
@@ -122,7 +153,18 @@ class RelayReader {
|
|
|
122
153
|
// match, then no data is expected to be present.
|
|
123
154
|
if (isDataExpectedToBePresent && abstractKey == null && record != null) {
|
|
124
155
|
const recordType = RelayModernRecord.getType(record);
|
|
125
|
-
if (
|
|
156
|
+
if (
|
|
157
|
+
recordType !== node.type &&
|
|
158
|
+
// The root record type is a special `__Root` type and may not match the
|
|
159
|
+
// type on the ast, so ignore type mismatches at the root.
|
|
160
|
+
// We currently detect whether we're at the root by checking against ROOT_ID,
|
|
161
|
+
// but this does not work for mutations/subscriptions which generate unique
|
|
162
|
+
// root ids. This is acceptable in practice as we don't read data for mutations/
|
|
163
|
+
// subscriptions in a situation where we would use isMissingData to decide whether
|
|
164
|
+
// to suspend or not.
|
|
165
|
+
// TODO T96653810: Correctly detect reading from root of mutation/subscription
|
|
166
|
+
dataID !== ROOT_ID
|
|
167
|
+
) {
|
|
126
168
|
isDataExpectedToBePresent = false;
|
|
127
169
|
}
|
|
128
170
|
}
|
|
@@ -131,12 +173,7 @@ class RelayReader {
|
|
|
131
173
|
// then data is only expected to be present if the record type is known to
|
|
132
174
|
// implement the interface. If we aren't sure whether the record implements
|
|
133
175
|
// the interface, that itself constitutes "expected" data being missing.
|
|
134
|
-
if (
|
|
135
|
-
isDataExpectedToBePresent &&
|
|
136
|
-
abstractKey != null &&
|
|
137
|
-
record != null &&
|
|
138
|
-
RelayFeatureFlags.ENABLE_PRECISE_TYPE_REFINEMENT
|
|
139
|
-
) {
|
|
176
|
+
if (isDataExpectedToBePresent && abstractKey != null && record != null) {
|
|
140
177
|
const recordType = RelayModernRecord.getType(record);
|
|
141
178
|
const typeID = generateTypeID(recordType);
|
|
142
179
|
const typeRecord = this._recordSource.get(typeID);
|
|
@@ -158,12 +195,36 @@ class RelayReader {
|
|
|
158
195
|
return {
|
|
159
196
|
data,
|
|
160
197
|
isMissingData: this._isMissingData && isDataExpectedToBePresent,
|
|
198
|
+
missingClientEdges:
|
|
199
|
+
RelayFeatureFlags.ENABLE_CLIENT_EDGES && this._missingClientEdges.length
|
|
200
|
+
? this._missingClientEdges
|
|
201
|
+
: null,
|
|
161
202
|
seenRecords: this._seenRecords,
|
|
162
203
|
selector: this._selector,
|
|
163
204
|
missingRequiredFields: this._missingRequiredFields,
|
|
164
205
|
};
|
|
165
206
|
}
|
|
166
207
|
|
|
208
|
+
_markDataAsMissing(): void {
|
|
209
|
+
this._isMissingData = true;
|
|
210
|
+
if (
|
|
211
|
+
RelayFeatureFlags.ENABLE_CLIENT_EDGES &&
|
|
212
|
+
this._clientEdgeTraversalPath.length
|
|
213
|
+
) {
|
|
214
|
+
const top =
|
|
215
|
+
this._clientEdgeTraversalPath[this._clientEdgeTraversalPath.length - 1];
|
|
216
|
+
// Top can be null if we've traversed past a client edge into an ordinary
|
|
217
|
+
// client extension field; we never want to fetch in response to missing
|
|
218
|
+
// data off of a client extension field.
|
|
219
|
+
if (top !== null) {
|
|
220
|
+
this._missingClientEdges.push({
|
|
221
|
+
request: top.readerClientEdge.operation,
|
|
222
|
+
clientEdgeDestinationID: top.clientEdgeDestinationID,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
167
228
|
_traverse(
|
|
168
229
|
node: ReaderNode,
|
|
169
230
|
dataID: DataID,
|
|
@@ -173,7 +234,7 @@ class RelayReader {
|
|
|
173
234
|
this._seenRecords.add(dataID);
|
|
174
235
|
if (record == null) {
|
|
175
236
|
if (record === undefined) {
|
|
176
|
-
this.
|
|
237
|
+
this._markDataAsMissing();
|
|
177
238
|
}
|
|
178
239
|
return record;
|
|
179
240
|
}
|
|
@@ -192,7 +253,6 @@ class RelayReader {
|
|
|
192
253
|
'RelayReader(): Undefined variable `%s`.',
|
|
193
254
|
name,
|
|
194
255
|
);
|
|
195
|
-
// $FlowFixMe[cannot-write]
|
|
196
256
|
return this._variables[name];
|
|
197
257
|
}
|
|
198
258
|
|
|
@@ -263,7 +323,9 @@ class RelayReader {
|
|
|
263
323
|
}
|
|
264
324
|
break;
|
|
265
325
|
case CONDITION:
|
|
266
|
-
const conditionValue =
|
|
326
|
+
const conditionValue = Boolean(
|
|
327
|
+
this._getVariableValue(selection.condition),
|
|
328
|
+
);
|
|
267
329
|
if (conditionValue === selection.passingValue) {
|
|
268
330
|
const hasExpectedData = this._traverseSelections(
|
|
269
331
|
selection.selections,
|
|
@@ -290,15 +352,15 @@ class RelayReader {
|
|
|
290
352
|
return false;
|
|
291
353
|
}
|
|
292
354
|
}
|
|
293
|
-
} else
|
|
355
|
+
} else {
|
|
294
356
|
// Similar to the logic in read(): data is only expected to be present
|
|
295
357
|
// if the record is known to conform to the interface. If we don't know
|
|
296
358
|
// whether the type conforms or not, that constitutes missing data.
|
|
297
359
|
|
|
298
360
|
// store flags to reset after reading
|
|
299
361
|
const parentIsMissingData = this._isMissingData;
|
|
300
|
-
const parentIsWithinUnmatchedTypeRefinement =
|
|
301
|
-
._isWithinUnmatchedTypeRefinement;
|
|
362
|
+
const parentIsWithinUnmatchedTypeRefinement =
|
|
363
|
+
this._isWithinUnmatchedTypeRefinement;
|
|
302
364
|
|
|
303
365
|
const typeName = RelayModernRecord.getType(record);
|
|
304
366
|
const typeID = generateTypeID(typeName);
|
|
@@ -311,22 +373,26 @@ class RelayReader {
|
|
|
311
373
|
parentIsWithinUnmatchedTypeRefinement ||
|
|
312
374
|
implementsInterface === false;
|
|
313
375
|
this._traverseSelections(selection.selections, record, data);
|
|
314
|
-
this._isWithinUnmatchedTypeRefinement =
|
|
376
|
+
this._isWithinUnmatchedTypeRefinement =
|
|
377
|
+
parentIsWithinUnmatchedTypeRefinement;
|
|
315
378
|
|
|
316
379
|
if (implementsInterface === false) {
|
|
317
380
|
// Type known to not implement the interface, no data expected
|
|
318
381
|
this._isMissingData = parentIsMissingData;
|
|
319
382
|
} else if (implementsInterface == null) {
|
|
320
383
|
// Don't know if the type implements the interface or not
|
|
321
|
-
this.
|
|
384
|
+
this._markDataAsMissing();
|
|
322
385
|
}
|
|
323
|
-
} else {
|
|
324
|
-
// legacy behavior for abstract refinements: always read even
|
|
325
|
-
// if the type doesn't conform and don't reset isMissingData
|
|
326
|
-
this._traverseSelections(selection.selections, record, data);
|
|
327
386
|
}
|
|
328
387
|
break;
|
|
329
388
|
}
|
|
389
|
+
case RELAY_RESOLVER: {
|
|
390
|
+
if (!RelayFeatureFlags.ENABLE_RELAY_RESOLVERS) {
|
|
391
|
+
throw new Error('Relay Resolver fields are not yet supported.');
|
|
392
|
+
}
|
|
393
|
+
this._readResolverField(selection, record, data);
|
|
394
|
+
break;
|
|
395
|
+
}
|
|
330
396
|
case FRAGMENT_SPREAD:
|
|
331
397
|
this._createFragmentPointer(selection, record, data);
|
|
332
398
|
break;
|
|
@@ -334,17 +400,33 @@ class RelayReader {
|
|
|
334
400
|
this._readModuleImport(selection, record, data);
|
|
335
401
|
break;
|
|
336
402
|
case INLINE_DATA_FRAGMENT_SPREAD:
|
|
337
|
-
this.
|
|
403
|
+
this._createInlineDataOrResolverFragmentPointer(
|
|
404
|
+
selection,
|
|
405
|
+
record,
|
|
406
|
+
data,
|
|
407
|
+
);
|
|
338
408
|
break;
|
|
339
409
|
case DEFER:
|
|
340
410
|
case CLIENT_EXTENSION: {
|
|
341
411
|
const isMissingData = this._isMissingData;
|
|
412
|
+
const alreadyMissingClientEdges = this._missingClientEdges.length;
|
|
413
|
+
if (RelayFeatureFlags.ENABLE_CLIENT_EDGES) {
|
|
414
|
+
this._clientEdgeTraversalPath.push(null);
|
|
415
|
+
}
|
|
342
416
|
const hasExpectedData = this._traverseSelections(
|
|
343
417
|
selection.selections,
|
|
344
418
|
record,
|
|
345
419
|
data,
|
|
346
420
|
);
|
|
347
|
-
|
|
421
|
+
// The only case where we want to suspend due to missing data off of
|
|
422
|
+
// a client extension is if we reached a client edge that we might be
|
|
423
|
+
// able to fetch:
|
|
424
|
+
this._isMissingData =
|
|
425
|
+
isMissingData ||
|
|
426
|
+
this._missingClientEdges.length > alreadyMissingClientEdges;
|
|
427
|
+
if (RelayFeatureFlags.ENABLE_CLIENT_EDGES) {
|
|
428
|
+
this._clientEdgeTraversalPath.pop();
|
|
429
|
+
}
|
|
348
430
|
if (!hasExpectedData) {
|
|
349
431
|
return false;
|
|
350
432
|
}
|
|
@@ -368,6 +450,16 @@ class RelayReader {
|
|
|
368
450
|
throw new Error('Flight fields are not yet supported.');
|
|
369
451
|
}
|
|
370
452
|
break;
|
|
453
|
+
case ACTOR_CHANGE:
|
|
454
|
+
this._readActorChange(selection, record, data);
|
|
455
|
+
break;
|
|
456
|
+
case CLIENT_EDGE:
|
|
457
|
+
if (RelayFeatureFlags.ENABLE_CLIENT_EDGES) {
|
|
458
|
+
this._readClientEdge(selection, record, data);
|
|
459
|
+
} else {
|
|
460
|
+
throw new Error('Client edges are not yet supported.');
|
|
461
|
+
}
|
|
462
|
+
break;
|
|
371
463
|
default:
|
|
372
464
|
(selection: empty);
|
|
373
465
|
invariant(
|
|
@@ -394,6 +486,12 @@ class RelayReader {
|
|
|
394
486
|
} else {
|
|
395
487
|
return this._readLink(selection.field, record, data);
|
|
396
488
|
}
|
|
489
|
+
case RELAY_RESOLVER:
|
|
490
|
+
if (!RelayFeatureFlags.ENABLE_RELAY_RESOLVERS) {
|
|
491
|
+
throw new Error('Relay Resolver fields are not yet supported.');
|
|
492
|
+
}
|
|
493
|
+
this._readResolverField(selection.field, record, data);
|
|
494
|
+
break;
|
|
397
495
|
default:
|
|
398
496
|
(selection.field.kind: empty);
|
|
399
497
|
invariant(
|
|
@@ -404,6 +502,145 @@ class RelayReader {
|
|
|
404
502
|
}
|
|
405
503
|
}
|
|
406
504
|
|
|
505
|
+
_readResolverField(
|
|
506
|
+
field: ReaderRelayResolver,
|
|
507
|
+
record: Record,
|
|
508
|
+
data: SelectorData,
|
|
509
|
+
): void {
|
|
510
|
+
const {resolverModule, fragment} = field;
|
|
511
|
+
const storageKey = getStorageKey(field, this._variables);
|
|
512
|
+
const resolverID = ClientID.generateClientID(
|
|
513
|
+
RelayModernRecord.getDataID(record),
|
|
514
|
+
storageKey,
|
|
515
|
+
);
|
|
516
|
+
|
|
517
|
+
// Found when reading the resolver fragment, which can happen either when
|
|
518
|
+
// evaluating the resolver and it calls readFragment, or when checking if the
|
|
519
|
+
// inputs have changed since a previous evaluation:
|
|
520
|
+
let fragmentValue;
|
|
521
|
+
let fragmentReaderSelector;
|
|
522
|
+
const fragmentSeenRecordIDs = new Set();
|
|
523
|
+
|
|
524
|
+
const getDataForResolverFragment = singularReaderSelector => {
|
|
525
|
+
if (fragmentValue != null) {
|
|
526
|
+
// It was already read when checking for input staleness; no need to read it again.
|
|
527
|
+
// Note that the variables like fragmentSeenRecordIDs in the outer closure will have
|
|
528
|
+
// already been set and will still be used in this case.
|
|
529
|
+
return fragmentValue;
|
|
530
|
+
}
|
|
531
|
+
fragmentReaderSelector = singularReaderSelector;
|
|
532
|
+
const existingSeenRecords = this._seenRecords;
|
|
533
|
+
try {
|
|
534
|
+
this._seenRecords = fragmentSeenRecordIDs;
|
|
535
|
+
const resolverFragmentData = {};
|
|
536
|
+
this._createInlineDataOrResolverFragmentPointer(
|
|
537
|
+
singularReaderSelector.node,
|
|
538
|
+
record,
|
|
539
|
+
resolverFragmentData,
|
|
540
|
+
);
|
|
541
|
+
fragmentValue = resolverFragmentData[FRAGMENTS_KEY]?.[fragment.name];
|
|
542
|
+
invariant(
|
|
543
|
+
typeof fragmentValue === 'object' && fragmentValue !== null,
|
|
544
|
+
`Expected reader data to contain a __fragments property with a property for the fragment named ${fragment.name}, but it is missing.`,
|
|
545
|
+
);
|
|
546
|
+
return fragmentValue;
|
|
547
|
+
} finally {
|
|
548
|
+
this._seenRecords = existingSeenRecords;
|
|
549
|
+
}
|
|
550
|
+
};
|
|
551
|
+
const resolverContext = {getDataForResolverFragment};
|
|
552
|
+
|
|
553
|
+
const [result, seenRecord] = this._resolverCache.readFromCacheOrEvaluate(
|
|
554
|
+
record,
|
|
555
|
+
field,
|
|
556
|
+
this._variables,
|
|
557
|
+
() => {
|
|
558
|
+
const key = {
|
|
559
|
+
__id: RelayModernRecord.getDataID(record),
|
|
560
|
+
__fragmentOwner: this._owner,
|
|
561
|
+
__fragments: {
|
|
562
|
+
[fragment.name]: {}, // Arguments to this fragment; not yet supported.
|
|
563
|
+
},
|
|
564
|
+
};
|
|
565
|
+
return withResolverContext(resolverContext, () => {
|
|
566
|
+
// $FlowFixMe[prop-missing] - resolver module's type signature is a lie
|
|
567
|
+
const resolverResult = resolverModule(key);
|
|
568
|
+
return {
|
|
569
|
+
resolverResult,
|
|
570
|
+
fragmentValue,
|
|
571
|
+
resolverID,
|
|
572
|
+
seenRecordIDs: fragmentSeenRecordIDs,
|
|
573
|
+
readerSelector: fragmentReaderSelector,
|
|
574
|
+
};
|
|
575
|
+
});
|
|
576
|
+
},
|
|
577
|
+
getDataForResolverFragment,
|
|
578
|
+
);
|
|
579
|
+
if (seenRecord != null) {
|
|
580
|
+
this._seenRecords.add(seenRecord);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
const applicationName = field.alias ?? field.name;
|
|
584
|
+
data[applicationName] = result;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
_readClientEdge(
|
|
588
|
+
field: ReaderClientEdge,
|
|
589
|
+
record: Record,
|
|
590
|
+
data: SelectorData,
|
|
591
|
+
): void {
|
|
592
|
+
const backingField = field.backingField;
|
|
593
|
+
|
|
594
|
+
// Because ReaderClientExtension doesn't have `alias` or `name` and so I don't know
|
|
595
|
+
// how to get its applicationName or storageKey yet:
|
|
596
|
+
invariant(
|
|
597
|
+
backingField.kind !== 'ClientExtension',
|
|
598
|
+
'Client extension client edges are not yet implemented.',
|
|
599
|
+
);
|
|
600
|
+
|
|
601
|
+
const applicationName = backingField.alias ?? backingField.name;
|
|
602
|
+
|
|
603
|
+
const backingFieldData = {};
|
|
604
|
+
this._traverseSelections([backingField], record, backingFieldData);
|
|
605
|
+
const destinationDataID = backingFieldData[applicationName];
|
|
606
|
+
|
|
607
|
+
if (destinationDataID == null) {
|
|
608
|
+
data[applicationName] = destinationDataID;
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
invariant(
|
|
613
|
+
typeof destinationDataID === 'string',
|
|
614
|
+
'Plural client edges not are yet implemented',
|
|
615
|
+
); // FIXME support plural
|
|
616
|
+
|
|
617
|
+
// Not wrapping the push/pop in a try/finally because if we throw, the
|
|
618
|
+
// Reader object is not usable after that anyway.
|
|
619
|
+
this._clientEdgeTraversalPath.push({
|
|
620
|
+
readerClientEdge: field,
|
|
621
|
+
clientEdgeDestinationID: destinationDataID,
|
|
622
|
+
});
|
|
623
|
+
|
|
624
|
+
const prevData = data[applicationName];
|
|
625
|
+
invariant(
|
|
626
|
+
prevData == null || typeof prevData === 'object',
|
|
627
|
+
'RelayReader(): Expected data for field `%s` on record `%s` ' +
|
|
628
|
+
'to be an object, got `%s`.',
|
|
629
|
+
applicationName,
|
|
630
|
+
RelayModernRecord.getDataID(record),
|
|
631
|
+
prevData,
|
|
632
|
+
);
|
|
633
|
+
const value = this._traverse(
|
|
634
|
+
field.linkedField,
|
|
635
|
+
destinationDataID,
|
|
636
|
+
// $FlowFixMe[incompatible-variance]
|
|
637
|
+
prevData,
|
|
638
|
+
);
|
|
639
|
+
data[applicationName] = value;
|
|
640
|
+
|
|
641
|
+
this._clientEdgeTraversalPath.pop();
|
|
642
|
+
}
|
|
643
|
+
|
|
407
644
|
_readFlightField(
|
|
408
645
|
field: ReaderFlightField,
|
|
409
646
|
record: Record,
|
|
@@ -411,14 +648,12 @@ class RelayReader {
|
|
|
411
648
|
): ?mixed {
|
|
412
649
|
const applicationName = field.alias ?? field.name;
|
|
413
650
|
const storageKey = getStorageKey(field, this._variables);
|
|
414
|
-
const reactFlightClientResponseRecordID =
|
|
415
|
-
record,
|
|
416
|
-
storageKey,
|
|
417
|
-
);
|
|
651
|
+
const reactFlightClientResponseRecordID =
|
|
652
|
+
RelayModernRecord.getLinkedRecordID(record, storageKey);
|
|
418
653
|
if (reactFlightClientResponseRecordID == null) {
|
|
419
654
|
data[applicationName] = reactFlightClientResponseRecordID;
|
|
420
655
|
if (reactFlightClientResponseRecordID === undefined) {
|
|
421
|
-
this.
|
|
656
|
+
this._markDataAsMissing();
|
|
422
657
|
}
|
|
423
658
|
return reactFlightClientResponseRecordID;
|
|
424
659
|
}
|
|
@@ -429,7 +664,7 @@ class RelayReader {
|
|
|
429
664
|
if (reactFlightClientResponseRecord == null) {
|
|
430
665
|
data[applicationName] = reactFlightClientResponseRecord;
|
|
431
666
|
if (reactFlightClientResponseRecord === undefined) {
|
|
432
|
-
this.
|
|
667
|
+
this._markDataAsMissing();
|
|
433
668
|
}
|
|
434
669
|
return reactFlightClientResponseRecord;
|
|
435
670
|
}
|
|
@@ -449,7 +684,7 @@ class RelayReader {
|
|
|
449
684
|
const storageKey = getStorageKey(field, this._variables);
|
|
450
685
|
const value = RelayModernRecord.getValue(record, storageKey);
|
|
451
686
|
if (value === undefined) {
|
|
452
|
-
this.
|
|
687
|
+
this._markDataAsMissing();
|
|
453
688
|
}
|
|
454
689
|
data[applicationName] = value;
|
|
455
690
|
return value;
|
|
@@ -466,7 +701,7 @@ class RelayReader {
|
|
|
466
701
|
if (linkedID == null) {
|
|
467
702
|
data[applicationName] = linkedID;
|
|
468
703
|
if (linkedID === undefined) {
|
|
469
|
-
this.
|
|
704
|
+
this._markDataAsMissing();
|
|
470
705
|
}
|
|
471
706
|
return linkedID;
|
|
472
707
|
}
|
|
@@ -486,6 +721,42 @@ class RelayReader {
|
|
|
486
721
|
return value;
|
|
487
722
|
}
|
|
488
723
|
|
|
724
|
+
_readActorChange(
|
|
725
|
+
field: ReaderActorChange,
|
|
726
|
+
record: Record,
|
|
727
|
+
data: SelectorData,
|
|
728
|
+
): ?mixed {
|
|
729
|
+
const applicationName = field.alias ?? field.name;
|
|
730
|
+
const storageKey = getStorageKey(field, this._variables);
|
|
731
|
+
const externalRef = RelayModernRecord.getActorLinkedRecordID(
|
|
732
|
+
record,
|
|
733
|
+
storageKey,
|
|
734
|
+
);
|
|
735
|
+
|
|
736
|
+
if (externalRef == null) {
|
|
737
|
+
data[applicationName] = externalRef;
|
|
738
|
+
if (externalRef === undefined) {
|
|
739
|
+
this._markDataAsMissing();
|
|
740
|
+
}
|
|
741
|
+
return data[applicationName];
|
|
742
|
+
}
|
|
743
|
+
const [actorIdentifier, dataID] = externalRef;
|
|
744
|
+
|
|
745
|
+
const fragmentRef = {};
|
|
746
|
+
this._createFragmentPointer(
|
|
747
|
+
field.fragmentSpread,
|
|
748
|
+
{
|
|
749
|
+
__id: dataID,
|
|
750
|
+
},
|
|
751
|
+
fragmentRef,
|
|
752
|
+
);
|
|
753
|
+
data[applicationName] = {
|
|
754
|
+
__fragmentRef: fragmentRef,
|
|
755
|
+
__viewer: actorIdentifier,
|
|
756
|
+
};
|
|
757
|
+
return data[applicationName];
|
|
758
|
+
}
|
|
759
|
+
|
|
489
760
|
_readPluralLink(
|
|
490
761
|
field: ReaderLinkedField,
|
|
491
762
|
record: Record,
|
|
@@ -498,7 +769,7 @@ class RelayReader {
|
|
|
498
769
|
if (linkedIDs == null) {
|
|
499
770
|
data[applicationName] = linkedIDs;
|
|
500
771
|
if (linkedIDs === undefined) {
|
|
501
|
-
this.
|
|
772
|
+
this._markDataAsMissing();
|
|
502
773
|
}
|
|
503
774
|
return linkedIDs;
|
|
504
775
|
}
|
|
@@ -516,7 +787,7 @@ class RelayReader {
|
|
|
516
787
|
linkedIDs.forEach((linkedID, nextIndex) => {
|
|
517
788
|
if (linkedID == null) {
|
|
518
789
|
if (linkedID === undefined) {
|
|
519
|
-
this.
|
|
790
|
+
this._markDataAsMissing();
|
|
520
791
|
}
|
|
521
792
|
// $FlowFixMe[cannot-write]
|
|
522
793
|
linkedArray[nextIndex] = linkedID;
|
|
@@ -554,7 +825,7 @@ class RelayReader {
|
|
|
554
825
|
const component = RelayModernRecord.getValue(record, componentKey);
|
|
555
826
|
if (component == null) {
|
|
556
827
|
if (component === undefined) {
|
|
557
|
-
this.
|
|
828
|
+
this._markDataAsMissing();
|
|
558
829
|
}
|
|
559
830
|
return;
|
|
560
831
|
}
|
|
@@ -568,7 +839,7 @@ class RelayReader {
|
|
|
568
839
|
{
|
|
569
840
|
kind: 'FragmentSpread',
|
|
570
841
|
name: moduleImport.fragmentName,
|
|
571
|
-
args:
|
|
842
|
+
args: moduleImport.args,
|
|
572
843
|
},
|
|
573
844
|
record,
|
|
574
845
|
data,
|
|
@@ -599,16 +870,23 @@ class RelayReader {
|
|
|
599
870
|
? getArgumentValues(fragmentSpread.args, this._variables)
|
|
600
871
|
: {};
|
|
601
872
|
data[FRAGMENT_OWNER_KEY] = this._owner;
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
873
|
+
data[IS_WITHIN_UNMATCHED_TYPE_REFINEMENT] =
|
|
874
|
+
this._isWithinUnmatchedTypeRefinement;
|
|
875
|
+
|
|
876
|
+
if (RelayFeatureFlags.ENABLE_CLIENT_EDGES) {
|
|
877
|
+
if (
|
|
878
|
+
this._clientEdgeTraversalPath.length > 0 &&
|
|
879
|
+
this._clientEdgeTraversalPath[
|
|
880
|
+
this._clientEdgeTraversalPath.length - 1
|
|
881
|
+
] !== null
|
|
882
|
+
) {
|
|
883
|
+
data[CLIENT_EDGE_TRAVERSAL_PATH] = [...this._clientEdgeTraversalPath];
|
|
884
|
+
}
|
|
607
885
|
}
|
|
608
886
|
}
|
|
609
887
|
|
|
610
|
-
|
|
611
|
-
|
|
888
|
+
_createInlineDataOrResolverFragmentPointer(
|
|
889
|
+
fragmentSpreadOrFragment: ReaderInlineDataFragmentSpread | ReaderFragment,
|
|
612
890
|
record: Record,
|
|
613
891
|
data: SelectorData,
|
|
614
892
|
): void {
|
|
@@ -626,12 +904,12 @@ class RelayReader {
|
|
|
626
904
|
}
|
|
627
905
|
const inlineData = {};
|
|
628
906
|
this._traverseSelections(
|
|
629
|
-
|
|
907
|
+
fragmentSpreadOrFragment.selections,
|
|
630
908
|
record,
|
|
631
909
|
inlineData,
|
|
632
910
|
);
|
|
633
911
|
// $FlowFixMe[cannot-write] - writing into read-only field
|
|
634
|
-
fragmentPointers[
|
|
912
|
+
fragmentPointers[fragmentSpreadOrFragment.name] = inlineData;
|
|
635
913
|
}
|
|
636
914
|
}
|
|
637
915
|
|