relay-runtime 11.0.0-rc.0 → 12.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/handlers/connection/ConnectionHandler.js.flow +7 -0
- package/handlers/connection/MutationHandlers.js.flow +28 -0
- package/index.js +1 -1
- package/index.js.flow +20 -3
- package/lib/handlers/RelayDefaultHandlerProvider.js +1 -1
- package/lib/handlers/connection/ConnectionHandler.js +12 -6
- package/lib/handlers/connection/MutationHandlers.js +67 -8
- package/lib/index.js +15 -0
- package/lib/multi-actor-environment/ActorIdentifier.js +33 -0
- package/lib/multi-actor-environment/ActorSpecificEnvironment.js +148 -0
- package/lib/multi-actor-environment/ActorUtils.js +27 -0
- package/lib/multi-actor-environment/MultiActorEnvironment.js +406 -0
- package/lib/multi-actor-environment/MultiActorEnvironmentTypes.js +11 -0
- package/lib/multi-actor-environment/index.js +21 -0
- package/lib/mutations/RelayRecordProxy.js +1 -1
- package/lib/mutations/RelayRecordSourceMutator.js +1 -1
- package/lib/mutations/RelayRecordSourceProxy.js +1 -1
- package/lib/mutations/RelayRecordSourceSelectorProxy.js +7 -2
- package/lib/mutations/applyOptimisticMutation.js +1 -1
- package/lib/mutations/commitMutation.js +5 -2
- package/lib/mutations/validateMutation.js +39 -17
- package/lib/network/RelayNetwork.js +1 -1
- package/lib/network/RelayObservable.js +3 -1
- package/lib/network/RelayQueryResponseCache.js +20 -3
- package/lib/network/wrapNetworkWithLogObserver.js +78 -0
- package/lib/query/GraphQLTag.js +1 -1
- package/lib/query/fetchQuery.js +1 -1
- package/lib/query/fetchQueryInternal.js +1 -1
- package/lib/store/DataChecker.js +132 -50
- package/lib/store/{RelayModernQueryExecutor.js → OperationExecutor.js} +524 -187
- package/lib/store/RelayConcreteVariables.js +29 -4
- package/lib/store/RelayModernEnvironment.js +137 -220
- package/lib/store/RelayModernFragmentSpecResolver.js +49 -23
- package/lib/store/RelayModernRecord.js +36 -2
- package/lib/store/RelayModernSelector.js +1 -1
- package/lib/store/RelayModernStore.js +53 -22
- package/lib/store/RelayOperationTracker.js +34 -24
- package/lib/store/RelayPublishQueue.js +30 -8
- package/lib/store/RelayReader.js +177 -29
- package/lib/store/RelayRecordSource.js +87 -3
- package/lib/store/RelayReferenceMarker.js +53 -28
- package/lib/store/RelayResponseNormalizer.js +247 -108
- package/lib/store/RelayStoreReactFlightUtils.js +7 -11
- package/lib/store/RelayStoreSubscriptions.js +8 -5
- package/lib/store/RelayStoreUtils.js +10 -4
- package/lib/store/ResolverCache.js +213 -0
- package/lib/store/ResolverFragments.js +57 -0
- package/lib/store/cloneRelayHandleSourceField.js +1 -1
- package/lib/store/cloneRelayScalarHandleSourceField.js +1 -1
- package/lib/store/createRelayContext.js +2 -2
- package/lib/store/defaultGetDataID.js +3 -1
- package/lib/store/readInlineData.js +1 -1
- package/lib/subscription/requestSubscription.js +32 -6
- package/lib/util/RelayConcreteNode.js +3 -0
- package/lib/util/RelayFeatureFlags.js +5 -4
- package/lib/util/RelayProfiler.js +17 -187
- package/lib/util/RelayReplaySubject.js +22 -7
- package/lib/util/deepFreeze.js +1 -0
- package/lib/util/getPaginationMetadata.js +41 -0
- package/lib/util/getPaginationVariables.js +67 -0
- package/lib/util/getPendingOperationsForFragment.js +55 -0
- package/lib/util/getRefetchMetadata.js +36 -0
- package/lib/util/getRelayHandleKey.js +1 -1
- package/lib/util/getRequestIdentifier.js +1 -1
- package/lib/util/getValueAtPath.js +51 -0
- package/lib/util/isEmptyObject.js +1 -1
- package/lib/util/registerEnvironmentWithDevTools.js +26 -0
- package/lib/util/withDuration.js +31 -0
- package/multi-actor-environment/ActorIdentifier.js.flow +43 -0
- package/multi-actor-environment/ActorSpecificEnvironment.js.flow +217 -0
- package/multi-actor-environment/ActorUtils.js.flow +33 -0
- package/multi-actor-environment/MultiActorEnvironment.js.flow +485 -0
- package/multi-actor-environment/MultiActorEnvironmentTypes.js.flow +245 -0
- package/multi-actor-environment/index.js.flow +27 -0
- package/mutations/RelayRecordSourceSelectorProxy.js.flow +7 -2
- package/mutations/commitMutation.js.flow +3 -1
- package/mutations/validateMutation.js.flow +42 -16
- package/network/RelayNetworkTypes.js.flow +17 -8
- package/network/RelayObservable.js.flow +2 -0
- package/network/RelayQueryResponseCache.js.flow +31 -17
- package/network/wrapNetworkWithLogObserver.js.flow +99 -0
- package/package.json +3 -2
- package/relay-runtime.js +2 -2
- package/relay-runtime.min.js +2 -2
- package/store/ClientID.js.flow +5 -1
- package/store/DataChecker.js.flow +148 -44
- package/store/{RelayModernQueryExecutor.js.flow → OperationExecutor.js.flow} +578 -237
- package/store/RelayConcreteVariables.js.flow +31 -1
- package/store/RelayModernEnvironment.js.flow +132 -220
- package/store/RelayModernFragmentSpecResolver.js.flow +40 -14
- package/store/RelayModernOperationDescriptor.js.flow +9 -3
- package/store/RelayModernRecord.js.flow +49 -0
- package/store/RelayModernStore.js.flow +57 -17
- package/store/RelayOperationTracker.js.flow +56 -34
- package/store/RelayPublishQueue.js.flow +37 -11
- package/store/RelayReader.js.flow +186 -27
- package/store/RelayRecordSource.js.flow +72 -6
- package/store/RelayReferenceMarker.js.flow +51 -21
- package/store/RelayResponseNormalizer.js.flow +251 -67
- package/store/RelayStoreReactFlightUtils.js.flow +6 -9
- package/store/RelayStoreSubscriptions.js.flow +10 -3
- package/store/RelayStoreTypes.js.flow +144 -21
- package/store/RelayStoreUtils.js.flow +19 -4
- package/store/ResolverCache.js.flow +247 -0
- package/store/ResolverFragments.js.flow +128 -0
- package/store/createRelayContext.js.flow +1 -1
- package/store/defaultGetDataID.js.flow +3 -1
- package/subscription/requestSubscription.js.flow +43 -8
- package/util/NormalizationNode.js.flow +16 -3
- package/util/ReaderNode.js.flow +29 -2
- package/util/RelayConcreteNode.js.flow +3 -0
- package/util/RelayFeatureFlags.js.flow +10 -6
- package/util/RelayProfiler.js.flow +22 -194
- package/util/RelayReplaySubject.js.flow +7 -6
- package/util/RelayRuntimeTypes.js.flow +4 -2
- package/util/deepFreeze.js.flow +2 -1
- package/util/getPaginationMetadata.js.flow +74 -0
- package/util/getPaginationVariables.js.flow +112 -0
- package/util/getPendingOperationsForFragment.js.flow +62 -0
- package/util/getRefetchMetadata.js.flow +80 -0
- package/util/getValueAtPath.js.flow +46 -0
- package/util/isEmptyObject.js.flow +2 -1
- package/util/registerEnvironmentWithDevTools.js.flow +33 -0
- package/util/withDuration.js.flow +32 -0
- package/lib/store/RelayRecordSourceMapImpl.js +0 -107
- package/lib/store/RelayStoreSubscriptionsUsingMapByID.js +0 -318
- package/store/RelayRecordSourceMapImpl.js.flow +0 -91
- package/store/RelayStoreSubscriptionsUsingMapByID.js.flow +0 -283
|
@@ -12,6 +12,10 @@
|
|
|
12
12
|
|
|
13
13
|
'use strict';
|
|
14
14
|
|
|
15
|
+
import type {
|
|
16
|
+
ActorIdentifier,
|
|
17
|
+
IActorEnvironment,
|
|
18
|
+
} from '../multi-actor-environment';
|
|
15
19
|
import type {
|
|
16
20
|
GraphQLResponse,
|
|
17
21
|
INetwork,
|
|
@@ -27,6 +31,7 @@ import type {
|
|
|
27
31
|
NormalizationRootNode,
|
|
28
32
|
NormalizationScalarField,
|
|
29
33
|
NormalizationSelectableNode,
|
|
34
|
+
NormalizationArgument,
|
|
30
35
|
} from '../util/NormalizationNode';
|
|
31
36
|
import type {ReaderFragment} from '../util/ReaderNode';
|
|
32
37
|
import type {
|
|
@@ -144,6 +149,9 @@ export type Props = {[key: string]: mixed, ...};
|
|
|
144
149
|
*/
|
|
145
150
|
export type RelayContext = {|
|
|
146
151
|
environment: IEnvironment,
|
|
152
|
+
getEnvironmentForActor?: ?(
|
|
153
|
+
actorIdentifier: ActorIdentifier,
|
|
154
|
+
) => IActorEnvironment,
|
|
147
155
|
|};
|
|
148
156
|
|
|
149
157
|
/**
|
|
@@ -190,7 +198,7 @@ export interface FragmentSpecResolver {
|
|
|
190
198
|
* Subscribe to resolver updates.
|
|
191
199
|
* Overrides existing callback (if one has been specified).
|
|
192
200
|
*/
|
|
193
|
-
setCallback(callback: () => void): void;
|
|
201
|
+
setCallback(props: Props, callback: () => void): void;
|
|
194
202
|
}
|
|
195
203
|
|
|
196
204
|
/**
|
|
@@ -216,8 +224,10 @@ export interface MutableRecordSource extends RecordSource {
|
|
|
216
224
|
}
|
|
217
225
|
|
|
218
226
|
export type CheckOptions = {|
|
|
219
|
-
target: MutableRecordSource,
|
|
220
227
|
handlers: $ReadOnlyArray<MissingFieldHandler>,
|
|
228
|
+
defaultActorIdentifier: ActorIdentifier,
|
|
229
|
+
getTargetForActor: (actorIdentifier: ActorIdentifier) => MutableRecordSource,
|
|
230
|
+
getSourceForActor: (actorIdentifier: ActorIdentifier) => RecordSource,
|
|
221
231
|
|};
|
|
222
232
|
|
|
223
233
|
export type OperationAvailability =
|
|
@@ -332,6 +342,11 @@ export interface Store {
|
|
|
332
342
|
invalidationState: InvalidationState,
|
|
333
343
|
callback: () => void,
|
|
334
344
|
): Disposable;
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Get the current write epoch
|
|
348
|
+
*/
|
|
349
|
+
getEpoch(): number;
|
|
335
350
|
}
|
|
336
351
|
|
|
337
352
|
export interface StoreSubscriptions {
|
|
@@ -359,7 +374,7 @@ export interface StoreSubscriptions {
|
|
|
359
374
|
/**
|
|
360
375
|
* Notifies each subscription if the snapshot for the subscription selector has changed.
|
|
361
376
|
* Mutates the updatedOwners array with any owners (RequestDescriptors) associated
|
|
362
|
-
* with the subscriptions that were
|
|
377
|
+
* with the subscriptions that were notified; i.e. the owners affected by the changes.
|
|
363
378
|
*/
|
|
364
379
|
updateSubscriptions(
|
|
365
380
|
source: RecordSource,
|
|
@@ -445,6 +460,23 @@ export interface RecordSourceSelectorProxy extends RecordSourceProxy {
|
|
|
445
460
|
}
|
|
446
461
|
|
|
447
462
|
export type LogEvent =
|
|
463
|
+
| {|
|
|
464
|
+
+name: 'suspense.fragment',
|
|
465
|
+
+data: mixed,
|
|
466
|
+
+fragment: ReaderFragment,
|
|
467
|
+
+isRelayHooks: boolean,
|
|
468
|
+
+isMissingData: boolean,
|
|
469
|
+
+isPromiseCached: boolean,
|
|
470
|
+
+pendingOperations: $ReadOnlyArray<RequestDescriptor>,
|
|
471
|
+
|}
|
|
472
|
+
| {|
|
|
473
|
+
+name: 'suspense.query',
|
|
474
|
+
+fetchPolicy: string,
|
|
475
|
+
+isPromiseCached: boolean,
|
|
476
|
+
+operation: OperationDescriptor,
|
|
477
|
+
+queryAvailability: ?OperationAvailability,
|
|
478
|
+
+renderPolicy: RenderPolicy,
|
|
479
|
+
|}
|
|
448
480
|
| {|
|
|
449
481
|
+name: 'queryresource.fetch',
|
|
450
482
|
// ID of this query resource request and will be the same
|
|
@@ -456,7 +488,7 @@ export type LogEvent =
|
|
|
456
488
|
// FetchPolicy from Relay Hooks
|
|
457
489
|
+fetchPolicy: string,
|
|
458
490
|
// RenderPolicy from Relay Hooks
|
|
459
|
-
+renderPolicy:
|
|
491
|
+
+renderPolicy: RenderPolicy,
|
|
460
492
|
+queryAvailability: OperationAvailability,
|
|
461
493
|
+shouldFetch: boolean,
|
|
462
494
|
|}
|
|
@@ -468,33 +500,67 @@ export type LogEvent =
|
|
|
468
500
|
|}
|
|
469
501
|
| {|
|
|
470
502
|
+name: 'network.info',
|
|
471
|
-
+
|
|
503
|
+
+networkRequestId: number,
|
|
472
504
|
+info: mixed,
|
|
473
505
|
|}
|
|
474
506
|
| {|
|
|
475
507
|
+name: 'network.start',
|
|
476
|
-
+
|
|
508
|
+
+networkRequestId: number,
|
|
477
509
|
+params: RequestParameters,
|
|
478
510
|
+variables: Variables,
|
|
479
511
|
+cacheConfig: CacheConfig,
|
|
480
512
|
|}
|
|
481
513
|
| {|
|
|
482
514
|
+name: 'network.next',
|
|
483
|
-
+
|
|
515
|
+
+networkRequestId: number,
|
|
484
516
|
+response: GraphQLResponse,
|
|
485
517
|
|}
|
|
486
518
|
| {|
|
|
487
519
|
+name: 'network.error',
|
|
488
|
-
+
|
|
520
|
+
+networkRequestId: number,
|
|
489
521
|
+error: Error,
|
|
490
522
|
|}
|
|
491
523
|
| {|
|
|
492
524
|
+name: 'network.complete',
|
|
493
|
-
+
|
|
525
|
+
+networkRequestId: number,
|
|
494
526
|
|}
|
|
495
527
|
| {|
|
|
496
528
|
+name: 'network.unsubscribe',
|
|
497
|
-
+
|
|
529
|
+
+networkRequestId: number,
|
|
530
|
+
|}
|
|
531
|
+
| {|
|
|
532
|
+
+name: 'execute.start',
|
|
533
|
+
+executeId: number,
|
|
534
|
+
+params: RequestParameters,
|
|
535
|
+
+variables: Variables,
|
|
536
|
+
+cacheConfig: CacheConfig,
|
|
537
|
+
|}
|
|
538
|
+
| {|
|
|
539
|
+
+name: 'execute.next',
|
|
540
|
+
+executeId: number,
|
|
541
|
+
+response: GraphQLResponse,
|
|
542
|
+
+duration: number,
|
|
543
|
+
|}
|
|
544
|
+
| {|
|
|
545
|
+
+name: 'execute.async.module',
|
|
546
|
+
+executeId: number,
|
|
547
|
+
+operationName: string,
|
|
548
|
+
+duration: number,
|
|
549
|
+
|}
|
|
550
|
+
| {|
|
|
551
|
+
+name: 'execute.flight.payload_deserialize',
|
|
552
|
+
+executeId: number,
|
|
553
|
+
+operationName: string,
|
|
554
|
+
+duration: number,
|
|
555
|
+
|}
|
|
556
|
+
| {|
|
|
557
|
+
+name: 'execute.error',
|
|
558
|
+
+executeId: number,
|
|
559
|
+
+error: Error,
|
|
560
|
+
|}
|
|
561
|
+
| {|
|
|
562
|
+
+name: 'execute.complete',
|
|
563
|
+
+executeId: number,
|
|
498
564
|
|}
|
|
499
565
|
| {|
|
|
500
566
|
+name: 'store.publish',
|
|
@@ -584,6 +650,19 @@ export interface IEnvironment {
|
|
|
584
650
|
*/
|
|
585
651
|
applyUpdate(optimisticUpdate: OptimisticUpdateFunction): Disposable;
|
|
586
652
|
|
|
653
|
+
/**
|
|
654
|
+
* Revert updates for the `update` function.
|
|
655
|
+
*/
|
|
656
|
+
revertUpdate(update: OptimisticUpdateFunction): void;
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* Revert updates for the `update` function, and apply the `replacement` update.
|
|
660
|
+
*/
|
|
661
|
+
replaceUpdate(
|
|
662
|
+
update: OptimisticUpdateFunction,
|
|
663
|
+
replacement: OptimisticUpdateFunction,
|
|
664
|
+
): void;
|
|
665
|
+
|
|
587
666
|
/**
|
|
588
667
|
* Apply an optimistic mutation response and/or updater. The mutation can be
|
|
589
668
|
* reverted by calling `dispose()` on the returned value.
|
|
@@ -658,18 +737,14 @@ export interface IEnvironment {
|
|
|
658
737
|
* the result is subscribed to:
|
|
659
738
|
* environment.executeMutation({...}).subscribe({...}).
|
|
660
739
|
*/
|
|
661
|
-
executeMutation(
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
optimisticResponse?: ?Object,
|
|
665
|
-
updater?: ?SelectorStoreUpdater,
|
|
666
|
-
uploadables?: ?UploadableMap,
|
|
667
|
-
|}): RelayObservable<GraphQLResponse>;
|
|
740
|
+
executeMutation(
|
|
741
|
+
config: ExecuteMutationConfig,
|
|
742
|
+
): RelayObservable<GraphQLResponse>;
|
|
668
743
|
|
|
669
744
|
/**
|
|
670
745
|
* Returns an Observable of GraphQLResponse resulting from executing the
|
|
671
746
|
* provided Query or Subscription operation responses, the result of which is
|
|
672
|
-
* then normalized and
|
|
747
|
+
* then normalized and committed to the publish queue.
|
|
673
748
|
*
|
|
674
749
|
* Note: Observables are lazy, so calling this method will do nothing until
|
|
675
750
|
* the result is subscribed to:
|
|
@@ -754,6 +829,7 @@ export type HandleFieldPayload = {|
|
|
|
754
829
|
* with a `@module` fragment spread, or a Flight field's:
|
|
755
830
|
*
|
|
756
831
|
* ## @module Fragment Spread
|
|
832
|
+
* - args: Local arguments from the parent
|
|
757
833
|
* - data: The GraphQL response value for the @match field.
|
|
758
834
|
* - dataID: The ID of the store object linked to by the @match field.
|
|
759
835
|
* - operationReference: A reference to a generated module containing the
|
|
@@ -781,14 +857,48 @@ export type HandleFieldPayload = {|
|
|
|
781
857
|
* root data.
|
|
782
858
|
*/
|
|
783
859
|
export type ModuleImportPayload = {|
|
|
860
|
+
+kind: 'ModuleImportPayload',
|
|
861
|
+
+args: ?$ReadOnlyArray<NormalizationArgument>,
|
|
784
862
|
+data: PayloadData,
|
|
785
863
|
+dataID: DataID,
|
|
786
864
|
+operationReference: mixed,
|
|
787
865
|
+path: $ReadOnlyArray<string>,
|
|
788
866
|
+typeName: string,
|
|
789
867
|
+variables: Variables,
|
|
868
|
+
+actorIdentifier: ?ActorIdentifier,
|
|
869
|
+
|};
|
|
870
|
+
|
|
871
|
+
/**
|
|
872
|
+
* A payload that represents data necessary to process the results of an object
|
|
873
|
+
* with experimental actor change directive.
|
|
874
|
+
*
|
|
875
|
+
* - data: The GraphQL response value for the actor change field.
|
|
876
|
+
* - dataID: The ID of the store object linked to by the actor change field.
|
|
877
|
+
* - node: NormalizationLinkedField, where the actor change directive is used
|
|
878
|
+
* - path: to a field in the response
|
|
879
|
+
* - variables: Query variables.
|
|
880
|
+
* - typeName: the type that matched.
|
|
881
|
+
*
|
|
882
|
+
* The dataID, variables, and fragmentName can be used to create a Selector
|
|
883
|
+
* which can in turn be used to normalize and publish the data. The dataID and
|
|
884
|
+
* typeName can also be used to construct a root record for normalization.
|
|
885
|
+
*/
|
|
886
|
+
export type ActorPayload = {|
|
|
887
|
+
+kind: 'ActorPayload',
|
|
888
|
+
+data: PayloadData,
|
|
889
|
+
+dataID: DataID,
|
|
890
|
+
+node: NormalizationLinkedField,
|
|
891
|
+
+path: $ReadOnlyArray<string>,
|
|
892
|
+
+typeName: string,
|
|
893
|
+
+variables: Variables,
|
|
894
|
+
+actorIdentifier: ActorIdentifier,
|
|
790
895
|
|};
|
|
791
896
|
|
|
897
|
+
/**
|
|
898
|
+
* Union type of possible payload followups we may handle during normalization.
|
|
899
|
+
*/
|
|
900
|
+
export type FollowupPayload = ModuleImportPayload | ActorPayload;
|
|
901
|
+
|
|
792
902
|
/**
|
|
793
903
|
* Data emitted after processing a Defer or Stream node during normalization
|
|
794
904
|
* that describes how to process the corresponding response chunk when it
|
|
@@ -801,6 +911,7 @@ export type DeferPlaceholder = {|
|
|
|
801
911
|
+path: $ReadOnlyArray<string>,
|
|
802
912
|
+selector: NormalizationSelector,
|
|
803
913
|
+typeName: string,
|
|
914
|
+
+actorIdentifier: ?ActorIdentifier,
|
|
804
915
|
|};
|
|
805
916
|
export type StreamPlaceholder = {|
|
|
806
917
|
+kind: 'stream',
|
|
@@ -809,6 +920,7 @@ export type StreamPlaceholder = {|
|
|
|
809
920
|
+parentID: DataID,
|
|
810
921
|
+node: NormalizationSelectableNode,
|
|
811
922
|
+variables: Variables,
|
|
923
|
+
+actorIdentifier: ?ActorIdentifier,
|
|
812
924
|
|};
|
|
813
925
|
export type IncrementalDataPlaceholder = DeferPlaceholder | StreamPlaceholder;
|
|
814
926
|
|
|
@@ -930,13 +1042,24 @@ export type RelayResponsePayload = {|
|
|
|
930
1042
|
+errors: ?Array<PayloadError>,
|
|
931
1043
|
+fieldPayloads: ?Array<HandleFieldPayload>,
|
|
932
1044
|
+incrementalPlaceholders: ?Array<IncrementalDataPlaceholder>,
|
|
933
|
-
+
|
|
1045
|
+
+followupPayloads: ?Array<FollowupPayload>,
|
|
934
1046
|
+source: MutableRecordSource,
|
|
935
1047
|
+isFinal: boolean,
|
|
936
1048
|
|};
|
|
937
1049
|
|
|
938
1050
|
/**
|
|
939
|
-
*
|
|
1051
|
+
* Configuration on the executeMutation(...).
|
|
1052
|
+
*/
|
|
1053
|
+
export type ExecuteMutationConfig = {|
|
|
1054
|
+
operation: OperationDescriptor,
|
|
1055
|
+
optimisticUpdater?: ?SelectorStoreUpdater,
|
|
1056
|
+
optimisticResponse?: ?Object,
|
|
1057
|
+
updater?: ?SelectorStoreUpdater,
|
|
1058
|
+
uploadables?: ?UploadableMap,
|
|
1059
|
+
|};
|
|
1060
|
+
|
|
1061
|
+
/**
|
|
1062
|
+
* Public interface for Publish Queue.
|
|
940
1063
|
*/
|
|
941
1064
|
export interface PublishQueue {
|
|
942
1065
|
/**
|
|
@@ -990,7 +1113,7 @@ export interface PublishQueue {
|
|
|
990
1113
|
*/
|
|
991
1114
|
export type ReactFlightClientResponse = {readRoot: () => mixed, ...};
|
|
992
1115
|
|
|
993
|
-
export type
|
|
1116
|
+
export type ReactFlightReachableExecutableDefinitions = {|
|
|
994
1117
|
+module: mixed,
|
|
995
1118
|
+variables: Variables,
|
|
996
1119
|
|};
|
|
@@ -23,10 +23,14 @@ import type {
|
|
|
23
23
|
NormalizationArgument,
|
|
24
24
|
NormalizationField,
|
|
25
25
|
} from '../util/NormalizationNode';
|
|
26
|
-
import type {
|
|
26
|
+
import type {
|
|
27
|
+
ReaderArgument,
|
|
28
|
+
ReaderField,
|
|
29
|
+
ReaderActorChange,
|
|
30
|
+
} from '../util/ReaderNode';
|
|
27
31
|
import type {Variables} from '../util/RelayRuntimeTypes';
|
|
28
32
|
|
|
29
|
-
export type Arguments = {+[string]: mixed
|
|
33
|
+
export type Arguments = interface {+[string]: mixed};
|
|
30
34
|
|
|
31
35
|
const {VARIABLE, LITERAL, OBJECT_VALUE, LIST_VALUE} = RelayConcreteNode;
|
|
32
36
|
|
|
@@ -121,14 +125,19 @@ function getHandleStorageKey(
|
|
|
121
125
|
* used here for consistency.
|
|
122
126
|
*/
|
|
123
127
|
function getStorageKey(
|
|
124
|
-
field:
|
|
128
|
+
field:
|
|
129
|
+
| NormalizationField
|
|
130
|
+
| NormalizationHandle
|
|
131
|
+
| ReaderField
|
|
132
|
+
| ReaderActorChange,
|
|
125
133
|
variables: Variables,
|
|
126
134
|
): string {
|
|
127
135
|
if (field.storageKey) {
|
|
128
136
|
// TODO T23663664: Handle nodes do not yet define a static storageKey.
|
|
129
137
|
return (field: $FlowFixMe).storageKey;
|
|
130
138
|
}
|
|
131
|
-
const
|
|
139
|
+
const args = typeof field.args === 'undefined' ? undefined : field.args;
|
|
140
|
+
const name = field.name;
|
|
132
141
|
return args && args.length !== 0
|
|
133
142
|
? formatStorageKey(name, getArgumentValues(args, variables))
|
|
134
143
|
: name;
|
|
@@ -178,6 +187,7 @@ function getStableVariableValue(name: string, variables: Variables): mixed {
|
|
|
178
187
|
'getVariableValue(): Undefined variable `%s`.',
|
|
179
188
|
name,
|
|
180
189
|
);
|
|
190
|
+
// $FlowFixMe[cannot-write]
|
|
181
191
|
return stableCopy(variables[name]);
|
|
182
192
|
}
|
|
183
193
|
|
|
@@ -193,6 +203,7 @@ function getModuleOperationKey(documentName: string): string {
|
|
|
193
203
|
* Constants shared by all implementations of RecordSource/MutableRecordSource/etc.
|
|
194
204
|
*/
|
|
195
205
|
const RelayStoreUtils = {
|
|
206
|
+
ACTOR_IDENTIFIER_KEY: '__actorIdentifier',
|
|
196
207
|
FRAGMENTS_KEY: '__fragments',
|
|
197
208
|
FRAGMENT_OWNER_KEY: '__fragmentOwner',
|
|
198
209
|
FRAGMENT_PROP_NAME_KEY: '__fragmentPropName',
|
|
@@ -205,6 +216,10 @@ const RelayStoreUtils = {
|
|
|
205
216
|
TYPENAME_KEY: '__typename',
|
|
206
217
|
INVALIDATED_AT_KEY: '__invalidated_at',
|
|
207
218
|
IS_WITHIN_UNMATCHED_TYPE_REFINEMENT: '__isWithinUnmatchedTypeRefinement',
|
|
219
|
+
RELAY_RESOLVER_VALUE_KEY: '__resolverValue',
|
|
220
|
+
RELAY_RESOLVER_INVALIDATION_KEY: '__resolverValueMayBeInvalid',
|
|
221
|
+
RELAY_RESOLVER_INPUTS_KEY: '__resolverInputValues',
|
|
222
|
+
RELAY_RESOLVER_READER_SELECTOR_KEY: '__resolverReaderSelector',
|
|
208
223
|
|
|
209
224
|
formatStorageKey,
|
|
210
225
|
getArgumentValue,
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @flow strict-local
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// flowlint ambiguous-object-type:error
|
|
12
|
+
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
const RelayModernRecord = require('./RelayModernRecord');
|
|
16
|
+
|
|
17
|
+
const recycleNodesInto = require('../util/recycleNodesInto');
|
|
18
|
+
const warning = require('warning');
|
|
19
|
+
|
|
20
|
+
const {generateClientID} = require('./ClientID');
|
|
21
|
+
const {
|
|
22
|
+
RELAY_RESOLVER_VALUE_KEY,
|
|
23
|
+
RELAY_RESOLVER_INVALIDATION_KEY,
|
|
24
|
+
RELAY_RESOLVER_INPUTS_KEY,
|
|
25
|
+
RELAY_RESOLVER_READER_SELECTOR_KEY,
|
|
26
|
+
getStorageKey,
|
|
27
|
+
} = require('./RelayStoreUtils');
|
|
28
|
+
|
|
29
|
+
import type {ReaderRelayResolver} from '../util/ReaderNode';
|
|
30
|
+
import type {DataID, Variables} from '../util/RelayRuntimeTypes';
|
|
31
|
+
import type {
|
|
32
|
+
MutableRecordSource,
|
|
33
|
+
Record,
|
|
34
|
+
SingularReaderSelector,
|
|
35
|
+
} from './RelayStoreTypes';
|
|
36
|
+
|
|
37
|
+
type ResolverID = string;
|
|
38
|
+
|
|
39
|
+
type EvaluationResult<T> = {|
|
|
40
|
+
resolverResult: T,
|
|
41
|
+
fragmentValue: {...},
|
|
42
|
+
resolverID: ResolverID,
|
|
43
|
+
seenRecordIDs: Set<DataID>,
|
|
44
|
+
readerSelector: SingularReaderSelector,
|
|
45
|
+
|};
|
|
46
|
+
|
|
47
|
+
export interface ResolverCache {
|
|
48
|
+
readFromCacheOrEvaluate<T>(
|
|
49
|
+
record: Record,
|
|
50
|
+
field: ReaderRelayResolver,
|
|
51
|
+
variables: Variables,
|
|
52
|
+
evaluate: () => EvaluationResult<T>,
|
|
53
|
+
getDataForResolverFragment: (SingularReaderSelector) => mixed,
|
|
54
|
+
): [T /* Answer */, ?DataID /* Seen record */];
|
|
55
|
+
invalidateDataIDs(
|
|
56
|
+
updatedDataIDs: Set<DataID>, // Mutated in place
|
|
57
|
+
): void;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// $FlowFixMe[unclear-type] - will always be empty
|
|
61
|
+
const emptySet: $ReadOnlySet<any> = new Set();
|
|
62
|
+
|
|
63
|
+
class NoopResolverCache implements ResolverCache {
|
|
64
|
+
readFromCacheOrEvaluate<T>(
|
|
65
|
+
record: Record,
|
|
66
|
+
field: ReaderRelayResolver,
|
|
67
|
+
variables: Variables,
|
|
68
|
+
evaluate: () => EvaluationResult<T>,
|
|
69
|
+
getDataForResolverFragment: SingularReaderSelector => mixed,
|
|
70
|
+
): [T /* Answer */, ?DataID /* Seen record */] {
|
|
71
|
+
return [evaluate().resolverResult, undefined];
|
|
72
|
+
}
|
|
73
|
+
invalidateDataIDs(updatedDataIDs: Set<DataID>): void {}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function addDependencyEdge(edges, from, to): void {
|
|
77
|
+
let set = edges.get(from);
|
|
78
|
+
if (!set) {
|
|
79
|
+
set = new Set();
|
|
80
|
+
edges.set(from, set);
|
|
81
|
+
}
|
|
82
|
+
set.add(to);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
class RecordResolverCache implements ResolverCache {
|
|
86
|
+
_resolverIDToRecordIDs: Map<ResolverID, Set<DataID>>;
|
|
87
|
+
_recordIDToResolverIDs: Map<DataID, Set<ResolverID>>;
|
|
88
|
+
|
|
89
|
+
_getRecordSource: () => MutableRecordSource;
|
|
90
|
+
|
|
91
|
+
constructor(getRecordSource: () => MutableRecordSource) {
|
|
92
|
+
this._resolverIDToRecordIDs = new Map();
|
|
93
|
+
this._recordIDToResolverIDs = new Map();
|
|
94
|
+
this._getRecordSource = getRecordSource;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
readFromCacheOrEvaluate<T>(
|
|
98
|
+
record: Record,
|
|
99
|
+
field: ReaderRelayResolver,
|
|
100
|
+
variables: Variables,
|
|
101
|
+
evaluate: () => EvaluationResult<T>,
|
|
102
|
+
getDataForResolverFragment: SingularReaderSelector => mixed,
|
|
103
|
+
): [T /* Answer */, ?DataID /* Seen record */] {
|
|
104
|
+
const recordSource = this._getRecordSource();
|
|
105
|
+
const recordID = RelayModernRecord.getDataID(record);
|
|
106
|
+
|
|
107
|
+
const storageKey = getStorageKey(field, variables);
|
|
108
|
+
let linkedID = RelayModernRecord.getLinkedRecordID(record, storageKey);
|
|
109
|
+
let linkedRecord = linkedID == null ? null : recordSource.get(linkedID);
|
|
110
|
+
if (
|
|
111
|
+
linkedRecord == null ||
|
|
112
|
+
this._isInvalid(linkedRecord, getDataForResolverFragment)
|
|
113
|
+
) {
|
|
114
|
+
// Cache miss; evaluate the selector and store the result in a new record:
|
|
115
|
+
linkedID = linkedID ?? generateClientID(recordID, storageKey);
|
|
116
|
+
linkedRecord = RelayModernRecord.create(linkedID, '__RELAY_RESOLVER__');
|
|
117
|
+
|
|
118
|
+
const evaluationResult = evaluate();
|
|
119
|
+
RelayModernRecord.setValue(
|
|
120
|
+
linkedRecord,
|
|
121
|
+
RELAY_RESOLVER_VALUE_KEY,
|
|
122
|
+
evaluationResult.resolverResult,
|
|
123
|
+
);
|
|
124
|
+
RelayModernRecord.setValue(
|
|
125
|
+
linkedRecord,
|
|
126
|
+
RELAY_RESOLVER_INPUTS_KEY,
|
|
127
|
+
evaluationResult.fragmentValue,
|
|
128
|
+
);
|
|
129
|
+
RelayModernRecord.setValue(
|
|
130
|
+
linkedRecord,
|
|
131
|
+
RELAY_RESOLVER_READER_SELECTOR_KEY,
|
|
132
|
+
evaluationResult.readerSelector,
|
|
133
|
+
);
|
|
134
|
+
recordSource.set(linkedID, linkedRecord);
|
|
135
|
+
|
|
136
|
+
// Link the resolver value record to the resolver field of the record being read:
|
|
137
|
+
const nextRecord = RelayModernRecord.clone(record);
|
|
138
|
+
RelayModernRecord.setLinkedRecordID(nextRecord, storageKey, linkedID);
|
|
139
|
+
recordSource.set(RelayModernRecord.getDataID(nextRecord), nextRecord);
|
|
140
|
+
|
|
141
|
+
// Put records observed by the resolver into the dependency graph:
|
|
142
|
+
const resolverID = evaluationResult.resolverID;
|
|
143
|
+
addDependencyEdge(this._resolverIDToRecordIDs, resolverID, linkedID);
|
|
144
|
+
addDependencyEdge(this._recordIDToResolverIDs, recordID, resolverID);
|
|
145
|
+
for (const seenRecordID of evaluationResult.seenRecordIDs) {
|
|
146
|
+
addDependencyEdge(
|
|
147
|
+
this._recordIDToResolverIDs,
|
|
148
|
+
seenRecordID,
|
|
149
|
+
resolverID,
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// $FlowFixMe[incompatible-type] - will always be empty
|
|
155
|
+
const answer: T = linkedRecord[RELAY_RESOLVER_VALUE_KEY];
|
|
156
|
+
return [answer, linkedID];
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
invalidateDataIDs(
|
|
160
|
+
updatedDataIDs: Set<DataID>, // Mutated in place
|
|
161
|
+
): void {
|
|
162
|
+
const recordSource = this._getRecordSource();
|
|
163
|
+
const visited: Set<string> = new Set();
|
|
164
|
+
const recordsToVisit = Array.from(updatedDataIDs);
|
|
165
|
+
while (recordsToVisit.length) {
|
|
166
|
+
const recordID = recordsToVisit.pop();
|
|
167
|
+
updatedDataIDs.add(recordID);
|
|
168
|
+
for (const fragment of this._recordIDToResolverIDs.get(recordID) ??
|
|
169
|
+
emptySet) {
|
|
170
|
+
if (!visited.has(fragment)) {
|
|
171
|
+
for (const anotherRecordID of this._resolverIDToRecordIDs.get(
|
|
172
|
+
fragment,
|
|
173
|
+
) ?? emptySet) {
|
|
174
|
+
this._markInvalidatedResolverRecord(
|
|
175
|
+
anotherRecordID,
|
|
176
|
+
recordSource,
|
|
177
|
+
updatedDataIDs,
|
|
178
|
+
);
|
|
179
|
+
if (!visited.has(anotherRecordID)) {
|
|
180
|
+
recordsToVisit.push(anotherRecordID);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
_markInvalidatedResolverRecord(
|
|
189
|
+
dataID: DataID,
|
|
190
|
+
recordSource: MutableRecordSource, // Written to
|
|
191
|
+
updatedDataIDs: Set<DataID>, // Mutated in place
|
|
192
|
+
) {
|
|
193
|
+
const record = recordSource.get(dataID);
|
|
194
|
+
if (!record) {
|
|
195
|
+
warning(
|
|
196
|
+
false,
|
|
197
|
+
'Expected a resolver record with ID %s, but it was missing.',
|
|
198
|
+
dataID,
|
|
199
|
+
);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
const nextRecord = RelayModernRecord.clone(record);
|
|
203
|
+
RelayModernRecord.setValue(
|
|
204
|
+
nextRecord,
|
|
205
|
+
RELAY_RESOLVER_INVALIDATION_KEY,
|
|
206
|
+
true,
|
|
207
|
+
);
|
|
208
|
+
recordSource.set(dataID, nextRecord);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
_isInvalid(
|
|
212
|
+
record: Record,
|
|
213
|
+
getDataForResolverFragment: SingularReaderSelector => mixed,
|
|
214
|
+
): boolean {
|
|
215
|
+
if (!RelayModernRecord.getValue(record, RELAY_RESOLVER_INVALIDATION_KEY)) {
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
const originalInputs = RelayModernRecord.getValue(
|
|
219
|
+
record,
|
|
220
|
+
RELAY_RESOLVER_INPUTS_KEY,
|
|
221
|
+
);
|
|
222
|
+
// $FlowFixMe[incompatible-type] - storing values in records is not typed
|
|
223
|
+
const readerSelector: ?SingularReaderSelector = RelayModernRecord.getValue(
|
|
224
|
+
record,
|
|
225
|
+
RELAY_RESOLVER_READER_SELECTOR_KEY,
|
|
226
|
+
);
|
|
227
|
+
if (originalInputs == null || readerSelector == null) {
|
|
228
|
+
warning(
|
|
229
|
+
false,
|
|
230
|
+
'Expected previous inputs and reader selector on resolver record with ID %s, but they were missing.',
|
|
231
|
+
RelayModernRecord.getDataID(record),
|
|
232
|
+
);
|
|
233
|
+
return true;
|
|
234
|
+
}
|
|
235
|
+
const latestValues = getDataForResolverFragment(readerSelector);
|
|
236
|
+
const recycled = recycleNodesInto(originalInputs, latestValues);
|
|
237
|
+
if (recycled !== originalInputs) {
|
|
238
|
+
return true;
|
|
239
|
+
}
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
module.exports = {
|
|
245
|
+
NoopResolverCache,
|
|
246
|
+
RecordResolverCache,
|
|
247
|
+
};
|