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
|
@@ -14,31 +14,42 @@
|
|
|
14
14
|
'use strict';
|
|
15
15
|
|
|
16
16
|
const RelayError = require('../util/RelayError');
|
|
17
|
+
const RelayFeatureFlags = require('../util/RelayFeatureFlags');
|
|
17
18
|
const RelayModernRecord = require('./RelayModernRecord');
|
|
18
19
|
const RelayObservable = require('../network/RelayObservable');
|
|
19
20
|
const RelayRecordSource = require('./RelayRecordSource');
|
|
20
21
|
const RelayResponseNormalizer = require('./RelayResponseNormalizer');
|
|
21
22
|
|
|
23
|
+
const generateID = require('../util/generateID');
|
|
22
24
|
const getOperation = require('../util/getOperation');
|
|
23
25
|
const invariant = require('invariant');
|
|
24
26
|
const stableCopy = require('../util/stableCopy');
|
|
25
27
|
const warning = require('warning');
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const {
|
|
28
|
+
const withDuration = require('../util/withDuration');
|
|
29
|
+
|
|
30
|
+
const {generateClientID, generateUniqueClientID} = require('./ClientID');
|
|
31
|
+
const {getLocalVariables} = require('./RelayConcreteVariables');
|
|
32
|
+
const {
|
|
33
|
+
createNormalizationSelector,
|
|
34
|
+
createReaderSelector,
|
|
35
|
+
} = require('./RelayModernSelector');
|
|
29
36
|
const {ROOT_TYPE, TYPENAME_KEY, getStorageKey} = require('./RelayStoreUtils');
|
|
30
37
|
|
|
38
|
+
import type {ActorIdentifier} from '../multi-actor-environment/ActorIdentifier';
|
|
31
39
|
import type {
|
|
32
40
|
GraphQLResponse,
|
|
33
41
|
GraphQLSingularResponse,
|
|
34
42
|
GraphQLResponseWithData,
|
|
43
|
+
ReactFlightServerTree,
|
|
35
44
|
} from '../network/RelayNetworkTypes';
|
|
36
45
|
import type {Sink, Subscription} from '../network/RelayObservable';
|
|
37
46
|
import type {
|
|
38
47
|
DeferPlaceholder,
|
|
48
|
+
FollowupPayload,
|
|
39
49
|
RequestDescriptor,
|
|
40
50
|
HandleFieldPayload,
|
|
41
51
|
IncrementalDataPlaceholder,
|
|
52
|
+
LogFunction,
|
|
42
53
|
ModuleImportPayload,
|
|
43
54
|
NormalizationSelector,
|
|
44
55
|
OperationDescriptor,
|
|
@@ -49,6 +60,7 @@ import type {
|
|
|
49
60
|
PublishQueue,
|
|
50
61
|
ReactFlightPayloadDeserializer,
|
|
51
62
|
ReactFlightServerErrorHandler,
|
|
63
|
+
ReactFlightClientResponse,
|
|
52
64
|
Record,
|
|
53
65
|
RelayResponsePayload,
|
|
54
66
|
SelectorStoreUpdater,
|
|
@@ -67,22 +79,25 @@ import type {GetDataID} from './RelayResponseNormalizer';
|
|
|
67
79
|
import type {NormalizationOptions} from './RelayResponseNormalizer';
|
|
68
80
|
|
|
69
81
|
export type ExecuteConfig = {|
|
|
82
|
+
+actorIdentifier: ActorIdentifier,
|
|
70
83
|
+getDataID: GetDataID,
|
|
71
|
-
+
|
|
84
|
+
+getPublishQueue: (actorIdentifier: ActorIdentifier) => PublishQueue,
|
|
85
|
+
+getStore: (actorIdentifier: ActorIdentifier) => Store,
|
|
86
|
+
+isClientPayload?: boolean,
|
|
72
87
|
+operation: OperationDescriptor,
|
|
73
88
|
+operationExecutions: Map<string, ActiveState>,
|
|
74
89
|
+operationLoader: ?OperationLoader,
|
|
75
|
-
+operationTracker
|
|
90
|
+
+operationTracker: OperationTracker,
|
|
76
91
|
+optimisticConfig: ?OptimisticResponseConfig,
|
|
77
|
-
+publishQueue: PublishQueue,
|
|
78
92
|
+reactFlightPayloadDeserializer?: ?ReactFlightPayloadDeserializer,
|
|
79
93
|
+reactFlightServerErrorHandler?: ?ReactFlightServerErrorHandler,
|
|
80
94
|
+scheduler?: ?TaskScheduler,
|
|
95
|
+
+shouldProcessClientComponents?: ?boolean,
|
|
81
96
|
+sink: Sink<GraphQLResponse>,
|
|
82
97
|
+source: RelayObservable<GraphQLResponse>,
|
|
83
|
-
+
|
|
98
|
+
+treatMissingFieldsAsNull: boolean,
|
|
84
99
|
+updater?: ?SelectorStoreUpdater,
|
|
85
|
-
+
|
|
100
|
+
+log: LogFunction,
|
|
86
101
|
|};
|
|
87
102
|
|
|
88
103
|
export type ActiveState = 'active' | 'inactive';
|
|
@@ -120,21 +135,25 @@ function execute(config: ExecuteConfig): Executor {
|
|
|
120
135
|
* dependencies, etc.
|
|
121
136
|
*/
|
|
122
137
|
class Executor {
|
|
138
|
+
_actorIdentifier: ActorIdentifier;
|
|
123
139
|
_getDataID: GetDataID;
|
|
124
140
|
_treatMissingFieldsAsNull: boolean;
|
|
125
141
|
_incrementalPayloadsPending: boolean;
|
|
126
142
|
_incrementalResults: Map<Label, Map<PathKey, IncrementalResults>>;
|
|
143
|
+
_log: LogFunction;
|
|
144
|
+
_executeId: number;
|
|
127
145
|
_nextSubscriptionId: number;
|
|
128
146
|
_operation: OperationDescriptor;
|
|
129
147
|
_operationExecutions: Map<string, ActiveState>;
|
|
130
148
|
_operationLoader: ?OperationLoader;
|
|
131
|
-
_operationTracker:
|
|
149
|
+
_operationTracker: OperationTracker;
|
|
132
150
|
_operationUpdateEpochs: Map<string, number>;
|
|
133
151
|
_optimisticUpdates: null | Array<OptimisticUpdate>;
|
|
134
152
|
_pendingModulePayloadsCount: number;
|
|
135
|
-
|
|
153
|
+
+_getPublishQueue: (actorIdentifier: ActorIdentifier) => PublishQueue;
|
|
136
154
|
_reactFlightPayloadDeserializer: ?ReactFlightPayloadDeserializer;
|
|
137
155
|
_reactFlightServerErrorHandler: ?ReactFlightServerErrorHandler;
|
|
156
|
+
_shouldProcessClientComponents: ?boolean;
|
|
138
157
|
_scheduler: ?TaskScheduler;
|
|
139
158
|
_sink: Sink<GraphQLResponse>;
|
|
140
159
|
_source: Map<
|
|
@@ -142,34 +161,44 @@ class Executor {
|
|
|
142
161
|
{|+record: Record, +fieldPayloads: Array<HandleFieldPayload>|},
|
|
143
162
|
>;
|
|
144
163
|
_state: 'started' | 'loading_incremental' | 'loading_final' | 'completed';
|
|
145
|
-
|
|
164
|
+
+_getStore: (actorIdentifier: ActorIdentifier) => Store;
|
|
146
165
|
_subscriptions: Map<number, Subscription>;
|
|
147
166
|
_updater: ?SelectorStoreUpdater;
|
|
148
|
-
|
|
167
|
+
_asyncStoreUpdateDisposable: ?Disposable;
|
|
168
|
+
_completeFns: Array<() => void>;
|
|
169
|
+
+_retainDisposables: Map<ActorIdentifier, Disposable>;
|
|
149
170
|
+_isClientPayload: boolean;
|
|
171
|
+
+_isSubscriptionOperation: boolean;
|
|
172
|
+
+_seenActors: Set<ActorIdentifier>;
|
|
150
173
|
|
|
151
174
|
constructor({
|
|
175
|
+
actorIdentifier,
|
|
176
|
+
getDataID,
|
|
177
|
+
getPublishQueue,
|
|
178
|
+
getStore,
|
|
179
|
+
isClientPayload,
|
|
152
180
|
operation,
|
|
153
181
|
operationExecutions,
|
|
154
182
|
operationLoader,
|
|
183
|
+
operationTracker,
|
|
155
184
|
optimisticConfig,
|
|
156
|
-
|
|
185
|
+
reactFlightPayloadDeserializer,
|
|
186
|
+
reactFlightServerErrorHandler,
|
|
157
187
|
scheduler,
|
|
188
|
+
shouldProcessClientComponents,
|
|
158
189
|
sink,
|
|
159
190
|
source,
|
|
160
|
-
store,
|
|
161
|
-
updater,
|
|
162
|
-
operationTracker,
|
|
163
191
|
treatMissingFieldsAsNull,
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
reactFlightPayloadDeserializer,
|
|
167
|
-
reactFlightServerErrorHandler,
|
|
192
|
+
updater,
|
|
193
|
+
log,
|
|
168
194
|
}: ExecuteConfig): void {
|
|
195
|
+
this._actorIdentifier = actorIdentifier;
|
|
169
196
|
this._getDataID = getDataID;
|
|
170
197
|
this._treatMissingFieldsAsNull = treatMissingFieldsAsNull;
|
|
171
198
|
this._incrementalPayloadsPending = false;
|
|
172
199
|
this._incrementalResults = new Map();
|
|
200
|
+
this._log = log;
|
|
201
|
+
this._executeId = generateID();
|
|
173
202
|
this._nextSubscriptionId = 0;
|
|
174
203
|
this._operation = operation;
|
|
175
204
|
this._operationExecutions = operationExecutions;
|
|
@@ -178,17 +207,23 @@ class Executor {
|
|
|
178
207
|
this._operationUpdateEpochs = new Map();
|
|
179
208
|
this._optimisticUpdates = null;
|
|
180
209
|
this._pendingModulePayloadsCount = 0;
|
|
181
|
-
this.
|
|
210
|
+
this._getPublishQueue = getPublishQueue;
|
|
182
211
|
this._scheduler = scheduler;
|
|
183
212
|
this._sink = sink;
|
|
184
213
|
this._source = new Map();
|
|
185
214
|
this._state = 'started';
|
|
186
|
-
this.
|
|
215
|
+
this._getStore = getStore;
|
|
187
216
|
this._subscriptions = new Map();
|
|
188
217
|
this._updater = updater;
|
|
189
218
|
this._isClientPayload = isClientPayload === true;
|
|
190
219
|
this._reactFlightPayloadDeserializer = reactFlightPayloadDeserializer;
|
|
191
220
|
this._reactFlightServerErrorHandler = reactFlightServerErrorHandler;
|
|
221
|
+
this._isSubscriptionOperation =
|
|
222
|
+
this._operation.request.node.params.operationKind === 'subscription';
|
|
223
|
+
this._shouldProcessClientComponents = shouldProcessClientComponents;
|
|
224
|
+
this._retainDisposables = new Map();
|
|
225
|
+
this._seenActors = new Set();
|
|
226
|
+
this._completeFns = [];
|
|
192
227
|
|
|
193
228
|
const id = this._nextSubscriptionId++;
|
|
194
229
|
source.subscribe({
|
|
@@ -201,7 +236,16 @@ class Executor {
|
|
|
201
236
|
sink.error(error);
|
|
202
237
|
}
|
|
203
238
|
},
|
|
204
|
-
start: subscription =>
|
|
239
|
+
start: subscription => {
|
|
240
|
+
this._start(id, subscription);
|
|
241
|
+
this._log({
|
|
242
|
+
name: 'execute.start',
|
|
243
|
+
executeId: this._executeId,
|
|
244
|
+
params: this._operation.request.node.params,
|
|
245
|
+
variables: this._operation.request.variables,
|
|
246
|
+
cacheConfig: this._operation.request.cacheConfig ?? {},
|
|
247
|
+
});
|
|
248
|
+
},
|
|
205
249
|
});
|
|
206
250
|
|
|
207
251
|
if (optimisticConfig != null) {
|
|
@@ -231,18 +275,41 @@ class Executor {
|
|
|
231
275
|
if (optimisticUpdates !== null) {
|
|
232
276
|
this._optimisticUpdates = null;
|
|
233
277
|
optimisticUpdates.forEach(update =>
|
|
234
|
-
this.
|
|
278
|
+
this._getPublishQueueAndSaveActor().revertUpdate(update),
|
|
235
279
|
);
|
|
236
|
-
|
|
280
|
+
// OK: run revert on cancel
|
|
281
|
+
this._runPublishQueue();
|
|
237
282
|
}
|
|
238
283
|
this._incrementalResults.clear();
|
|
239
|
-
this.
|
|
240
|
-
|
|
241
|
-
this.
|
|
242
|
-
this._retainDisposable = null;
|
|
284
|
+
if (this._asyncStoreUpdateDisposable != null) {
|
|
285
|
+
this._asyncStoreUpdateDisposable.dispose();
|
|
286
|
+
this._asyncStoreUpdateDisposable = null;
|
|
243
287
|
}
|
|
288
|
+
this._completeFns = [];
|
|
289
|
+
this._completeOperationTracker();
|
|
290
|
+
this._disposeRetainedData();
|
|
244
291
|
}
|
|
245
292
|
|
|
293
|
+
_deserializeReactFlightPayloadWithLogging = (
|
|
294
|
+
tree: ReactFlightServerTree,
|
|
295
|
+
): ReactFlightClientResponse => {
|
|
296
|
+
const reactFlightPayloadDeserializer = this._reactFlightPayloadDeserializer;
|
|
297
|
+
invariant(
|
|
298
|
+
typeof reactFlightPayloadDeserializer === 'function',
|
|
299
|
+
'OperationExecutor: Expected reactFlightPayloadDeserializer to be available when calling _deserializeReactFlightPayloadWithLogging.',
|
|
300
|
+
);
|
|
301
|
+
const [duration, result] = withDuration(() => {
|
|
302
|
+
return reactFlightPayloadDeserializer(tree);
|
|
303
|
+
});
|
|
304
|
+
this._log({
|
|
305
|
+
name: 'execute.flight.payload_deserialize',
|
|
306
|
+
executeId: this._executeId,
|
|
307
|
+
operationName: this._operation.request.node.params.name,
|
|
308
|
+
duration,
|
|
309
|
+
});
|
|
310
|
+
return result;
|
|
311
|
+
};
|
|
312
|
+
|
|
246
313
|
_updateActiveState(): void {
|
|
247
314
|
let activeState;
|
|
248
315
|
switch (this._state) {
|
|
@@ -265,7 +332,7 @@ class Executor {
|
|
|
265
332
|
}
|
|
266
333
|
default:
|
|
267
334
|
(this._state: empty);
|
|
268
|
-
invariant(false, '
|
|
335
|
+
invariant(false, 'OperationExecutor: invalid executor state.');
|
|
269
336
|
}
|
|
270
337
|
this._operationExecutions.set(
|
|
271
338
|
this._operation.request.identifier,
|
|
@@ -302,12 +369,21 @@ class Executor {
|
|
|
302
369
|
if (this._subscriptions.size === 0) {
|
|
303
370
|
this.cancel();
|
|
304
371
|
this._sink.complete();
|
|
372
|
+
this._log({
|
|
373
|
+
name: 'execute.complete',
|
|
374
|
+
executeId: this._executeId,
|
|
375
|
+
});
|
|
305
376
|
}
|
|
306
377
|
}
|
|
307
378
|
|
|
308
379
|
_error(error: Error): void {
|
|
309
380
|
this.cancel();
|
|
310
381
|
this._sink.error(error);
|
|
382
|
+
this._log({
|
|
383
|
+
name: 'execute.error',
|
|
384
|
+
executeId: this._executeId,
|
|
385
|
+
error,
|
|
386
|
+
});
|
|
311
387
|
}
|
|
312
388
|
|
|
313
389
|
_start(id: number, subscription: Subscription): void {
|
|
@@ -318,8 +394,16 @@ class Executor {
|
|
|
318
394
|
// Handle a raw GraphQL response.
|
|
319
395
|
_next(_id: number, response: GraphQLResponse): void {
|
|
320
396
|
this._schedule(() => {
|
|
321
|
-
|
|
322
|
-
|
|
397
|
+
const [duration] = withDuration(() => {
|
|
398
|
+
this._handleNext(response);
|
|
399
|
+
this._maybeCompleteSubscriptionOperationTracking();
|
|
400
|
+
});
|
|
401
|
+
this._log({
|
|
402
|
+
name: 'execute.next',
|
|
403
|
+
executeId: this._executeId,
|
|
404
|
+
response,
|
|
405
|
+
duration,
|
|
406
|
+
});
|
|
323
407
|
});
|
|
324
408
|
}
|
|
325
409
|
|
|
@@ -383,7 +467,10 @@ class Executor {
|
|
|
383
467
|
responsePart => responsePart.extensions?.isOptimistic === true,
|
|
384
468
|
)
|
|
385
469
|
) {
|
|
386
|
-
invariant(
|
|
470
|
+
invariant(
|
|
471
|
+
false,
|
|
472
|
+
'OperationExecutor: Optimistic responses cannot be batched.',
|
|
473
|
+
);
|
|
387
474
|
}
|
|
388
475
|
return false;
|
|
389
476
|
}
|
|
@@ -392,7 +479,7 @@ class Executor {
|
|
|
392
479
|
if (isOptimistic && this._state !== 'started') {
|
|
393
480
|
invariant(
|
|
394
481
|
false,
|
|
395
|
-
'
|
|
482
|
+
'OperationExecutor: optimistic payload received after server payload.',
|
|
396
483
|
);
|
|
397
484
|
}
|
|
398
485
|
if (isOptimistic) {
|
|
@@ -411,6 +498,7 @@ class Executor {
|
|
|
411
498
|
if (this._state === 'completed') {
|
|
412
499
|
return;
|
|
413
500
|
}
|
|
501
|
+
this._seenActors.clear();
|
|
414
502
|
|
|
415
503
|
const responses = Array.isArray(response) ? response : [response];
|
|
416
504
|
const responsesWithData = this._handleErrorResponse(responses);
|
|
@@ -438,6 +526,7 @@ class Executor {
|
|
|
438
526
|
nonIncrementalResponses,
|
|
439
527
|
incrementalResponses,
|
|
440
528
|
] = partitionGraphQLResponses(responsesWithData);
|
|
529
|
+
const hasNonIncrementalResponses = nonIncrementalResponses.length > 0;
|
|
441
530
|
|
|
442
531
|
// In theory this doesn't preserve the ordering of the batch.
|
|
443
532
|
// The idea is that a batch is always:
|
|
@@ -446,30 +535,66 @@ class Executor {
|
|
|
446
535
|
// The non-incremental payload can appear if the server sends a batch
|
|
447
536
|
// with the initial payload followed by some early-to-resolve incremental
|
|
448
537
|
// payloads (although, can that even happen?)
|
|
449
|
-
if (
|
|
538
|
+
if (hasNonIncrementalResponses) {
|
|
539
|
+
// For subscriptions, to avoid every new payload from overwriting existing
|
|
540
|
+
// data from previous payloads, assign a unique rootID for every new
|
|
541
|
+
// non-incremental payload.
|
|
542
|
+
if (this._isSubscriptionOperation) {
|
|
543
|
+
const nextID = generateUniqueClientID();
|
|
544
|
+
this._operation = {
|
|
545
|
+
request: this._operation.request,
|
|
546
|
+
fragment: createReaderSelector(
|
|
547
|
+
this._operation.fragment.node,
|
|
548
|
+
nextID,
|
|
549
|
+
this._operation.fragment.variables,
|
|
550
|
+
this._operation.fragment.owner,
|
|
551
|
+
),
|
|
552
|
+
root: createNormalizationSelector(
|
|
553
|
+
this._operation.root.node,
|
|
554
|
+
nextID,
|
|
555
|
+
this._operation.root.variables,
|
|
556
|
+
),
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
|
|
450
560
|
const payloadFollowups = this._processResponses(nonIncrementalResponses);
|
|
451
|
-
// Please note that we're passing `this._operation` to the publish
|
|
452
|
-
// queue here, which will later passed to the store (via notify)
|
|
453
|
-
// to indicate that this is an operation that caused the store to update
|
|
454
|
-
const updatedOwners = this._publishQueue.run(this._operation);
|
|
455
|
-
this._updateOperationTracker(updatedOwners);
|
|
456
561
|
this._processPayloadFollowups(payloadFollowups);
|
|
457
|
-
if (this._incrementalPayloadsPending && !this._retainDisposable) {
|
|
458
|
-
this._retainDisposable = this._store.retain(this._operation);
|
|
459
|
-
}
|
|
460
562
|
}
|
|
461
563
|
|
|
462
564
|
if (incrementalResponses.length > 0) {
|
|
463
565
|
const payloadFollowups = this._processIncrementalResponses(
|
|
464
566
|
incrementalResponses,
|
|
465
567
|
);
|
|
466
|
-
|
|
467
|
-
// for already initiated operation (and we're not passing it to
|
|
468
|
-
// the run(...) call)
|
|
469
|
-
const updatedOwners = this._publishQueue.run();
|
|
470
|
-
this._updateOperationTracker(updatedOwners);
|
|
568
|
+
|
|
471
569
|
this._processPayloadFollowups(payloadFollowups);
|
|
472
570
|
}
|
|
571
|
+
if (this._isSubscriptionOperation) {
|
|
572
|
+
// We attach the id to allow the `requestSubscription` to read from the store using
|
|
573
|
+
// the current id in its `onNext` callback
|
|
574
|
+
if (responsesWithData[0].extensions == null) {
|
|
575
|
+
// $FlowFixMe[cannot-write]
|
|
576
|
+
responsesWithData[0].extensions = {
|
|
577
|
+
__relay_subscription_root_id: this._operation.fragment.dataID,
|
|
578
|
+
};
|
|
579
|
+
} else {
|
|
580
|
+
responsesWithData[0].extensions.__relay_subscription_root_id = this._operation.fragment.dataID;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// OK: run once after each new payload
|
|
585
|
+
// If we have non-incremental responses, we passing `this._operation` to
|
|
586
|
+
// the publish queue here, which will later be passed to the store (via
|
|
587
|
+
// notify) to indicate that this operation caused the store to update
|
|
588
|
+
const updatedOwners = this._runPublishQueue(
|
|
589
|
+
hasNonIncrementalResponses ? this._operation : undefined,
|
|
590
|
+
);
|
|
591
|
+
|
|
592
|
+
if (hasNonIncrementalResponses) {
|
|
593
|
+
if (this._incrementalPayloadsPending) {
|
|
594
|
+
this._retainData();
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
this._updateOperationTracker(updatedOwners);
|
|
473
598
|
this._sink.next(response);
|
|
474
599
|
}
|
|
475
600
|
|
|
@@ -480,7 +605,7 @@ class Executor {
|
|
|
480
605
|
): void {
|
|
481
606
|
invariant(
|
|
482
607
|
this._optimisticUpdates === null,
|
|
483
|
-
'environment.execute: only support one optimistic response per ' +
|
|
608
|
+
'OperationExecutor: environment.execute: only support one optimistic response per ' +
|
|
484
609
|
'execute.',
|
|
485
610
|
);
|
|
486
611
|
if (response == null && updater == null) {
|
|
@@ -493,10 +618,15 @@ class Executor {
|
|
|
493
618
|
this._operation.root,
|
|
494
619
|
ROOT_TYPE,
|
|
495
620
|
{
|
|
621
|
+
actorIdentifier: this._actorIdentifier,
|
|
496
622
|
getDataID: this._getDataID,
|
|
497
623
|
path: [],
|
|
498
|
-
reactFlightPayloadDeserializer:
|
|
624
|
+
reactFlightPayloadDeserializer:
|
|
625
|
+
this._reactFlightPayloadDeserializer != null
|
|
626
|
+
? this._deserializeReactFlightPayloadWithLogging
|
|
627
|
+
: null,
|
|
499
628
|
reactFlightServerErrorHandler: this._reactFlightServerErrorHandler,
|
|
629
|
+
shouldProcessClientComponents: this._shouldProcessClientComponents,
|
|
500
630
|
treatMissingFieldsAsNull,
|
|
501
631
|
},
|
|
502
632
|
);
|
|
@@ -514,7 +644,7 @@ class Executor {
|
|
|
514
644
|
errors: null,
|
|
515
645
|
fieldPayloads: null,
|
|
516
646
|
incrementalPlaceholders: null,
|
|
517
|
-
|
|
647
|
+
followupPayloads: null,
|
|
518
648
|
source: RelayRecordSource.create(),
|
|
519
649
|
isFinal: false,
|
|
520
650
|
},
|
|
@@ -522,61 +652,95 @@ class Executor {
|
|
|
522
652
|
});
|
|
523
653
|
}
|
|
524
654
|
this._optimisticUpdates = optimisticUpdates;
|
|
525
|
-
optimisticUpdates.forEach(update =>
|
|
526
|
-
|
|
655
|
+
optimisticUpdates.forEach(update =>
|
|
656
|
+
this._getPublishQueueAndSaveActor().applyUpdate(update),
|
|
657
|
+
);
|
|
658
|
+
// OK: only called on construction and when receiving an optimistic payload from network,
|
|
659
|
+
// which doesn't fall-through to the regular next() handling
|
|
660
|
+
this._runPublishQueue();
|
|
527
661
|
}
|
|
528
662
|
|
|
529
663
|
_processOptimisticFollowups(
|
|
530
664
|
payload: RelayResponsePayload,
|
|
531
665
|
optimisticUpdates: Array<OptimisticUpdate>,
|
|
532
666
|
): void {
|
|
533
|
-
if (payload.
|
|
534
|
-
const
|
|
535
|
-
const
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
667
|
+
if (payload.followupPayloads && payload.followupPayloads.length) {
|
|
668
|
+
const followupPayloads = payload.followupPayloads;
|
|
669
|
+
for (const followupPayload of followupPayloads) {
|
|
670
|
+
switch (followupPayload.kind) {
|
|
671
|
+
case 'ModuleImportPayload':
|
|
672
|
+
const operationLoader = this._expectOperationLoader();
|
|
673
|
+
const operation = operationLoader.get(
|
|
674
|
+
followupPayload.operationReference,
|
|
675
|
+
);
|
|
676
|
+
if (operation == null) {
|
|
677
|
+
this._processAsyncOptimisticModuleImport(followupPayload);
|
|
678
|
+
} else {
|
|
679
|
+
const moduleImportOptimisticUpdates = this._processOptimisticModuleImport(
|
|
680
|
+
operation,
|
|
681
|
+
followupPayload,
|
|
682
|
+
);
|
|
683
|
+
optimisticUpdates.push(...moduleImportOptimisticUpdates);
|
|
684
|
+
}
|
|
685
|
+
break;
|
|
686
|
+
case 'ActorPayload':
|
|
687
|
+
warning(
|
|
688
|
+
false,
|
|
689
|
+
'OperationExecutor: Unexpected optimistic ActorPayload. These updates are not supported.',
|
|
690
|
+
);
|
|
691
|
+
break;
|
|
692
|
+
default:
|
|
693
|
+
(followupPayload: empty);
|
|
694
|
+
invariant(
|
|
695
|
+
false,
|
|
696
|
+
'OperationExecutor: Unexpected followup kind `%s`. when processing optimistic updates.',
|
|
697
|
+
followupPayload.kind,
|
|
698
|
+
);
|
|
556
699
|
}
|
|
557
700
|
}
|
|
558
701
|
}
|
|
559
702
|
}
|
|
560
703
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
704
|
+
/**
|
|
705
|
+
* Normalize Data for @module payload, and actor-specific payload
|
|
706
|
+
*/
|
|
707
|
+
_normalizeFollowupPayload(
|
|
708
|
+
followupPayload: FollowupPayload,
|
|
709
|
+
normalizationNode: NormalizationSelectableNode,
|
|
564
710
|
) {
|
|
711
|
+
let variables;
|
|
712
|
+
if (
|
|
713
|
+
normalizationNode.kind === 'SplitOperation' &&
|
|
714
|
+
followupPayload.kind === 'ModuleImportPayload'
|
|
715
|
+
) {
|
|
716
|
+
variables = getLocalVariables(
|
|
717
|
+
followupPayload.variables,
|
|
718
|
+
normalizationNode.argumentDefinitions,
|
|
719
|
+
followupPayload.args,
|
|
720
|
+
);
|
|
721
|
+
} else {
|
|
722
|
+
variables = followupPayload.variables;
|
|
723
|
+
}
|
|
565
724
|
const selector = createNormalizationSelector(
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
725
|
+
normalizationNode,
|
|
726
|
+
followupPayload.dataID,
|
|
727
|
+
variables,
|
|
569
728
|
);
|
|
570
729
|
return normalizeResponse(
|
|
571
|
-
{data:
|
|
730
|
+
{data: followupPayload.data},
|
|
572
731
|
selector,
|
|
573
|
-
|
|
732
|
+
followupPayload.typeName,
|
|
574
733
|
{
|
|
734
|
+
actorIdentifier: this._actorIdentifier,
|
|
575
735
|
getDataID: this._getDataID,
|
|
576
|
-
path:
|
|
577
|
-
reactFlightPayloadDeserializer:
|
|
736
|
+
path: followupPayload.path,
|
|
737
|
+
reactFlightPayloadDeserializer:
|
|
738
|
+
this._reactFlightPayloadDeserializer != null
|
|
739
|
+
? this._deserializeReactFlightPayloadWithLogging
|
|
740
|
+
: null,
|
|
578
741
|
reactFlightServerErrorHandler: this._reactFlightServerErrorHandler,
|
|
579
742
|
treatMissingFieldsAsNull: this._treatMissingFieldsAsNull,
|
|
743
|
+
shouldProcessClientComponents: this._shouldProcessClientComponents,
|
|
580
744
|
},
|
|
581
745
|
);
|
|
582
746
|
}
|
|
@@ -587,7 +751,7 @@ class Executor {
|
|
|
587
751
|
): $ReadOnlyArray<OptimisticUpdate> {
|
|
588
752
|
const operation = getOperation(normalizationRootNode);
|
|
589
753
|
const optimisticUpdates = [];
|
|
590
|
-
const modulePayload = this.
|
|
754
|
+
const modulePayload = this._normalizeFollowupPayload(
|
|
591
755
|
moduleImportPayload,
|
|
592
756
|
operation,
|
|
593
757
|
);
|
|
@@ -602,10 +766,9 @@ class Executor {
|
|
|
602
766
|
}
|
|
603
767
|
|
|
604
768
|
_processAsyncOptimisticModuleImport(
|
|
605
|
-
operationLoader: OperationLoader,
|
|
606
769
|
moduleImportPayload: ModuleImportPayload,
|
|
607
770
|
): void {
|
|
608
|
-
|
|
771
|
+
this._expectOperationLoader()
|
|
609
772
|
.load(moduleImportPayload.operationReference)
|
|
610
773
|
.then(operation => {
|
|
611
774
|
if (operation == null || this._state !== 'started') {
|
|
@@ -616,27 +779,30 @@ class Executor {
|
|
|
616
779
|
moduleImportPayload,
|
|
617
780
|
);
|
|
618
781
|
moduleImportOptimisticUpdates.forEach(update =>
|
|
619
|
-
this.
|
|
782
|
+
this._getPublishQueueAndSaveActor().applyUpdate(update),
|
|
620
783
|
);
|
|
621
784
|
if (this._optimisticUpdates == null) {
|
|
622
785
|
warning(
|
|
623
786
|
false,
|
|
624
|
-
'
|
|
787
|
+
'OperationExecutor: Unexpected ModuleImport optimistic ' +
|
|
625
788
|
'update in operation %s.' +
|
|
626
789
|
this._operation.request.node.params.name,
|
|
627
790
|
);
|
|
628
791
|
} else {
|
|
629
792
|
this._optimisticUpdates.push(...moduleImportOptimisticUpdates);
|
|
630
|
-
|
|
793
|
+
// OK: always have to run() after an module import resolves async
|
|
794
|
+
this._runPublishQueue();
|
|
631
795
|
}
|
|
632
796
|
});
|
|
633
797
|
}
|
|
634
798
|
|
|
635
|
-
_processResponses(
|
|
799
|
+
_processResponses(
|
|
800
|
+
responses: $ReadOnlyArray<GraphQLResponseWithData>,
|
|
801
|
+
): $ReadOnlyArray<RelayResponsePayload> {
|
|
636
802
|
if (this._optimisticUpdates !== null) {
|
|
637
|
-
this._optimisticUpdates.forEach(update =>
|
|
638
|
-
this.
|
|
639
|
-
);
|
|
803
|
+
this._optimisticUpdates.forEach(update => {
|
|
804
|
+
this._getPublishQueueAndSaveActor().revertUpdate(update);
|
|
805
|
+
});
|
|
640
806
|
this._optimisticUpdates = null;
|
|
641
807
|
}
|
|
642
808
|
|
|
@@ -649,18 +815,24 @@ class Executor {
|
|
|
649
815
|
this._operation.root,
|
|
650
816
|
ROOT_TYPE,
|
|
651
817
|
{
|
|
818
|
+
actorIdentifier: this._actorIdentifier,
|
|
652
819
|
getDataID: this._getDataID,
|
|
653
820
|
path: [],
|
|
654
|
-
reactFlightPayloadDeserializer:
|
|
821
|
+
reactFlightPayloadDeserializer:
|
|
822
|
+
this._reactFlightPayloadDeserializer != null
|
|
823
|
+
? this._deserializeReactFlightPayloadWithLogging
|
|
824
|
+
: null,
|
|
655
825
|
reactFlightServerErrorHandler: this._reactFlightServerErrorHandler,
|
|
656
826
|
treatMissingFieldsAsNull: this._treatMissingFieldsAsNull,
|
|
827
|
+
shouldProcessClientComponents: this._shouldProcessClientComponents,
|
|
657
828
|
},
|
|
658
829
|
);
|
|
659
|
-
this.
|
|
830
|
+
this._getPublishQueueAndSaveActor().commitPayload(
|
|
660
831
|
this._operation,
|
|
661
832
|
relayPayload,
|
|
662
833
|
this._updater,
|
|
663
834
|
);
|
|
835
|
+
|
|
664
836
|
return relayPayload;
|
|
665
837
|
});
|
|
666
838
|
}
|
|
@@ -676,30 +848,30 @@ class Executor {
|
|
|
676
848
|
return;
|
|
677
849
|
}
|
|
678
850
|
payloads.forEach(payload => {
|
|
679
|
-
const {incrementalPlaceholders,
|
|
851
|
+
const {incrementalPlaceholders, followupPayloads, isFinal} = payload;
|
|
680
852
|
this._state = isFinal ? 'loading_final' : 'loading_incremental';
|
|
681
853
|
this._updateActiveState();
|
|
682
854
|
if (isFinal) {
|
|
683
855
|
this._incrementalPayloadsPending = false;
|
|
684
856
|
}
|
|
685
|
-
if (
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
moduleImportPayloads.forEach(moduleImportPayload => {
|
|
693
|
-
this._processModuleImportPayload(
|
|
694
|
-
moduleImportPayload,
|
|
695
|
-
operationLoader,
|
|
696
|
-
);
|
|
857
|
+
if (followupPayloads && followupPayloads.length !== 0) {
|
|
858
|
+
followupPayloads.forEach(followupPayload => {
|
|
859
|
+
const prevActorIdentifier = this._actorIdentifier;
|
|
860
|
+
this._actorIdentifier =
|
|
861
|
+
followupPayload.actorIdentifier ?? this._actorIdentifier;
|
|
862
|
+
this._processFollowupPayload(followupPayload);
|
|
863
|
+
this._actorIdentifier = prevActorIdentifier;
|
|
697
864
|
});
|
|
698
865
|
}
|
|
866
|
+
|
|
699
867
|
if (incrementalPlaceholders && incrementalPlaceholders.length !== 0) {
|
|
700
868
|
this._incrementalPayloadsPending = this._state !== 'loading_final';
|
|
701
869
|
incrementalPlaceholders.forEach(incrementalPlaceholder => {
|
|
870
|
+
const prevActorIdentifier = this._actorIdentifier;
|
|
871
|
+
this._actorIdentifier =
|
|
872
|
+
incrementalPlaceholder.actorIdentifier ?? this._actorIdentifier;
|
|
702
873
|
this._processIncrementalPlaceholder(payload, incrementalPlaceholder);
|
|
874
|
+
this._actorIdentifier = prevActorIdentifier;
|
|
703
875
|
});
|
|
704
876
|
|
|
705
877
|
if (this._isClientPayload || this._state === 'loading_final') {
|
|
@@ -731,8 +903,6 @@ class Executor {
|
|
|
731
903
|
}
|
|
732
904
|
});
|
|
733
905
|
if (relayPayloads.length > 0) {
|
|
734
|
-
const updatedOwners = this._publishQueue.run();
|
|
735
|
-
this._updateOperationTracker(updatedOwners);
|
|
736
906
|
this._processPayloadFollowups(relayPayloads);
|
|
737
907
|
}
|
|
738
908
|
}
|
|
@@ -741,9 +911,7 @@ class Executor {
|
|
|
741
911
|
}
|
|
742
912
|
|
|
743
913
|
_maybeCompleteSubscriptionOperationTracking() {
|
|
744
|
-
|
|
745
|
-
this._operation.request.node.params.operationKind === 'subscription';
|
|
746
|
-
if (!isSubscriptionOperation) {
|
|
914
|
+
if (!this._isSubscriptionOperation) {
|
|
747
915
|
return;
|
|
748
916
|
}
|
|
749
917
|
if (
|
|
@@ -761,73 +929,154 @@ class Executor {
|
|
|
761
929
|
* defer, stream, etc); these are handled by calling
|
|
762
930
|
* `_processPayloadFollowups()`.
|
|
763
931
|
*/
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
932
|
+
_processFollowupPayload(followupPayload: FollowupPayload): void {
|
|
933
|
+
switch (followupPayload.kind) {
|
|
934
|
+
case 'ModuleImportPayload':
|
|
935
|
+
const operationLoader = this._expectOperationLoader();
|
|
936
|
+
const node = operationLoader.get(followupPayload.operationReference);
|
|
937
|
+
if (node != null) {
|
|
938
|
+
// If the operation module is available synchronously, normalize the
|
|
939
|
+
// data synchronously.
|
|
940
|
+
this._processFollowupPayloadWithNormalizationNode(
|
|
941
|
+
followupPayload,
|
|
942
|
+
getOperation(node),
|
|
943
|
+
);
|
|
944
|
+
} else {
|
|
945
|
+
// Otherwise load the operation module and schedule a task to normalize
|
|
946
|
+
// the data when the module is available.
|
|
947
|
+
const id = this._nextSubscriptionId++;
|
|
948
|
+
this._pendingModulePayloadsCount++;
|
|
949
|
+
|
|
950
|
+
const decrementPendingCount = () => {
|
|
951
|
+
this._pendingModulePayloadsCount--;
|
|
952
|
+
this._maybeCompleteSubscriptionOperationTracking();
|
|
953
|
+
};
|
|
954
|
+
|
|
955
|
+
// Observable.from(operationLoader.load()) wouldn't catch synchronous
|
|
956
|
+
// errors thrown by the load function, which is user-defined. Guard
|
|
957
|
+
// against that with Observable.from(new Promise(<work>)).
|
|
958
|
+
const networkObservable = RelayObservable.from(
|
|
959
|
+
new Promise((resolve, reject) => {
|
|
960
|
+
operationLoader
|
|
961
|
+
.load(followupPayload.operationReference)
|
|
962
|
+
.then(resolve, reject);
|
|
963
|
+
}),
|
|
964
|
+
);
|
|
965
|
+
RelayObservable.create(sink => {
|
|
966
|
+
let cancellationToken;
|
|
967
|
+
const subscription = networkObservable.subscribe({
|
|
968
|
+
next: (loadedNode: ?NormalizationRootNode) => {
|
|
969
|
+
if (loadedNode != null) {
|
|
970
|
+
const publishModuleImportPayload = () => {
|
|
971
|
+
try {
|
|
972
|
+
const operation = getOperation(loadedNode);
|
|
973
|
+
const batchAsyncModuleUpdatesFN =
|
|
974
|
+
RelayFeatureFlags.BATCH_ASYNC_MODULE_UPDATES_FN;
|
|
975
|
+
const shouldScheduleAsyncStoreUpdate =
|
|
976
|
+
batchAsyncModuleUpdatesFN != null &&
|
|
977
|
+
this._pendingModulePayloadsCount > 1;
|
|
978
|
+
const [duration] = withDuration(() => {
|
|
979
|
+
this._handleFollowupPayload(followupPayload, operation);
|
|
980
|
+
// OK: always have to run after an async module import resolves
|
|
981
|
+
if (shouldScheduleAsyncStoreUpdate) {
|
|
982
|
+
this._scheduleAsyncStoreUpdate(
|
|
983
|
+
// $FlowFixMe[incompatible-call] `shouldScheduleAsyncStoreUpdate` check should cover `null` case
|
|
984
|
+
batchAsyncModuleUpdatesFN,
|
|
985
|
+
sink.complete,
|
|
986
|
+
);
|
|
987
|
+
} else {
|
|
988
|
+
const updatedOwners = this._runPublishQueue();
|
|
989
|
+
this._updateOperationTracker(updatedOwners);
|
|
990
|
+
}
|
|
991
|
+
});
|
|
992
|
+
this._log({
|
|
993
|
+
name: 'execute.async.module',
|
|
994
|
+
executeId: this._executeId,
|
|
995
|
+
operationName: operation.name,
|
|
996
|
+
duration,
|
|
997
|
+
});
|
|
998
|
+
if (!shouldScheduleAsyncStoreUpdate) {
|
|
999
|
+
sink.complete();
|
|
1000
|
+
}
|
|
1001
|
+
} catch (error) {
|
|
1002
|
+
sink.error(error);
|
|
1003
|
+
}
|
|
1004
|
+
};
|
|
1005
|
+
const scheduler = this._scheduler;
|
|
1006
|
+
if (scheduler == null) {
|
|
1007
|
+
publishModuleImportPayload();
|
|
1008
|
+
} else {
|
|
1009
|
+
cancellationToken = scheduler.schedule(
|
|
1010
|
+
publishModuleImportPayload,
|
|
1011
|
+
);
|
|
1012
|
+
}
|
|
1013
|
+
} else {
|
|
1014
|
+
sink.complete();
|
|
1015
|
+
}
|
|
1016
|
+
},
|
|
1017
|
+
error: sink.error,
|
|
803
1018
|
});
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
1019
|
+
return () => {
|
|
1020
|
+
subscription.unsubscribe();
|
|
1021
|
+
if (this._scheduler != null && cancellationToken != null) {
|
|
1022
|
+
this._scheduler.cancel(cancellationToken);
|
|
1023
|
+
}
|
|
1024
|
+
};
|
|
1025
|
+
}).subscribe({
|
|
1026
|
+
complete: () => {
|
|
1027
|
+
this._complete(id);
|
|
1028
|
+
decrementPendingCount();
|
|
1029
|
+
},
|
|
1030
|
+
error: error => {
|
|
1031
|
+
this._error(error);
|
|
1032
|
+
decrementPendingCount();
|
|
1033
|
+
},
|
|
1034
|
+
start: subscription => this._start(id, subscription),
|
|
1035
|
+
});
|
|
1036
|
+
}
|
|
1037
|
+
break;
|
|
1038
|
+
case 'ActorPayload':
|
|
1039
|
+
this._processFollowupPayloadWithNormalizationNode(
|
|
1040
|
+
followupPayload,
|
|
1041
|
+
followupPayload.node,
|
|
1042
|
+
);
|
|
1043
|
+
break;
|
|
1044
|
+
default:
|
|
1045
|
+
(followupPayload: empty);
|
|
1046
|
+
invariant(
|
|
1047
|
+
false,
|
|
1048
|
+
'OperationExecutor: Unexpected followup kind `%s`.',
|
|
1049
|
+
followupPayload.kind,
|
|
1050
|
+
);
|
|
817
1051
|
}
|
|
818
1052
|
}
|
|
819
1053
|
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
1054
|
+
_processFollowupPayloadWithNormalizationNode(
|
|
1055
|
+
followupPayload: FollowupPayload,
|
|
1056
|
+
normalizationNode:
|
|
1057
|
+
| NormalizationSplitOperation
|
|
1058
|
+
| NormalizationOperation
|
|
1059
|
+
| NormalizationLinkedField,
|
|
1060
|
+
) {
|
|
1061
|
+
this._handleFollowupPayload(followupPayload, normalizationNode);
|
|
1062
|
+
this._maybeCompleteSubscriptionOperationTracking();
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
_handleFollowupPayload(
|
|
1066
|
+
followupPayload: FollowupPayload,
|
|
1067
|
+
normalizationNode:
|
|
1068
|
+
| NormalizationSplitOperation
|
|
1069
|
+
| NormalizationOperation
|
|
1070
|
+
| NormalizationLinkedField,
|
|
823
1071
|
): void {
|
|
824
|
-
const relayPayload = this.
|
|
825
|
-
|
|
826
|
-
|
|
1072
|
+
const relayPayload = this._normalizeFollowupPayload(
|
|
1073
|
+
followupPayload,
|
|
1074
|
+
normalizationNode,
|
|
1075
|
+
);
|
|
1076
|
+
this._getPublishQueueAndSaveActor().commitPayload(
|
|
1077
|
+
this._operation,
|
|
1078
|
+
relayPayload,
|
|
827
1079
|
);
|
|
828
|
-
this._publishQueue.commitPayload(this._operation, relayPayload);
|
|
829
|
-
const updatedOwners = this._publishQueue.run();
|
|
830
|
-
this._updateOperationTracker(updatedOwners);
|
|
831
1080
|
this._processPayloadFollowups([relayPayload]);
|
|
832
1081
|
}
|
|
833
1082
|
|
|
@@ -873,7 +1122,7 @@ class Executor {
|
|
|
873
1122
|
(placeholder: empty);
|
|
874
1123
|
invariant(
|
|
875
1124
|
false,
|
|
876
|
-
'Unsupported incremental placeholder kind `%s`.',
|
|
1125
|
+
'OperationExecutor: Unsupported incremental placeholder kind `%s`.',
|
|
877
1126
|
placeholder.kind,
|
|
878
1127
|
);
|
|
879
1128
|
}
|
|
@@ -897,7 +1146,7 @@ class Executor {
|
|
|
897
1146
|
// exist.
|
|
898
1147
|
invariant(
|
|
899
1148
|
parentRecord != null,
|
|
900
|
-
'
|
|
1149
|
+
'OperationExecutor: Expected record `%s` to exist.',
|
|
901
1150
|
parentID,
|
|
902
1151
|
);
|
|
903
1152
|
let nextParentRecord;
|
|
@@ -926,14 +1175,13 @@ class Executor {
|
|
|
926
1175
|
record: nextParentRecord,
|
|
927
1176
|
fieldPayloads: nextParentPayloads,
|
|
928
1177
|
});
|
|
1178
|
+
|
|
929
1179
|
// If there were any queued responses, process them now that placeholders
|
|
930
1180
|
// are in place
|
|
931
1181
|
if (pendingResponses != null) {
|
|
932
1182
|
const payloadFollowups = this._processIncrementalResponses(
|
|
933
1183
|
pendingResponses,
|
|
934
1184
|
);
|
|
935
|
-
const updatedOwners = this._publishQueue.run();
|
|
936
|
-
this._updateOperationTracker(updatedOwners);
|
|
937
1185
|
this._processPayloadFollowups(payloadFollowups);
|
|
938
1186
|
}
|
|
939
1187
|
}
|
|
@@ -969,7 +1217,7 @@ class Executor {
|
|
|
969
1217
|
const placeholder = resultForPath.placeholder;
|
|
970
1218
|
invariant(
|
|
971
1219
|
placeholder.kind === 'defer',
|
|
972
|
-
'
|
|
1220
|
+
'OperationExecutor: Expected data for path `%s` for label `%s` ' +
|
|
973
1221
|
'to be data for @defer, was `@%s`.',
|
|
974
1222
|
pathKey,
|
|
975
1223
|
label,
|
|
@@ -999,7 +1247,7 @@ class Executor {
|
|
|
999
1247
|
const placeholder = resultForPath.placeholder;
|
|
1000
1248
|
invariant(
|
|
1001
1249
|
placeholder.kind === 'stream',
|
|
1002
|
-
'
|
|
1250
|
+
'OperationExecutor: Expected data for path `%s` for label `%s` ' +
|
|
1003
1251
|
'to be data for @stream, was `@%s`.',
|
|
1004
1252
|
pathKey,
|
|
1005
1253
|
label,
|
|
@@ -1020,26 +1268,37 @@ class Executor {
|
|
|
1020
1268
|
response: GraphQLResponseWithData,
|
|
1021
1269
|
): RelayResponsePayload {
|
|
1022
1270
|
const {dataID: parentID} = placeholder.selector;
|
|
1271
|
+
const prevActorIdentifier = this._actorIdentifier;
|
|
1272
|
+
this._actorIdentifier =
|
|
1273
|
+
placeholder.actorIdentifier ?? this._actorIdentifier;
|
|
1023
1274
|
const relayPayload = normalizeResponse(
|
|
1024
1275
|
response,
|
|
1025
1276
|
placeholder.selector,
|
|
1026
1277
|
placeholder.typeName,
|
|
1027
1278
|
{
|
|
1279
|
+
actorIdentifier: this._actorIdentifier,
|
|
1028
1280
|
getDataID: this._getDataID,
|
|
1029
1281
|
path: placeholder.path,
|
|
1030
|
-
reactFlightPayloadDeserializer:
|
|
1282
|
+
reactFlightPayloadDeserializer:
|
|
1283
|
+
this._reactFlightPayloadDeserializer != null
|
|
1284
|
+
? this._deserializeReactFlightPayloadWithLogging
|
|
1285
|
+
: null,
|
|
1031
1286
|
reactFlightServerErrorHandler: this._reactFlightServerErrorHandler,
|
|
1032
1287
|
treatMissingFieldsAsNull: this._treatMissingFieldsAsNull,
|
|
1288
|
+
shouldProcessClientComponents: this._shouldProcessClientComponents,
|
|
1033
1289
|
},
|
|
1034
1290
|
);
|
|
1035
|
-
this.
|
|
1291
|
+
this._getPublishQueueAndSaveActor().commitPayload(
|
|
1292
|
+
this._operation,
|
|
1293
|
+
relayPayload,
|
|
1294
|
+
);
|
|
1036
1295
|
|
|
1037
1296
|
// Load the version of the parent record from which this incremental data
|
|
1038
1297
|
// was derived
|
|
1039
1298
|
const parentEntry = this._source.get(parentID);
|
|
1040
1299
|
invariant(
|
|
1041
1300
|
parentEntry != null,
|
|
1042
|
-
'
|
|
1301
|
+
'OperationExecutor: Expected the parent record `%s` for @defer ' +
|
|
1043
1302
|
'data to exist.',
|
|
1044
1303
|
parentID,
|
|
1045
1304
|
);
|
|
@@ -1049,15 +1308,17 @@ class Executor {
|
|
|
1049
1308
|
errors: null,
|
|
1050
1309
|
fieldPayloads,
|
|
1051
1310
|
incrementalPlaceholders: null,
|
|
1052
|
-
|
|
1311
|
+
followupPayloads: null,
|
|
1053
1312
|
source: RelayRecordSource.create(),
|
|
1054
1313
|
isFinal: response.extensions?.is_final === true,
|
|
1055
1314
|
};
|
|
1056
|
-
this.
|
|
1315
|
+
this._getPublishQueueAndSaveActor().commitPayload(
|
|
1057
1316
|
this._operation,
|
|
1058
1317
|
handleFieldsRelayPayload,
|
|
1059
1318
|
);
|
|
1060
1319
|
}
|
|
1320
|
+
|
|
1321
|
+
this._actorIdentifier = prevActorIdentifier;
|
|
1061
1322
|
return relayPayload;
|
|
1062
1323
|
}
|
|
1063
1324
|
|
|
@@ -1070,12 +1331,14 @@ class Executor {
|
|
|
1070
1331
|
placeholder: StreamPlaceholder,
|
|
1071
1332
|
response: GraphQLResponseWithData,
|
|
1072
1333
|
): RelayResponsePayload {
|
|
1073
|
-
const {parentID, node, variables} = placeholder;
|
|
1334
|
+
const {parentID, node, variables, actorIdentifier} = placeholder;
|
|
1335
|
+
const prevActorIdentifier = this._actorIdentifier;
|
|
1336
|
+
this._actorIdentifier = actorIdentifier ?? this._actorIdentifier;
|
|
1074
1337
|
// Find the LinkedField where @stream was applied
|
|
1075
1338
|
const field = node.selections[0];
|
|
1076
1339
|
invariant(
|
|
1077
1340
|
field != null && field.kind === 'LinkedField' && field.plural === true,
|
|
1078
|
-
'
|
|
1341
|
+
'OperationExecutor: Expected @stream to be used on a plural field.',
|
|
1079
1342
|
);
|
|
1080
1343
|
const {
|
|
1081
1344
|
fieldPayloads,
|
|
@@ -1095,34 +1358,38 @@ class Executor {
|
|
|
1095
1358
|
// Publish the new item and update the parent record to set
|
|
1096
1359
|
// field[index] = item *if* the parent record hasn't been concurrently
|
|
1097
1360
|
// modified.
|
|
1098
|
-
this.
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1361
|
+
this._getPublishQueueAndSaveActor().commitPayload(
|
|
1362
|
+
this._operation,
|
|
1363
|
+
relayPayload,
|
|
1364
|
+
store => {
|
|
1365
|
+
const currentParentRecord = store.get(parentID);
|
|
1366
|
+
if (currentParentRecord == null) {
|
|
1367
|
+
// parent has since been deleted, stream data is stale
|
|
1368
|
+
return;
|
|
1369
|
+
}
|
|
1370
|
+
const currentItems = currentParentRecord.getLinkedRecords(storageKey);
|
|
1371
|
+
if (currentItems == null) {
|
|
1372
|
+
// field has since been deleted, stream data is stale
|
|
1373
|
+
return;
|
|
1374
|
+
}
|
|
1375
|
+
if (
|
|
1376
|
+
currentItems.length !== prevIDs.length ||
|
|
1377
|
+
currentItems.some(
|
|
1378
|
+
(currentItem, index) =>
|
|
1379
|
+
prevIDs[index] !== (currentItem && currentItem.getDataID()),
|
|
1380
|
+
)
|
|
1381
|
+
) {
|
|
1382
|
+
// field has been modified by something other than this query,
|
|
1383
|
+
// stream data is stale
|
|
1384
|
+
return;
|
|
1385
|
+
}
|
|
1386
|
+
// parent.field has not been concurrently modified:
|
|
1387
|
+
// update `parent.field[index] = item`
|
|
1388
|
+
const nextItems = [...currentItems];
|
|
1389
|
+
nextItems[itemIndex] = store.get(itemID);
|
|
1390
|
+
currentParentRecord.setLinkedRecords(nextItems, storageKey);
|
|
1391
|
+
},
|
|
1392
|
+
);
|
|
1126
1393
|
|
|
1127
1394
|
// Now that the parent record has been updated to include the new item,
|
|
1128
1395
|
// also update any handle fields that are derived from the parent record.
|
|
@@ -1131,15 +1398,17 @@ class Executor {
|
|
|
1131
1398
|
errors: null,
|
|
1132
1399
|
fieldPayloads,
|
|
1133
1400
|
incrementalPlaceholders: null,
|
|
1134
|
-
|
|
1401
|
+
followupPayloads: null,
|
|
1135
1402
|
source: RelayRecordSource.create(),
|
|
1136
1403
|
isFinal: false,
|
|
1137
1404
|
};
|
|
1138
|
-
this.
|
|
1405
|
+
this._getPublishQueueAndSaveActor().commitPayload(
|
|
1139
1406
|
this._operation,
|
|
1140
1407
|
handleFieldsRelayPayload,
|
|
1141
1408
|
);
|
|
1142
1409
|
}
|
|
1410
|
+
|
|
1411
|
+
this._actorIdentifier = prevActorIdentifier;
|
|
1143
1412
|
return relayPayload;
|
|
1144
1413
|
}
|
|
1145
1414
|
|
|
@@ -1161,7 +1430,7 @@ class Executor {
|
|
|
1161
1430
|
const {data} = response;
|
|
1162
1431
|
invariant(
|
|
1163
1432
|
typeof data === 'object',
|
|
1164
|
-
'
|
|
1433
|
+
'OperationExecutor: Expected the GraphQL @stream payload `data` ' +
|
|
1165
1434
|
'value to be an object.',
|
|
1166
1435
|
);
|
|
1167
1436
|
const responseKey = field.alias ?? field.name;
|
|
@@ -1172,7 +1441,7 @@ class Executor {
|
|
|
1172
1441
|
const parentEntry = this._source.get(parentID);
|
|
1173
1442
|
invariant(
|
|
1174
1443
|
parentEntry != null,
|
|
1175
|
-
'
|
|
1444
|
+
'OperationExecutor: Expected the parent record `%s` for @stream ' +
|
|
1176
1445
|
'data to exist.',
|
|
1177
1446
|
parentID,
|
|
1178
1447
|
);
|
|
@@ -1187,7 +1456,7 @@ class Executor {
|
|
|
1187
1456
|
);
|
|
1188
1457
|
invariant(
|
|
1189
1458
|
prevIDs != null,
|
|
1190
|
-
'
|
|
1459
|
+
'OperationExecutor: Expected record `%s` to have fetched field ' +
|
|
1191
1460
|
'`%s` with @stream.',
|
|
1192
1461
|
parentID,
|
|
1193
1462
|
field.name,
|
|
@@ -1198,7 +1467,7 @@ class Executor {
|
|
|
1198
1467
|
const itemIndex = parseInt(finalPathEntry, 10);
|
|
1199
1468
|
invariant(
|
|
1200
1469
|
itemIndex === finalPathEntry && itemIndex >= 0,
|
|
1201
|
-
'
|
|
1470
|
+
'OperationExecutor: Expected path for @stream to end in a ' +
|
|
1202
1471
|
'positive integer index, got `%s`',
|
|
1203
1472
|
finalPathEntry,
|
|
1204
1473
|
);
|
|
@@ -1206,7 +1475,7 @@ class Executor {
|
|
|
1206
1475
|
const typeName = field.concreteType ?? data[TYPENAME_KEY];
|
|
1207
1476
|
invariant(
|
|
1208
1477
|
typeof typeName === 'string',
|
|
1209
|
-
'
|
|
1478
|
+
'OperationExecutor: Expected @stream field `%s` to have a ' +
|
|
1210
1479
|
'__typename.',
|
|
1211
1480
|
field.name,
|
|
1212
1481
|
);
|
|
@@ -1221,7 +1490,7 @@ class Executor {
|
|
|
1221
1490
|
generateClientID(parentID, storageKey, itemIndex);
|
|
1222
1491
|
invariant(
|
|
1223
1492
|
typeof itemID === 'string',
|
|
1224
|
-
'
|
|
1493
|
+
'OperationExecutor: Expected id of elements of field `%s` to ' +
|
|
1225
1494
|
'be strings.',
|
|
1226
1495
|
storageKey,
|
|
1227
1496
|
);
|
|
@@ -1241,11 +1510,16 @@ class Executor {
|
|
|
1241
1510
|
fieldPayloads,
|
|
1242
1511
|
});
|
|
1243
1512
|
const relayPayload = normalizeResponse(response, selector, typeName, {
|
|
1513
|
+
actorIdentifier: this._actorIdentifier,
|
|
1244
1514
|
getDataID: this._getDataID,
|
|
1245
1515
|
path: [...normalizationPath, responseKey, String(itemIndex)],
|
|
1246
|
-
reactFlightPayloadDeserializer:
|
|
1516
|
+
reactFlightPayloadDeserializer:
|
|
1517
|
+
this._reactFlightPayloadDeserializer != null
|
|
1518
|
+
? this._deserializeReactFlightPayloadWithLogging
|
|
1519
|
+
: null,
|
|
1247
1520
|
reactFlightServerErrorHandler: this._reactFlightServerErrorHandler,
|
|
1248
1521
|
treatMissingFieldsAsNull: this._treatMissingFieldsAsNull,
|
|
1522
|
+
shouldProcessClientComponents: this._shouldProcessClientComponents,
|
|
1249
1523
|
});
|
|
1250
1524
|
return {
|
|
1251
1525
|
fieldPayloads,
|
|
@@ -1257,14 +1531,29 @@ class Executor {
|
|
|
1257
1531
|
};
|
|
1258
1532
|
}
|
|
1259
1533
|
|
|
1534
|
+
_scheduleAsyncStoreUpdate(
|
|
1535
|
+
scheduleFn: (() => void) => Disposable,
|
|
1536
|
+
completeFn: () => void,
|
|
1537
|
+
): void {
|
|
1538
|
+
this._completeFns.push(completeFn);
|
|
1539
|
+
if (this._asyncStoreUpdateDisposable != null) {
|
|
1540
|
+
return;
|
|
1541
|
+
}
|
|
1542
|
+
this._asyncStoreUpdateDisposable = scheduleFn(() => {
|
|
1543
|
+
this._asyncStoreUpdateDisposable = null;
|
|
1544
|
+
const updatedOwners = this._runPublishQueue();
|
|
1545
|
+
this._updateOperationTracker(updatedOwners);
|
|
1546
|
+
for (const complete of this._completeFns) {
|
|
1547
|
+
complete();
|
|
1548
|
+
}
|
|
1549
|
+
this._completeFns = [];
|
|
1550
|
+
});
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1260
1553
|
_updateOperationTracker(
|
|
1261
1554
|
updatedOwners: ?$ReadOnlyArray<RequestDescriptor>,
|
|
1262
1555
|
): void {
|
|
1263
|
-
if (
|
|
1264
|
-
this._operationTracker != null &&
|
|
1265
|
-
updatedOwners != null &&
|
|
1266
|
-
updatedOwners.length > 0
|
|
1267
|
-
) {
|
|
1556
|
+
if (updatedOwners != null && updatedOwners.length > 0) {
|
|
1268
1557
|
this._operationTracker.update(
|
|
1269
1558
|
this._operation.request,
|
|
1270
1559
|
new Set(updatedOwners),
|
|
@@ -1273,10 +1562,60 @@ class Executor {
|
|
|
1273
1562
|
}
|
|
1274
1563
|
|
|
1275
1564
|
_completeOperationTracker() {
|
|
1276
|
-
|
|
1277
|
-
|
|
1565
|
+
this._operationTracker.complete(this._operation.request);
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
_getPublishQueueAndSaveActor(): PublishQueue {
|
|
1569
|
+
this._seenActors.add(this._actorIdentifier);
|
|
1570
|
+
return this._getPublishQueue(this._actorIdentifier);
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1573
|
+
_getActorsToVisit(): $ReadOnlySet<ActorIdentifier> {
|
|
1574
|
+
if (this._seenActors.size === 0) {
|
|
1575
|
+
return new Set([this._actorIdentifier]);
|
|
1576
|
+
} else {
|
|
1577
|
+
return this._seenActors;
|
|
1278
1578
|
}
|
|
1279
1579
|
}
|
|
1580
|
+
|
|
1581
|
+
_runPublishQueue(
|
|
1582
|
+
operation?: OperationDescriptor,
|
|
1583
|
+
): $ReadOnlyArray<RequestDescriptor> {
|
|
1584
|
+
const updatedOwners = new Set();
|
|
1585
|
+
for (const actorIdentifier of this._getActorsToVisit()) {
|
|
1586
|
+
const owners = this._getPublishQueue(actorIdentifier).run(operation);
|
|
1587
|
+
owners.forEach(owner => updatedOwners.add(owner));
|
|
1588
|
+
}
|
|
1589
|
+
return Array.from(updatedOwners);
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
_retainData() {
|
|
1593
|
+
for (const actorIdentifier of this._getActorsToVisit()) {
|
|
1594
|
+
if (!this._retainDisposables.has(actorIdentifier)) {
|
|
1595
|
+
this._retainDisposables.set(
|
|
1596
|
+
actorIdentifier,
|
|
1597
|
+
this._getStore(actorIdentifier).retain(this._operation),
|
|
1598
|
+
);
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
_disposeRetainedData() {
|
|
1604
|
+
for (const disposable of this._retainDisposables.values()) {
|
|
1605
|
+
disposable.dispose();
|
|
1606
|
+
}
|
|
1607
|
+
this._retainDisposables.clear();
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
_expectOperationLoader(): OperationLoader {
|
|
1611
|
+
const operationLoader = this._operationLoader;
|
|
1612
|
+
invariant(
|
|
1613
|
+
operationLoader,
|
|
1614
|
+
'OperationExecutor: Expected an operationLoader to be ' +
|
|
1615
|
+
'configured when using `@match`.',
|
|
1616
|
+
);
|
|
1617
|
+
return operationLoader;
|
|
1618
|
+
}
|
|
1280
1619
|
}
|
|
1281
1620
|
|
|
1282
1621
|
function partitionGraphQLResponses(
|
|
@@ -1293,7 +1632,7 @@ function partitionGraphQLResponses(
|
|
|
1293
1632
|
if (label == null || path == null) {
|
|
1294
1633
|
invariant(
|
|
1295
1634
|
false,
|
|
1296
|
-
'
|
|
1635
|
+
'OperationExecutor: invalid incremental payload, expected ' +
|
|
1297
1636
|
'`path` and `label` to either both be null/undefined, or ' +
|
|
1298
1637
|
'`path` to be an `Array<string | number>` and `label` to be a ' +
|
|
1299
1638
|
'`string`.',
|
|
@@ -1345,11 +1684,13 @@ function validateOptimisticResponsePayload(
|
|
|
1345
1684
|
if (incrementalPlaceholders != null && incrementalPlaceholders.length !== 0) {
|
|
1346
1685
|
invariant(
|
|
1347
1686
|
false,
|
|
1348
|
-
'
|
|
1687
|
+
'OperationExecutor: optimistic responses cannot be returned ' +
|
|
1349
1688
|
'for operations that use incremental data delivery (@defer, ' +
|
|
1350
1689
|
'@stream, and @stream_connection).',
|
|
1351
1690
|
);
|
|
1352
1691
|
}
|
|
1353
1692
|
}
|
|
1354
1693
|
|
|
1355
|
-
module.exports = {
|
|
1694
|
+
module.exports = {
|
|
1695
|
+
execute,
|
|
1696
|
+
};
|