relay-runtime 10.0.0 → 10.1.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/RelayDefaultHandlerProvider.js.flow +6 -0
- package/handlers/connection/MutationHandlers.js.flow +121 -3
- package/index.js +1 -1
- package/index.js.flow +16 -1
- package/lib/handlers/RelayDefaultHandlerProvider.js +9 -0
- package/lib/handlers/connection/MutationHandlers.js +147 -14
- package/lib/index.js +7 -0
- package/lib/mutations/RelayDeclarativeMutationConfig.js +5 -7
- package/lib/mutations/commitMutation.js +1 -4
- package/lib/mutations/validateMutation.js +28 -12
- package/lib/network/RelayQueryResponseCache.js +3 -7
- package/lib/query/GraphQLTag.js +2 -1
- package/lib/query/fetchQuery.js +2 -3
- package/lib/query/fetchQueryInternal.js +2 -3
- package/lib/store/DataChecker.js +85 -10
- package/lib/store/RelayConcreteVariables.js +2 -6
- package/lib/store/RelayModernEnvironment.js +81 -72
- package/lib/store/RelayModernFragmentSpecResolver.js +14 -7
- package/lib/store/RelayModernOperationDescriptor.js +6 -5
- package/lib/store/RelayModernQueryExecutor.js +46 -33
- package/lib/store/RelayModernRecord.js +3 -7
- package/lib/store/RelayModernStore.js +45 -143
- package/lib/store/RelayOperationTracker.js +7 -9
- package/lib/store/RelayOptimisticRecordSource.js +2 -6
- package/lib/store/RelayPublishQueue.js +1 -1
- package/lib/store/RelayReader.js +200 -49
- package/lib/store/RelayRecordSourceMapImpl.js +3 -5
- package/lib/store/RelayReferenceMarker.js +87 -5
- package/lib/store/RelayResponseNormalizer.js +123 -54
- package/lib/store/RelayStoreReactFlightUtils.js +47 -0
- package/lib/store/RelayStoreSubscriptions.js +162 -0
- package/lib/store/RelayStoreSubscriptionsUsingMapByID.js +258 -0
- package/lib/store/StoreInspector.js +3 -9
- package/lib/store/createRelayContext.js +5 -0
- package/lib/store/defaultRequiredFieldLogger.js +18 -0
- package/lib/store/normalizeRelayPayload.js +2 -6
- package/lib/subscription/requestSubscription.js +2 -3
- package/lib/util/NormalizationNode.js +1 -5
- package/lib/util/RelayConcreteNode.js +2 -0
- package/lib/util/RelayFeatureFlags.js +6 -2
- package/lib/util/createPayloadFor3DField.js +2 -7
- package/lib/util/getFragmentIdentifier.js +12 -3
- package/lib/util/getOperation.js +33 -0
- package/lib/util/isEmptyObject.js +25 -0
- package/lib/util/recycleNodesInto.js +6 -9
- package/lib/util/reportMissingRequiredFields.js +48 -0
- package/mutations/commitMutation.js.flow +1 -2
- package/mutations/validateMutation.js.flow +34 -5
- package/network/RelayNetworkTypes.js.flow +22 -0
- package/package.json +2 -2
- package/query/GraphQLTag.js.flow +3 -1
- package/query/fetchQuery.js.flow +2 -2
- package/query/fetchQueryInternal.js.flow +0 -5
- package/relay-runtime.js +2 -2
- package/relay-runtime.min.js +2 -2
- package/store/DataChecker.js.flow +68 -2
- package/store/RelayModernEnvironment.js.flow +107 -87
- package/store/RelayModernFragmentSpecResolver.js.flow +13 -1
- package/store/RelayModernOperationDescriptor.js.flow +5 -1
- package/store/RelayModernQueryExecutor.js.flow +47 -23
- package/store/RelayModernStore.js.flow +40 -114
- package/store/RelayPublishQueue.js.flow +1 -1
- package/store/RelayReader.js.flow +184 -27
- package/store/RelayReferenceMarker.js.flow +72 -5
- package/store/RelayResponseNormalizer.js.flow +140 -50
- package/store/RelayStoreReactFlightUtils.js.flow +64 -0
- package/store/RelayStoreSubscriptions.js.flow +168 -0
- package/store/RelayStoreSubscriptionsUsingMapByID.js.flow +259 -0
- package/store/RelayStoreTypes.js.flow +130 -37
- package/store/StoreInspector.js.flow +1 -3
- package/store/createRelayContext.js.flow +3 -0
- package/store/defaultRequiredFieldLogger.js.flow +23 -0
- package/subscription/requestSubscription.js.flow +5 -2
- package/util/NormalizationNode.js.flow +17 -2
- package/util/ReaderNode.js.flow +20 -1
- package/util/RelayConcreteNode.js.flow +6 -0
- package/util/RelayFeatureFlags.js.flow +10 -1
- package/util/getFragmentIdentifier.js.flow +33 -9
- package/util/getOperation.js.flow +40 -0
- package/util/isEmptyObject.js.flow +25 -0
- package/util/recycleNodesInto.js.flow +13 -8
- package/util/reportMissingRequiredFields.js.flow +51 -0
|
@@ -19,6 +19,7 @@ const RelayObservable = require('../network/RelayObservable');
|
|
|
19
19
|
const RelayRecordSource = require('./RelayRecordSource');
|
|
20
20
|
const RelayResponseNormalizer = require('./RelayResponseNormalizer');
|
|
21
21
|
|
|
22
|
+
const getOperation = require('../util/getOperation');
|
|
22
23
|
const invariant = require('invariant');
|
|
23
24
|
const stableCopy = require('../util/stableCopy');
|
|
24
25
|
const warning = require('warning');
|
|
@@ -46,6 +47,7 @@ import type {
|
|
|
46
47
|
OptimisticResponseConfig,
|
|
47
48
|
OptimisticUpdate,
|
|
48
49
|
PublishQueue,
|
|
50
|
+
ReactFlightPayloadDeserializer,
|
|
49
51
|
Record,
|
|
50
52
|
RelayResponsePayload,
|
|
51
53
|
SelectorStoreUpdater,
|
|
@@ -54,10 +56,12 @@ import type {
|
|
|
54
56
|
} from '../store/RelayStoreTypes';
|
|
55
57
|
import type {
|
|
56
58
|
NormalizationLinkedField,
|
|
57
|
-
|
|
59
|
+
NormalizationOperation,
|
|
60
|
+
NormalizationRootNode,
|
|
58
61
|
NormalizationSelectableNode,
|
|
62
|
+
NormalizationSplitOperation,
|
|
59
63
|
} from '../util/NormalizationNode';
|
|
60
|
-
import type {DataID, Variables} from '../util/RelayRuntimeTypes';
|
|
64
|
+
import type {DataID, Variables, Disposable} from '../util/RelayRuntimeTypes';
|
|
61
65
|
import type {GetDataID} from './RelayResponseNormalizer';
|
|
62
66
|
import type {NormalizationOptions} from './RelayResponseNormalizer';
|
|
63
67
|
|
|
@@ -70,6 +74,7 @@ export type ExecuteConfig = {|
|
|
|
70
74
|
+operationTracker?: ?OperationTracker,
|
|
71
75
|
+optimisticConfig: ?OptimisticResponseConfig,
|
|
72
76
|
+publishQueue: PublishQueue,
|
|
77
|
+
+reactFlightPayloadDeserializer?: ?ReactFlightPayloadDeserializer,
|
|
73
78
|
+scheduler?: ?TaskScheduler,
|
|
74
79
|
+sink: Sink<GraphQLResponse>,
|
|
75
80
|
+source: RelayObservable<GraphQLResponse>,
|
|
@@ -126,6 +131,7 @@ class Executor {
|
|
|
126
131
|
_optimisticUpdates: null | Array<OptimisticUpdate>;
|
|
127
132
|
_pendingModulePayloadsCount: number;
|
|
128
133
|
_publishQueue: PublishQueue;
|
|
134
|
+
_reactFlightPayloadDeserializer: ?ReactFlightPayloadDeserializer;
|
|
129
135
|
_scheduler: ?TaskScheduler;
|
|
130
136
|
_sink: Sink<GraphQLResponse>;
|
|
131
137
|
_source: Map<
|
|
@@ -136,6 +142,7 @@ class Executor {
|
|
|
136
142
|
_store: Store;
|
|
137
143
|
_subscriptions: Map<number, Subscription>;
|
|
138
144
|
_updater: ?SelectorStoreUpdater;
|
|
145
|
+
_retainDisposable: ?Disposable;
|
|
139
146
|
+_isClientPayload: boolean;
|
|
140
147
|
|
|
141
148
|
constructor({
|
|
@@ -153,6 +160,7 @@ class Executor {
|
|
|
153
160
|
treatMissingFieldsAsNull,
|
|
154
161
|
getDataID,
|
|
155
162
|
isClientPayload,
|
|
163
|
+
reactFlightPayloadDeserializer,
|
|
156
164
|
}: ExecuteConfig): void {
|
|
157
165
|
this._getDataID = getDataID;
|
|
158
166
|
this._treatMissingFieldsAsNull = treatMissingFieldsAsNull;
|
|
@@ -175,6 +183,7 @@ class Executor {
|
|
|
175
183
|
this._subscriptions = new Map();
|
|
176
184
|
this._updater = updater;
|
|
177
185
|
this._isClientPayload = isClientPayload === true;
|
|
186
|
+
this._reactFlightPayloadDeserializer = reactFlightPayloadDeserializer;
|
|
178
187
|
|
|
179
188
|
const id = this._nextSubscriptionId++;
|
|
180
189
|
source.subscribe({
|
|
@@ -223,6 +232,10 @@ class Executor {
|
|
|
223
232
|
}
|
|
224
233
|
this._incrementalResults.clear();
|
|
225
234
|
this._completeOperationTracker();
|
|
235
|
+
if (this._retainDisposable) {
|
|
236
|
+
this._retainDisposable.dispose();
|
|
237
|
+
this._retainDisposable = null;
|
|
238
|
+
}
|
|
226
239
|
}
|
|
227
240
|
|
|
228
241
|
_updateActiveState(): void {
|
|
@@ -423,19 +436,22 @@ class Executor {
|
|
|
423
436
|
|
|
424
437
|
// In theory this doesn't preserve the ordering of the batch.
|
|
425
438
|
// The idea is that a batch is always:
|
|
426
|
-
// * at
|
|
427
|
-
// * followed zero or more incremental payloads
|
|
439
|
+
// * at most one non-incremental payload
|
|
440
|
+
// * followed by zero or more incremental payloads
|
|
428
441
|
// The non-incremental payload can appear if the server sends a batch
|
|
429
|
-
//
|
|
442
|
+
// with the initial payload followed by some early-to-resolve incremental
|
|
430
443
|
// payloads (although, can that even happen?)
|
|
431
444
|
if (nonIncrementalResponses.length > 0) {
|
|
432
445
|
const payloadFollowups = this._processResponses(nonIncrementalResponses);
|
|
433
|
-
// Please note
|
|
446
|
+
// Please note that we're passing `this._operation` to the publish
|
|
434
447
|
// queue here, which will later passed to the store (via notify)
|
|
435
|
-
// to indicate that this is an operation that
|
|
448
|
+
// to indicate that this is an operation that caused the store to update
|
|
436
449
|
const updatedOwners = this._publishQueue.run(this._operation);
|
|
437
450
|
this._updateOperationTracker(updatedOwners);
|
|
438
451
|
this._processPayloadFollowups(payloadFollowups);
|
|
452
|
+
if (this._incrementalPayloadsPending && !this._retainDisposable) {
|
|
453
|
+
this._retainDisposable = this._store.retain(this._operation);
|
|
454
|
+
}
|
|
439
455
|
}
|
|
440
456
|
|
|
441
457
|
if (incrementalResponses.length > 0) {
|
|
@@ -474,6 +490,7 @@ class Executor {
|
|
|
474
490
|
{
|
|
475
491
|
getDataID: this._getDataID,
|
|
476
492
|
path: [],
|
|
493
|
+
reactFlightPayloadDeserializer: this._reactFlightPayloadDeserializer,
|
|
477
494
|
treatMissingFieldsAsNull,
|
|
478
495
|
},
|
|
479
496
|
);
|
|
@@ -525,11 +542,11 @@ class Executor {
|
|
|
525
542
|
moduleImportPayload,
|
|
526
543
|
);
|
|
527
544
|
} else {
|
|
528
|
-
const
|
|
545
|
+
const moduleImportOptimisticUpdates = this._processOptimisticModuleImport(
|
|
529
546
|
operation,
|
|
530
547
|
moduleImportPayload,
|
|
531
548
|
);
|
|
532
|
-
optimisticUpdates.push(...
|
|
549
|
+
optimisticUpdates.push(...moduleImportOptimisticUpdates);
|
|
533
550
|
}
|
|
534
551
|
}
|
|
535
552
|
}
|
|
@@ -551,15 +568,17 @@ class Executor {
|
|
|
551
568
|
{
|
|
552
569
|
getDataID: this._getDataID,
|
|
553
570
|
path: moduleImportPayload.path,
|
|
571
|
+
reactFlightPayloadDeserializer: this._reactFlightPayloadDeserializer,
|
|
554
572
|
treatMissingFieldsAsNull: this._treatMissingFieldsAsNull,
|
|
555
573
|
},
|
|
556
574
|
);
|
|
557
575
|
}
|
|
558
576
|
|
|
559
577
|
_processOptimisticModuleImport(
|
|
560
|
-
|
|
578
|
+
normalizationRootNode: NormalizationRootNode,
|
|
561
579
|
moduleImportPayload: ModuleImportPayload,
|
|
562
580
|
): $ReadOnlyArray<OptimisticUpdate> {
|
|
581
|
+
const operation = getOperation(normalizationRootNode);
|
|
563
582
|
const optimisticUpdates = [];
|
|
564
583
|
const modulePayload = this._normalizeModuleImport(
|
|
565
584
|
moduleImportPayload,
|
|
@@ -585,22 +604,22 @@ class Executor {
|
|
|
585
604
|
if (operation == null || this._state !== 'started') {
|
|
586
605
|
return;
|
|
587
606
|
}
|
|
588
|
-
const
|
|
607
|
+
const moduleImportOptimisticUpdates = this._processOptimisticModuleImport(
|
|
589
608
|
operation,
|
|
590
609
|
moduleImportPayload,
|
|
591
610
|
);
|
|
592
|
-
|
|
611
|
+
moduleImportOptimisticUpdates.forEach(update =>
|
|
593
612
|
this._publishQueue.applyUpdate(update),
|
|
594
613
|
);
|
|
595
614
|
if (this._optimisticUpdates == null) {
|
|
596
615
|
warning(
|
|
597
616
|
false,
|
|
598
|
-
'RelayModernQueryExecutor: Unexpected ModuleImport
|
|
617
|
+
'RelayModernQueryExecutor: Unexpected ModuleImport optimistic ' +
|
|
599
618
|
'update in operation %s.' +
|
|
600
619
|
this._operation.request.node.params.name,
|
|
601
620
|
);
|
|
602
621
|
} else {
|
|
603
|
-
this._optimisticUpdates.push(...
|
|
622
|
+
this._optimisticUpdates.push(...moduleImportOptimisticUpdates);
|
|
604
623
|
this._publishQueue.run();
|
|
605
624
|
}
|
|
606
625
|
});
|
|
@@ -624,8 +643,9 @@ class Executor {
|
|
|
624
643
|
ROOT_TYPE,
|
|
625
644
|
{
|
|
626
645
|
getDataID: this._getDataID,
|
|
627
|
-
treatMissingFieldsAsNull: this._treatMissingFieldsAsNull,
|
|
628
646
|
path: [],
|
|
647
|
+
reactFlightPayloadDeserializer: this._reactFlightPayloadDeserializer,
|
|
648
|
+
treatMissingFieldsAsNull: this._treatMissingFieldsAsNull,
|
|
629
649
|
},
|
|
630
650
|
);
|
|
631
651
|
this._publishQueue.commitPayload(
|
|
@@ -737,13 +757,12 @@ class Executor {
|
|
|
737
757
|
moduleImportPayload: ModuleImportPayload,
|
|
738
758
|
operationLoader: OperationLoader,
|
|
739
759
|
): void {
|
|
740
|
-
const
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
if (syncOperation != null) {
|
|
760
|
+
const node = operationLoader.get(moduleImportPayload.operationReference);
|
|
761
|
+
if (node != null) {
|
|
762
|
+
const operation = getOperation(node);
|
|
744
763
|
// If the operation module is available synchronously, normalize the
|
|
745
764
|
// data synchronously.
|
|
746
|
-
this._handleModuleImportPayload(moduleImportPayload,
|
|
765
|
+
this._handleModuleImportPayload(moduleImportPayload, operation);
|
|
747
766
|
this._maybeCompleteSubscriptionOperationTracking();
|
|
748
767
|
} else {
|
|
749
768
|
// Otherwise load the operation module and schedule a task to normalize
|
|
@@ -766,10 +785,13 @@ class Executor {
|
|
|
766
785
|
.then(resolve, reject);
|
|
767
786
|
}),
|
|
768
787
|
)
|
|
769
|
-
.map((operation: ?
|
|
788
|
+
.map((operation: ?NormalizationRootNode) => {
|
|
770
789
|
if (operation != null) {
|
|
771
790
|
this._schedule(() => {
|
|
772
|
-
this._handleModuleImportPayload(
|
|
791
|
+
this._handleModuleImportPayload(
|
|
792
|
+
moduleImportPayload,
|
|
793
|
+
getOperation(operation),
|
|
794
|
+
);
|
|
773
795
|
});
|
|
774
796
|
}
|
|
775
797
|
})
|
|
@@ -789,7 +811,7 @@ class Executor {
|
|
|
789
811
|
|
|
790
812
|
_handleModuleImportPayload(
|
|
791
813
|
moduleImportPayload: ModuleImportPayload,
|
|
792
|
-
operation: NormalizationSplitOperation,
|
|
814
|
+
operation: NormalizationSplitOperation | NormalizationOperation,
|
|
793
815
|
): void {
|
|
794
816
|
const relayPayload = this._normalizeModuleImport(
|
|
795
817
|
moduleImportPayload,
|
|
@@ -997,6 +1019,7 @@ class Executor {
|
|
|
997
1019
|
{
|
|
998
1020
|
getDataID: this._getDataID,
|
|
999
1021
|
path: placeholder.path,
|
|
1022
|
+
reactFlightPayloadDeserializer: this._reactFlightPayloadDeserializer,
|
|
1000
1023
|
treatMissingFieldsAsNull: this._treatMissingFieldsAsNull,
|
|
1001
1024
|
},
|
|
1002
1025
|
);
|
|
@@ -1211,6 +1234,7 @@ class Executor {
|
|
|
1211
1234
|
const relayPayload = normalizeResponse(response, selector, typeName, {
|
|
1212
1235
|
getDataID: this._getDataID,
|
|
1213
1236
|
path: [...normalizationPath, responseKey, String(itemIndex)],
|
|
1237
|
+
reactFlightPayloadDeserializer: this._reactFlightPayloadDeserializer,
|
|
1214
1238
|
treatMissingFieldsAsNull: this._treatMissingFieldsAsNull,
|
|
1215
1239
|
});
|
|
1216
1240
|
return {
|
|
@@ -13,18 +13,20 @@
|
|
|
13
13
|
'use strict';
|
|
14
14
|
|
|
15
15
|
const DataChecker = require('./DataChecker');
|
|
16
|
+
const RelayFeatureFlags = require('../util/RelayFeatureFlags');
|
|
16
17
|
const RelayModernRecord = require('./RelayModernRecord');
|
|
17
18
|
const RelayOptimisticRecordSource = require('./RelayOptimisticRecordSource');
|
|
18
19
|
const RelayProfiler = require('../util/RelayProfiler');
|
|
19
20
|
const RelayReader = require('./RelayReader');
|
|
20
21
|
const RelayReferenceMarker = require('./RelayReferenceMarker');
|
|
22
|
+
const RelayStoreReactFlightUtils = require('./RelayStoreReactFlightUtils');
|
|
23
|
+
const RelayStoreSubscriptions = require('./RelayStoreSubscriptions');
|
|
24
|
+
const RelayStoreSubscriptionsUsingMapByID = require('./RelayStoreSubscriptionsUsingMapByID');
|
|
21
25
|
const RelayStoreUtils = require('./RelayStoreUtils');
|
|
22
26
|
|
|
23
27
|
const deepFreeze = require('../util/deepFreeze');
|
|
24
28
|
const defaultGetDataID = require('./defaultGetDataID');
|
|
25
|
-
const hasOverlappingIDs = require('./hasOverlappingIDs');
|
|
26
29
|
const invariant = require('invariant');
|
|
27
|
-
const recycleNodesInto = require('../util/recycleNodesInto');
|
|
28
30
|
const resolveImmediate = require('../util/resolveImmediate');
|
|
29
31
|
|
|
30
32
|
const {ROOT_ID, ROOT_TYPE} = require('./RelayStoreUtils');
|
|
@@ -45,6 +47,7 @@ import type {
|
|
|
45
47
|
SingularReaderSelector,
|
|
46
48
|
Snapshot,
|
|
47
49
|
Store,
|
|
50
|
+
StoreSubscriptions,
|
|
48
51
|
UpdatedRecords,
|
|
49
52
|
} from './RelayStoreTypes';
|
|
50
53
|
|
|
@@ -53,14 +56,6 @@ export opaque type InvalidationState = {|
|
|
|
53
56
|
invalidations: Map<DataID, ?number>,
|
|
54
57
|
|};
|
|
55
58
|
|
|
56
|
-
type Subscription = {
|
|
57
|
-
callback: (snapshot: Snapshot) => void,
|
|
58
|
-
snapshot: Snapshot,
|
|
59
|
-
stale: boolean,
|
|
60
|
-
backup: ?Snapshot,
|
|
61
|
-
...
|
|
62
|
-
};
|
|
63
|
-
|
|
64
59
|
type InvalidationSubscription = {|
|
|
65
60
|
callback: () => void,
|
|
66
61
|
invalidationState: InvalidationState,
|
|
@@ -90,7 +85,7 @@ class RelayModernStore implements Store {
|
|
|
90
85
|
_globalInvalidationEpoch: ?number;
|
|
91
86
|
_invalidationSubscriptions: Set<InvalidationSubscription>;
|
|
92
87
|
_invalidatedRecordIDs: Set<DataID>;
|
|
93
|
-
|
|
88
|
+
__log: ?LogFunction;
|
|
94
89
|
_queryCacheExpirationTime: ?number;
|
|
95
90
|
_operationLoader: ?OperationLoader;
|
|
96
91
|
_optimisticSource: ?MutableRecordSource;
|
|
@@ -106,7 +101,7 @@ class RelayModernStore implements Store {
|
|
|
106
101
|
|},
|
|
107
102
|
>;
|
|
108
103
|
_shouldScheduleGC: boolean;
|
|
109
|
-
|
|
104
|
+
_storeSubscriptions: StoreSubscriptions;
|
|
110
105
|
_updatedRecordIDs: UpdatedRecords;
|
|
111
106
|
|
|
112
107
|
constructor(
|
|
@@ -141,7 +136,7 @@ class RelayModernStore implements Store {
|
|
|
141
136
|
this._globalInvalidationEpoch = null;
|
|
142
137
|
this._invalidationSubscriptions = new Set();
|
|
143
138
|
this._invalidatedRecordIDs = new Set();
|
|
144
|
-
this.
|
|
139
|
+
this.__log = options?.log ?? null;
|
|
145
140
|
this._queryCacheExpirationTime = options?.queryCacheExpirationTime;
|
|
146
141
|
this._operationLoader = options?.operationLoader ?? null;
|
|
147
142
|
this._optimisticSource = null;
|
|
@@ -149,7 +144,10 @@ class RelayModernStore implements Store {
|
|
|
149
144
|
this._releaseBuffer = [];
|
|
150
145
|
this._roots = new Map();
|
|
151
146
|
this._shouldScheduleGC = false;
|
|
152
|
-
this.
|
|
147
|
+
this._storeSubscriptions =
|
|
148
|
+
RelayFeatureFlags.ENABLE_STORE_SUBSCRIPTIONS_REFACTOR === true
|
|
149
|
+
? new RelayStoreSubscriptionsUsingMapByID()
|
|
150
|
+
: new RelayStoreSubscriptions();
|
|
153
151
|
this._updatedRecordIDs = {};
|
|
154
152
|
|
|
155
153
|
initializeRecordSource(this._recordSource);
|
|
@@ -232,7 +230,7 @@ class RelayModernStore implements Store {
|
|
|
232
230
|
|
|
233
231
|
if (rootEntryIsStale) {
|
|
234
232
|
this._roots.delete(id);
|
|
235
|
-
this.
|
|
233
|
+
this.scheduleGC();
|
|
236
234
|
} else {
|
|
237
235
|
this._releaseBuffer.push(id);
|
|
238
236
|
|
|
@@ -242,7 +240,7 @@ class RelayModernStore implements Store {
|
|
|
242
240
|
if (this._releaseBuffer.length > this._gcReleaseBufferSize) {
|
|
243
241
|
const _id = this._releaseBuffer.shift();
|
|
244
242
|
this._roots.delete(_id);
|
|
245
|
-
this.
|
|
243
|
+
this.scheduleGC();
|
|
246
244
|
}
|
|
247
245
|
}
|
|
248
246
|
}
|
|
@@ -285,7 +283,7 @@ class RelayModernStore implements Store {
|
|
|
285
283
|
sourceOperation?: OperationDescriptor,
|
|
286
284
|
invalidateStore?: boolean,
|
|
287
285
|
): $ReadOnlyArray<RequestDescriptor> {
|
|
288
|
-
const log = this.
|
|
286
|
+
const log = this.__log;
|
|
289
287
|
if (log != null) {
|
|
290
288
|
log({
|
|
291
289
|
name: 'store.notify.start',
|
|
@@ -302,12 +300,11 @@ class RelayModernStore implements Store {
|
|
|
302
300
|
|
|
303
301
|
const source = this.getSource();
|
|
304
302
|
const updatedOwners = [];
|
|
305
|
-
this.
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
});
|
|
303
|
+
this._storeSubscriptions.updateSubscriptions(
|
|
304
|
+
source,
|
|
305
|
+
this._updatedRecordIDs,
|
|
306
|
+
updatedOwners,
|
|
307
|
+
);
|
|
311
308
|
this._invalidationSubscriptions.forEach(subscription => {
|
|
312
309
|
this._updateInvalidationSubscription(
|
|
313
310
|
subscription,
|
|
@@ -375,7 +372,7 @@ class RelayModernStore implements Store {
|
|
|
375
372
|
);
|
|
376
373
|
// NOTE: log *after* processing the source so that even if a bad log function
|
|
377
374
|
// mutates the source, it doesn't affect Relay processing of it.
|
|
378
|
-
const log = this.
|
|
375
|
+
const log = this.__log;
|
|
379
376
|
if (log != null) {
|
|
380
377
|
log({
|
|
381
378
|
name: 'store.publish',
|
|
@@ -389,12 +386,7 @@ class RelayModernStore implements Store {
|
|
|
389
386
|
snapshot: Snapshot,
|
|
390
387
|
callback: (snapshot: Snapshot) => void,
|
|
391
388
|
): Disposable {
|
|
392
|
-
|
|
393
|
-
const dispose = () => {
|
|
394
|
-
this._subscriptions.delete(subscription);
|
|
395
|
-
};
|
|
396
|
-
this._subscriptions.add(subscription);
|
|
397
|
-
return {dispose};
|
|
389
|
+
return this._storeSubscriptions.subscribe(snapshot, callback);
|
|
398
390
|
}
|
|
399
391
|
|
|
400
392
|
holdGC(): Disposable {
|
|
@@ -407,7 +399,7 @@ class RelayModernStore implements Store {
|
|
|
407
399
|
if (this._gcHoldCounter > 0) {
|
|
408
400
|
this._gcHoldCounter--;
|
|
409
401
|
if (this._gcHoldCounter === 0 && this._shouldScheduleGC) {
|
|
410
|
-
this.
|
|
402
|
+
this.scheduleGC();
|
|
411
403
|
this._shouldScheduleGC = false;
|
|
412
404
|
}
|
|
413
405
|
}
|
|
@@ -424,42 +416,6 @@ class RelayModernStore implements Store {
|
|
|
424
416
|
return this._updatedRecordIDs;
|
|
425
417
|
}
|
|
426
418
|
|
|
427
|
-
// Returns the owner (RequestDescriptor) if the subscription was affected by the
|
|
428
|
-
// latest update, or null if it was not affected.
|
|
429
|
-
_updateSubscription(
|
|
430
|
-
source: RecordSource,
|
|
431
|
-
subscription: Subscription,
|
|
432
|
-
): ?RequestDescriptor {
|
|
433
|
-
const {backup, callback, snapshot, stale} = subscription;
|
|
434
|
-
const hasOverlappingUpdates = hasOverlappingIDs(
|
|
435
|
-
snapshot.seenRecords,
|
|
436
|
-
this._updatedRecordIDs,
|
|
437
|
-
);
|
|
438
|
-
if (!stale && !hasOverlappingUpdates) {
|
|
439
|
-
return;
|
|
440
|
-
}
|
|
441
|
-
let nextSnapshot: Snapshot =
|
|
442
|
-
hasOverlappingUpdates || !backup
|
|
443
|
-
? RelayReader.read(source, snapshot.selector)
|
|
444
|
-
: backup;
|
|
445
|
-
const nextData = recycleNodesInto(snapshot.data, nextSnapshot.data);
|
|
446
|
-
nextSnapshot = ({
|
|
447
|
-
data: nextData,
|
|
448
|
-
isMissingData: nextSnapshot.isMissingData,
|
|
449
|
-
seenRecords: nextSnapshot.seenRecords,
|
|
450
|
-
selector: nextSnapshot.selector,
|
|
451
|
-
}: Snapshot);
|
|
452
|
-
if (__DEV__) {
|
|
453
|
-
deepFreeze(nextSnapshot);
|
|
454
|
-
}
|
|
455
|
-
subscription.snapshot = nextSnapshot;
|
|
456
|
-
subscription.stale = false;
|
|
457
|
-
if (nextSnapshot.data !== snapshot.data) {
|
|
458
|
-
callback(nextSnapshot);
|
|
459
|
-
return snapshot.selector.owner;
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
|
|
463
419
|
lookupInvalidationState(dataIDs: $ReadOnlyArray<DataID>): InvalidationState {
|
|
464
420
|
const invalidations = new Map();
|
|
465
421
|
dataIDs.forEach(dataID => {
|
|
@@ -533,35 +489,13 @@ class RelayModernStore implements Store {
|
|
|
533
489
|
'RelayModernStore: Unexpected call to snapshot() while a previous ' +
|
|
534
490
|
'snapshot exists.',
|
|
535
491
|
);
|
|
536
|
-
const log = this.
|
|
492
|
+
const log = this.__log;
|
|
537
493
|
if (log != null) {
|
|
538
494
|
log({
|
|
539
495
|
name: 'store.snapshot',
|
|
540
496
|
});
|
|
541
497
|
}
|
|
542
|
-
this.
|
|
543
|
-
// Backup occurs after writing a new "final" payload(s) and before (re)applying
|
|
544
|
-
// optimistic changes. Each subscription's `snapshot` represents what was *last
|
|
545
|
-
// published to the subscriber*, which notably may include previous optimistic
|
|
546
|
-
// updates. Therefore a subscription can be in any of the following states:
|
|
547
|
-
// - stale=true: This subscription was restored to a different value than
|
|
548
|
-
// `snapshot`. That means this subscription has changes relative to its base,
|
|
549
|
-
// but its base has changed (we just applied a final payload): recompute
|
|
550
|
-
// a backup so that we can later restore to the state the subscription
|
|
551
|
-
// should be in.
|
|
552
|
-
// - stale=false: This subscription was restored to the same value than
|
|
553
|
-
// `snapshot`. That means this subscription does *not* have changes relative
|
|
554
|
-
// to its base, so the current `snapshot` is valid to use as a backup.
|
|
555
|
-
if (!subscription.stale) {
|
|
556
|
-
subscription.backup = subscription.snapshot;
|
|
557
|
-
return;
|
|
558
|
-
}
|
|
559
|
-
const snapshot = subscription.snapshot;
|
|
560
|
-
const backup = RelayReader.read(this.getSource(), snapshot.selector);
|
|
561
|
-
const nextData = recycleNodesInto(snapshot.data, backup.data);
|
|
562
|
-
(backup: $FlowFixMe).data = nextData; // backup owns the snapshot and can safely mutate
|
|
563
|
-
subscription.backup = backup;
|
|
564
|
-
});
|
|
498
|
+
this._storeSubscriptions.snapshotSubscriptions(this.getSource());
|
|
565
499
|
if (this._gcRun) {
|
|
566
500
|
this._gcRun = null;
|
|
567
501
|
this._shouldScheduleGC = true;
|
|
@@ -577,7 +511,7 @@ class RelayModernStore implements Store {
|
|
|
577
511
|
'RelayModernStore: Unexpected call to restore(), expected a snapshot ' +
|
|
578
512
|
'to exist (make sure to call snapshot()).',
|
|
579
513
|
);
|
|
580
|
-
const log = this.
|
|
514
|
+
const log = this.__log;
|
|
581
515
|
if (log != null) {
|
|
582
516
|
log({
|
|
583
517
|
name: 'store.restore',
|
|
@@ -585,28 +519,12 @@ class RelayModernStore implements Store {
|
|
|
585
519
|
}
|
|
586
520
|
this._optimisticSource = null;
|
|
587
521
|
if (this._shouldScheduleGC) {
|
|
588
|
-
this.
|
|
522
|
+
this.scheduleGC();
|
|
589
523
|
}
|
|
590
|
-
this.
|
|
591
|
-
const backup = subscription.backup;
|
|
592
|
-
subscription.backup = null;
|
|
593
|
-
if (backup) {
|
|
594
|
-
if (backup.data !== subscription.snapshot.data) {
|
|
595
|
-
subscription.stale = true;
|
|
596
|
-
}
|
|
597
|
-
subscription.snapshot = {
|
|
598
|
-
data: subscription.snapshot.data,
|
|
599
|
-
isMissingData: backup.isMissingData,
|
|
600
|
-
seenRecords: backup.seenRecords,
|
|
601
|
-
selector: backup.selector,
|
|
602
|
-
};
|
|
603
|
-
} else {
|
|
604
|
-
subscription.stale = true;
|
|
605
|
-
}
|
|
606
|
-
});
|
|
524
|
+
this._storeSubscriptions.restoreSubscriptions();
|
|
607
525
|
}
|
|
608
526
|
|
|
609
|
-
|
|
527
|
+
scheduleGC() {
|
|
610
528
|
if (this._gcHoldCounter > 0) {
|
|
611
529
|
this._shouldScheduleGC = true;
|
|
612
530
|
return;
|
|
@@ -664,7 +582,7 @@ class RelayModernStore implements Store {
|
|
|
664
582
|
}
|
|
665
583
|
}
|
|
666
584
|
|
|
667
|
-
const log = this.
|
|
585
|
+
const log = this.__log;
|
|
668
586
|
if (log != null) {
|
|
669
587
|
log({
|
|
670
588
|
name: 'store.gc',
|
|
@@ -701,7 +619,7 @@ function initializeRecordSource(target: MutableRecordSource) {
|
|
|
701
619
|
/**
|
|
702
620
|
* Updates the target with information from source, also updating a mapping of
|
|
703
621
|
* which records in the target were changed as a result.
|
|
704
|
-
* Additionally, will
|
|
622
|
+
* Additionally, will mark records as invalidated at the current write epoch
|
|
705
623
|
* given the set of record ids marked as stale in this update.
|
|
706
624
|
*/
|
|
707
625
|
function updateTargetFromSource(
|
|
@@ -770,7 +688,15 @@ function updateTargetFromSource(
|
|
|
770
688
|
}
|
|
771
689
|
}
|
|
772
690
|
if (sourceRecord && targetRecord) {
|
|
773
|
-
|
|
691
|
+
// ReactFlightClientResponses are lazy and only materialize when readRoot
|
|
692
|
+
// is called when we read the field, so if the record is a Flight field
|
|
693
|
+
// we always use the new record's data regardless of whether
|
|
694
|
+
// it actually changed. Let React take care of reconciliation instead.
|
|
695
|
+
const nextRecord =
|
|
696
|
+
RelayModernRecord.getType(targetRecord) ===
|
|
697
|
+
RelayStoreReactFlightUtils.REACT_FLIGHT_TYPE_NAME
|
|
698
|
+
? sourceRecord
|
|
699
|
+
: RelayModernRecord.update(targetRecord, sourceRecord);
|
|
774
700
|
if (nextRecord !== targetRecord) {
|
|
775
701
|
// Prevent mutation of a record from outside the store.
|
|
776
702
|
if (__DEV__) {
|
|
@@ -186,7 +186,7 @@ class RelayPublishQueue implements PublishQueue {
|
|
|
186
186
|
warning(
|
|
187
187
|
this._isRunning !== true,
|
|
188
188
|
'A store update was detected within another store update. Please ' +
|
|
189
|
-
|
|
189
|
+
"make sure new store updates aren't being executed within an " +
|
|
190
190
|
'updater function for a different update.',
|
|
191
191
|
);
|
|
192
192
|
this._isRunning = true;
|