relay-runtime 11.0.2 → 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/index.js +1 -1
- package/index.js.flow +16 -1
- package/lib/index.js +15 -0
- package/lib/multi-actor-environment/ActorIdentifier.js +11 -1
- package/lib/multi-actor-environment/ActorSpecificEnvironment.js +59 -19
- package/lib/multi-actor-environment/ActorUtils.js +27 -0
- package/lib/multi-actor-environment/MultiActorEnvironment.js +305 -55
- package/lib/multi-actor-environment/index.js +5 -1
- package/lib/mutations/RelayRecordSourceSelectorProxy.js +6 -1
- package/lib/mutations/commitMutation.js +4 -1
- package/lib/mutations/validateMutation.js +6 -1
- package/lib/network/RelayObservable.js +3 -1
- package/lib/network/RelayQueryResponseCache.js +19 -3
- package/lib/network/wrapNetworkWithLogObserver.js +78 -0
- package/lib/store/DataChecker.js +110 -40
- package/lib/store/OperationExecutor.js +478 -204
- package/lib/store/RelayConcreteVariables.js +21 -0
- package/lib/store/RelayModernEnvironment.js +41 -85
- package/lib/store/RelayModernFragmentSpecResolver.js +48 -22
- package/lib/store/RelayModernRecord.js +35 -1
- package/lib/store/RelayModernStore.js +48 -14
- package/lib/store/RelayOperationTracker.js +33 -23
- package/lib/store/RelayPublishQueue.js +23 -5
- package/lib/store/RelayReader.js +138 -44
- package/lib/store/RelayRecordSource.js +87 -3
- package/lib/store/RelayReferenceMarker.js +28 -15
- package/lib/store/RelayResponseNormalizer.js +164 -91
- package/lib/store/RelayStoreReactFlightUtils.js +1 -7
- package/lib/store/RelayStoreSubscriptions.js +8 -5
- package/lib/store/RelayStoreUtils.js +7 -2
- package/lib/store/ResolverCache.js +213 -0
- package/lib/store/ResolverFragments.js +1 -1
- package/lib/store/createRelayContext.js +1 -1
- package/lib/subscription/requestSubscription.js +27 -29
- package/lib/util/RelayConcreteNode.js +1 -0
- package/lib/util/RelayFeatureFlags.js +3 -5
- package/lib/util/RelayReplaySubject.js +21 -6
- 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/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 +17 -1
- package/multi-actor-environment/ActorSpecificEnvironment.js.flow +72 -44
- package/multi-actor-environment/ActorUtils.js.flow +33 -0
- package/multi-actor-environment/MultiActorEnvironment.js.flow +332 -80
- package/multi-actor-environment/MultiActorEnvironmentTypes.js.flow +61 -12
- package/multi-actor-environment/index.js.flow +3 -0
- package/mutations/RelayRecordSourceSelectorProxy.js.flow +7 -2
- package/mutations/commitMutation.js.flow +2 -0
- package/mutations/validateMutation.js.flow +8 -0
- package/network/RelayObservable.js.flow +2 -0
- package/network/RelayQueryResponseCache.js.flow +31 -18
- package/network/wrapNetworkWithLogObserver.js.flow +99 -0
- package/package.json +1 -1
- 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 +126 -35
- package/store/OperationExecutor.js.flow +528 -265
- package/store/RelayConcreteVariables.js.flow +26 -1
- package/store/RelayModernEnvironment.js.flow +41 -94
- 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 +50 -12
- package/store/RelayOperationTracker.js.flow +56 -34
- package/store/RelayPublishQueue.js.flow +31 -8
- package/store/RelayReader.js.flow +148 -42
- package/store/RelayRecordSource.js.flow +72 -6
- package/store/RelayReferenceMarker.js.flow +29 -12
- package/store/RelayResponseNormalizer.js.flow +164 -48
- package/store/RelayStoreReactFlightUtils.js.flow +1 -7
- package/store/RelayStoreSubscriptions.js.flow +10 -3
- package/store/RelayStoreTypes.js.flow +128 -12
- package/store/RelayStoreUtils.js.flow +17 -3
- package/store/ResolverCache.js.flow +247 -0
- package/store/ResolverFragments.js.flow +6 -3
- package/store/createRelayContext.js.flow +1 -1
- package/subscription/requestSubscription.js.flow +41 -29
- package/util/NormalizationNode.js.flow +10 -3
- package/util/ReaderNode.js.flow +15 -1
- package/util/RelayConcreteNode.js.flow +1 -0
- package/util/RelayFeatureFlags.js.flow +8 -10
- package/util/RelayReplaySubject.js.flow +7 -6
- 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 +1 -0
- 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,7 +14,13 @@
|
|
|
14
14
|
|
|
15
15
|
const invariant = require('invariant');
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
const {getArgumentValues} = require('./RelayStoreUtils');
|
|
18
|
+
|
|
19
|
+
import type {
|
|
20
|
+
NormalizationLocalArgumentDefinition,
|
|
21
|
+
NormalizationArgument,
|
|
22
|
+
NormalizationOperation,
|
|
23
|
+
} from '../util/NormalizationNode';
|
|
18
24
|
import type {ReaderFragment} from '../util/ReaderNode';
|
|
19
25
|
import type {Variables} from '../util/RelayRuntimeTypes';
|
|
20
26
|
|
|
@@ -95,7 +101,26 @@ function getOperationVariables(
|
|
|
95
101
|
return operationVariables;
|
|
96
102
|
}
|
|
97
103
|
|
|
104
|
+
function getLocalVariables(
|
|
105
|
+
currentVariables: Variables,
|
|
106
|
+
argumentDefinitions: ?$ReadOnlyArray<NormalizationLocalArgumentDefinition>,
|
|
107
|
+
args: ?$ReadOnlyArray<NormalizationArgument>,
|
|
108
|
+
): Variables {
|
|
109
|
+
if (argumentDefinitions == null) {
|
|
110
|
+
return currentVariables;
|
|
111
|
+
}
|
|
112
|
+
const nextVariables = {...currentVariables};
|
|
113
|
+
const nextArgs = args ? getArgumentValues(args, currentVariables) : {};
|
|
114
|
+
argumentDefinitions.forEach(def => {
|
|
115
|
+
// $FlowFixMe[cannot-write]
|
|
116
|
+
const value = nextArgs[def.name] ?? def.defaultValue;
|
|
117
|
+
nextVariables[def.name] = value;
|
|
118
|
+
});
|
|
119
|
+
return nextVariables;
|
|
120
|
+
}
|
|
121
|
+
|
|
98
122
|
module.exports = {
|
|
123
|
+
getLocalVariables,
|
|
99
124
|
getFragmentVariables,
|
|
100
125
|
getOperationVariables,
|
|
101
126
|
};
|
|
@@ -23,23 +23,23 @@ const RelayRecordSource = require('./RelayRecordSource');
|
|
|
23
23
|
|
|
24
24
|
const defaultGetDataID = require('./defaultGetDataID');
|
|
25
25
|
const defaultRequiredFieldLogger = require('./defaultRequiredFieldLogger');
|
|
26
|
-
const generateID = require('../util/generateID');
|
|
27
26
|
const invariant = require('invariant');
|
|
27
|
+
const registerEnvironmentWithDevTools = require('../util/registerEnvironmentWithDevTools');
|
|
28
|
+
const wrapNetworkWithLogObserver = require('../network/wrapNetworkWithLogObserver');
|
|
29
|
+
|
|
30
|
+
const {
|
|
31
|
+
INTERNAL_ACTOR_IDENTIFIER_DO_NOT_USE,
|
|
32
|
+
assertInternalActorIndentifier,
|
|
33
|
+
} = require('../multi-actor-environment/ActorIdentifier');
|
|
28
34
|
|
|
29
35
|
import type {HandlerProvider} from '../handlers/RelayDefaultHandlerProvider';
|
|
36
|
+
import type {ActorIdentifier} from '../multi-actor-environment/ActorIdentifier';
|
|
30
37
|
import type {
|
|
31
38
|
GraphQLResponse,
|
|
32
39
|
INetwork,
|
|
33
40
|
PayloadData,
|
|
34
|
-
UploadableMap,
|
|
35
41
|
} from '../network/RelayNetworkTypes';
|
|
36
|
-
import type {
|
|
37
|
-
import type {
|
|
38
|
-
CacheConfig,
|
|
39
|
-
Disposable,
|
|
40
|
-
RenderPolicy,
|
|
41
|
-
Variables,
|
|
42
|
-
} from '../util/RelayRuntimeTypes';
|
|
42
|
+
import type {Disposable, RenderPolicy} from '../util/RelayRuntimeTypes';
|
|
43
43
|
import type {ActiveState, TaskScheduler} from './OperationExecutor';
|
|
44
44
|
import type {GetDataID} from './RelayResponseNormalizer';
|
|
45
45
|
import type {
|
|
@@ -143,7 +143,7 @@ class RelayModernEnvironment implements IEnvironment {
|
|
|
143
143
|
: 'full';
|
|
144
144
|
this._operationLoader = operationLoader;
|
|
145
145
|
this._operationExecutions = new Map();
|
|
146
|
-
this._network = this
|
|
146
|
+
this._network = wrapNetworkWithLogObserver(this, config.network);
|
|
147
147
|
this._getDataID = config.getDataID ?? defaultGetDataID;
|
|
148
148
|
this._publishQueue = new RelayPublishQueue(
|
|
149
149
|
config.store,
|
|
@@ -156,31 +156,23 @@ class RelayModernEnvironment implements IEnvironment {
|
|
|
156
156
|
this._isServer = config.isServer ?? false;
|
|
157
157
|
|
|
158
158
|
(this: any).__setNet = newNet =>
|
|
159
|
-
(this._network = this
|
|
159
|
+
(this._network = wrapNetworkWithLogObserver(this, newNet));
|
|
160
160
|
|
|
161
161
|
if (__DEV__) {
|
|
162
162
|
const {inspect} = require('./StoreInspector');
|
|
163
163
|
(this: any).DEBUG_inspect = (dataID: ?string) => inspect(this, dataID);
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
-
// Register this Relay Environment with Relay DevTools if it exists.
|
|
167
|
-
// Note: this must always be the last step in the constructor.
|
|
168
|
-
const _global =
|
|
169
|
-
typeof global !== 'undefined'
|
|
170
|
-
? global
|
|
171
|
-
: typeof window !== 'undefined'
|
|
172
|
-
? window
|
|
173
|
-
: undefined;
|
|
174
|
-
const devToolsHook = _global && _global.__RELAY_DEVTOOLS_HOOK__;
|
|
175
|
-
if (devToolsHook) {
|
|
176
|
-
devToolsHook.registerEnvironment(this);
|
|
177
|
-
}
|
|
178
166
|
this._missingFieldHandlers = config.missingFieldHandlers;
|
|
179
167
|
this._operationTracker =
|
|
180
168
|
config.operationTracker ?? new RelayOperationTracker();
|
|
181
169
|
this._reactFlightPayloadDeserializer = reactFlightPayloadDeserializer;
|
|
182
170
|
this._reactFlightServerErrorHandler = reactFlightServerErrorHandler;
|
|
183
171
|
this._shouldProcessClientComponents = config.shouldProcessClientComponents;
|
|
172
|
+
|
|
173
|
+
// Register this Relay Environment with Relay DevTools if it exists.
|
|
174
|
+
// Note: this must always be the last step in the constructor.
|
|
175
|
+
registerEnvironmentWithDevTools(this);
|
|
184
176
|
}
|
|
185
177
|
|
|
186
178
|
getStore(): Store {
|
|
@@ -303,7 +295,19 @@ class RelayModernEnvironment implements IEnvironment {
|
|
|
303
295
|
handlers: $ReadOnlyArray<MissingFieldHandler>,
|
|
304
296
|
): OperationAvailability {
|
|
305
297
|
const target = RelayRecordSource.create();
|
|
306
|
-
const
|
|
298
|
+
const source = this._store.getSource();
|
|
299
|
+
const result = this._store.check(operation, {
|
|
300
|
+
handlers,
|
|
301
|
+
defaultActorIdentifier: INTERNAL_ACTOR_IDENTIFIER_DO_NOT_USE,
|
|
302
|
+
getSourceForActor(actorIdentifier: ActorIdentifier) {
|
|
303
|
+
assertInternalActorIndentifier(actorIdentifier);
|
|
304
|
+
return source;
|
|
305
|
+
},
|
|
306
|
+
getTargetForActor(actorIdentifier: ActorIdentifier) {
|
|
307
|
+
assertInternalActorIndentifier(actorIdentifier);
|
|
308
|
+
return target;
|
|
309
|
+
},
|
|
310
|
+
});
|
|
307
311
|
if (target.size() > 0) {
|
|
308
312
|
this._scheduleUpdates(() => {
|
|
309
313
|
this._publishQueue.commitSource(target);
|
|
@@ -398,7 +402,7 @@ class RelayModernEnvironment implements IEnvironment {
|
|
|
398
402
|
/**
|
|
399
403
|
* Returns an Observable of GraphQLResponse resulting from executing the
|
|
400
404
|
* provided Query or Subscription operation responses, the result of which is
|
|
401
|
-
* then normalized and
|
|
405
|
+
* then normalized and committed to the publish queue.
|
|
402
406
|
*
|
|
403
407
|
* Note: Observables are lazy, so calling this method will do nothing until
|
|
404
408
|
* the result is subscribed to:
|
|
@@ -437,16 +441,23 @@ class RelayModernEnvironment implements IEnvironment {
|
|
|
437
441
|
optimisticConfig: ?OptimisticResponseConfig,
|
|
438
442
|
updater: ?SelectorStoreUpdater,
|
|
439
443
|
|}): RelayObservable<GraphQLResponse> {
|
|
444
|
+
const publishQueue = this._publishQueue;
|
|
445
|
+
const store = this._store;
|
|
440
446
|
return RelayObservable.create(sink => {
|
|
441
447
|
const executor = OperationExecutor.execute({
|
|
448
|
+
actorIdentifier: INTERNAL_ACTOR_IDENTIFIER_DO_NOT_USE,
|
|
442
449
|
getDataID: this._getDataID,
|
|
443
450
|
isClientPayload,
|
|
451
|
+
log: this.__log,
|
|
444
452
|
operation,
|
|
445
453
|
operationExecutions: this._operationExecutions,
|
|
446
454
|
operationLoader: this._operationLoader,
|
|
447
455
|
operationTracker: this._operationTracker,
|
|
448
456
|
optimisticConfig,
|
|
449
|
-
|
|
457
|
+
getPublishQueue(actorIdentifier: ActorIdentifier) {
|
|
458
|
+
assertInternalActorIndentifier(actorIdentifier);
|
|
459
|
+
return publishQueue;
|
|
460
|
+
},
|
|
450
461
|
reactFlightPayloadDeserializer: this._reactFlightPayloadDeserializer,
|
|
451
462
|
reactFlightServerErrorHandler: this._reactFlightServerErrorHandler,
|
|
452
463
|
scheduler: this._scheduler,
|
|
@@ -455,80 +466,16 @@ class RelayModernEnvironment implements IEnvironment {
|
|
|
455
466
|
// NOTE: Some product tests expect `Network.execute` to be called only
|
|
456
467
|
// when the Observable is executed.
|
|
457
468
|
source: createSource(),
|
|
458
|
-
|
|
469
|
+
getStore(actorIdentifier: ActorIdentifier) {
|
|
470
|
+
assertInternalActorIndentifier(actorIdentifier);
|
|
471
|
+
return store;
|
|
472
|
+
},
|
|
459
473
|
treatMissingFieldsAsNull: this._treatMissingFieldsAsNull,
|
|
460
474
|
updater,
|
|
461
475
|
});
|
|
462
476
|
return () => executor.cancel();
|
|
463
477
|
});
|
|
464
478
|
}
|
|
465
|
-
|
|
466
|
-
/**
|
|
467
|
-
* Wraps the network with logging to ensure that network requests are
|
|
468
|
-
* always logged. Relying on each network callsite to be wrapped is
|
|
469
|
-
* untenable and will eventually lead to holes in the logging.
|
|
470
|
-
*/
|
|
471
|
-
__wrapNetworkWithLogObserver(network: INetwork): INetwork {
|
|
472
|
-
const that = this;
|
|
473
|
-
return {
|
|
474
|
-
execute(
|
|
475
|
-
params: RequestParameters,
|
|
476
|
-
variables: Variables,
|
|
477
|
-
cacheConfig: CacheConfig,
|
|
478
|
-
uploadables?: ?UploadableMap,
|
|
479
|
-
): RelayObservable<GraphQLResponse> {
|
|
480
|
-
const transactionID = generateID();
|
|
481
|
-
const log = that.__log;
|
|
482
|
-
const logObserver = {
|
|
483
|
-
start: subscription => {
|
|
484
|
-
log({
|
|
485
|
-
name: 'network.start',
|
|
486
|
-
transactionID,
|
|
487
|
-
params,
|
|
488
|
-
variables,
|
|
489
|
-
cacheConfig,
|
|
490
|
-
});
|
|
491
|
-
},
|
|
492
|
-
next: response => {
|
|
493
|
-
log({
|
|
494
|
-
name: 'network.next',
|
|
495
|
-
transactionID,
|
|
496
|
-
response,
|
|
497
|
-
});
|
|
498
|
-
},
|
|
499
|
-
error: error => {
|
|
500
|
-
log({
|
|
501
|
-
name: 'network.error',
|
|
502
|
-
transactionID,
|
|
503
|
-
error,
|
|
504
|
-
});
|
|
505
|
-
},
|
|
506
|
-
complete: () => {
|
|
507
|
-
log({
|
|
508
|
-
name: 'network.complete',
|
|
509
|
-
transactionID,
|
|
510
|
-
});
|
|
511
|
-
},
|
|
512
|
-
unsubscribe: () => {
|
|
513
|
-
log({
|
|
514
|
-
name: 'network.unsubscribe',
|
|
515
|
-
transactionID,
|
|
516
|
-
});
|
|
517
|
-
},
|
|
518
|
-
};
|
|
519
|
-
const logRequestInfo = info => {
|
|
520
|
-
log({
|
|
521
|
-
name: 'network.info',
|
|
522
|
-
transactionID,
|
|
523
|
-
info,
|
|
524
|
-
});
|
|
525
|
-
};
|
|
526
|
-
return network
|
|
527
|
-
.execute(params, variables, cacheConfig, uploadables, logRequestInfo)
|
|
528
|
-
.do(logObserver);
|
|
529
|
-
},
|
|
530
|
-
};
|
|
531
|
-
}
|
|
532
479
|
}
|
|
533
480
|
|
|
534
481
|
// Add a sigil for detection by `isRelayModernEnvironment()` to avoid a
|
|
@@ -15,12 +15,13 @@
|
|
|
15
15
|
const RelayFeatureFlags = require('../util/RelayFeatureFlags');
|
|
16
16
|
|
|
17
17
|
const areEqual = require('areEqual');
|
|
18
|
+
const getPendingOperationsForFragment = require('../util/getPendingOperationsForFragment');
|
|
18
19
|
const invariant = require('invariant');
|
|
19
20
|
const isScalarAndEqual = require('../util/isScalarAndEqual');
|
|
21
|
+
const recycleNodesInto = require('../util/recycleNodesInto');
|
|
20
22
|
const reportMissingRequiredFields = require('../util/reportMissingRequiredFields');
|
|
21
23
|
const warning = require('warning');
|
|
22
24
|
|
|
23
|
-
const {getPromiseForActiveRequest} = require('../query/fetchQueryInternal');
|
|
24
25
|
const {createRequestDescriptor} = require('./RelayModernOperationDescriptor');
|
|
25
26
|
const {
|
|
26
27
|
areEqualSelectors,
|
|
@@ -137,13 +138,16 @@ class RelayModernFragmentSpecResolver implements FragmentSpecResolver {
|
|
|
137
138
|
return this._data;
|
|
138
139
|
}
|
|
139
140
|
|
|
140
|
-
setCallback(callback: () => void): void {
|
|
141
|
+
setCallback(props: Props, callback: () => void): void {
|
|
141
142
|
this._callback = callback;
|
|
143
|
+
if (RelayFeatureFlags.ENABLE_CONTAINERS_SUBSCRIBE_ON_COMMIT === true) {
|
|
144
|
+
this.setProps(props);
|
|
145
|
+
}
|
|
142
146
|
}
|
|
143
147
|
|
|
144
148
|
setProps(props: Props): void {
|
|
145
|
-
const ownedSelectors = getSelectorsFromObject(this._fragments, props);
|
|
146
149
|
this._props = {};
|
|
150
|
+
const ownedSelectors = getSelectorsFromObject(this._fragments, props);
|
|
147
151
|
|
|
148
152
|
for (const key in ownedSelectors) {
|
|
149
153
|
if (ownedSelectors.hasOwnProperty(key)) {
|
|
@@ -160,6 +164,7 @@ class RelayModernFragmentSpecResolver implements FragmentSpecResolver {
|
|
|
160
164
|
this._context.environment,
|
|
161
165
|
this._rootIsQueryRenderer,
|
|
162
166
|
ownedSelector,
|
|
167
|
+
this._callback != null,
|
|
163
168
|
this._onChange,
|
|
164
169
|
);
|
|
165
170
|
} else {
|
|
@@ -176,6 +181,7 @@ class RelayModernFragmentSpecResolver implements FragmentSpecResolver {
|
|
|
176
181
|
this._context.environment,
|
|
177
182
|
this._rootIsQueryRenderer,
|
|
178
183
|
ownedSelector,
|
|
184
|
+
this._callback != null,
|
|
179
185
|
this._onChange,
|
|
180
186
|
);
|
|
181
187
|
} else {
|
|
@@ -232,6 +238,7 @@ class SelectorResolver {
|
|
|
232
238
|
environment: IEnvironment,
|
|
233
239
|
rootIsQueryRenderer: boolean,
|
|
234
240
|
selector: SingularReaderSelector,
|
|
241
|
+
subscribeOnConstruction: boolean,
|
|
235
242
|
callback: () => void,
|
|
236
243
|
) {
|
|
237
244
|
const snapshot = environment.lookup(selector);
|
|
@@ -242,7 +249,13 @@ class SelectorResolver {
|
|
|
242
249
|
this._environment = environment;
|
|
243
250
|
this._rootIsQueryRenderer = rootIsQueryRenderer;
|
|
244
251
|
this._selector = selector;
|
|
245
|
-
|
|
252
|
+
if (RelayFeatureFlags.ENABLE_CONTAINERS_SUBSCRIBE_ON_COMMIT === true) {
|
|
253
|
+
if (subscribeOnConstruction) {
|
|
254
|
+
this._subscription = environment.subscribe(snapshot, this._onChange);
|
|
255
|
+
}
|
|
256
|
+
} else {
|
|
257
|
+
this._subscription = environment.subscribe(snapshot, this._onChange);
|
|
258
|
+
}
|
|
246
259
|
}
|
|
247
260
|
|
|
248
261
|
dispose(): void {
|
|
@@ -253,10 +266,7 @@ class SelectorResolver {
|
|
|
253
266
|
}
|
|
254
267
|
|
|
255
268
|
resolve(): ?Object {
|
|
256
|
-
if (
|
|
257
|
-
RelayFeatureFlags.ENABLE_RELAY_CONTAINERS_SUSPENSE === true &&
|
|
258
|
-
this._isMissingData === true
|
|
259
|
-
) {
|
|
269
|
+
if (this._isMissingData === true) {
|
|
260
270
|
// NOTE: This branch exists to handle the case in which:
|
|
261
271
|
// - A RelayModern container is rendered as a descendant of a Relay Hook
|
|
262
272
|
// root using a "partial" renderPolicy (this means that eargerly
|
|
@@ -278,11 +288,12 @@ class SelectorResolver {
|
|
|
278
288
|
// This should eventually go away with something like @optional, where we only
|
|
279
289
|
// suspend at specific boundaries depending on whether the boundary
|
|
280
290
|
// can be fulfilled or not.
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
this.
|
|
284
|
-
|
|
285
|
-
|
|
291
|
+
const pendingOperationsResult = getPendingOperationsForFragment(
|
|
292
|
+
this._environment,
|
|
293
|
+
this._selector.node,
|
|
294
|
+
this._selector.owner,
|
|
295
|
+
);
|
|
296
|
+
const promise: void | Promise<void> = pendingOperationsResult?.promise;
|
|
286
297
|
if (promise != null) {
|
|
287
298
|
if (this._rootIsQueryRenderer) {
|
|
288
299
|
warning(
|
|
@@ -293,6 +304,8 @@ class SelectorResolver {
|
|
|
293
304
|
this._selector.node.name,
|
|
294
305
|
);
|
|
295
306
|
} else {
|
|
307
|
+
const pendingOperations =
|
|
308
|
+
pendingOperationsResult?.pendingOperations ?? [];
|
|
296
309
|
warning(
|
|
297
310
|
false,
|
|
298
311
|
'Relay: Relay Container for fragment `%s` suspended. When using ' +
|
|
@@ -300,6 +313,15 @@ class SelectorResolver {
|
|
|
300
313
|
'of a Relay Container.',
|
|
301
314
|
this._selector.node.name,
|
|
302
315
|
);
|
|
316
|
+
this._environment.__log({
|
|
317
|
+
name: 'suspense.fragment',
|
|
318
|
+
data: this._data,
|
|
319
|
+
fragment: this._selector.node,
|
|
320
|
+
isRelayHooks: false,
|
|
321
|
+
isMissingData: this._isMissingData,
|
|
322
|
+
isPromiseCached: false,
|
|
323
|
+
pendingOperations,
|
|
324
|
+
});
|
|
303
325
|
throw promise;
|
|
304
326
|
}
|
|
305
327
|
}
|
|
@@ -322,7 +344,7 @@ class SelectorResolver {
|
|
|
322
344
|
}
|
|
323
345
|
this.dispose();
|
|
324
346
|
const snapshot = this._environment.lookup(selector);
|
|
325
|
-
this._data = snapshot.data;
|
|
347
|
+
this._data = recycleNodesInto(this._data, snapshot.data);
|
|
326
348
|
this._isMissingData = snapshot.isMissingData;
|
|
327
349
|
this._missingRequiredFields = snapshot.missingRequiredFields;
|
|
328
350
|
this._selector = selector;
|
|
@@ -375,11 +397,13 @@ class SelectorListResolver {
|
|
|
375
397
|
_resolvers: Array<SelectorResolver>;
|
|
376
398
|
_rootIsQueryRenderer: boolean;
|
|
377
399
|
_stale: boolean;
|
|
400
|
+
_subscribeOnConstruction: boolean;
|
|
378
401
|
|
|
379
402
|
constructor(
|
|
380
403
|
environment: IEnvironment,
|
|
381
404
|
rootIsQueryRenderer: boolean,
|
|
382
405
|
selector: PluralReaderSelector,
|
|
406
|
+
subscribeOnConstruction: boolean,
|
|
383
407
|
callback: () => void,
|
|
384
408
|
) {
|
|
385
409
|
this._callback = callback;
|
|
@@ -388,6 +412,7 @@ class SelectorListResolver {
|
|
|
388
412
|
this._resolvers = [];
|
|
389
413
|
this._stale = true;
|
|
390
414
|
this._rootIsQueryRenderer = rootIsQueryRenderer;
|
|
415
|
+
this._subscribeOnConstruction = subscribeOnConstruction;
|
|
391
416
|
|
|
392
417
|
this.setSelector(selector);
|
|
393
418
|
}
|
|
@@ -433,6 +458,7 @@ class SelectorListResolver {
|
|
|
433
458
|
this._environment,
|
|
434
459
|
this._rootIsQueryRenderer,
|
|
435
460
|
selectors[ii],
|
|
461
|
+
this._subscribeOnConstruction,
|
|
436
462
|
this._onChange,
|
|
437
463
|
);
|
|
438
464
|
}
|
|
@@ -23,7 +23,13 @@ const {
|
|
|
23
23
|
const {ROOT_ID} = require('./RelayStoreUtils');
|
|
24
24
|
|
|
25
25
|
import type {ConcreteRequest} from '../util/RelayConcreteNode';
|
|
26
|
-
import type {
|
|
26
|
+
import type {
|
|
27
|
+
CacheConfig,
|
|
28
|
+
DataID,
|
|
29
|
+
Variables,
|
|
30
|
+
VariablesOf,
|
|
31
|
+
OperationType,
|
|
32
|
+
} from '../util/RelayRuntimeTypes';
|
|
27
33
|
import type {OperationDescriptor, RequestDescriptor} from './RelayStoreTypes';
|
|
28
34
|
|
|
29
35
|
/**
|
|
@@ -32,9 +38,9 @@ import type {OperationDescriptor, RequestDescriptor} from './RelayStoreTypes';
|
|
|
32
38
|
* are filtered to exclude variables that do not match defined arguments on the
|
|
33
39
|
* operation, and default values are populated for null values.
|
|
34
40
|
*/
|
|
35
|
-
function createOperationDescriptor(
|
|
41
|
+
function createOperationDescriptor<TQuery: OperationType>(
|
|
36
42
|
request: ConcreteRequest,
|
|
37
|
-
variables:
|
|
43
|
+
variables: VariablesOf<TQuery>,
|
|
38
44
|
cacheConfig?: ?CacheConfig,
|
|
39
45
|
dataID?: DataID = ROOT_ID,
|
|
40
46
|
): OperationDescriptor {
|
|
@@ -19,6 +19,7 @@ const warning = require('warning');
|
|
|
19
19
|
|
|
20
20
|
const {isClientID} = require('./ClientID');
|
|
21
21
|
const {
|
|
22
|
+
ACTOR_IDENTIFIER_KEY,
|
|
22
23
|
ID_KEY,
|
|
23
24
|
REF_KEY,
|
|
24
25
|
REFS_KEY,
|
|
@@ -27,6 +28,7 @@ const {
|
|
|
27
28
|
ROOT_ID,
|
|
28
29
|
} = require('./RelayStoreUtils');
|
|
29
30
|
|
|
31
|
+
import type {ActorIdentifier} from '../multi-actor-environment/ActorIdentifier';
|
|
30
32
|
import type {DataID} from '../util/RelayRuntimeTypes';
|
|
31
33
|
import type {Record} from './RelayStoreTypes';
|
|
32
34
|
|
|
@@ -384,6 +386,51 @@ function setLinkedRecordIDs(
|
|
|
384
386
|
record[storageKey] = links;
|
|
385
387
|
}
|
|
386
388
|
|
|
389
|
+
/**
|
|
390
|
+
* @public
|
|
391
|
+
*
|
|
392
|
+
* Set the value of a field to a reference to another record in the actor specific store.
|
|
393
|
+
*/
|
|
394
|
+
function setActorLinkedRecordID(
|
|
395
|
+
record: Record,
|
|
396
|
+
storageKey: string,
|
|
397
|
+
actorIdentifier: ActorIdentifier,
|
|
398
|
+
linkedID: DataID,
|
|
399
|
+
): void {
|
|
400
|
+
// See perf note above for why we aren't using computed property access.
|
|
401
|
+
const link = {};
|
|
402
|
+
link[REF_KEY] = linkedID;
|
|
403
|
+
link[ACTOR_IDENTIFIER_KEY] = actorIdentifier;
|
|
404
|
+
record[storageKey] = link;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* @public
|
|
409
|
+
*
|
|
410
|
+
* Get link to a record and the actor identifier for the store.
|
|
411
|
+
*/
|
|
412
|
+
function getActorLinkedRecordID(
|
|
413
|
+
record: Record,
|
|
414
|
+
storageKey: string,
|
|
415
|
+
): ?[ActorIdentifier, DataID] {
|
|
416
|
+
const link = record[storageKey];
|
|
417
|
+
if (link == null) {
|
|
418
|
+
return link;
|
|
419
|
+
}
|
|
420
|
+
invariant(
|
|
421
|
+
typeof link === 'object' &&
|
|
422
|
+
typeof link[REF_KEY] === 'string' &&
|
|
423
|
+
link[ACTOR_IDENTIFIER_KEY] != null,
|
|
424
|
+
'RelayModernRecord.getActorLinkedRecordID(): Expected `%s.%s` to be an actor specific linked ID, ' +
|
|
425
|
+
'was `%s`.',
|
|
426
|
+
record[ID_KEY],
|
|
427
|
+
storageKey,
|
|
428
|
+
JSON.stringify(link),
|
|
429
|
+
);
|
|
430
|
+
|
|
431
|
+
return [(link[ACTOR_IDENTIFIER_KEY]: any), (link[REF_KEY]: any)];
|
|
432
|
+
}
|
|
433
|
+
|
|
387
434
|
module.exports = {
|
|
388
435
|
clone,
|
|
389
436
|
copyFields,
|
|
@@ -400,4 +447,6 @@ module.exports = {
|
|
|
400
447
|
setLinkedRecordID,
|
|
401
448
|
setLinkedRecordIDs,
|
|
402
449
|
update,
|
|
450
|
+
getActorLinkedRecordID,
|
|
451
|
+
setActorLinkedRecordID,
|
|
403
452
|
};
|
|
@@ -20,7 +20,6 @@ const RelayReader = require('./RelayReader');
|
|
|
20
20
|
const RelayReferenceMarker = require('./RelayReferenceMarker');
|
|
21
21
|
const RelayStoreReactFlightUtils = require('./RelayStoreReactFlightUtils');
|
|
22
22
|
const RelayStoreSubscriptions = require('./RelayStoreSubscriptions');
|
|
23
|
-
const RelayStoreSubscriptionsUsingMapByID = require('./RelayStoreSubscriptionsUsingMapByID');
|
|
24
23
|
const RelayStoreUtils = require('./RelayStoreUtils');
|
|
25
24
|
|
|
26
25
|
const deepFreeze = require('../util/deepFreeze');
|
|
@@ -28,8 +27,14 @@ const defaultGetDataID = require('./defaultGetDataID');
|
|
|
28
27
|
const invariant = require('invariant');
|
|
29
28
|
const resolveImmediate = require('../util/resolveImmediate');
|
|
30
29
|
|
|
30
|
+
const {
|
|
31
|
+
INTERNAL_ACTOR_IDENTIFIER_DO_NOT_USE,
|
|
32
|
+
assertInternalActorIndentifier,
|
|
33
|
+
} = require('../multi-actor-environment/ActorIdentifier');
|
|
31
34
|
const {ROOT_ID, ROOT_TYPE} = require('./RelayStoreUtils');
|
|
35
|
+
const {RecordResolverCache} = require('./ResolverCache');
|
|
32
36
|
|
|
37
|
+
import type {ActorIdentifier} from '../multi-actor-environment/ActorIdentifier';
|
|
33
38
|
import type {DataID, Disposable} from '../util/RelayRuntimeTypes';
|
|
34
39
|
import type {Availability} from './DataChecker';
|
|
35
40
|
import type {GetDataID} from './RelayResponseNormalizer';
|
|
@@ -49,6 +54,7 @@ import type {
|
|
|
49
54
|
StoreSubscriptions,
|
|
50
55
|
DataIDSet,
|
|
51
56
|
} from './RelayStoreTypes';
|
|
57
|
+
import type {ResolverCache} from './ResolverCache';
|
|
52
58
|
|
|
53
59
|
export opaque type InvalidationState = {|
|
|
54
60
|
dataIDs: $ReadOnlyArray<DataID>,
|
|
@@ -89,6 +95,7 @@ class RelayModernStore implements Store {
|
|
|
89
95
|
_operationLoader: ?OperationLoader;
|
|
90
96
|
_optimisticSource: ?MutableRecordSource;
|
|
91
97
|
_recordSource: MutableRecordSource;
|
|
98
|
+
_resolverCache: ResolverCache;
|
|
92
99
|
_releaseBuffer: Array<string>;
|
|
93
100
|
_roots: Map<
|
|
94
101
|
string,
|
|
@@ -144,10 +151,13 @@ class RelayModernStore implements Store {
|
|
|
144
151
|
this._releaseBuffer = [];
|
|
145
152
|
this._roots = new Map();
|
|
146
153
|
this._shouldScheduleGC = false;
|
|
147
|
-
this.
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
154
|
+
this._resolverCache = new RecordResolverCache(() =>
|
|
155
|
+
this._getMutableRecordSource(),
|
|
156
|
+
);
|
|
157
|
+
this._storeSubscriptions = new RelayStoreSubscriptions(
|
|
158
|
+
options?.log,
|
|
159
|
+
this._resolverCache,
|
|
160
|
+
);
|
|
151
161
|
this._updatedRecordIDs = new Set();
|
|
152
162
|
this._shouldProcessClientComponents =
|
|
153
163
|
options?.shouldProcessClientComponents;
|
|
@@ -159,12 +169,16 @@ class RelayModernStore implements Store {
|
|
|
159
169
|
return this._optimisticSource ?? this._recordSource;
|
|
160
170
|
}
|
|
161
171
|
|
|
172
|
+
_getMutableRecordSource(): MutableRecordSource {
|
|
173
|
+
return this._optimisticSource ?? this._recordSource;
|
|
174
|
+
}
|
|
175
|
+
|
|
162
176
|
check(
|
|
163
177
|
operation: OperationDescriptor,
|
|
164
178
|
options?: CheckOptions,
|
|
165
179
|
): OperationAvailability {
|
|
166
180
|
const selector = operation.root;
|
|
167
|
-
const source = this.
|
|
181
|
+
const source = this._getMutableRecordSource();
|
|
168
182
|
const globalInvalidationEpoch = this._globalInvalidationEpoch;
|
|
169
183
|
|
|
170
184
|
const rootEntry = this._roots.get(operation.request.identifier);
|
|
@@ -173,7 +187,7 @@ class RelayModernStore implements Store {
|
|
|
173
187
|
// Check if store has been globally invalidated
|
|
174
188
|
if (globalInvalidationEpoch != null) {
|
|
175
189
|
// If so, check if the operation we're checking was last written
|
|
176
|
-
// before or after invalidation
|
|
190
|
+
// before or after invalidation occurred.
|
|
177
191
|
if (
|
|
178
192
|
operationLastWrittenAt == null ||
|
|
179
193
|
operationLastWrittenAt <= globalInvalidationEpoch
|
|
@@ -186,11 +200,24 @@ class RelayModernStore implements Store {
|
|
|
186
200
|
}
|
|
187
201
|
}
|
|
188
202
|
|
|
189
|
-
const target = options?.target ?? source;
|
|
190
203
|
const handlers = options?.handlers ?? [];
|
|
204
|
+
const getSourceForActor =
|
|
205
|
+
options?.getSourceForActor ??
|
|
206
|
+
(actorIdentifier => {
|
|
207
|
+
assertInternalActorIndentifier(actorIdentifier);
|
|
208
|
+
return source;
|
|
209
|
+
});
|
|
210
|
+
const getTargetForActor =
|
|
211
|
+
options?.getTargetForActor ??
|
|
212
|
+
(actorIdentifier => {
|
|
213
|
+
assertInternalActorIndentifier(actorIdentifier);
|
|
214
|
+
return source;
|
|
215
|
+
});
|
|
216
|
+
|
|
191
217
|
const operationAvailability = DataChecker.check(
|
|
192
|
-
|
|
193
|
-
|
|
218
|
+
getSourceForActor,
|
|
219
|
+
getTargetForActor,
|
|
220
|
+
options?.defaultActorIdentifier ?? INTERNAL_ACTOR_IDENTIFIER_DO_NOT_USE,
|
|
194
221
|
selector,
|
|
195
222
|
handlers,
|
|
196
223
|
this._operationLoader,
|
|
@@ -274,7 +301,7 @@ class RelayModernStore implements Store {
|
|
|
274
301
|
|
|
275
302
|
lookup(selector: SingularReaderSelector): Snapshot {
|
|
276
303
|
const source = this.getSource();
|
|
277
|
-
const snapshot = RelayReader.read(source, selector);
|
|
304
|
+
const snapshot = RelayReader.read(source, selector, this._resolverCache);
|
|
278
305
|
if (__DEV__) {
|
|
279
306
|
deepFreeze(snapshot);
|
|
280
307
|
}
|
|
@@ -302,6 +329,13 @@ class RelayModernStore implements Store {
|
|
|
302
329
|
this._globalInvalidationEpoch = this._currentWriteEpoch;
|
|
303
330
|
}
|
|
304
331
|
|
|
332
|
+
if (RelayFeatureFlags.ENABLE_RELAY_RESOLVERS) {
|
|
333
|
+
// When a record is updated, we need to also handle records that depend on it,
|
|
334
|
+
// specifically Relay Resolver result records containing results based on the
|
|
335
|
+
// updated records. This both adds to updatedRecordIDs and invalidates any
|
|
336
|
+
// cached data as needed.
|
|
337
|
+
this._resolverCache.invalidateDataIDs(this._updatedRecordIDs);
|
|
338
|
+
}
|
|
305
339
|
const source = this.getSource();
|
|
306
340
|
const updatedOwners = [];
|
|
307
341
|
this._storeSubscriptions.updateSubscriptions(
|
|
@@ -364,7 +398,7 @@ class RelayModernStore implements Store {
|
|
|
364
398
|
}
|
|
365
399
|
|
|
366
400
|
publish(source: RecordSource, idsMarkedForInvalidation?: DataIDSet): void {
|
|
367
|
-
const target = this.
|
|
401
|
+
const target = this._getMutableRecordSource();
|
|
368
402
|
updateTargetFromSource(
|
|
369
403
|
target,
|
|
370
404
|
source,
|
|
@@ -417,6 +451,10 @@ class RelayModernStore implements Store {
|
|
|
417
451
|
return 'RelayModernStore()';
|
|
418
452
|
}
|
|
419
453
|
|
|
454
|
+
getEpoch(): number {
|
|
455
|
+
return this._currentWriteEpoch;
|
|
456
|
+
}
|
|
457
|
+
|
|
420
458
|
// Internal API
|
|
421
459
|
__getUpdatedRecordIDs(): DataIDSet {
|
|
422
460
|
return this._updatedRecordIDs;
|