relay-runtime 10.1.3 → 11.0.2
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 +60 -0
- package/handlers/connection/MutationHandlers.js.flow +28 -0
- package/index.js +1 -1
- package/index.js.flow +9 -3
- package/lib/handlers/RelayDefaultHandlerProvider.js +1 -1
- package/lib/handlers/connection/ConnectionHandler.js +68 -6
- package/lib/handlers/connection/MutationHandlers.js +67 -8
- package/lib/index.js +3 -0
- package/lib/multi-actor-environment/ActorIdentifier.js +23 -0
- package/lib/multi-actor-environment/ActorSpecificEnvironment.js +108 -0
- package/lib/multi-actor-environment/MultiActorEnvironment.js +156 -0
- package/lib/multi-actor-environment/MultiActorEnvironmentTypes.js +11 -0
- package/lib/multi-actor-environment/index.js +17 -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 +1 -1
- package/lib/mutations/applyOptimisticMutation.js +1 -1
- package/lib/mutations/commitMutation.js +1 -1
- package/lib/mutations/validateMutation.js +36 -15
- package/lib/network/RelayNetwork.js +1 -1
- package/lib/network/RelayQueryResponseCache.js +3 -2
- package/lib/query/GraphQLTag.js +1 -1
- package/lib/query/fetchQuery.js +129 -13
- package/lib/query/fetchQueryInternal.js +3 -4
- package/lib/query/fetchQuery_DEPRECATED.js +39 -0
- package/lib/store/DataChecker.js +26 -14
- package/lib/store/{RelayModernQueryExecutor.js → OperationExecutor.js} +117 -47
- package/lib/store/RelayConcreteVariables.js +8 -4
- package/lib/store/RelayModernEnvironment.js +105 -136
- package/lib/store/RelayModernFragmentSpecResolver.js +16 -9
- package/lib/store/RelayModernRecord.js +1 -1
- package/lib/store/RelayModernSelector.js +1 -1
- package/lib/store/RelayModernStore.js +19 -20
- package/lib/store/RelayOperationTracker.js +55 -49
- package/lib/store/RelayPublishQueue.js +9 -5
- package/lib/store/RelayReader.js +68 -14
- package/lib/store/RelayReferenceMarker.js +28 -14
- package/lib/store/RelayResponseNormalizer.js +109 -15
- package/lib/store/RelayStoreReactFlightUtils.js +6 -4
- package/lib/store/RelayStoreSubscriptions.js +18 -8
- package/lib/store/RelayStoreSubscriptionsUsingMapByID.js +90 -30
- package/lib/store/RelayStoreUtils.js +3 -2
- package/lib/store/ResolverFragments.js +57 -0
- package/lib/store/cloneRelayHandleSourceField.js +1 -1
- package/lib/store/cloneRelayScalarHandleSourceField.js +1 -1
- package/lib/store/createFragmentSpecResolver.js +2 -2
- package/lib/store/createRelayContext.js +1 -1
- package/lib/store/defaultGetDataID.js +3 -1
- package/lib/store/hasOverlappingIDs.js +11 -3
- package/lib/store/readInlineData.js +1 -1
- package/lib/subscription/requestSubscription.js +33 -5
- package/lib/util/RelayConcreteNode.js +2 -0
- package/lib/util/RelayFeatureFlags.js +8 -3
- package/lib/util/RelayProfiler.js +17 -187
- package/lib/util/RelayReplaySubject.js +1 -1
- package/lib/util/deepFreeze.js +1 -0
- package/lib/util/getRelayHandleKey.js +1 -1
- package/lib/util/getRequestIdentifier.js +1 -1
- package/multi-actor-environment/ActorIdentifier.js.flow +27 -0
- package/multi-actor-environment/ActorSpecificEnvironment.js.flow +189 -0
- package/multi-actor-environment/MultiActorEnvironment.js.flow +233 -0
- package/multi-actor-environment/MultiActorEnvironmentTypes.js.flow +196 -0
- package/multi-actor-environment/index.js.flow +24 -0
- package/mutations/RelayRecordSourceProxy.js.flow +3 -2
- package/mutations/commitMutation.js.flow +1 -1
- package/mutations/validateMutation.js.flow +40 -15
- package/network/RelayNetworkTypes.js.flow +31 -11
- package/network/RelayQueryResponseCache.js.flow +2 -1
- package/package.json +3 -2
- package/query/fetchQuery.js.flow +147 -20
- package/query/fetchQueryInternal.js.flow +2 -3
- package/query/fetchQuery_DEPRECATED.js.flow +47 -0
- package/relay-runtime.js +2 -2
- package/relay-runtime.min.js +2 -2
- package/store/DataChecker.js.flow +23 -15
- package/store/{RelayModernQueryExecutor.js.flow → OperationExecutor.js.flow} +128 -40
- package/store/RelayConcreteVariables.js.flow +5 -0
- package/store/RelayModernEnvironment.js.flow +100 -130
- package/store/RelayModernFragmentSpecResolver.js.flow +30 -8
- package/store/RelayModernStore.js.flow +28 -24
- package/store/RelayOperationTracker.js.flow +69 -56
- package/store/RelayPublishQueue.js.flow +7 -4
- package/store/RelayReader.js.flow +63 -11
- package/store/RelayRecordSource.js.flow +3 -3
- package/store/RelayRecordSourceMapImpl.js.flow +6 -2
- package/store/RelayReferenceMarker.js.flow +28 -18
- package/store/RelayResponseNormalizer.js.flow +134 -23
- package/store/RelayStoreReactFlightUtils.js.flow +9 -4
- package/store/RelayStoreSubscriptions.js.flow +22 -7
- package/store/RelayStoreSubscriptionsUsingMapByID.js.flow +36 -12
- package/store/RelayStoreTypes.js.flow +51 -22
- package/store/RelayStoreUtils.js.flow +2 -1
- package/store/ResolverFragments.js.flow +125 -0
- package/store/createFragmentSpecResolver.js.flow +2 -0
- package/store/defaultGetDataID.js.flow +3 -1
- package/store/hasOverlappingIDs.js.flow +11 -9
- package/subscription/requestSubscription.js.flow +25 -2
- package/util/NormalizationNode.js.flow +13 -0
- package/util/ReaderNode.js.flow +14 -1
- package/util/RelayConcreteNode.js.flow +2 -0
- package/util/RelayFeatureFlags.js.flow +12 -2
- package/util/RelayProfiler.js.flow +22 -194
- package/util/RelayRuntimeTypes.js.flow +4 -5
- package/util/deepFreeze.js.flow +2 -1
- package/util/isEmptyObject.js.flow +1 -1
|
@@ -14,7 +14,6 @@
|
|
|
14
14
|
|
|
15
15
|
const RelayFeatureFlags = require('../util/RelayFeatureFlags');
|
|
16
16
|
const RelayModernRecord = require('./RelayModernRecord');
|
|
17
|
-
const RelayProfiler = require('../util/RelayProfiler');
|
|
18
17
|
|
|
19
18
|
const areEqual = require('areEqual');
|
|
20
19
|
const invariant = require('invariant');
|
|
@@ -22,9 +21,11 @@ const warning = require('warning');
|
|
|
22
21
|
|
|
23
22
|
const {
|
|
24
23
|
CONDITION,
|
|
24
|
+
CLIENT_COMPONENT,
|
|
25
25
|
CLIENT_EXTENSION,
|
|
26
26
|
DEFER,
|
|
27
27
|
FLIGHT_FIELD,
|
|
28
|
+
FRAGMENT_SPREAD,
|
|
28
29
|
INLINE_FRAGMENT,
|
|
29
30
|
LINKED_FIELD,
|
|
30
31
|
LINKED_HANDLE,
|
|
@@ -38,7 +39,7 @@ const {generateClientID, isClientID} = require('./ClientID');
|
|
|
38
39
|
const {createNormalizationSelector} = require('./RelayModernSelector');
|
|
39
40
|
const {
|
|
40
41
|
refineToReactFlightPayloadData,
|
|
41
|
-
|
|
42
|
+
REACT_FLIGHT_EXECUTABLE_DEFINITIONS_STORAGE_KEY,
|
|
42
43
|
REACT_FLIGHT_TREE_STORAGE_KEY,
|
|
43
44
|
REACT_FLIGHT_TYPE_NAME,
|
|
44
45
|
} = require('./RelayStoreReactFlightUtils');
|
|
@@ -71,14 +72,15 @@ import type {
|
|
|
71
72
|
ModuleImportPayload,
|
|
72
73
|
MutableRecordSource,
|
|
73
74
|
NormalizationSelector,
|
|
74
|
-
|
|
75
|
+
ReactFlightReachableExecutableDefinitions,
|
|
75
76
|
ReactFlightPayloadDeserializer,
|
|
77
|
+
ReactFlightServerErrorHandler,
|
|
76
78
|
Record,
|
|
77
79
|
RelayResponsePayload,
|
|
78
80
|
} from './RelayStoreTypes';
|
|
79
81
|
|
|
80
82
|
export type GetDataID = (
|
|
81
|
-
fieldValue: {[string]: mixed
|
|
83
|
+
fieldValue: interface {[string]: mixed},
|
|
82
84
|
typeName: string,
|
|
83
85
|
) => mixed;
|
|
84
86
|
|
|
@@ -87,6 +89,8 @@ export type NormalizationOptions = {|
|
|
|
87
89
|
+treatMissingFieldsAsNull: boolean,
|
|
88
90
|
+path?: $ReadOnlyArray<string>,
|
|
89
91
|
+reactFlightPayloadDeserializer?: ?ReactFlightPayloadDeserializer,
|
|
92
|
+
+reactFlightServerErrorHandler?: ?ReactFlightServerErrorHandler,
|
|
93
|
+
+shouldProcessClientComponents?: ?boolean,
|
|
90
94
|
|};
|
|
91
95
|
|
|
92
96
|
/**
|
|
@@ -125,6 +129,8 @@ class RelayResponseNormalizer {
|
|
|
125
129
|
_recordSource: MutableRecordSource;
|
|
126
130
|
_variables: Variables;
|
|
127
131
|
_reactFlightPayloadDeserializer: ?ReactFlightPayloadDeserializer;
|
|
132
|
+
_reactFlightServerErrorHandler: ?ReactFlightServerErrorHandler;
|
|
133
|
+
_shouldProcessClientComponents: ?boolean;
|
|
128
134
|
|
|
129
135
|
constructor(
|
|
130
136
|
recordSource: MutableRecordSource,
|
|
@@ -143,6 +149,8 @@ class RelayResponseNormalizer {
|
|
|
143
149
|
this._variables = variables;
|
|
144
150
|
this._reactFlightPayloadDeserializer =
|
|
145
151
|
options.reactFlightPayloadDeserializer;
|
|
152
|
+
this._reactFlightServerErrorHandler = options.reactFlightServerErrorHandler;
|
|
153
|
+
this._shouldProcessClientComponents = options.shouldProcessClientComponents;
|
|
146
154
|
}
|
|
147
155
|
|
|
148
156
|
normalizeResponse(
|
|
@@ -173,6 +181,7 @@ class RelayResponseNormalizer {
|
|
|
173
181
|
'RelayResponseNormalizer(): Undefined variable `%s`.',
|
|
174
182
|
name,
|
|
175
183
|
);
|
|
184
|
+
// $FlowFixMe[cannot-write]
|
|
176
185
|
return this._variables[name];
|
|
177
186
|
}
|
|
178
187
|
|
|
@@ -204,6 +213,10 @@ class RelayResponseNormalizer {
|
|
|
204
213
|
this._traverseSelections(selection, record, data);
|
|
205
214
|
}
|
|
206
215
|
break;
|
|
216
|
+
case FRAGMENT_SPREAD: {
|
|
217
|
+
this._traverseSelections(selection.fragment, record, data);
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
207
220
|
case INLINE_FRAGMENT: {
|
|
208
221
|
const {abstractKey} = selection;
|
|
209
222
|
if (abstractKey == null) {
|
|
@@ -293,6 +306,12 @@ class RelayResponseNormalizer {
|
|
|
293
306
|
this._traverseSelections(selection, record, data);
|
|
294
307
|
this._isClientExtension = isClientExtension;
|
|
295
308
|
break;
|
|
309
|
+
case CLIENT_COMPONENT:
|
|
310
|
+
if (this._shouldProcessClientComponents === false) {
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
this._traverseSelections(selection.fragment, record, data);
|
|
314
|
+
break;
|
|
296
315
|
case FLIGHT_FIELD:
|
|
297
316
|
if (RelayFeatureFlags.ENABLE_REACT_FLIGHT_COMPONENT_FIELD) {
|
|
298
317
|
this._normalizeFlightField(node, selection, record, data);
|
|
@@ -515,31 +534,73 @@ class RelayResponseNormalizer {
|
|
|
515
534
|
const fieldValue = data[responseKey];
|
|
516
535
|
|
|
517
536
|
if (fieldValue == null) {
|
|
537
|
+
if (fieldValue === undefined) {
|
|
538
|
+
// Flight field may be missing in the response if:
|
|
539
|
+
// - It is inside an abstract type refinement where the concrete type does
|
|
540
|
+
// not conform to the interface/union.
|
|
541
|
+
// However an otherwise-required field may also be missing if the server
|
|
542
|
+
// is configured to skip fields with `null` values, in which case the
|
|
543
|
+
// client is assumed to be correctly configured with
|
|
544
|
+
// treatMissingFieldsAsNull=true.
|
|
545
|
+
if (this._isUnmatchedAbstractType) {
|
|
546
|
+
// Field not expected to exist regardless of whether the server is pruning null
|
|
547
|
+
// fields or not.
|
|
548
|
+
return;
|
|
549
|
+
} else if (!this._treatMissingFieldsAsNull) {
|
|
550
|
+
// Not optional and the server is not pruning null fields: field is expected
|
|
551
|
+
// to be present
|
|
552
|
+
if (__DEV__) {
|
|
553
|
+
warning(
|
|
554
|
+
false,
|
|
555
|
+
'RelayResponseNormalizer: Payload did not contain a value ' +
|
|
556
|
+
'for field `%s: %s`. Check that you are parsing with the same ' +
|
|
557
|
+
'query that was used to fetch the payload.',
|
|
558
|
+
responseKey,
|
|
559
|
+
storageKey,
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
518
565
|
RelayModernRecord.setValue(record, storageKey, null);
|
|
519
566
|
return;
|
|
520
567
|
}
|
|
521
568
|
|
|
522
569
|
const reactFlightPayload = refineToReactFlightPayloadData(fieldValue);
|
|
570
|
+
const reactFlightPayloadDeserializer = this._reactFlightPayloadDeserializer;
|
|
523
571
|
|
|
524
572
|
invariant(
|
|
525
573
|
reactFlightPayload != null,
|
|
526
|
-
'RelayResponseNormalizer
|
|
527
|
-
'
|
|
574
|
+
'RelayResponseNormalizer: Expected React Flight payload data to be an ' +
|
|
575
|
+
'object with `status`, tree`, `queries` and `errors` properties, got ' +
|
|
576
|
+
'`%s`.',
|
|
528
577
|
fieldValue,
|
|
529
578
|
);
|
|
530
579
|
invariant(
|
|
531
|
-
typeof
|
|
580
|
+
typeof reactFlightPayloadDeserializer === 'function',
|
|
532
581
|
'RelayResponseNormalizer: Expected reactFlightPayloadDeserializer to ' +
|
|
533
582
|
'be a function, got `%s`.',
|
|
534
|
-
|
|
583
|
+
reactFlightPayloadDeserializer,
|
|
535
584
|
);
|
|
536
585
|
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
586
|
+
if (reactFlightPayload.errors.length > 0) {
|
|
587
|
+
if (typeof this._reactFlightServerErrorHandler === 'function') {
|
|
588
|
+
this._reactFlightServerErrorHandler(
|
|
589
|
+
reactFlightPayload.status,
|
|
590
|
+
reactFlightPayload.errors,
|
|
591
|
+
);
|
|
592
|
+
} else {
|
|
593
|
+
warning(
|
|
594
|
+
false,
|
|
595
|
+
'RelayResponseNormalizer: Received server errors for field `%s`.\n\n' +
|
|
596
|
+
'%s\n%s',
|
|
597
|
+
responseKey,
|
|
598
|
+
reactFlightPayload.errors[0].message,
|
|
599
|
+
reactFlightPayload.errors[0].stack,
|
|
600
|
+
);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
543
604
|
const reactFlightID = generateClientID(
|
|
544
605
|
RelayModernRecord.getDataID(record),
|
|
545
606
|
getStorageKey(selection, this._variables),
|
|
@@ -552,12 +613,49 @@ class RelayResponseNormalizer {
|
|
|
552
613
|
);
|
|
553
614
|
this._recordSource.set(reactFlightID, reactFlightClientResponseRecord);
|
|
554
615
|
}
|
|
616
|
+
|
|
617
|
+
if (reactFlightPayload.tree == null) {
|
|
618
|
+
// This typically indicates that a fatal server error prevented rows from
|
|
619
|
+
// being written. When this occurs, we should not continue normalization of
|
|
620
|
+
// the Flight field because the row response is malformed.
|
|
621
|
+
//
|
|
622
|
+
// Receiving empty rows is OK because it can indicate the start of a stream.
|
|
623
|
+
warning(
|
|
624
|
+
false,
|
|
625
|
+
'RelayResponseNormalizer: Expected `tree` not to be null. This ' +
|
|
626
|
+
'typically indicates that a fatal server error prevented any Server ' +
|
|
627
|
+
'Component rows from being written.',
|
|
628
|
+
);
|
|
629
|
+
// We create the flight record with a null value for the tree
|
|
630
|
+
// and empty reachable definitions
|
|
631
|
+
RelayModernRecord.setValue(
|
|
632
|
+
reactFlightClientResponseRecord,
|
|
633
|
+
REACT_FLIGHT_TREE_STORAGE_KEY,
|
|
634
|
+
null,
|
|
635
|
+
);
|
|
636
|
+
RelayModernRecord.setValue(
|
|
637
|
+
reactFlightClientResponseRecord,
|
|
638
|
+
REACT_FLIGHT_EXECUTABLE_DEFINITIONS_STORAGE_KEY,
|
|
639
|
+
[],
|
|
640
|
+
);
|
|
641
|
+
RelayModernRecord.setLinkedRecordID(record, storageKey, reactFlightID);
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
// We store the deserialized reactFlightClientResponse in a separate
|
|
646
|
+
// record and link it to the parent record. This is so we can GC the Flight
|
|
647
|
+
// tree later even if the parent record is still reachable.
|
|
648
|
+
const reactFlightClientResponse = reactFlightPayloadDeserializer(
|
|
649
|
+
reactFlightPayload.tree,
|
|
650
|
+
);
|
|
651
|
+
|
|
555
652
|
RelayModernRecord.setValue(
|
|
556
653
|
reactFlightClientResponseRecord,
|
|
557
654
|
REACT_FLIGHT_TREE_STORAGE_KEY,
|
|
558
655
|
reactFlightClientResponse,
|
|
559
656
|
);
|
|
560
|
-
|
|
657
|
+
|
|
658
|
+
const reachableExecutableDefinitions: Array<ReactFlightReachableExecutableDefinitions> = [];
|
|
561
659
|
for (const query of reactFlightPayload.queries) {
|
|
562
660
|
if (query.response.data != null) {
|
|
563
661
|
this._moduleImportPayloads.push({
|
|
@@ -569,15 +667,31 @@ class RelayResponseNormalizer {
|
|
|
569
667
|
variables: query.variables,
|
|
570
668
|
});
|
|
571
669
|
}
|
|
572
|
-
|
|
670
|
+
reachableExecutableDefinitions.push({
|
|
573
671
|
module: query.module,
|
|
574
672
|
variables: query.variables,
|
|
575
673
|
});
|
|
576
674
|
}
|
|
675
|
+
for (const fragment of reactFlightPayload.fragments) {
|
|
676
|
+
if (fragment.response.data != null) {
|
|
677
|
+
this._moduleImportPayloads.push({
|
|
678
|
+
data: fragment.response.data,
|
|
679
|
+
dataID: fragment.__id,
|
|
680
|
+
operationReference: fragment.module,
|
|
681
|
+
path: [],
|
|
682
|
+
typeName: fragment.__typename,
|
|
683
|
+
variables: fragment.variables,
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
reachableExecutableDefinitions.push({
|
|
687
|
+
module: fragment.module,
|
|
688
|
+
variables: fragment.variables,
|
|
689
|
+
});
|
|
690
|
+
}
|
|
577
691
|
RelayModernRecord.setValue(
|
|
578
692
|
reactFlightClientResponseRecord,
|
|
579
|
-
|
|
580
|
-
|
|
693
|
+
REACT_FLIGHT_EXECUTABLE_DEFINITIONS_STORAGE_KEY,
|
|
694
|
+
reachableExecutableDefinitions,
|
|
581
695
|
);
|
|
582
696
|
RelayModernRecord.setLinkedRecordID(record, storageKey, reactFlightID);
|
|
583
697
|
}
|
|
@@ -783,9 +897,6 @@ class RelayResponseNormalizer {
|
|
|
783
897
|
}
|
|
784
898
|
}
|
|
785
899
|
|
|
786
|
-
|
|
787
|
-
'RelayResponseNormalizer.normalize',
|
|
900
|
+
module.exports = {
|
|
788
901
|
normalize,
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
module.exports = {normalize: instrumentedNormalize};
|
|
902
|
+
};
|
|
@@ -19,7 +19,9 @@ const {getType} = require('./RelayModernRecord');
|
|
|
19
19
|
import type {ReactFlightPayloadData} from '../network/RelayNetworkTypes';
|
|
20
20
|
import type {ReactFlightClientResponse, Record} from './RelayStoreTypes';
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
// Reachable (client) executable definitions encountered while server component
|
|
23
|
+
// rendering
|
|
24
|
+
const REACT_FLIGHT_EXECUTABLE_DEFINITIONS_STORAGE_KEY = 'executableDefinitions';
|
|
23
25
|
const REACT_FLIGHT_TREE_STORAGE_KEY = 'tree';
|
|
24
26
|
const REACT_FLIGHT_TYPE_NAME = 'ReactFlightComponent';
|
|
25
27
|
|
|
@@ -29,8 +31,11 @@ function refineToReactFlightPayloadData(
|
|
|
29
31
|
if (
|
|
30
32
|
payload == null ||
|
|
31
33
|
typeof payload !== 'object' ||
|
|
32
|
-
|
|
33
|
-
!Array.isArray(payload.
|
|
34
|
+
typeof payload.status !== 'string' ||
|
|
35
|
+
(!Array.isArray(payload.tree) && payload.tree !== null) ||
|
|
36
|
+
!Array.isArray(payload.queries) ||
|
|
37
|
+
!Array.isArray(payload.fragments) ||
|
|
38
|
+
!Array.isArray(payload.errors)
|
|
34
39
|
) {
|
|
35
40
|
return null;
|
|
36
41
|
}
|
|
@@ -56,7 +61,7 @@ function getReactFlightClientResponse(
|
|
|
56
61
|
}
|
|
57
62
|
|
|
58
63
|
module.exports = {
|
|
59
|
-
|
|
64
|
+
REACT_FLIGHT_EXECUTABLE_DEFINITIONS_STORAGE_KEY,
|
|
60
65
|
REACT_FLIGHT_TREE_STORAGE_KEY,
|
|
61
66
|
REACT_FLIGHT_TYPE_NAME,
|
|
62
67
|
getReactFlightClientResponse,
|
|
@@ -12,20 +12,22 @@
|
|
|
12
12
|
|
|
13
13
|
'use strict';
|
|
14
14
|
|
|
15
|
+
const RelayFeatureFlags = require('../util/RelayFeatureFlags');
|
|
15
16
|
const RelayReader = require('./RelayReader');
|
|
16
17
|
|
|
17
18
|
const deepFreeze = require('../util/deepFreeze');
|
|
18
19
|
const hasOverlappingIDs = require('./hasOverlappingIDs');
|
|
19
|
-
const isEmptyObject = require('../util/isEmptyObject');
|
|
20
20
|
const recycleNodesInto = require('../util/recycleNodesInto');
|
|
21
21
|
|
|
22
22
|
import type {Disposable} from '../util/RelayRuntimeTypes';
|
|
23
23
|
import type {
|
|
24
|
+
LogFunction,
|
|
25
|
+
OperationDescriptor,
|
|
26
|
+
DataIDSet,
|
|
24
27
|
RecordSource,
|
|
25
28
|
RequestDescriptor,
|
|
26
29
|
Snapshot,
|
|
27
30
|
StoreSubscriptions,
|
|
28
|
-
UpdatedRecords,
|
|
29
31
|
} from './RelayStoreTypes';
|
|
30
32
|
|
|
31
33
|
type Subscription = {|
|
|
@@ -37,9 +39,11 @@ type Subscription = {|
|
|
|
37
39
|
|
|
38
40
|
class RelayStoreSubscriptions implements StoreSubscriptions {
|
|
39
41
|
_subscriptions: Set<Subscription>;
|
|
42
|
+
__log: ?LogFunction;
|
|
40
43
|
|
|
41
|
-
constructor() {
|
|
44
|
+
constructor(log?: ?LogFunction) {
|
|
42
45
|
this._subscriptions = new Set();
|
|
46
|
+
this.__log = log;
|
|
43
47
|
}
|
|
44
48
|
|
|
45
49
|
subscribe(
|
|
@@ -65,7 +69,7 @@ class RelayStoreSubscriptions implements StoreSubscriptions {
|
|
|
65
69
|
// but its base has changed (we just applied a final payload): recompute
|
|
66
70
|
// a backup so that we can later restore to the state the subscription
|
|
67
71
|
// should be in.
|
|
68
|
-
// - stale=false: This subscription was restored to the same value
|
|
72
|
+
// - stale=false: This subscription was restored to the same value as
|
|
69
73
|
// `snapshot`. That means this subscription does *not* have changes relative
|
|
70
74
|
// to its base, so the current `snapshot` is valid to use as a backup.
|
|
71
75
|
if (!subscription.stale) {
|
|
@@ -103,16 +107,18 @@ class RelayStoreSubscriptions implements StoreSubscriptions {
|
|
|
103
107
|
|
|
104
108
|
updateSubscriptions(
|
|
105
109
|
source: RecordSource,
|
|
106
|
-
updatedRecordIDs:
|
|
110
|
+
updatedRecordIDs: DataIDSet,
|
|
107
111
|
updatedOwners: Array<RequestDescriptor>,
|
|
112
|
+
sourceOperation?: OperationDescriptor,
|
|
108
113
|
) {
|
|
109
|
-
const hasUpdatedRecords =
|
|
114
|
+
const hasUpdatedRecords = updatedRecordIDs.size !== 0;
|
|
110
115
|
this._subscriptions.forEach(subscription => {
|
|
111
116
|
const owner = this._updateSubscription(
|
|
112
117
|
source,
|
|
113
118
|
subscription,
|
|
114
119
|
updatedRecordIDs,
|
|
115
120
|
hasUpdatedRecords,
|
|
121
|
+
sourceOperation,
|
|
116
122
|
);
|
|
117
123
|
if (owner != null) {
|
|
118
124
|
updatedOwners.push(owner);
|
|
@@ -131,8 +137,9 @@ class RelayStoreSubscriptions implements StoreSubscriptions {
|
|
|
131
137
|
_updateSubscription(
|
|
132
138
|
source: RecordSource,
|
|
133
139
|
subscription: Subscription,
|
|
134
|
-
updatedRecordIDs:
|
|
140
|
+
updatedRecordIDs: DataIDSet,
|
|
135
141
|
hasUpdatedRecords: boolean,
|
|
142
|
+
sourceOperation?: OperationDescriptor,
|
|
136
143
|
): ?RequestDescriptor {
|
|
137
144
|
const {backup, callback, snapshot, stale} = subscription;
|
|
138
145
|
const hasOverlappingUpdates =
|
|
@@ -159,6 +166,14 @@ class RelayStoreSubscriptions implements StoreSubscriptions {
|
|
|
159
166
|
subscription.snapshot = nextSnapshot;
|
|
160
167
|
subscription.stale = false;
|
|
161
168
|
if (nextSnapshot.data !== snapshot.data) {
|
|
169
|
+
if (this.__log && RelayFeatureFlags.ENABLE_NOTIFY_SUBSCRIPTION) {
|
|
170
|
+
this.__log({
|
|
171
|
+
name: 'store.notify.subscription',
|
|
172
|
+
sourceOperation,
|
|
173
|
+
snapshot,
|
|
174
|
+
nextSnapshot,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
162
177
|
callback(nextSnapshot);
|
|
163
178
|
return snapshot.selector.owner;
|
|
164
179
|
}
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
'use strict';
|
|
14
14
|
|
|
15
|
+
const RelayFeatureFlags = require('../util/RelayFeatureFlags');
|
|
15
16
|
const RelayReader = require('./RelayReader');
|
|
16
17
|
|
|
17
18
|
const deepFreeze = require('../util/deepFreeze');
|
|
@@ -19,12 +20,13 @@ const recycleNodesInto = require('../util/recycleNodesInto');
|
|
|
19
20
|
|
|
20
21
|
import type {DataID, Disposable} from '../util/RelayRuntimeTypes';
|
|
21
22
|
import type {
|
|
22
|
-
|
|
23
|
+
LogFunction,
|
|
24
|
+
OperationDescriptor,
|
|
23
25
|
RecordSource,
|
|
24
26
|
RequestDescriptor,
|
|
25
27
|
Snapshot,
|
|
26
28
|
StoreSubscriptions,
|
|
27
|
-
|
|
29
|
+
DataIDSet,
|
|
28
30
|
} from './RelayStoreTypes';
|
|
29
31
|
|
|
30
32
|
type Subscription = {|
|
|
@@ -40,12 +42,14 @@ class RelayStoreSubscriptionsUsingMapByID implements StoreSubscriptions {
|
|
|
40
42
|
_snapshotRevision: number;
|
|
41
43
|
_subscriptionsByDataId: Map<DataID, Set<Subscription>>;
|
|
42
44
|
_staleSubscriptions: Set<Subscription>;
|
|
45
|
+
__log: ?LogFunction;
|
|
43
46
|
|
|
44
|
-
constructor() {
|
|
47
|
+
constructor(log?: ?LogFunction) {
|
|
45
48
|
this._notifiedRevision = 0;
|
|
46
49
|
this._snapshotRevision = 0;
|
|
47
50
|
this._subscriptionsByDataId = new Map();
|
|
48
51
|
this._staleSubscriptions = new Set();
|
|
52
|
+
this.__log = log;
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
subscribe(
|
|
@@ -60,7 +64,7 @@ class RelayStoreSubscriptionsUsingMapByID implements StoreSubscriptions {
|
|
|
60
64
|
snapshot,
|
|
61
65
|
};
|
|
62
66
|
const dispose = () => {
|
|
63
|
-
for (const dataId
|
|
67
|
+
for (const dataId of snapshot.seenRecords) {
|
|
64
68
|
const subscriptionsForDataId = this._subscriptionsByDataId.get(dataId);
|
|
65
69
|
if (subscriptionsForDataId != null) {
|
|
66
70
|
subscriptionsForDataId.delete(subscription);
|
|
@@ -71,7 +75,7 @@ class RelayStoreSubscriptionsUsingMapByID implements StoreSubscriptions {
|
|
|
71
75
|
}
|
|
72
76
|
};
|
|
73
77
|
|
|
74
|
-
for (const dataId
|
|
78
|
+
for (const dataId of snapshot.seenRecords) {
|
|
75
79
|
const subscriptionsForDataId = this._subscriptionsByDataId.get(dataId);
|
|
76
80
|
if (subscriptionsForDataId != null) {
|
|
77
81
|
subscriptionsForDataId.add(subscription);
|
|
@@ -150,11 +154,12 @@ class RelayStoreSubscriptionsUsingMapByID implements StoreSubscriptions {
|
|
|
150
154
|
|
|
151
155
|
updateSubscriptions(
|
|
152
156
|
source: RecordSource,
|
|
153
|
-
updatedRecordIDs:
|
|
157
|
+
updatedRecordIDs: DataIDSet,
|
|
154
158
|
updatedOwners: Array<RequestDescriptor>,
|
|
159
|
+
sourceOperation?: OperationDescriptor,
|
|
155
160
|
) {
|
|
156
161
|
this._notifiedRevision++;
|
|
157
|
-
|
|
162
|
+
updatedRecordIDs.forEach(updatedRecordId => {
|
|
158
163
|
const subcriptionsForDataId = this._subscriptionsByDataId.get(
|
|
159
164
|
updatedRecordId,
|
|
160
165
|
);
|
|
@@ -165,7 +170,12 @@ class RelayStoreSubscriptionsUsingMapByID implements StoreSubscriptions {
|
|
|
165
170
|
if (subscription.notifiedRevision === this._notifiedRevision) {
|
|
166
171
|
return;
|
|
167
172
|
}
|
|
168
|
-
const owner = this._updateSubscription(
|
|
173
|
+
const owner = this._updateSubscription(
|
|
174
|
+
source,
|
|
175
|
+
subscription,
|
|
176
|
+
false,
|
|
177
|
+
sourceOperation,
|
|
178
|
+
);
|
|
169
179
|
if (owner != null) {
|
|
170
180
|
updatedOwners.push(owner);
|
|
171
181
|
}
|
|
@@ -175,7 +185,12 @@ class RelayStoreSubscriptionsUsingMapByID implements StoreSubscriptions {
|
|
|
175
185
|
if (subscription.notifiedRevision === this._notifiedRevision) {
|
|
176
186
|
return;
|
|
177
187
|
}
|
|
178
|
-
const owner = this._updateSubscription(
|
|
188
|
+
const owner = this._updateSubscription(
|
|
189
|
+
source,
|
|
190
|
+
subscription,
|
|
191
|
+
true,
|
|
192
|
+
sourceOperation,
|
|
193
|
+
);
|
|
179
194
|
if (owner != null) {
|
|
180
195
|
updatedOwners.push(owner);
|
|
181
196
|
}
|
|
@@ -196,6 +211,7 @@ class RelayStoreSubscriptionsUsingMapByID implements StoreSubscriptions {
|
|
|
196
211
|
source: RecordSource,
|
|
197
212
|
subscription: Subscription,
|
|
198
213
|
stale: boolean,
|
|
214
|
+
sourceOperation?: OperationDescriptor,
|
|
199
215
|
): ?RequestDescriptor {
|
|
200
216
|
const {backup, callback, snapshot} = subscription;
|
|
201
217
|
let nextSnapshot: Snapshot =
|
|
@@ -220,6 +236,14 @@ class RelayStoreSubscriptionsUsingMapByID implements StoreSubscriptions {
|
|
|
220
236
|
this._updateSubscriptionsMap(subscription, prevSeenRecords);
|
|
221
237
|
|
|
222
238
|
if (nextSnapshot.data !== snapshot.data) {
|
|
239
|
+
if (this.__log && RelayFeatureFlags.ENABLE_NOTIFY_SUBSCRIPTION) {
|
|
240
|
+
this.__log({
|
|
241
|
+
name: 'store.notify.subscription',
|
|
242
|
+
sourceOperation,
|
|
243
|
+
snapshot,
|
|
244
|
+
nextSnapshot,
|
|
245
|
+
});
|
|
246
|
+
}
|
|
223
247
|
callback(nextSnapshot);
|
|
224
248
|
return snapshot.selector.owner;
|
|
225
249
|
}
|
|
@@ -233,9 +257,9 @@ class RelayStoreSubscriptionsUsingMapByID implements StoreSubscriptions {
|
|
|
233
257
|
*/
|
|
234
258
|
_updateSubscriptionsMap(
|
|
235
259
|
subscription: Subscription,
|
|
236
|
-
prevSeenRecords:
|
|
260
|
+
prevSeenRecords: DataIDSet,
|
|
237
261
|
) {
|
|
238
|
-
for (const dataId
|
|
262
|
+
for (const dataId of prevSeenRecords) {
|
|
239
263
|
const subscriptionsForDataId = this._subscriptionsByDataId.get(dataId);
|
|
240
264
|
if (subscriptionsForDataId != null) {
|
|
241
265
|
subscriptionsForDataId.delete(subscription);
|
|
@@ -245,7 +269,7 @@ class RelayStoreSubscriptionsUsingMapByID implements StoreSubscriptions {
|
|
|
245
269
|
}
|
|
246
270
|
}
|
|
247
271
|
|
|
248
|
-
for (const dataId
|
|
272
|
+
for (const dataId of subscription.snapshot.seenRecords) {
|
|
249
273
|
const subscriptionsForDataId = this._subscriptionsByDataId.get(dataId);
|
|
250
274
|
if (subscriptionsForDataId != null) {
|
|
251
275
|
subscriptionsForDataId.add(subscription);
|