relay-runtime 11.0.0-rc.0 → 12.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/handlers/connection/ConnectionHandler.js.flow +7 -0
- package/handlers/connection/MutationHandlers.js.flow +28 -0
- package/index.js +1 -1
- package/index.js.flow +20 -3
- package/lib/handlers/RelayDefaultHandlerProvider.js +1 -1
- package/lib/handlers/connection/ConnectionHandler.js +12 -6
- package/lib/handlers/connection/MutationHandlers.js +67 -8
- package/lib/index.js +15 -0
- package/lib/multi-actor-environment/ActorIdentifier.js +33 -0
- package/lib/multi-actor-environment/ActorSpecificEnvironment.js +148 -0
- package/lib/multi-actor-environment/ActorUtils.js +27 -0
- package/lib/multi-actor-environment/MultiActorEnvironment.js +406 -0
- package/lib/multi-actor-environment/MultiActorEnvironmentTypes.js +11 -0
- package/lib/multi-actor-environment/index.js +21 -0
- package/lib/mutations/RelayRecordProxy.js +1 -1
- package/lib/mutations/RelayRecordSourceMutator.js +1 -1
- package/lib/mutations/RelayRecordSourceProxy.js +1 -1
- package/lib/mutations/RelayRecordSourceSelectorProxy.js +7 -2
- package/lib/mutations/applyOptimisticMutation.js +1 -1
- package/lib/mutations/commitMutation.js +5 -2
- package/lib/mutations/validateMutation.js +39 -17
- package/lib/network/RelayNetwork.js +1 -1
- package/lib/network/RelayObservable.js +3 -1
- package/lib/network/RelayQueryResponseCache.js +20 -3
- package/lib/network/wrapNetworkWithLogObserver.js +78 -0
- package/lib/query/GraphQLTag.js +1 -1
- package/lib/query/fetchQuery.js +1 -1
- package/lib/query/fetchQueryInternal.js +1 -1
- package/lib/store/DataChecker.js +132 -50
- package/lib/store/{RelayModernQueryExecutor.js → OperationExecutor.js} +524 -187
- package/lib/store/RelayConcreteVariables.js +29 -4
- package/lib/store/RelayModernEnvironment.js +137 -220
- package/lib/store/RelayModernFragmentSpecResolver.js +49 -23
- package/lib/store/RelayModernRecord.js +36 -2
- package/lib/store/RelayModernSelector.js +1 -1
- package/lib/store/RelayModernStore.js +53 -22
- package/lib/store/RelayOperationTracker.js +34 -24
- package/lib/store/RelayPublishQueue.js +30 -8
- package/lib/store/RelayReader.js +177 -29
- package/lib/store/RelayRecordSource.js +87 -3
- package/lib/store/RelayReferenceMarker.js +53 -28
- package/lib/store/RelayResponseNormalizer.js +247 -108
- package/lib/store/RelayStoreReactFlightUtils.js +7 -11
- package/lib/store/RelayStoreSubscriptions.js +8 -5
- package/lib/store/RelayStoreUtils.js +10 -4
- package/lib/store/ResolverCache.js +213 -0
- package/lib/store/ResolverFragments.js +57 -0
- package/lib/store/cloneRelayHandleSourceField.js +1 -1
- package/lib/store/cloneRelayScalarHandleSourceField.js +1 -1
- package/lib/store/createRelayContext.js +2 -2
- package/lib/store/defaultGetDataID.js +3 -1
- package/lib/store/readInlineData.js +1 -1
- package/lib/subscription/requestSubscription.js +32 -6
- package/lib/util/RelayConcreteNode.js +3 -0
- package/lib/util/RelayFeatureFlags.js +5 -4
- package/lib/util/RelayProfiler.js +17 -187
- package/lib/util/RelayReplaySubject.js +22 -7
- package/lib/util/deepFreeze.js +1 -0
- package/lib/util/getPaginationMetadata.js +41 -0
- package/lib/util/getPaginationVariables.js +67 -0
- package/lib/util/getPendingOperationsForFragment.js +55 -0
- package/lib/util/getRefetchMetadata.js +36 -0
- package/lib/util/getRelayHandleKey.js +1 -1
- package/lib/util/getRequestIdentifier.js +1 -1
- 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 +217 -0
- package/multi-actor-environment/ActorUtils.js.flow +33 -0
- package/multi-actor-environment/MultiActorEnvironment.js.flow +485 -0
- package/multi-actor-environment/MultiActorEnvironmentTypes.js.flow +245 -0
- package/multi-actor-environment/index.js.flow +27 -0
- package/mutations/RelayRecordSourceSelectorProxy.js.flow +7 -2
- package/mutations/commitMutation.js.flow +3 -1
- package/mutations/validateMutation.js.flow +42 -16
- package/network/RelayNetworkTypes.js.flow +17 -8
- package/network/RelayObservable.js.flow +2 -0
- package/network/RelayQueryResponseCache.js.flow +31 -17
- package/network/wrapNetworkWithLogObserver.js.flow +99 -0
- package/package.json +3 -2
- package/relay-runtime.js +2 -2
- package/relay-runtime.min.js +2 -2
- package/store/ClientID.js.flow +5 -1
- package/store/DataChecker.js.flow +148 -44
- package/store/{RelayModernQueryExecutor.js.flow → OperationExecutor.js.flow} +578 -237
- package/store/RelayConcreteVariables.js.flow +31 -1
- package/store/RelayModernEnvironment.js.flow +132 -220
- package/store/RelayModernFragmentSpecResolver.js.flow +40 -14
- package/store/RelayModernOperationDescriptor.js.flow +9 -3
- package/store/RelayModernRecord.js.flow +49 -0
- package/store/RelayModernStore.js.flow +57 -17
- package/store/RelayOperationTracker.js.flow +56 -34
- package/store/RelayPublishQueue.js.flow +37 -11
- package/store/RelayReader.js.flow +186 -27
- package/store/RelayRecordSource.js.flow +72 -6
- package/store/RelayReferenceMarker.js.flow +51 -21
- package/store/RelayResponseNormalizer.js.flow +251 -67
- package/store/RelayStoreReactFlightUtils.js.flow +6 -9
- package/store/RelayStoreSubscriptions.js.flow +10 -3
- package/store/RelayStoreTypes.js.flow +144 -21
- package/store/RelayStoreUtils.js.flow +19 -4
- package/store/ResolverCache.js.flow +247 -0
- package/store/ResolverFragments.js.flow +128 -0
- package/store/createRelayContext.js.flow +1 -1
- package/store/defaultGetDataID.js.flow +3 -1
- package/subscription/requestSubscription.js.flow +43 -8
- package/util/NormalizationNode.js.flow +16 -3
- package/util/ReaderNode.js.flow +29 -2
- package/util/RelayConcreteNode.js.flow +3 -0
- package/util/RelayFeatureFlags.js.flow +10 -6
- package/util/RelayProfiler.js.flow +22 -194
- package/util/RelayReplaySubject.js.flow +7 -6
- package/util/RelayRuntimeTypes.js.flow +4 -2
- package/util/deepFreeze.js.flow +2 -1
- package/util/getPaginationMetadata.js.flow +74 -0
- package/util/getPaginationVariables.js.flow +112 -0
- package/util/getPendingOperationsForFragment.js.flow +62 -0
- package/util/getRefetchMetadata.js.flow +80 -0
- package/util/getValueAtPath.js.flow +46 -0
- package/util/isEmptyObject.js.flow +2 -1
- package/util/registerEnvironmentWithDevTools.js.flow +33 -0
- 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,7 +12,6 @@
|
|
|
12
12
|
|
|
13
13
|
'use strict';
|
|
14
14
|
|
|
15
|
-
const ErrorUtils = require('ErrorUtils');
|
|
16
15
|
const RelayReader = require('./RelayReader');
|
|
17
16
|
const RelayRecordSource = require('./RelayRecordSource');
|
|
18
17
|
const RelayRecordSourceMutator = require('../mutations/RelayRecordSourceMutator');
|
|
@@ -55,6 +54,10 @@ type PendingUpdater = {|
|
|
|
55
54
|
+updater: StoreUpdater,
|
|
56
55
|
|};
|
|
57
56
|
|
|
57
|
+
const applyWithGuard =
|
|
58
|
+
global?.ErrorUtils?.applyWithGuard ??
|
|
59
|
+
((callback, context, args, onError, name) => callback.apply(context, args));
|
|
60
|
+
|
|
58
61
|
/**
|
|
59
62
|
* Coordinates the concurrent modification of a `Store` due to optimistic and
|
|
60
63
|
* non-revertable client updates and server payloads:
|
|
@@ -182,7 +185,20 @@ class RelayPublishQueue implements PublishQueue {
|
|
|
182
185
|
run(
|
|
183
186
|
sourceOperation?: OperationDescriptor,
|
|
184
187
|
): $ReadOnlyArray<RequestDescriptor> {
|
|
188
|
+
const runWillClearGcHold =
|
|
189
|
+
this._appliedOptimisticUpdates === 0 && !!this._gcHold;
|
|
190
|
+
const runIsANoop =
|
|
191
|
+
// this._pendingBackupRebase is true if an applied optimistic
|
|
192
|
+
// update has potentially been reverted or if this._pendingData is not empty.
|
|
193
|
+
!this._pendingBackupRebase &&
|
|
194
|
+
this._pendingOptimisticUpdates.size === 0 &&
|
|
195
|
+
!runWillClearGcHold;
|
|
196
|
+
|
|
185
197
|
if (__DEV__) {
|
|
198
|
+
warning(
|
|
199
|
+
!runIsANoop,
|
|
200
|
+
'RelayPublishQueue.run was called, but the call would have been a noop.',
|
|
201
|
+
);
|
|
186
202
|
warning(
|
|
187
203
|
this._isRunning !== true,
|
|
188
204
|
'A store update was detected within another store update. Please ' +
|
|
@@ -191,6 +207,14 @@ class RelayPublishQueue implements PublishQueue {
|
|
|
191
207
|
);
|
|
192
208
|
this._isRunning = true;
|
|
193
209
|
}
|
|
210
|
+
|
|
211
|
+
if (runIsANoop) {
|
|
212
|
+
if (__DEV__) {
|
|
213
|
+
this._isRunning = false;
|
|
214
|
+
}
|
|
215
|
+
return [];
|
|
216
|
+
}
|
|
217
|
+
|
|
194
218
|
if (this._pendingBackupRebase) {
|
|
195
219
|
if (this._hasStoreSnapshot) {
|
|
196
220
|
this._store.restore();
|
|
@@ -299,7 +323,7 @@ class RelayPublishQueue implements PublishQueue {
|
|
|
299
323
|
mutator,
|
|
300
324
|
this._getDataID,
|
|
301
325
|
);
|
|
302
|
-
|
|
326
|
+
applyWithGuard(
|
|
303
327
|
updater,
|
|
304
328
|
null,
|
|
305
329
|
[recordSourceProxy],
|
|
@@ -334,7 +358,7 @@ class RelayPublishQueue implements PublishQueue {
|
|
|
334
358
|
const processUpdate = optimisticUpdate => {
|
|
335
359
|
if (optimisticUpdate.storeUpdater) {
|
|
336
360
|
const {storeUpdater} = optimisticUpdate;
|
|
337
|
-
|
|
361
|
+
applyWithGuard(
|
|
338
362
|
storeUpdater,
|
|
339
363
|
null,
|
|
340
364
|
[recordSourceProxy],
|
|
@@ -344,18 +368,20 @@ class RelayPublishQueue implements PublishQueue {
|
|
|
344
368
|
} else {
|
|
345
369
|
const {operation, payload, updater} = optimisticUpdate;
|
|
346
370
|
const {source, fieldPayloads} = payload;
|
|
347
|
-
const recordSourceSelectorProxy = new RelayRecordSourceSelectorProxy(
|
|
348
|
-
mutator,
|
|
349
|
-
recordSourceProxy,
|
|
350
|
-
operation.fragment,
|
|
351
|
-
);
|
|
352
|
-
let selectorData;
|
|
353
371
|
if (source) {
|
|
354
372
|
recordSourceProxy.publishSource(source, fieldPayloads);
|
|
355
|
-
selectorData = lookupSelector(source, operation.fragment);
|
|
356
373
|
}
|
|
357
374
|
if (updater) {
|
|
358
|
-
|
|
375
|
+
let selectorData;
|
|
376
|
+
if (source) {
|
|
377
|
+
selectorData = lookupSelector(source, operation.fragment);
|
|
378
|
+
}
|
|
379
|
+
const recordSourceSelectorProxy = new RelayRecordSourceSelectorProxy(
|
|
380
|
+
mutator,
|
|
381
|
+
recordSourceProxy,
|
|
382
|
+
operation.fragment,
|
|
383
|
+
);
|
|
384
|
+
applyWithGuard(
|
|
359
385
|
updater,
|
|
360
386
|
null,
|
|
361
387
|
[recordSourceSelectorProxy, selectorData],
|
|
@@ -12,12 +12,14 @@
|
|
|
12
12
|
|
|
13
13
|
'use strict';
|
|
14
14
|
|
|
15
|
+
const ClientID = require('./ClientID');
|
|
15
16
|
const RelayFeatureFlags = require('../util/RelayFeatureFlags');
|
|
16
17
|
const RelayModernRecord = require('./RelayModernRecord');
|
|
17
18
|
|
|
18
19
|
const invariant = require('invariant');
|
|
19
20
|
|
|
20
21
|
const {
|
|
22
|
+
ACTOR_CHANGE,
|
|
21
23
|
CLIENT_EXTENSION,
|
|
22
24
|
CONDITION,
|
|
23
25
|
DEFER,
|
|
@@ -28,6 +30,7 @@ const {
|
|
|
28
30
|
LINKED_FIELD,
|
|
29
31
|
MODULE_IMPORT,
|
|
30
32
|
REQUIRED_FIELD,
|
|
33
|
+
RELAY_RESOLVER,
|
|
31
34
|
SCALAR_FIELD,
|
|
32
35
|
STREAM,
|
|
33
36
|
} = require('../util/RelayConcreteNode');
|
|
@@ -44,15 +47,20 @@ const {
|
|
|
44
47
|
getStorageKey,
|
|
45
48
|
getModuleComponentKey,
|
|
46
49
|
} = require('./RelayStoreUtils');
|
|
50
|
+
const {NoopResolverCache} = require('./ResolverCache');
|
|
51
|
+
const {withResolverContext} = require('./ResolverFragments');
|
|
47
52
|
const {generateTypeID} = require('./TypeID');
|
|
48
53
|
|
|
49
54
|
import type {
|
|
50
55
|
ReaderFlightField,
|
|
56
|
+
ReaderFragment,
|
|
51
57
|
ReaderFragmentSpread,
|
|
52
58
|
ReaderInlineDataFragmentSpread,
|
|
53
59
|
ReaderLinkedField,
|
|
60
|
+
ReaderActorChange,
|
|
54
61
|
ReaderModuleImport,
|
|
55
62
|
ReaderNode,
|
|
63
|
+
ReaderRelayResolver,
|
|
56
64
|
ReaderRequiredField,
|
|
57
65
|
ReaderScalarField,
|
|
58
66
|
ReaderSelection,
|
|
@@ -68,12 +76,18 @@ import type {
|
|
|
68
76
|
MissingRequiredFields,
|
|
69
77
|
DataIDSet,
|
|
70
78
|
} from './RelayStoreTypes';
|
|
79
|
+
import type {ResolverCache} from './ResolverCache';
|
|
71
80
|
|
|
72
81
|
function read(
|
|
73
82
|
recordSource: RecordSource,
|
|
74
83
|
selector: SingularReaderSelector,
|
|
84
|
+
resolverCache?: ResolverCache,
|
|
75
85
|
): Snapshot {
|
|
76
|
-
const reader = new RelayReader(
|
|
86
|
+
const reader = new RelayReader(
|
|
87
|
+
recordSource,
|
|
88
|
+
selector,
|
|
89
|
+
resolverCache ?? new NoopResolverCache(),
|
|
90
|
+
);
|
|
77
91
|
return reader.read();
|
|
78
92
|
}
|
|
79
93
|
|
|
@@ -89,8 +103,13 @@ class RelayReader {
|
|
|
89
103
|
_seenRecords: DataIDSet;
|
|
90
104
|
_selector: SingularReaderSelector;
|
|
91
105
|
_variables: Variables;
|
|
106
|
+
_resolverCache: ResolverCache;
|
|
92
107
|
|
|
93
|
-
constructor(
|
|
108
|
+
constructor(
|
|
109
|
+
recordSource: RecordSource,
|
|
110
|
+
selector: SingularReaderSelector,
|
|
111
|
+
resolverCache: ResolverCache,
|
|
112
|
+
) {
|
|
94
113
|
this._isMissingData = false;
|
|
95
114
|
this._isWithinUnmatchedTypeRefinement = false;
|
|
96
115
|
this._missingRequiredFields = null;
|
|
@@ -99,6 +118,7 @@ class RelayReader {
|
|
|
99
118
|
this._seenRecords = new Set();
|
|
100
119
|
this._selector = selector;
|
|
101
120
|
this._variables = selector.variables;
|
|
121
|
+
this._resolverCache = resolverCache;
|
|
102
122
|
}
|
|
103
123
|
|
|
104
124
|
read(): Snapshot {
|
|
@@ -122,7 +142,18 @@ class RelayReader {
|
|
|
122
142
|
// match, then no data is expected to be present.
|
|
123
143
|
if (isDataExpectedToBePresent && abstractKey == null && record != null) {
|
|
124
144
|
const recordType = RelayModernRecord.getType(record);
|
|
125
|
-
if (
|
|
145
|
+
if (
|
|
146
|
+
recordType !== node.type &&
|
|
147
|
+
// The root record type is a special `__Root` type and may not match the
|
|
148
|
+
// type on the ast, so ignore type mismatches at the root.
|
|
149
|
+
// We currently detect whether we're at the root by checking against ROOT_ID,
|
|
150
|
+
// but this does not work for mutations/subscriptions which generate unique
|
|
151
|
+
// root ids. This is acceptable in practice as we don't read data for mutations/
|
|
152
|
+
// subscriptions in a situation where we would use isMissingData to decide whether
|
|
153
|
+
// to suspend or not.
|
|
154
|
+
// TODO T96653810: Correctly detect reading from root of mutation/subscription
|
|
155
|
+
dataID !== ROOT_ID
|
|
156
|
+
) {
|
|
126
157
|
isDataExpectedToBePresent = false;
|
|
127
158
|
}
|
|
128
159
|
}
|
|
@@ -131,12 +162,7 @@ class RelayReader {
|
|
|
131
162
|
// then data is only expected to be present if the record type is known to
|
|
132
163
|
// implement the interface. If we aren't sure whether the record implements
|
|
133
164
|
// 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
|
-
) {
|
|
165
|
+
if (isDataExpectedToBePresent && abstractKey != null && record != null) {
|
|
140
166
|
const recordType = RelayModernRecord.getType(record);
|
|
141
167
|
const typeID = generateTypeID(recordType);
|
|
142
168
|
const typeRecord = this._recordSource.get(typeID);
|
|
@@ -192,6 +218,7 @@ class RelayReader {
|
|
|
192
218
|
'RelayReader(): Undefined variable `%s`.',
|
|
193
219
|
name,
|
|
194
220
|
);
|
|
221
|
+
// $FlowFixMe[cannot-write]
|
|
195
222
|
return this._variables[name];
|
|
196
223
|
}
|
|
197
224
|
|
|
@@ -262,7 +289,9 @@ class RelayReader {
|
|
|
262
289
|
}
|
|
263
290
|
break;
|
|
264
291
|
case CONDITION:
|
|
265
|
-
const conditionValue =
|
|
292
|
+
const conditionValue = Boolean(
|
|
293
|
+
this._getVariableValue(selection.condition),
|
|
294
|
+
);
|
|
266
295
|
if (conditionValue === selection.passingValue) {
|
|
267
296
|
const hasExpectedData = this._traverseSelections(
|
|
268
297
|
selection.selections,
|
|
@@ -289,7 +318,7 @@ class RelayReader {
|
|
|
289
318
|
return false;
|
|
290
319
|
}
|
|
291
320
|
}
|
|
292
|
-
} else
|
|
321
|
+
} else {
|
|
293
322
|
// Similar to the logic in read(): data is only expected to be present
|
|
294
323
|
// if the record is known to conform to the interface. If we don't know
|
|
295
324
|
// whether the type conforms or not, that constitutes missing data.
|
|
@@ -319,13 +348,16 @@ class RelayReader {
|
|
|
319
348
|
// Don't know if the type implements the interface or not
|
|
320
349
|
this._isMissingData = true;
|
|
321
350
|
}
|
|
322
|
-
} else {
|
|
323
|
-
// legacy behavior for abstract refinements: always read even
|
|
324
|
-
// if the type doesn't conform and don't reset isMissingData
|
|
325
|
-
this._traverseSelections(selection.selections, record, data);
|
|
326
351
|
}
|
|
327
352
|
break;
|
|
328
353
|
}
|
|
354
|
+
case RELAY_RESOLVER: {
|
|
355
|
+
if (!RelayFeatureFlags.ENABLE_RELAY_RESOLVERS) {
|
|
356
|
+
throw new Error('Relay Resolver fields are not yet supported.');
|
|
357
|
+
}
|
|
358
|
+
this._readResolverField(selection, record, data);
|
|
359
|
+
break;
|
|
360
|
+
}
|
|
329
361
|
case FRAGMENT_SPREAD:
|
|
330
362
|
this._createFragmentPointer(selection, record, data);
|
|
331
363
|
break;
|
|
@@ -333,7 +365,11 @@ class RelayReader {
|
|
|
333
365
|
this._readModuleImport(selection, record, data);
|
|
334
366
|
break;
|
|
335
367
|
case INLINE_DATA_FRAGMENT_SPREAD:
|
|
336
|
-
this.
|
|
368
|
+
this._createInlineDataOrResolverFragmentPointer(
|
|
369
|
+
selection,
|
|
370
|
+
record,
|
|
371
|
+
data,
|
|
372
|
+
);
|
|
337
373
|
break;
|
|
338
374
|
case DEFER:
|
|
339
375
|
case CLIENT_EXTENSION: {
|
|
@@ -367,6 +403,9 @@ class RelayReader {
|
|
|
367
403
|
throw new Error('Flight fields are not yet supported.');
|
|
368
404
|
}
|
|
369
405
|
break;
|
|
406
|
+
case ACTOR_CHANGE:
|
|
407
|
+
this._readActorChange(selection, record, data);
|
|
408
|
+
break;
|
|
370
409
|
default:
|
|
371
410
|
(selection: empty);
|
|
372
411
|
invariant(
|
|
@@ -393,6 +432,12 @@ class RelayReader {
|
|
|
393
432
|
} else {
|
|
394
433
|
return this._readLink(selection.field, record, data);
|
|
395
434
|
}
|
|
435
|
+
case RELAY_RESOLVER:
|
|
436
|
+
if (!RelayFeatureFlags.ENABLE_RELAY_RESOLVERS) {
|
|
437
|
+
throw new Error('Relay Resolver fields are not yet supported.');
|
|
438
|
+
}
|
|
439
|
+
this._readResolverField(selection.field, record, data);
|
|
440
|
+
break;
|
|
396
441
|
default:
|
|
397
442
|
(selection.field.kind: empty);
|
|
398
443
|
invariant(
|
|
@@ -403,6 +448,87 @@ class RelayReader {
|
|
|
403
448
|
}
|
|
404
449
|
}
|
|
405
450
|
|
|
451
|
+
_readResolverField(
|
|
452
|
+
field: ReaderRelayResolver,
|
|
453
|
+
record: Record,
|
|
454
|
+
data: SelectorData,
|
|
455
|
+
): ?mixed {
|
|
456
|
+
const {resolverModule, fragment} = field;
|
|
457
|
+
const storageKey = getStorageKey(field, this._variables);
|
|
458
|
+
const resolverID = ClientID.generateClientID(
|
|
459
|
+
RelayModernRecord.getDataID(record),
|
|
460
|
+
storageKey,
|
|
461
|
+
);
|
|
462
|
+
|
|
463
|
+
// Found when reading the resolver fragment, which can happen either when
|
|
464
|
+
// evaluating the resolver and it calls readFragment, or when checking if the
|
|
465
|
+
// inputs have changed since a previous evaluation:
|
|
466
|
+
let fragmentValue;
|
|
467
|
+
let fragmentReaderSelector;
|
|
468
|
+
const fragmentSeenRecordIDs = new Set();
|
|
469
|
+
|
|
470
|
+
const getDataForResolverFragment = singularReaderSelector => {
|
|
471
|
+
if (fragmentValue != null) {
|
|
472
|
+
// It was already read when checking for input staleness; no need to read it again.
|
|
473
|
+
// Note that the variables like fragmentSeenRecordIDs in the outer closure will have
|
|
474
|
+
// already been set and will still be used in this case.
|
|
475
|
+
return fragmentValue;
|
|
476
|
+
}
|
|
477
|
+
fragmentReaderSelector = singularReaderSelector;
|
|
478
|
+
const existingSeenRecords = this._seenRecords;
|
|
479
|
+
try {
|
|
480
|
+
this._seenRecords = fragmentSeenRecordIDs;
|
|
481
|
+
const resolverFragmentData = {};
|
|
482
|
+
this._createInlineDataOrResolverFragmentPointer(
|
|
483
|
+
singularReaderSelector.node,
|
|
484
|
+
record,
|
|
485
|
+
resolverFragmentData,
|
|
486
|
+
);
|
|
487
|
+
fragmentValue = resolverFragmentData[FRAGMENTS_KEY]?.[fragment.name];
|
|
488
|
+
invariant(
|
|
489
|
+
typeof fragmentValue === 'object' && fragmentValue !== null,
|
|
490
|
+
`Expected reader data to contain a __fragments property with a property for the fragment named ${fragment.name}, but it is missing.`,
|
|
491
|
+
);
|
|
492
|
+
return fragmentValue;
|
|
493
|
+
} finally {
|
|
494
|
+
this._seenRecords = existingSeenRecords;
|
|
495
|
+
}
|
|
496
|
+
};
|
|
497
|
+
const resolverContext = {getDataForResolverFragment};
|
|
498
|
+
|
|
499
|
+
const [result, seenRecord] = this._resolverCache.readFromCacheOrEvaluate(
|
|
500
|
+
record,
|
|
501
|
+
field,
|
|
502
|
+
this._variables,
|
|
503
|
+
() => {
|
|
504
|
+
const key = {
|
|
505
|
+
__id: RelayModernRecord.getDataID(record),
|
|
506
|
+
__fragmentOwner: this._owner,
|
|
507
|
+
__fragments: {
|
|
508
|
+
[fragment.name]: {}, // Arguments to this fragment; not yet supported.
|
|
509
|
+
},
|
|
510
|
+
};
|
|
511
|
+
return withResolverContext(resolverContext, () => {
|
|
512
|
+
// $FlowFixMe[prop-missing] - resolver module's type signature is a lie
|
|
513
|
+
const resolverResult = resolverModule(key);
|
|
514
|
+
return {
|
|
515
|
+
resolverResult,
|
|
516
|
+
fragmentValue,
|
|
517
|
+
resolverID,
|
|
518
|
+
seenRecordIDs: fragmentSeenRecordIDs,
|
|
519
|
+
readerSelector: fragmentReaderSelector,
|
|
520
|
+
};
|
|
521
|
+
});
|
|
522
|
+
},
|
|
523
|
+
getDataForResolverFragment,
|
|
524
|
+
);
|
|
525
|
+
if (seenRecord != null) {
|
|
526
|
+
this._seenRecords.add(seenRecord);
|
|
527
|
+
}
|
|
528
|
+
data[storageKey] = result;
|
|
529
|
+
return result;
|
|
530
|
+
}
|
|
531
|
+
|
|
406
532
|
_readFlightField(
|
|
407
533
|
field: ReaderFlightField,
|
|
408
534
|
record: Record,
|
|
@@ -485,6 +611,42 @@ class RelayReader {
|
|
|
485
611
|
return value;
|
|
486
612
|
}
|
|
487
613
|
|
|
614
|
+
_readActorChange(
|
|
615
|
+
field: ReaderActorChange,
|
|
616
|
+
record: Record,
|
|
617
|
+
data: SelectorData,
|
|
618
|
+
): ?mixed {
|
|
619
|
+
const applicationName = field.alias ?? field.name;
|
|
620
|
+
const storageKey = getStorageKey(field, this._variables);
|
|
621
|
+
const externalRef = RelayModernRecord.getActorLinkedRecordID(
|
|
622
|
+
record,
|
|
623
|
+
storageKey,
|
|
624
|
+
);
|
|
625
|
+
|
|
626
|
+
if (externalRef == null) {
|
|
627
|
+
data[applicationName] = externalRef;
|
|
628
|
+
if (externalRef === undefined) {
|
|
629
|
+
this._isMissingData = true;
|
|
630
|
+
}
|
|
631
|
+
return data[applicationName];
|
|
632
|
+
}
|
|
633
|
+
const [actorIdentifier, dataID] = externalRef;
|
|
634
|
+
|
|
635
|
+
const fragmentRef = {};
|
|
636
|
+
this._createFragmentPointer(
|
|
637
|
+
field.fragmentSpread,
|
|
638
|
+
{
|
|
639
|
+
__id: dataID,
|
|
640
|
+
},
|
|
641
|
+
fragmentRef,
|
|
642
|
+
);
|
|
643
|
+
data[applicationName] = {
|
|
644
|
+
__fragmentRef: fragmentRef,
|
|
645
|
+
__viewer: actorIdentifier,
|
|
646
|
+
};
|
|
647
|
+
return data[applicationName];
|
|
648
|
+
}
|
|
649
|
+
|
|
488
650
|
_readPluralLink(
|
|
489
651
|
field: ReaderLinkedField,
|
|
490
652
|
record: Record,
|
|
@@ -567,7 +729,7 @@ class RelayReader {
|
|
|
567
729
|
{
|
|
568
730
|
kind: 'FragmentSpread',
|
|
569
731
|
name: moduleImport.fragmentName,
|
|
570
|
-
args:
|
|
732
|
+
args: moduleImport.args,
|
|
571
733
|
},
|
|
572
734
|
record,
|
|
573
735
|
data,
|
|
@@ -598,16 +760,13 @@ class RelayReader {
|
|
|
598
760
|
? getArgumentValues(fragmentSpread.args, this._variables)
|
|
599
761
|
: {};
|
|
600
762
|
data[FRAGMENT_OWNER_KEY] = this._owner;
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
IS_WITHIN_UNMATCHED_TYPE_REFINEMENT
|
|
605
|
-
] = this._isWithinUnmatchedTypeRefinement;
|
|
606
|
-
}
|
|
763
|
+
data[
|
|
764
|
+
IS_WITHIN_UNMATCHED_TYPE_REFINEMENT
|
|
765
|
+
] = this._isWithinUnmatchedTypeRefinement;
|
|
607
766
|
}
|
|
608
767
|
|
|
609
|
-
|
|
610
|
-
|
|
768
|
+
_createInlineDataOrResolverFragmentPointer(
|
|
769
|
+
fragmentSpreadOrFragment: ReaderInlineDataFragmentSpread | ReaderFragment,
|
|
611
770
|
record: Record,
|
|
612
771
|
data: SelectorData,
|
|
613
772
|
): void {
|
|
@@ -625,12 +784,12 @@ class RelayReader {
|
|
|
625
784
|
}
|
|
626
785
|
const inlineData = {};
|
|
627
786
|
this._traverseSelections(
|
|
628
|
-
|
|
787
|
+
fragmentSpreadOrFragment.selections,
|
|
629
788
|
record,
|
|
630
789
|
inlineData,
|
|
631
790
|
);
|
|
632
791
|
// $FlowFixMe[cannot-write] - writing into read-only field
|
|
633
|
-
fragmentPointers[
|
|
792
|
+
fragmentPointers[fragmentSpreadOrFragment.name] = inlineData;
|
|
634
793
|
}
|
|
635
794
|
}
|
|
636
795
|
|
|
@@ -12,17 +12,83 @@
|
|
|
12
12
|
|
|
13
13
|
'use strict';
|
|
14
14
|
|
|
15
|
-
const
|
|
15
|
+
const RelayRecordState = require('./RelayRecordState');
|
|
16
16
|
|
|
17
|
-
import type {
|
|
17
|
+
import type {DataID} from '../util/RelayRuntimeTypes';
|
|
18
|
+
import type {RecordState} from './RelayRecordState';
|
|
19
|
+
import type {
|
|
20
|
+
MutableRecordSource,
|
|
21
|
+
Record,
|
|
22
|
+
RecordObjectMap,
|
|
23
|
+
} from './RelayStoreTypes';
|
|
18
24
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
25
|
+
const {EXISTENT, NONEXISTENT, UNKNOWN} = RelayRecordState;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* An implementation of the `MutableRecordSource` interface (defined in
|
|
29
|
+
* `RelayStoreTypes`) that holds all records in memory (JS Map).
|
|
30
|
+
*/
|
|
31
|
+
class RelayRecordSource implements MutableRecordSource {
|
|
32
|
+
_records: Map<DataID, ?Record>;
|
|
33
|
+
|
|
34
|
+
constructor(records?: RecordObjectMap) {
|
|
35
|
+
this._records = new Map();
|
|
36
|
+
if (records != null) {
|
|
37
|
+
Object.keys(records).forEach(key => {
|
|
38
|
+
this._records.set(key, records[key]);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
22
41
|
}
|
|
23
42
|
|
|
24
43
|
static create(records?: RecordObjectMap): MutableRecordSource {
|
|
25
|
-
return new
|
|
44
|
+
return new RelayRecordSource(records);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
clear(): void {
|
|
48
|
+
this._records = new Map();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
delete(dataID: DataID): void {
|
|
52
|
+
this._records.set(dataID, null);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
get(dataID: DataID): ?Record {
|
|
56
|
+
return this._records.get(dataID);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
getRecordIDs(): Array<DataID> {
|
|
60
|
+
return Array.from(this._records.keys());
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
getStatus(dataID: DataID): RecordState {
|
|
64
|
+
if (!this._records.has(dataID)) {
|
|
65
|
+
return UNKNOWN;
|
|
66
|
+
}
|
|
67
|
+
return this._records.get(dataID) == null ? NONEXISTENT : EXISTENT;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
has(dataID: DataID): boolean {
|
|
71
|
+
return this._records.has(dataID);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
remove(dataID: DataID): void {
|
|
75
|
+
this._records.delete(dataID);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
set(dataID: DataID, record: Record): void {
|
|
79
|
+
this._records.set(dataID, record);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
size(): number {
|
|
83
|
+
return this._records.size;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
toJSON(): {[DataID]: ?Record, ...} {
|
|
87
|
+
const obj = {};
|
|
88
|
+
for (const [key, value] of this._records) {
|
|
89
|
+
obj[key] = value;
|
|
90
|
+
}
|
|
91
|
+
return obj;
|
|
26
92
|
}
|
|
27
93
|
}
|
|
28
94
|
|