relay-runtime 18.2.0 → 19.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/experimental.js +1 -1
- package/experimental.js.flow +8 -6
- package/index.js +1 -1
- package/index.js.flow +3 -0
- package/lib/experimental.js +5 -2
- package/lib/index.js +3 -0
- package/lib/multi-actor-environment/ActorSpecificEnvironment.js +1 -1
- package/lib/mutations/RelayRecordSourceProxy.js +2 -1
- package/lib/mutations/createUpdatableProxy.js +1 -1
- package/lib/mutations/validateMutation.js +2 -2
- package/lib/network/RelayObservable.js +1 -3
- package/lib/network/wrapNetworkWithLogObserver.js +2 -2
- package/lib/query/fetchQuery.js +1 -1
- package/lib/store/DataChecker.js +4 -5
- package/lib/store/OperationExecutor.js +11 -0
- package/lib/store/RelayModernEnvironment.js +13 -4
- package/lib/store/RelayModernFragmentSpecResolver.js +4 -4
- package/lib/store/RelayModernStore.js +43 -21
- package/lib/store/RelayPublishQueue.js +11 -15
- package/lib/store/RelayReader.js +131 -151
- package/lib/store/RelayReferenceMarker.js +3 -4
- package/lib/store/RelayResponseNormalizer.js +47 -26
- package/lib/store/RelayStoreSubscriptions.js +2 -2
- package/lib/store/RelayStoreUtils.js +8 -0
- package/lib/store/ResolverFragments.js +2 -2
- package/lib/store/createRelayLoggingContext.js +17 -0
- package/lib/store/generateTypenamePrefixedDataID.js +9 -0
- package/lib/store/live-resolvers/LiveResolverCache.js +2 -1
- package/lib/store/live-resolvers/resolverDataInjector.js +4 -4
- package/lib/store/observeFragmentExperimental.js +60 -13
- package/lib/store/observeQueryExperimental.js +21 -0
- package/lib/util/RelayFeatureFlags.js +6 -1
- package/lib/util/handlePotentialSnapshotErrors.js +11 -8
- package/multi-actor-environment/ActorSpecificEnvironment.js.flow +1 -0
- package/mutations/RelayRecordSourceProxy.js.flow +4 -0
- package/mutations/createUpdatableProxy.js.flow +1 -1
- package/mutations/validateMutation.js.flow +3 -3
- package/network/RelayNetworkTypes.js.flow +3 -0
- package/network/RelayObservable.js.flow +1 -5
- package/network/wrapNetworkWithLogObserver.js.flow +19 -1
- package/package.json +1 -1
- package/query/fetchQuery.js.flow +1 -1
- package/store/DataChecker.js.flow +5 -2
- package/store/OperationExecutor.js.flow +12 -1
- package/store/RelayExperimentalGraphResponseTransform.js.flow +4 -4
- package/store/RelayModernEnvironment.js.flow +22 -6
- package/store/RelayModernFragmentSpecResolver.js.flow +6 -6
- package/store/RelayModernSelector.js.flow +2 -0
- package/store/RelayModernStore.js.flow +74 -27
- package/store/RelayPublishQueue.js.flow +32 -21
- package/store/RelayReader.js.flow +159 -96
- package/store/RelayReferenceMarker.js.flow +3 -4
- package/store/RelayResponseNormalizer.js.flow +93 -67
- package/store/RelayStoreSubscriptions.js.flow +2 -2
- package/store/RelayStoreTypes.js.flow +33 -4
- package/store/RelayStoreUtils.js.flow +29 -0
- package/store/ResolverCache.js.flow +2 -2
- package/store/ResolverFragments.js.flow +5 -3
- package/store/StoreInspector.js.flow +5 -0
- package/store/createRelayContext.js.flow +3 -2
- package/store/createRelayLoggingContext.js.flow +46 -0
- package/store/generateTypenamePrefixedDataID.js.flow +25 -0
- package/store/live-resolvers/LiveResolverCache.js.flow +2 -1
- package/store/live-resolvers/resolverDataInjector.js.flow +10 -6
- package/store/observeFragmentExperimental.js.flow +82 -28
- package/store/observeQueryExperimental.js.flow +61 -0
- package/store/waitForFragmentExperimental.js.flow +4 -3
- package/util/NormalizationNode.js.flow +2 -1
- package/util/RelayConcreteNode.js.flow +2 -0
- package/util/RelayError.js.flow +1 -0
- package/util/RelayFeatureFlags.js.flow +18 -0
- package/util/RelayRuntimeTypes.js.flow +6 -3
- package/util/getPaginationVariables.js.flow +2 -0
- package/util/handlePotentialSnapshotErrors.js.flow +23 -11
- package/util/registerEnvironmentWithDevTools.js.flow +4 -2
- package/util/withProvidedVariables.js.flow +1 -0
- package/util/withStartAndDuration.js.flow +3 -0
- package/relay-runtime-experimental.js +0 -4
- package/relay-runtime-experimental.min.js +0 -9
- package/relay-runtime.js +0 -4
- package/relay-runtime.min.js +0 -9
|
@@ -12,12 +12,17 @@
|
|
|
12
12
|
'use strict';
|
|
13
13
|
import type ActorSpecificEnvironment from '../multi-actor-environment/ActorSpecificEnvironment';
|
|
14
14
|
import type RelayModernEnvironment from '../store/RelayModernEnvironment';
|
|
15
|
+
import type {
|
|
16
|
+
LogRequestInfoFunction,
|
|
17
|
+
OperationAvailability,
|
|
18
|
+
} from '../store/RelayStoreTypes';
|
|
15
19
|
import type {RequestParameters} from '../util/RelayConcreteNode';
|
|
16
20
|
import type {CacheConfig, Variables} from '../util/RelayRuntimeTypes';
|
|
17
21
|
import type {
|
|
18
22
|
GraphQLResponse,
|
|
19
23
|
INetwork,
|
|
20
24
|
UploadableMap,
|
|
25
|
+
preprocessResponseFunction,
|
|
21
26
|
} from './RelayNetworkTypes';
|
|
22
27
|
import type RelayObservable from './RelayObservable';
|
|
23
28
|
import type {Subscription} from './RelayObservable';
|
|
@@ -42,6 +47,10 @@ function wrapNetworkWithLogObserver(
|
|
|
42
47
|
variables: Variables,
|
|
43
48
|
cacheConfig: CacheConfig,
|
|
44
49
|
uploadables?: ?UploadableMap,
|
|
50
|
+
_?: ?LogRequestInfoFunction,
|
|
51
|
+
encryptedVariables?: ?string,
|
|
52
|
+
preprocessResponse?: ?preprocessResponseFunction,
|
|
53
|
+
checkOperation?: () => OperationAvailability,
|
|
45
54
|
): RelayObservable<GraphQLResponse> {
|
|
46
55
|
const networkRequestId = generateID();
|
|
47
56
|
const logObserver = {
|
|
@@ -89,7 +98,16 @@ function wrapNetworkWithLogObserver(
|
|
|
89
98
|
});
|
|
90
99
|
};
|
|
91
100
|
return network
|
|
92
|
-
.execute(
|
|
101
|
+
.execute(
|
|
102
|
+
params,
|
|
103
|
+
variables,
|
|
104
|
+
cacheConfig,
|
|
105
|
+
uploadables,
|
|
106
|
+
logRequestInfo,
|
|
107
|
+
encryptedVariables,
|
|
108
|
+
preprocessResponse,
|
|
109
|
+
checkOperation,
|
|
110
|
+
)
|
|
93
111
|
.do(logObserver);
|
|
94
112
|
},
|
|
95
113
|
};
|
package/package.json
CHANGED
package/query/fetchQuery.js.flow
CHANGED
|
@@ -138,7 +138,7 @@ function fetchQuery<TVariables: Variables, TData, TRawResponse>(
|
|
|
138
138
|
const fetchPolicy = options?.fetchPolicy ?? 'network-only';
|
|
139
139
|
|
|
140
140
|
function readData(snapshot: Snapshot): TData {
|
|
141
|
-
handlePotentialSnapshotErrors(environment, snapshot.
|
|
141
|
+
handlePotentialSnapshotErrors(environment, snapshot.fieldErrors);
|
|
142
142
|
/* $FlowFixMe[incompatible-return] we assume readData returns the right
|
|
143
143
|
* data just having written it from network or checked availability. */
|
|
144
144
|
return snapshot.data;
|
|
@@ -90,6 +90,7 @@ function check(
|
|
|
90
90
|
operationLoader,
|
|
91
91
|
getDataID,
|
|
92
92
|
shouldProcessClientComponents,
|
|
93
|
+
log,
|
|
93
94
|
);
|
|
94
95
|
const result = checker.check(node, dataID);
|
|
95
96
|
if (log != null) {
|
|
@@ -123,6 +124,7 @@ class DataChecker {
|
|
|
123
124
|
ActorIdentifier,
|
|
124
125
|
[RelayRecordSourceMutator, RelayRecordSourceProxy],
|
|
125
126
|
>;
|
|
127
|
+
_log: ?LogFunction;
|
|
126
128
|
|
|
127
129
|
constructor(
|
|
128
130
|
getSourceForActor: (actorIdentifier: ActorIdentifier) => RecordSource,
|
|
@@ -135,6 +137,7 @@ class DataChecker {
|
|
|
135
137
|
operationLoader: ?OperationLoader,
|
|
136
138
|
getDataID: GetDataID,
|
|
137
139
|
shouldProcessClientComponents: ?boolean,
|
|
140
|
+
log: ?LogFunction,
|
|
138
141
|
) {
|
|
139
142
|
this._getSourceForActor = getSourceForActor;
|
|
140
143
|
this._getTargetForActor = getTargetForActor;
|
|
@@ -152,6 +155,7 @@ class DataChecker {
|
|
|
152
155
|
this._recordWasMissing = false;
|
|
153
156
|
this._variables = variables;
|
|
154
157
|
this._shouldProcessClientComponents = shouldProcessClientComponents;
|
|
158
|
+
this._log = log;
|
|
155
159
|
}
|
|
156
160
|
|
|
157
161
|
_getMutatorAndRecordProxyForActor(
|
|
@@ -170,6 +174,7 @@ class DataChecker {
|
|
|
170
174
|
this._getDataID,
|
|
171
175
|
undefined,
|
|
172
176
|
this._handlers,
|
|
177
|
+
this._log,
|
|
173
178
|
);
|
|
174
179
|
tuple = [mutator, recordSourceProxy];
|
|
175
180
|
this._mutatorRecordSourceProxyCache.set(actorIdentifier, tuple);
|
|
@@ -449,8 +454,6 @@ class DataChecker {
|
|
|
449
454
|
this._traverseSelections(selection.fragment.selections, dataID);
|
|
450
455
|
break;
|
|
451
456
|
case 'RelayResolver':
|
|
452
|
-
this._checkResolver(selection, dataID);
|
|
453
|
-
break;
|
|
454
457
|
case 'RelayLiveResolver':
|
|
455
458
|
this._checkResolver(selection, dataID);
|
|
456
459
|
break;
|
|
@@ -245,6 +245,12 @@ class Executor<TMutation: MutationParameters> {
|
|
|
245
245
|
cacheConfig: this._operation.request.cacheConfig ?? {},
|
|
246
246
|
});
|
|
247
247
|
},
|
|
248
|
+
unsubscribe: () => {
|
|
249
|
+
this._log({
|
|
250
|
+
name: 'execute.unsubscribe',
|
|
251
|
+
executeId: this._executeId,
|
|
252
|
+
});
|
|
253
|
+
},
|
|
248
254
|
});
|
|
249
255
|
|
|
250
256
|
if (
|
|
@@ -293,7 +299,7 @@ class Executor<TMutation: MutationParameters> {
|
|
|
293
299
|
}
|
|
294
300
|
|
|
295
301
|
_updateActiveState(): void {
|
|
296
|
-
let activeState;
|
|
302
|
+
let activeState: ActiveState;
|
|
297
303
|
switch (this._state) {
|
|
298
304
|
case 'started': {
|
|
299
305
|
activeState = 'active';
|
|
@@ -606,6 +612,7 @@ class Executor<TMutation: MutationParameters> {
|
|
|
606
612
|
{
|
|
607
613
|
actorIdentifier: this._actorIdentifier,
|
|
608
614
|
getDataID: this._getDataID,
|
|
615
|
+
log: this._log,
|
|
609
616
|
path: [],
|
|
610
617
|
shouldProcessClientComponents: this._shouldProcessClientComponents,
|
|
611
618
|
treatMissingFieldsAsNull,
|
|
@@ -715,6 +722,7 @@ class Executor<TMutation: MutationParameters> {
|
|
|
715
722
|
{
|
|
716
723
|
actorIdentifier: this._actorIdentifier,
|
|
717
724
|
getDataID: this._getDataID,
|
|
725
|
+
log: this._log,
|
|
718
726
|
path: followupPayload.path,
|
|
719
727
|
treatMissingFieldsAsNull: this._treatMissingFieldsAsNull,
|
|
720
728
|
shouldProcessClientComponents: this._shouldProcessClientComponents,
|
|
@@ -797,6 +805,7 @@ class Executor<TMutation: MutationParameters> {
|
|
|
797
805
|
{
|
|
798
806
|
actorIdentifier: this._actorIdentifier,
|
|
799
807
|
getDataID: this._getDataID,
|
|
808
|
+
log: this._log,
|
|
800
809
|
path: [],
|
|
801
810
|
treatMissingFieldsAsNull: this._treatMissingFieldsAsNull,
|
|
802
811
|
shouldProcessClientComponents: this._shouldProcessClientComponents,
|
|
@@ -1253,6 +1262,7 @@ class Executor<TMutation: MutationParameters> {
|
|
|
1253
1262
|
{
|
|
1254
1263
|
actorIdentifier: this._actorIdentifier,
|
|
1255
1264
|
getDataID: this._getDataID,
|
|
1265
|
+
log: this._log,
|
|
1256
1266
|
path: placeholder.path,
|
|
1257
1267
|
treatMissingFieldsAsNull: this._treatMissingFieldsAsNull,
|
|
1258
1268
|
shouldProcessClientComponents: this._shouldProcessClientComponents,
|
|
@@ -1480,6 +1490,7 @@ class Executor<TMutation: MutationParameters> {
|
|
|
1480
1490
|
const relayPayload = this._normalizeResponse(response, selector, typeName, {
|
|
1481
1491
|
actorIdentifier: this._actorIdentifier,
|
|
1482
1492
|
getDataID: this._getDataID,
|
|
1493
|
+
log: this._log,
|
|
1483
1494
|
path: [...normalizationPath, responseKey, String(itemIndex)],
|
|
1484
1495
|
treatMissingFieldsAsNull: this._treatMissingFieldsAsNull,
|
|
1485
1496
|
shouldProcessClientComponents: this._shouldProcessClientComponents,
|
|
@@ -222,10 +222,10 @@ export class GraphModeNormalizer {
|
|
|
222
222
|
$streamID,
|
|
223
223
|
__id: dataID,
|
|
224
224
|
__typename: ROOT_TYPE,
|
|
225
|
-
};
|
|
225
|
+
} as RecordChunk;
|
|
226
226
|
yield {
|
|
227
227
|
$kind: 'Complete',
|
|
228
|
-
};
|
|
228
|
+
} as CompleteChunk;
|
|
229
229
|
}
|
|
230
230
|
|
|
231
231
|
*_flushFields(
|
|
@@ -247,9 +247,9 @@ export class GraphModeNormalizer {
|
|
|
247
247
|
__typename: typename,
|
|
248
248
|
__id: cacheKey,
|
|
249
249
|
$streamID,
|
|
250
|
-
};
|
|
250
|
+
} as RecordChunk;
|
|
251
251
|
} else if (Object.keys(fields).length > 0) {
|
|
252
|
-
yield {...fields, $kind: 'Extend', $streamID};
|
|
252
|
+
yield {...fields, $kind: 'Extend', $streamID} as ExtendChunk;
|
|
253
253
|
}
|
|
254
254
|
return $streamID;
|
|
255
255
|
}
|
|
@@ -58,6 +58,7 @@ const defaultGetDataID = require('./defaultGetDataID');
|
|
|
58
58
|
const defaultRelayFieldLogger = require('./defaultRelayFieldLogger');
|
|
59
59
|
const normalizeResponse = require('./normalizeResponse');
|
|
60
60
|
const OperationExecutor = require('./OperationExecutor');
|
|
61
|
+
const RelayModernStore = require('./RelayModernStore');
|
|
61
62
|
const RelayPublishQueue = require('./RelayPublishQueue');
|
|
62
63
|
const RelayRecordSource = require('./RelayRecordSource');
|
|
63
64
|
const invariant = require('invariant');
|
|
@@ -71,7 +72,7 @@ export type EnvironmentConfig = {
|
|
|
71
72
|
+network: INetwork,
|
|
72
73
|
+normalizeResponse?: ?NormalizeResponseFunction,
|
|
73
74
|
+scheduler?: ?TaskScheduler,
|
|
74
|
-
+store
|
|
75
|
+
+store?: Store,
|
|
75
76
|
+missingFieldHandlers?: ?$ReadOnlyArray<MissingFieldHandler>,
|
|
76
77
|
+operationTracker?: ?OperationTracker,
|
|
77
78
|
+getDataID?: ?GetDataID,
|
|
@@ -118,6 +119,15 @@ class RelayModernEnvironment implements IEnvironment {
|
|
|
118
119
|
);
|
|
119
120
|
}
|
|
120
121
|
}
|
|
122
|
+
const store =
|
|
123
|
+
config.store ??
|
|
124
|
+
new RelayModernStore(new RelayRecordSource(), {
|
|
125
|
+
log: config.log,
|
|
126
|
+
operationLoader: config.operationLoader,
|
|
127
|
+
getDataID: config.getDataID,
|
|
128
|
+
shouldProcessClientComponents: config.shouldProcessClientComponents,
|
|
129
|
+
});
|
|
130
|
+
|
|
121
131
|
this.__log = config.log ?? emptyFunction;
|
|
122
132
|
this.relayFieldLogger = config.relayFieldLogger ?? defaultRelayFieldLogger;
|
|
123
133
|
this._defaultRenderPolicy =
|
|
@@ -128,13 +138,14 @@ class RelayModernEnvironment implements IEnvironment {
|
|
|
128
138
|
this._getDataID = config.getDataID ?? defaultGetDataID;
|
|
129
139
|
this._missingFieldHandlers = config.missingFieldHandlers ?? [];
|
|
130
140
|
this._publishQueue = new RelayPublishQueue(
|
|
131
|
-
|
|
141
|
+
store,
|
|
132
142
|
config.handlerProvider ?? RelayDefaultHandlerProvider,
|
|
133
143
|
this._getDataID,
|
|
134
144
|
this._missingFieldHandlers,
|
|
145
|
+
this.__log,
|
|
135
146
|
);
|
|
136
147
|
this._scheduler = config.scheduler ?? null;
|
|
137
|
-
this._store =
|
|
148
|
+
this._store = store;
|
|
138
149
|
this.options = config.options;
|
|
139
150
|
this._isServer = config.isServer ?? false;
|
|
140
151
|
this._normalizeResponse = config.normalizeResponse ?? normalizeResponse;
|
|
@@ -327,13 +338,18 @@ class RelayModernEnvironment implements IEnvironment {
|
|
|
327
338
|
operation: OperationDescriptor,
|
|
328
339
|
}): RelayObservable<GraphQLResponse> {
|
|
329
340
|
return this._execute({
|
|
330
|
-
createSource: () =>
|
|
331
|
-
this.getNetwork().execute(
|
|
341
|
+
createSource: () => {
|
|
342
|
+
return this.getNetwork().execute(
|
|
332
343
|
operation.request.node.params,
|
|
333
344
|
operation.request.variables,
|
|
334
345
|
operation.request.cacheConfig || {},
|
|
335
346
|
null,
|
|
336
|
-
|
|
347
|
+
undefined,
|
|
348
|
+
undefined,
|
|
349
|
+
undefined,
|
|
350
|
+
() => this.check(operation),
|
|
351
|
+
);
|
|
352
|
+
},
|
|
337
353
|
isClientPayload: false,
|
|
338
354
|
operation,
|
|
339
355
|
optimisticConfig: null,
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
import type {ConcreteRequest} from '../util/RelayConcreteNode';
|
|
15
15
|
import type {Disposable, Variables} from '../util/RelayRuntimeTypes';
|
|
16
16
|
import type {
|
|
17
|
-
|
|
17
|
+
FieldErrors,
|
|
18
18
|
FragmentMap,
|
|
19
19
|
FragmentSpecResolver,
|
|
20
20
|
FragmentSpecResults,
|
|
@@ -228,7 +228,7 @@ class SelectorResolver {
|
|
|
228
228
|
_data: ?SelectorData;
|
|
229
229
|
_environment: IEnvironment;
|
|
230
230
|
_isMissingData: boolean;
|
|
231
|
-
|
|
231
|
+
_fieldErrors: ?FieldErrors;
|
|
232
232
|
_rootIsQueryRenderer: boolean;
|
|
233
233
|
_selector: SingularReaderSelector;
|
|
234
234
|
_subscription: ?Disposable;
|
|
@@ -244,7 +244,7 @@ class SelectorResolver {
|
|
|
244
244
|
this._callback = callback;
|
|
245
245
|
this._data = snapshot.data;
|
|
246
246
|
this._isMissingData = snapshot.isMissingData;
|
|
247
|
-
this.
|
|
247
|
+
this._fieldErrors = snapshot.fieldErrors;
|
|
248
248
|
this._environment = environment;
|
|
249
249
|
this._rootIsQueryRenderer = rootIsQueryRenderer;
|
|
250
250
|
this._selector = selector;
|
|
@@ -325,7 +325,7 @@ class SelectorResolver {
|
|
|
325
325
|
}
|
|
326
326
|
}
|
|
327
327
|
}
|
|
328
|
-
handlePotentialSnapshotErrors(this._environment, this.
|
|
328
|
+
handlePotentialSnapshotErrors(this._environment, this._fieldErrors);
|
|
329
329
|
return this._data;
|
|
330
330
|
}
|
|
331
331
|
|
|
@@ -340,7 +340,7 @@ class SelectorResolver {
|
|
|
340
340
|
const snapshot = this._environment.lookup(selector);
|
|
341
341
|
this._data = recycleNodesInto(this._data, snapshot.data);
|
|
342
342
|
this._isMissingData = snapshot.isMissingData;
|
|
343
|
-
this.
|
|
343
|
+
this._fieldErrors = snapshot.fieldErrors;
|
|
344
344
|
this._selector = selector;
|
|
345
345
|
this._subscription = this._environment.subscribe(snapshot, this._onChange);
|
|
346
346
|
}
|
|
@@ -376,7 +376,7 @@ class SelectorResolver {
|
|
|
376
376
|
_onChange = (snapshot: Snapshot): void => {
|
|
377
377
|
this._data = snapshot.data;
|
|
378
378
|
this._isMissingData = snapshot.isMissingData;
|
|
379
|
-
this.
|
|
379
|
+
this._fieldErrors = snapshot.fieldErrors;
|
|
380
380
|
this._callback();
|
|
381
381
|
};
|
|
382
382
|
}
|
|
@@ -340,6 +340,7 @@ function getVariablesFromObject(
|
|
|
340
340
|
const fragment = fragments[key];
|
|
341
341
|
const item = object[key];
|
|
342
342
|
const itemVariables = getVariablesFromFragment(fragment, item);
|
|
343
|
+
// $FlowFixMe[unsafe-object-assign]
|
|
343
344
|
Object.assign(variables, itemVariables);
|
|
344
345
|
}
|
|
345
346
|
}
|
|
@@ -397,6 +398,7 @@ function getVariablesFromPluralFragment(
|
|
|
397
398
|
if (value != null) {
|
|
398
399
|
const itemVariables = getVariablesFromSingularFragment(fragment, value);
|
|
399
400
|
if (itemVariables != null) {
|
|
401
|
+
// $FlowFixMe[unsafe-object-assign]
|
|
400
402
|
Object.assign(variables, itemVariables);
|
|
401
403
|
}
|
|
402
404
|
}
|
|
@@ -107,6 +107,7 @@ class RelayModernStore implements Store {
|
|
|
107
107
|
fetchTime: ?number,
|
|
108
108
|
},
|
|
109
109
|
>;
|
|
110
|
+
_shouldRetainWithinTTL_EXPERIMENTAL: boolean;
|
|
110
111
|
_shouldScheduleGC: boolean;
|
|
111
112
|
_storeSubscriptions: StoreSubscriptions;
|
|
112
113
|
_updatedRecordIDs: DataIDSet;
|
|
@@ -127,6 +128,9 @@ class RelayModernStore implements Store {
|
|
|
127
128
|
shouldProcessClientComponents?: ?boolean,
|
|
128
129
|
resolverContext?: ResolverContext,
|
|
129
130
|
|
|
131
|
+
// Experimental
|
|
132
|
+
shouldRetainWithinTTL_EXPERIMENTAL?: boolean,
|
|
133
|
+
|
|
130
134
|
// These additional config options are only used if the experimental
|
|
131
135
|
// @outputType resolver feature is used
|
|
132
136
|
treatMissingFieldsAsNull?: ?boolean,
|
|
@@ -147,6 +151,8 @@ class RelayModernStore implements Store {
|
|
|
147
151
|
this._gcHoldCounter = 0;
|
|
148
152
|
this._gcReleaseBufferSize =
|
|
149
153
|
options?.gcReleaseBufferSize ?? DEFAULT_RELEASE_BUFFER_SIZE;
|
|
154
|
+
this._shouldRetainWithinTTL_EXPERIMENTAL =
|
|
155
|
+
options?.shouldRetainWithinTTL_EXPERIMENTAL ?? false;
|
|
150
156
|
this._gcRun = null;
|
|
151
157
|
this._gcScheduler = options?.gcScheduler ?? resolveImmediate;
|
|
152
158
|
this._getDataID = options?.getDataID ?? defaultGetDataID;
|
|
@@ -165,14 +171,15 @@ class RelayModernStore implements Store {
|
|
|
165
171
|
() => this._getMutableRecordSource(),
|
|
166
172
|
this,
|
|
167
173
|
);
|
|
174
|
+
this._resolverContext = options?.resolverContext;
|
|
168
175
|
this._storeSubscriptions = new RelayStoreSubscriptions(
|
|
169
176
|
options?.log,
|
|
170
177
|
this._resolverCache,
|
|
178
|
+
this._resolverContext,
|
|
171
179
|
);
|
|
172
180
|
this._updatedRecordIDs = new Set();
|
|
173
181
|
this._shouldProcessClientComponents =
|
|
174
182
|
options?.shouldProcessClientComponents ?? false;
|
|
175
|
-
this._resolverContext = options?.resolverContext;
|
|
176
183
|
|
|
177
184
|
this._treatMissingFieldsAsNull = options?.treatMissingFieldsAsNull ?? false;
|
|
178
185
|
this._actorIdentifier = options?.actorIdentifier;
|
|
@@ -315,7 +322,9 @@ class RelayModernStore implements Store {
|
|
|
315
322
|
rootEntry.fetchTime <= Date.now() - _queryCacheExpirationTime;
|
|
316
323
|
|
|
317
324
|
if (rootEntryIsStale) {
|
|
318
|
-
this.
|
|
325
|
+
if (!this._shouldRetainWithinTTL_EXPERIMENTAL) {
|
|
326
|
+
this._roots.delete(id);
|
|
327
|
+
}
|
|
319
328
|
this.scheduleGC();
|
|
320
329
|
} else {
|
|
321
330
|
this._releaseBuffer.push(id);
|
|
@@ -325,8 +334,10 @@ class RelayModernStore implements Store {
|
|
|
325
334
|
// buffer have a refCount of 0.
|
|
326
335
|
if (this._releaseBuffer.length > this._gcReleaseBufferSize) {
|
|
327
336
|
const _id = this._releaseBuffer.shift();
|
|
328
|
-
|
|
329
|
-
|
|
337
|
+
if (!this._shouldRetainWithinTTL_EXPERIMENTAL) {
|
|
338
|
+
// $FlowFixMe[incompatible-call]
|
|
339
|
+
this._roots.delete(_id);
|
|
340
|
+
}
|
|
330
341
|
this.scheduleGC();
|
|
331
342
|
}
|
|
332
343
|
}
|
|
@@ -688,6 +699,14 @@ class RelayModernStore implements Store {
|
|
|
688
699
|
};
|
|
689
700
|
|
|
690
701
|
*_collect(): Generator<void, void, void> {
|
|
702
|
+
if (
|
|
703
|
+
this._shouldRetainWithinTTL_EXPERIMENTAL &&
|
|
704
|
+
this._queryCacheExpirationTime == null
|
|
705
|
+
) {
|
|
706
|
+
// Null expiration time indicates infinite TTL, so we don't need to
|
|
707
|
+
// run GC.
|
|
708
|
+
return;
|
|
709
|
+
}
|
|
691
710
|
/* eslint-disable no-labels */
|
|
692
711
|
const log = this.__log;
|
|
693
712
|
top: while (true) {
|
|
@@ -699,8 +718,30 @@ class RelayModernStore implements Store {
|
|
|
699
718
|
const startEpoch = this._currentWriteEpoch;
|
|
700
719
|
const references = new Set<DataID>();
|
|
701
720
|
|
|
702
|
-
|
|
703
|
-
|
|
721
|
+
for (const [
|
|
722
|
+
dataID,
|
|
723
|
+
{operation, refCount, fetchTime},
|
|
724
|
+
] of this._roots.entries()) {
|
|
725
|
+
if (this._shouldRetainWithinTTL_EXPERIMENTAL) {
|
|
726
|
+
// Do not mark records that should be garbage collected
|
|
727
|
+
const {_queryCacheExpirationTime} = this;
|
|
728
|
+
invariant(
|
|
729
|
+
_queryCacheExpirationTime != null,
|
|
730
|
+
'Query cache expiration time should be non-null if executing GC',
|
|
731
|
+
);
|
|
732
|
+
const recordHasExpired =
|
|
733
|
+
fetchTime == null ||
|
|
734
|
+
fetchTime <= Date.now() - _queryCacheExpirationTime;
|
|
735
|
+
const recordShouldBeCollected =
|
|
736
|
+
recordHasExpired &&
|
|
737
|
+
refCount === 0 &&
|
|
738
|
+
!this._releaseBuffer.includes(dataID);
|
|
739
|
+
if (recordShouldBeCollected) {
|
|
740
|
+
continue;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
// Mark all records that are traversable from a root that is still valid
|
|
704
745
|
const selector = operation.root;
|
|
705
746
|
RelayReferenceMarker.mark(
|
|
706
747
|
this._recordSource,
|
|
@@ -723,31 +764,36 @@ class RelayModernStore implements Store {
|
|
|
723
764
|
}
|
|
724
765
|
}
|
|
725
766
|
|
|
726
|
-
//
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
}
|
|
767
|
+
// NOTE: It may be tempting to use `this._recordSource.clear()`
|
|
768
|
+
// when no references are found, but that would prevent calling
|
|
769
|
+
// maybeResolverSubscription() on any records that have an active
|
|
770
|
+
// resolver subscription. This would result in a memory leak.
|
|
771
|
+
|
|
772
|
+
// Evict any unreferenced nodes
|
|
773
|
+
const storeIDs = this._recordSource.getRecordIDs();
|
|
774
|
+
for (let ii = 0; ii < storeIDs.length; ii++) {
|
|
775
|
+
const dataID = storeIDs[ii];
|
|
776
|
+
if (!references.has(dataID)) {
|
|
777
|
+
const record = this._recordSource.get(dataID);
|
|
778
|
+
if (record != null) {
|
|
779
|
+
const maybeResolverSubscription = RelayModernRecord.getValue(
|
|
780
|
+
record,
|
|
781
|
+
RELAY_RESOLVER_LIVE_STATE_SUBSCRIPTION_KEY,
|
|
782
|
+
);
|
|
783
|
+
if (maybeResolverSubscription != null) {
|
|
784
|
+
// $FlowFixMe - this value if it is not null, it is a function
|
|
785
|
+
maybeResolverSubscription();
|
|
746
786
|
}
|
|
747
|
-
|
|
787
|
+
}
|
|
788
|
+
this._recordSource.remove(dataID);
|
|
789
|
+
if (this._shouldRetainWithinTTL_EXPERIMENTAL) {
|
|
790
|
+
// Note: A record that was never retained will not be in the roots map
|
|
791
|
+
// but the following line should not throw
|
|
792
|
+
this._roots.delete(dataID);
|
|
748
793
|
}
|
|
749
794
|
}
|
|
750
795
|
}
|
|
796
|
+
|
|
751
797
|
if (log != null) {
|
|
752
798
|
log({
|
|
753
799
|
name: 'store.gc.end',
|
|
@@ -765,6 +811,7 @@ class RelayModernStore implements Store {
|
|
|
765
811
|
return {
|
|
766
812
|
path,
|
|
767
813
|
getDataID: this._getDataID,
|
|
814
|
+
log: this.__log,
|
|
768
815
|
treatMissingFieldsAsNull: this._treatMissingFieldsAsNull,
|
|
769
816
|
shouldProcessClientComponents: this._shouldProcessClientComponents,
|
|
770
817
|
actorIdentifier: this._actorIdentifier,
|
|
@@ -15,6 +15,7 @@ import type {HandlerProvider} from '../handlers/RelayDefaultHandlerProvider';
|
|
|
15
15
|
import type {Disposable} from '../util/RelayRuntimeTypes';
|
|
16
16
|
import type {GetDataID} from './RelayResponseNormalizer';
|
|
17
17
|
import type {
|
|
18
|
+
LogFunction,
|
|
18
19
|
MissingFieldHandler,
|
|
19
20
|
MutationParameters,
|
|
20
21
|
OperationDescriptor,
|
|
@@ -33,6 +34,7 @@ import type {
|
|
|
33
34
|
const RelayRecordSourceMutator = require('../mutations/RelayRecordSourceMutator');
|
|
34
35
|
const RelayRecordSourceProxy = require('../mutations/RelayRecordSourceProxy');
|
|
35
36
|
const RelayRecordSourceSelectorProxy = require('../mutations/RelayRecordSourceSelectorProxy');
|
|
37
|
+
const RelayFeatureFlags = require('../util/RelayFeatureFlags');
|
|
36
38
|
const RelayReader = require('./RelayReader');
|
|
37
39
|
const RelayRecordSource = require('./RelayRecordSource');
|
|
38
40
|
const invariant = require('invariant');
|
|
@@ -60,8 +62,10 @@ type PendingUpdater = {
|
|
|
60
62
|
const _global: typeof global | $FlowFixMe =
|
|
61
63
|
typeof global !== 'undefined'
|
|
62
64
|
? global
|
|
63
|
-
:
|
|
64
|
-
|
|
65
|
+
: // $FlowFixMe[cannot-resolve-name]
|
|
66
|
+
typeof window !== 'undefined'
|
|
67
|
+
? // $FlowFixMe[cannot-resolve-name]
|
|
68
|
+
window
|
|
65
69
|
: undefined;
|
|
66
70
|
|
|
67
71
|
const applyWithGuard =
|
|
@@ -84,6 +88,7 @@ class RelayPublishQueue implements PublishQueue {
|
|
|
84
88
|
_handlerProvider: ?HandlerProvider;
|
|
85
89
|
_missingFieldHandlers: $ReadOnlyArray<MissingFieldHandler>;
|
|
86
90
|
_getDataID: GetDataID;
|
|
91
|
+
_log: ?LogFunction;
|
|
87
92
|
|
|
88
93
|
_hasStoreSnapshot: boolean;
|
|
89
94
|
// True if the next `run()` should apply the backup and rerun all optimistic
|
|
@@ -112,6 +117,7 @@ class RelayPublishQueue implements PublishQueue {
|
|
|
112
117
|
handlerProvider?: ?HandlerProvider,
|
|
113
118
|
getDataID: GetDataID,
|
|
114
119
|
missingFieldHandlers: $ReadOnlyArray<MissingFieldHandler>,
|
|
120
|
+
log: LogFunction,
|
|
115
121
|
) {
|
|
116
122
|
this._hasStoreSnapshot = false;
|
|
117
123
|
this._handlerProvider = handlerProvider || null;
|
|
@@ -123,6 +129,7 @@ class RelayPublishQueue implements PublishQueue {
|
|
|
123
129
|
this._gcHold = null;
|
|
124
130
|
this._getDataID = getDataID;
|
|
125
131
|
this._missingFieldHandlers = missingFieldHandlers;
|
|
132
|
+
this._log = log;
|
|
126
133
|
}
|
|
127
134
|
|
|
128
135
|
/**
|
|
@@ -219,24 +226,27 @@ class RelayPublishQueue implements PublishQueue {
|
|
|
219
226
|
this._pendingOptimisticUpdates.size === 0 &&
|
|
220
227
|
!runWillClearGcHold;
|
|
221
228
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
229
|
+
warning(
|
|
230
|
+
!runIsANoop,
|
|
231
|
+
'RelayPublishQueue.run was called, but the call would have been a noop.',
|
|
232
|
+
);
|
|
233
|
+
RelayFeatureFlags.DISALLOW_NESTED_UPDATES
|
|
234
|
+
? invariant(
|
|
235
|
+
this._isRunning !== true,
|
|
236
|
+
'A store update was detected within another store update. Please ' +
|
|
237
|
+
"make sure new store updates aren't being executed within an " +
|
|
238
|
+
'updater function for a different update.',
|
|
239
|
+
)
|
|
240
|
+
: warning(
|
|
241
|
+
this._isRunning !== true,
|
|
242
|
+
'A store update was detected within another store update. Please ' +
|
|
243
|
+
"make sure new store updates aren't being executed within an " +
|
|
244
|
+
'updater function for a different update.',
|
|
245
|
+
);
|
|
246
|
+
this._isRunning = true;
|
|
235
247
|
|
|
236
248
|
if (runIsANoop) {
|
|
237
|
-
|
|
238
|
-
this._isRunning = false;
|
|
239
|
-
}
|
|
249
|
+
this._isRunning = false;
|
|
240
250
|
return [];
|
|
241
251
|
}
|
|
242
252
|
|
|
@@ -268,9 +278,7 @@ class RelayPublishQueue implements PublishQueue {
|
|
|
268
278
|
this._gcHold = null;
|
|
269
279
|
}
|
|
270
280
|
}
|
|
271
|
-
|
|
272
|
-
this._isRunning = false;
|
|
273
|
-
}
|
|
281
|
+
this._isRunning = false;
|
|
274
282
|
return this._store.notify(sourceOperation, invalidatedStore);
|
|
275
283
|
}
|
|
276
284
|
|
|
@@ -292,6 +300,7 @@ class RelayPublishQueue implements PublishQueue {
|
|
|
292
300
|
this._getDataID,
|
|
293
301
|
this._handlerProvider,
|
|
294
302
|
this._missingFieldHandlers,
|
|
303
|
+
this._log,
|
|
295
304
|
);
|
|
296
305
|
if (fieldPayloads && fieldPayloads.length) {
|
|
297
306
|
fieldPayloads.forEach(fieldPayload => {
|
|
@@ -355,6 +364,7 @@ class RelayPublishQueue implements PublishQueue {
|
|
|
355
364
|
this._getDataID,
|
|
356
365
|
this._handlerProvider,
|
|
357
366
|
this._missingFieldHandlers,
|
|
367
|
+
this._log,
|
|
358
368
|
);
|
|
359
369
|
applyWithGuard(
|
|
360
370
|
updater,
|
|
@@ -388,6 +398,7 @@ class RelayPublishQueue implements PublishQueue {
|
|
|
388
398
|
this._getDataID,
|
|
389
399
|
this._handlerProvider,
|
|
390
400
|
this._missingFieldHandlers,
|
|
401
|
+
this._log,
|
|
391
402
|
);
|
|
392
403
|
|
|
393
404
|
// $FlowFixMe[unclear-type] see explanation above.
|