@apollo/client 4.3.0-alpha.6 → 4.3.0-alpha.8
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/CHANGELOG.md +24 -0
- package/__cjs/cache/core/cache.cjs +25 -1
- package/__cjs/cache/core/cache.cjs.map +1 -1
- package/__cjs/cache/core/cache.d.cts +19 -1
- package/__cjs/cache/inmemory/entityStore.cjs +3 -3
- package/__cjs/cache/inmemory/inMemoryCache.cjs +10 -0
- package/__cjs/cache/inmemory/inMemoryCache.cjs.map +1 -1
- package/__cjs/cache/inmemory/inMemoryCache.d.cts +5 -1
- package/__cjs/cache/inmemory/key-extractor.cjs +1 -1
- package/__cjs/cache/inmemory/policies.cjs +5 -5
- package/__cjs/cache/inmemory/readFromStore.cjs +3 -3
- package/__cjs/cache/inmemory/writeToStore.cjs +4 -4
- package/__cjs/core/ApolloClient.cjs +14 -14
- package/__cjs/core/ObservableQuery.cjs +173 -61
- package/__cjs/core/ObservableQuery.cjs.map +1 -1
- package/__cjs/core/ObservableQuery.d.cts +3 -6
- package/__cjs/core/QueryInfo.cjs +11 -125
- package/__cjs/core/QueryInfo.cjs.map +1 -1
- package/__cjs/core/QueryInfo.d.cts +0 -24
- package/__cjs/core/QueryManager.cjs +23 -15
- package/__cjs/core/QueryManager.cjs.map +1 -1
- package/__cjs/core/RefetchEventManager.cjs +3 -3
- package/__cjs/incremental/handlers/graphql17Alpha9.cjs +1 -1
- package/__cjs/incremental/handlers/notImplemented.cjs +1 -1
- package/__cjs/invariantErrorCodes.cjs +141 -115
- package/__cjs/link/core/ApolloLink.cjs +3 -3
- package/__cjs/link/http/checkFetcher.cjs +1 -1
- package/__cjs/link/http/parseAndCheckHttpResponse.cjs +2 -2
- package/__cjs/link/http/parseAndCheckHttpResponse.cjs.map +1 -1
- package/__cjs/link/persisted-queries/index.cjs +2 -2
- package/__cjs/link/ws/index.cjs +1 -1
- package/__cjs/local-state/LocalState.cjs +11 -11
- package/__cjs/masking/maskDefinition.cjs +2 -2
- package/__cjs/masking/maskFragment.cjs +2 -2
- package/__cjs/masking/maskOperation.cjs +1 -1
- package/__cjs/masking/utils.cjs +3 -3
- package/__cjs/react/context/ApolloContext.cjs +1 -1
- package/__cjs/react/context/ApolloProvider.cjs +1 -1
- package/__cjs/react/hooks/internal/validateSuspenseHookOptions.cjs +2 -2
- package/__cjs/react/hooks/useApolloClient.cjs +1 -1
- package/__cjs/react/hooks/useLazyQuery.cjs +2 -2
- package/__cjs/react/hooks/useLoadableQuery.cjs +2 -2
- package/__cjs/react/hooks/useSubscription.cjs +1 -1
- package/__cjs/react/hooks/useSyncExternalStore.cjs +1 -1
- package/__cjs/react/internal/cache/QueryReference.cjs +1 -1
- package/__cjs/react/ssr/prerenderStatic.cjs +2 -2
- package/__cjs/testing/core/mocking/mockLink.cjs +4 -4
- package/__cjs/utilities/graphql/DocumentTransform.cjs +1 -1
- package/__cjs/utilities/internal/capitalize.cjs +12 -0
- package/__cjs/utilities/internal/capitalize.cjs.map +1 -0
- package/__cjs/utilities/internal/capitalize.d.cts +7 -0
- package/__cjs/utilities/internal/coerceScalarFieldsToParsed.cjs +69 -0
- package/__cjs/utilities/internal/coerceScalarFieldsToParsed.cjs.map +1 -0
- package/__cjs/utilities/internal/coerceScalarFieldsToParsed.d.cts +9 -0
- package/__cjs/utilities/internal/getFragmentDefinition.cjs +3 -3
- package/__cjs/utilities/internal/getFragmentFromSelection.cjs +1 -1
- package/__cjs/utilities/internal/getFragmentFromSelection.cjs.map +1 -1
- package/__cjs/utilities/internal/getFragmentQueryDocument.cjs +2 -2
- package/__cjs/utilities/internal/getMainDefinition.cjs +1 -1
- package/__cjs/utilities/internal/getQueryDefinition.cjs +1 -1
- package/__cjs/utilities/internal/index.cjs +6 -2
- package/__cjs/utilities/internal/index.cjs.map +1 -1
- package/__cjs/utilities/internal/index.d.cts +2 -0
- package/__cjs/utilities/internal/removeDirectivesFromDocument.cjs +1 -1
- package/__cjs/utilities/internal/shouldInclude.cjs +4 -4
- package/__cjs/utilities/internal/valueToObjectRepresentation.cjs +1 -1
- package/__cjs/version.cjs +1 -1
- package/cache/core/cache.d.ts +19 -1
- package/cache/core/cache.js +26 -2
- package/cache/core/cache.js.map +1 -1
- package/cache/inmemory/entityStore.js +3 -3
- package/cache/inmemory/inMemoryCache.d.ts +5 -1
- package/cache/inmemory/inMemoryCache.js +10 -0
- package/cache/inmemory/inMemoryCache.js.map +1 -1
- package/cache/inmemory/key-extractor.js +1 -1
- package/cache/inmemory/policies.js +5 -5
- package/cache/inmemory/readFromStore.js +3 -3
- package/cache/inmemory/writeToStore.js +4 -4
- package/core/ApolloClient.js +14 -14
- package/core/ObservableQuery.d.ts +3 -6
- package/core/ObservableQuery.js +169 -61
- package/core/ObservableQuery.js.map +1 -1
- package/core/QueryInfo.d.ts +1 -25
- package/core/QueryInfo.js +11 -125
- package/core/QueryInfo.js.map +1 -1
- package/core/QueryManager.js +24 -16
- package/core/QueryManager.js.map +1 -1
- package/core/RefetchEventManager.js +3 -3
- package/incremental/handlers/graphql17Alpha9.js +1 -1
- package/incremental/handlers/notImplemented.js +1 -1
- package/invariantErrorCodes.js +141 -115
- package/link/core/ApolloLink.js +3 -3
- package/link/http/checkFetcher.js +1 -1
- package/link/http/parseAndCheckHttpResponse.js +2 -2
- package/link/http/parseAndCheckHttpResponse.js.map +1 -1
- package/link/persisted-queries/index.js +2 -2
- package/link/ws/index.js +1 -1
- package/local-state/LocalState.js +11 -11
- package/masking/maskDefinition.js +2 -2
- package/masking/maskFragment.js +2 -2
- package/masking/maskOperation.js +1 -1
- package/masking/utils.js +3 -3
- package/package.json +1 -1
- package/react/context/ApolloContext.js +1 -1
- package/react/context/ApolloProvider.js +1 -1
- package/react/hooks/internal/validateSuspenseHookOptions.js +2 -2
- package/react/hooks/useApolloClient.js +1 -1
- package/react/hooks/useLazyQuery.js +2 -2
- package/react/hooks/useLoadableQuery.js +2 -2
- package/react/hooks/useSubscription.js +1 -1
- package/react/hooks/useSyncExternalStore.js +1 -1
- package/react/hooks-compiled/internal/validateSuspenseHookOptions.js +2 -2
- package/react/hooks-compiled/useApolloClient.js +1 -1
- package/react/hooks-compiled/useLazyQuery.js +2 -2
- package/react/hooks-compiled/useLoadableQuery.js +2 -2
- package/react/hooks-compiled/useSubscription.js +1 -1
- package/react/hooks-compiled/useSyncExternalStore.js +1 -1
- package/react/internal/cache/QueryReference.js +1 -1
- package/react/ssr/prerenderStatic.js +2 -2
- package/testing/core/mocking/mockLink.js +4 -4
- package/utilities/graphql/DocumentTransform.js +1 -1
- package/utilities/internal/capitalize.d.ts +7 -0
- package/utilities/internal/capitalize.js +9 -0
- package/utilities/internal/capitalize.js.map +1 -0
- package/utilities/internal/coerceScalarFieldsToParsed.d.ts +9 -0
- package/utilities/internal/coerceScalarFieldsToParsed.js +66 -0
- package/utilities/internal/coerceScalarFieldsToParsed.js.map +1 -0
- package/utilities/internal/getFragmentDefinition.js +3 -3
- package/utilities/internal/getFragmentFromSelection.js +1 -1
- package/utilities/internal/getFragmentFromSelection.js.map +1 -1
- package/utilities/internal/getFragmentQueryDocument.js +2 -2
- package/utilities/internal/getMainDefinition.js +1 -1
- package/utilities/internal/getQueryDefinition.js +1 -1
- package/utilities/internal/index.d.ts +2 -0
- package/utilities/internal/index.js +2 -0
- package/utilities/internal/index.js.map +1 -1
- package/utilities/internal/removeDirectivesFromDocument.js +1 -1
- package/utilities/internal/shouldInclude.js +4 -4
- package/utilities/internal/valueToObjectRepresentation.js +1 -1
- package/version.js +1 -1
|
@@ -242,7 +242,7 @@ export class Policies {
|
|
|
242
242
|
const rootId = "ROOT_" + which.toUpperCase();
|
|
243
243
|
const old = this.rootTypenamesById[rootId];
|
|
244
244
|
if (typename !== old) {
|
|
245
|
-
invariant(!old || old === which,
|
|
245
|
+
invariant(!old || old === which, 111, which);
|
|
246
246
|
// First, delete any old __typename associated with this rootId from
|
|
247
247
|
// rootIdsByTypename.
|
|
248
248
|
if (old)
|
|
@@ -385,7 +385,7 @@ export class Policies {
|
|
|
385
385
|
if (supertypeSet.has(supertype)) {
|
|
386
386
|
if (!typenameSupertypeSet.has(supertype)) {
|
|
387
387
|
if (checkingFuzzySubtypes) {
|
|
388
|
-
__DEV__ && invariant.warn(
|
|
388
|
+
__DEV__ && invariant.warn(112, typename, supertype);
|
|
389
389
|
}
|
|
390
390
|
// Record positive results for faster future lookup.
|
|
391
391
|
// Unfortunately, we cannot safely cache negative results,
|
|
@@ -641,7 +641,7 @@ export function normalizeReadFieldOptions(readFieldArgs, objectOrReference, vari
|
|
|
641
641
|
}
|
|
642
642
|
}
|
|
643
643
|
if (__DEV__ && options.from === void 0) {
|
|
644
|
-
__DEV__ && invariant.warn(
|
|
644
|
+
__DEV__ && invariant.warn(113, stringifyForDisplay(Array.from(readFieldArgs)));
|
|
645
645
|
}
|
|
646
646
|
if (void 0 === options.variables) {
|
|
647
647
|
options.variables = variables;
|
|
@@ -651,7 +651,7 @@ export function normalizeReadFieldOptions(readFieldArgs, objectOrReference, vari
|
|
|
651
651
|
function makeMergeObjectsFunction(store) {
|
|
652
652
|
return function mergeObjects(existing, incoming) {
|
|
653
653
|
if (isArray(existing) || isArray(incoming)) {
|
|
654
|
-
throw newInvariantError(
|
|
654
|
+
throw newInvariantError(114);
|
|
655
655
|
}
|
|
656
656
|
// These dynamic checks are necessary because the parameters of a
|
|
657
657
|
// custom merge function can easily have the any type, so the type
|
|
@@ -688,6 +688,6 @@ function makeMergeObjectsFunction(store) {
|
|
|
688
688
|
};
|
|
689
689
|
}
|
|
690
690
|
function warnAboutScalarConfig(typename, fieldName, scalar, kind) {
|
|
691
|
-
__DEV__ && invariant.warn(
|
|
691
|
+
__DEV__ && invariant.warn(115, `${typename}.${fieldName}`, scalar, kind);
|
|
692
692
|
}
|
|
693
693
|
//# sourceMappingURL=policies.js.map
|
|
@@ -282,7 +282,7 @@ export class StoreReader {
|
|
|
282
282
|
if (typename) {
|
|
283
283
|
const policy = policies["getFieldPolicy"](typename, fieldName);
|
|
284
284
|
if (policy?.scalar) {
|
|
285
|
-
__DEV__ && invariant.warn(
|
|
285
|
+
__DEV__ && invariant.warn(116, `${typename}.${fieldName}`, policy.scalar);
|
|
286
286
|
}
|
|
287
287
|
}
|
|
288
288
|
}
|
|
@@ -319,7 +319,7 @@ export class StoreReader {
|
|
|
319
319
|
else {
|
|
320
320
|
const fragment = getFragmentFromSelection(selection, context.lookupFragment);
|
|
321
321
|
if (!fragment && selection.kind === Kind.FRAGMENT_SPREAD) {
|
|
322
|
-
throw newInvariantError(
|
|
322
|
+
throw newInvariantError(117, selection.name.value);
|
|
323
323
|
}
|
|
324
324
|
if (fragment && policies.fragmentMatches(fragment, typename)) {
|
|
325
325
|
const isDeferBoundary = isDeferredFragment(selection, context.variables);
|
|
@@ -616,7 +616,7 @@ function assertSelectionSetForIdValue(store, field, fieldValue) {
|
|
|
616
616
|
if (isNonNullObject(value)) {
|
|
617
617
|
invariant(
|
|
618
618
|
!isReference(value),
|
|
619
|
-
|
|
619
|
+
118,
|
|
620
620
|
getTypenameFromStoreObject(store, value),
|
|
621
621
|
field.name.value
|
|
622
622
|
);
|
|
@@ -68,7 +68,7 @@ export class StoreWriter {
|
|
|
68
68
|
path: [],
|
|
69
69
|
});
|
|
70
70
|
if (!isReference(ref)) {
|
|
71
|
-
throw newInvariantError(
|
|
71
|
+
throw newInvariantError(119, result);
|
|
72
72
|
}
|
|
73
73
|
// So far, the store has not been modified, so now it's time to process
|
|
74
74
|
// context.incomingById and merge those incoming fields into context.store.
|
|
@@ -230,7 +230,7 @@ export class StoreWriter {
|
|
|
230
230
|
// provide a default value, so its absence from the written data should
|
|
231
231
|
// not be cause for alarm.
|
|
232
232
|
!policies.getReadFunction(typename, field.name.value)) {
|
|
233
|
-
invariant.error(
|
|
233
|
+
invariant.error(120, resultKeyNameFromField(field), result);
|
|
234
234
|
}
|
|
235
235
|
});
|
|
236
236
|
// Identify the result object, even if dataId was already provided,
|
|
@@ -378,7 +378,7 @@ export class StoreWriter {
|
|
|
378
378
|
else {
|
|
379
379
|
const fragment = getFragmentFromSelection(selection, context.lookupFragment);
|
|
380
380
|
if (!fragment && selection.kind === Kind.FRAGMENT_SPREAD) {
|
|
381
|
-
throw newInvariantError(
|
|
381
|
+
throw newInvariantError(121, selection.name.value);
|
|
382
382
|
}
|
|
383
383
|
if (fragment &&
|
|
384
384
|
policies.fragmentMatches(fragment, typename, result, context.variables)) {
|
|
@@ -550,7 +550,7 @@ function warnAboutDataLoss(existingRef, incomingObj, storeFieldName, store) {
|
|
|
550
550
|
}
|
|
551
551
|
});
|
|
552
552
|
}
|
|
553
|
-
__DEV__ && invariant.warn(
|
|
553
|
+
__DEV__ && invariant.warn(122, fieldName, parentType, childTypenames.length ?
|
|
554
554
|
"either ensure all objects of type " +
|
|
555
555
|
childTypenames.join(" and ") +
|
|
556
556
|
" have an ID or a custom merge function, or "
|
package/core/ApolloClient.js
CHANGED
|
@@ -71,8 +71,8 @@ export class ApolloClient {
|
|
|
71
71
|
*/
|
|
72
72
|
constructor(options) {
|
|
73
73
|
if (__DEV__) {
|
|
74
|
-
invariant(options.cache,
|
|
75
|
-
invariant(options.link,
|
|
74
|
+
invariant(options.cache, 69);
|
|
75
|
+
invariant(options.link, 70);
|
|
76
76
|
}
|
|
77
77
|
const { cache, documentTransform, ssrMode = false, ssrForceFetchDelay = 0, queryDeduplication = true, defaultOptions, defaultContext, assumeImmutableResults = cache.assumeImmutableResults, localState, devtools, dataMasking, link, incrementalHandler = new NotImplementedHandler(), experiments = [], refetchEventManager, } = options;
|
|
78
78
|
this.link = link;
|
|
@@ -260,12 +260,12 @@ export class ApolloClient {
|
|
|
260
260
|
if (refetchOn) {
|
|
261
261
|
const operationName = getOperationName(query, "(anonymous)");
|
|
262
262
|
if (!refetchEventManager) {
|
|
263
|
-
__DEV__ && invariant.warn(
|
|
263
|
+
__DEV__ && invariant.warn(71, operationName);
|
|
264
264
|
}
|
|
265
265
|
else if (typeof refetchOn === "object") {
|
|
266
266
|
Object.keys(refetchOn).forEach((source) => {
|
|
267
267
|
if (!refetchEventManager.hasSource(source)) {
|
|
268
|
-
__DEV__ && invariant.warn(
|
|
268
|
+
__DEV__ && invariant.warn(72, source, operationName);
|
|
269
269
|
}
|
|
270
270
|
});
|
|
271
271
|
}
|
|
@@ -287,13 +287,13 @@ export class ApolloClient {
|
|
|
287
287
|
options = mergeOptions(this.defaultOptions.query, options);
|
|
288
288
|
}
|
|
289
289
|
if (__DEV__) {
|
|
290
|
-
invariant(options.fetchPolicy !== "cache-and-network",
|
|
291
|
-
invariant(options.fetchPolicy !== "standby",
|
|
292
|
-
invariant(options.query,
|
|
293
|
-
invariant(options.query.kind === "Document",
|
|
294
|
-
invariant(!options.returnPartialData,
|
|
295
|
-
invariant(!options.pollInterval,
|
|
296
|
-
invariant(!options.notifyOnNetworkStatusChange,
|
|
290
|
+
invariant(options.fetchPolicy !== "cache-and-network", 73);
|
|
291
|
+
invariant(options.fetchPolicy !== "standby", 74);
|
|
292
|
+
invariant(options.query, 75);
|
|
293
|
+
invariant(options.query.kind === "Document", 76);
|
|
294
|
+
invariant(!options.returnPartialData, 77);
|
|
295
|
+
invariant(!options.pollInterval, 78);
|
|
296
|
+
invariant(!options.notifyOnNetworkStatusChange, 79);
|
|
297
297
|
}
|
|
298
298
|
return this.queryManager.query(options);
|
|
299
299
|
};
|
|
@@ -311,9 +311,9 @@ export class ApolloClient {
|
|
|
311
311
|
errorPolicy: "none",
|
|
312
312
|
}, this.defaultOptions.mutate), options);
|
|
313
313
|
if (__DEV__) {
|
|
314
|
-
invariant(optionsWithDefaults.mutation,
|
|
314
|
+
invariant(optionsWithDefaults.mutation, 80);
|
|
315
315
|
invariant(optionsWithDefaults.fetchPolicy === "network-only" ||
|
|
316
|
-
optionsWithDefaults.fetchPolicy === "no-cache",
|
|
316
|
+
optionsWithDefaults.fetchPolicy === "no-cache", 81);
|
|
317
317
|
}
|
|
318
318
|
checkDocument(optionsWithDefaults.mutation, OperationTypeNode.MUTATION);
|
|
319
319
|
return this.queryManager.mutate(optionsWithDefaults);
|
|
@@ -519,7 +519,7 @@ export class ApolloClient {
|
|
|
519
519
|
// result.queries and result.results instead, you shouldn't have to worry
|
|
520
520
|
// about preventing uncaught rejections for the Promise.all result.
|
|
521
521
|
result.catch((error) => {
|
|
522
|
-
__DEV__ && invariant.debug(
|
|
522
|
+
__DEV__ && invariant.debug(82, error);
|
|
523
523
|
});
|
|
524
524
|
return result;
|
|
525
525
|
}
|
|
@@ -278,12 +278,8 @@ export declare class ObservableQuery<TData = unknown, TVariables extends Operati
|
|
|
278
278
|
readonly options: ObservableQuery.Options<TData, TVariables>;
|
|
279
279
|
readonly queryName?: string;
|
|
280
280
|
private variablesUnknown;
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
*
|
|
284
|
-
* @deprecated This is an internal API and should not be used directly. This can be removed or changed at any time.
|
|
285
|
-
*/
|
|
286
|
-
_lastWrite?: unknown;
|
|
281
|
+
private didWarnOnFeud;
|
|
282
|
+
private lastMissing?;
|
|
287
283
|
get query(): TypedDocumentNode<TData, TVariables>;
|
|
288
284
|
/**
|
|
289
285
|
* An object containing the variables that were provided for the query.
|
|
@@ -469,6 +465,7 @@ export declare class ObservableQuery<TData = unknown, TVariables extends Operati
|
|
|
469
465
|
* @deprecated This is an internal API and should not be used directly. This can be removed or changed at any time.
|
|
470
466
|
*/
|
|
471
467
|
notify(scheduled?: boolean): void;
|
|
468
|
+
private deliverCacheDiff;
|
|
472
469
|
private activeOperations;
|
|
473
470
|
private pushOperation;
|
|
474
471
|
private calculateNetworkStatus;
|
package/core/ObservableQuery.js
CHANGED
|
@@ -21,16 +21,29 @@ const empty = {
|
|
|
21
21
|
dataState: "empty",
|
|
22
22
|
partial: true,
|
|
23
23
|
};
|
|
24
|
+
const destructiveMethodCounts = new WeakMap();
|
|
25
|
+
function wrapDestructiveCacheMethod(cache, methodName) {
|
|
26
|
+
const original = cache[methodName];
|
|
27
|
+
if (typeof original === "function") {
|
|
28
|
+
// @ts-expect-error this is just too generic to be typed correctly
|
|
29
|
+
cache[methodName] = function () {
|
|
30
|
+
destructiveMethodCounts.set(cache,
|
|
31
|
+
// The %1e15 allows the count to wrap around to 0 safely every
|
|
32
|
+
// quadrillion evictions, so there's no risk of overflow. To be
|
|
33
|
+
// clear, this is more of a pedantic principle than something
|
|
34
|
+
// that matters in any conceivable practical scenario.
|
|
35
|
+
(destructiveMethodCounts.get(cache) + 1) % 1e15);
|
|
36
|
+
// @ts-expect-error this is just too generic to be typed correctly
|
|
37
|
+
return original.apply(this, arguments);
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
24
41
|
export class ObservableQuery {
|
|
25
42
|
options;
|
|
26
43
|
queryName;
|
|
27
44
|
variablesUnknown = false;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
*
|
|
31
|
-
* @deprecated This is an internal API and should not be used directly. This can be removed or changed at any time.
|
|
32
|
-
*/
|
|
33
|
-
_lastWrite;
|
|
45
|
+
didWarnOnFeud = false;
|
|
46
|
+
lastMissing;
|
|
34
47
|
// The `query` computed property will always reflect the document transformed
|
|
35
48
|
// by the last run query. `this.options.query` will always reflect the raw
|
|
36
49
|
// untransformed query to ensure document transforms with runtime conditionals
|
|
@@ -67,6 +80,18 @@ export class ObservableQuery {
|
|
|
67
80
|
}
|
|
68
81
|
constructor({ queryManager, options, transformedQuery = queryManager.transform(options.query), }) {
|
|
69
82
|
this.queryManager = queryManager;
|
|
83
|
+
// Track how often destructive cache methods are called, since we want
|
|
84
|
+
// eviction to override the feud-stopping logic in `shouldAutoRefetch`,
|
|
85
|
+
// by causing it to return true. Wrapping these cache methods is a bit of a
|
|
86
|
+
// hack, but it saves us from having to make eviction counting an official
|
|
87
|
+
// part of the ApolloCache API.
|
|
88
|
+
const { cache } = queryManager;
|
|
89
|
+
if (!destructiveMethodCounts.has(cache)) {
|
|
90
|
+
destructiveMethodCounts.set(cache, 0);
|
|
91
|
+
wrapDestructiveCacheMethod(cache, "evict");
|
|
92
|
+
wrapDestructiveCacheMethod(cache, "modify");
|
|
93
|
+
wrapDestructiveCacheMethod(cache, "reset");
|
|
94
|
+
}
|
|
70
95
|
// active state
|
|
71
96
|
this.waitForNetworkResult = options.fetchPolicy === "network-only";
|
|
72
97
|
this.isTornDown = false;
|
|
@@ -77,7 +102,7 @@ export class ObservableQuery {
|
|
|
77
102
|
// Make sure we don't store "standby" as the initialFetchPolicy.
|
|
78
103
|
initialFetchPolicy = fetchPolicy === "standby" ? defaultFetchPolicy : (fetchPolicy), } = options;
|
|
79
104
|
if (options[variablesUnknownSymbol]) {
|
|
80
|
-
invariant(fetchPolicy === "standby",
|
|
105
|
+
invariant(fetchPolicy === "standby", 83);
|
|
81
106
|
this.variablesUnknown = true;
|
|
82
107
|
}
|
|
83
108
|
this.lastQuery = transformedQuery;
|
|
@@ -386,7 +411,7 @@ export class ObservableQuery {
|
|
|
386
411
|
const queryDef = getQueryDefinition(this.query);
|
|
387
412
|
const vars = queryDef.variableDefinitions;
|
|
388
413
|
if (!vars || !vars.some((v) => v.variable.name.value === "variables")) {
|
|
389
|
-
__DEV__ && invariant.warn(
|
|
414
|
+
__DEV__ && invariant.warn(84, variables, queryDef.name?.value || queryDef);
|
|
390
415
|
}
|
|
391
416
|
}
|
|
392
417
|
if (variables && !equal(this.variables, variables)) {
|
|
@@ -394,7 +419,6 @@ export class ObservableQuery {
|
|
|
394
419
|
reobserveOptions.variables = this.options.variables =
|
|
395
420
|
this.getVariablesWithDefaults({ ...this.variables, ...variables });
|
|
396
421
|
}
|
|
397
|
-
this._lastWrite = undefined;
|
|
398
422
|
return this._reobserve(reobserveOptions, {
|
|
399
423
|
newNetworkStatus: NetworkStatus.refetch,
|
|
400
424
|
});
|
|
@@ -402,7 +426,7 @@ export class ObservableQuery {
|
|
|
402
426
|
fetchMore({ query, variables, context, errorPolicy, updateQuery, }) {
|
|
403
427
|
invariant(
|
|
404
428
|
this.options.fetchPolicy !== "cache-only",
|
|
405
|
-
|
|
429
|
+
85,
|
|
406
430
|
getOperationName(this.query, "(anonymous)")
|
|
407
431
|
);
|
|
408
432
|
const combinedOptions = {
|
|
@@ -436,7 +460,7 @@ export class ObservableQuery {
|
|
|
436
460
|
let wasUpdated = false;
|
|
437
461
|
const isCached = this.options.fetchPolicy !== "no-cache";
|
|
438
462
|
if (!isCached) {
|
|
439
|
-
invariant(updateQuery,
|
|
463
|
+
invariant(updateQuery, 86);
|
|
440
464
|
}
|
|
441
465
|
const { finalize, pushNotification } = this.pushOperation(NetworkStatus.fetchMore);
|
|
442
466
|
pushNotification({
|
|
@@ -610,7 +634,7 @@ export class ObservableQuery {
|
|
|
610
634
|
onError(error);
|
|
611
635
|
}
|
|
612
636
|
else {
|
|
613
|
-
invariant.error(
|
|
637
|
+
invariant.error(87, error);
|
|
614
638
|
}
|
|
615
639
|
return;
|
|
616
640
|
}
|
|
@@ -861,7 +885,7 @@ export class ObservableQuery {
|
|
|
861
885
|
if (!this.didWarnCacheOnlyPolling &&
|
|
862
886
|
pollInterval &&
|
|
863
887
|
fetchPolicy === "cache-only") {
|
|
864
|
-
__DEV__ && invariant.warn(
|
|
888
|
+
__DEV__ && invariant.warn(88, getOperationName(this.query, "(anonymous)"));
|
|
865
889
|
this.didWarnCacheOnlyPolling = true;
|
|
866
890
|
}
|
|
867
891
|
}
|
|
@@ -882,7 +906,6 @@ export class ObservableQuery {
|
|
|
882
906
|
if (this.pollingInfo) {
|
|
883
907
|
if (!isNetworkRequestInFlight(this.networkStatus) &&
|
|
884
908
|
!this.options.skipPollAttempt?.()) {
|
|
885
|
-
this._lastWrite = undefined;
|
|
886
909
|
this._reobserve({
|
|
887
910
|
// Most fetchPolicy options don't make sense to use in a polling context, as
|
|
888
911
|
// users wouldn't want to be polling the cache directly. However, network-only and
|
|
@@ -928,7 +951,10 @@ export class ObservableQuery {
|
|
|
928
951
|
}
|
|
929
952
|
_reobserve(newOptions, internalOptions) {
|
|
930
953
|
this.isTornDown = false;
|
|
931
|
-
let { newNetworkStatus } = internalOptions || {};
|
|
954
|
+
let { newNetworkStatus, keepLastMissing } = internalOptions || {};
|
|
955
|
+
if (!keepLastMissing) {
|
|
956
|
+
this.lastMissing = undefined;
|
|
957
|
+
}
|
|
932
958
|
this.queryManager.obsQueries.add(this);
|
|
933
959
|
const useDisposableObservable =
|
|
934
960
|
// Refetching uses a disposable Observable to allow refetches using different
|
|
@@ -1069,7 +1095,7 @@ export class ObservableQuery {
|
|
|
1069
1095
|
this.queryManager.obsQueries.delete(this);
|
|
1070
1096
|
this.isTornDown = true;
|
|
1071
1097
|
this.abortActiveOperations();
|
|
1072
|
-
this.
|
|
1098
|
+
this.lastMissing = undefined;
|
|
1073
1099
|
}
|
|
1074
1100
|
transformDocument(document) {
|
|
1075
1101
|
return this.queryManager.transform(document);
|
|
@@ -1127,51 +1153,126 @@ export class ObservableQuery {
|
|
|
1127
1153
|
return;
|
|
1128
1154
|
}
|
|
1129
1155
|
}
|
|
1130
|
-
const { dirty } = this;
|
|
1156
|
+
const { dirty, lastMissing } = this;
|
|
1157
|
+
const { fetchPolicy } = this.options;
|
|
1131
1158
|
this.resetNotifications();
|
|
1132
|
-
if (dirty
|
|
1133
|
-
(
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1159
|
+
if (!dirty ||
|
|
1160
|
+
(fetchPolicy !== "cache-only" &&
|
|
1161
|
+
fetchPolicy !== "cache-and-network" &&
|
|
1162
|
+
this.activeOperations.size)) {
|
|
1163
|
+
return;
|
|
1164
|
+
}
|
|
1165
|
+
const diff = this.getCacheDiff();
|
|
1166
|
+
const current = this.getCurrentResult();
|
|
1167
|
+
// `fromOptimisticTransaction` is not available through the `cache.diff`
|
|
1168
|
+
// code path, so we need to check whether the cache result is an optimistic
|
|
1169
|
+
// result this way.
|
|
1170
|
+
const isOptimistic = !equal(diff.result, this.getCacheDiff({ optimistic: false }).result);
|
|
1171
|
+
if (
|
|
1172
|
+
// When this diff came from an optimistic transaction, deliver the
|
|
1173
|
+
// current cache data to the ObservableQuery, but don't perform a
|
|
1174
|
+
// reobservation, since oq.reobserveCacheFirst might make a network
|
|
1175
|
+
// request, and we never want to trigger network requests in the
|
|
1176
|
+
// middle of optimistic updates.
|
|
1177
|
+
isOptimistic ||
|
|
1178
|
+
// If we get a cache update in the middle of streaming (possible with
|
|
1179
|
+
// cache-and-network fetch policy), just deliver the cache value without
|
|
1180
|
+
// going through the full reobserve which would otherwise trigger another
|
|
1181
|
+
// request (deduplication should kick in, but doing so replays any
|
|
1182
|
+
// previous emits from the link chain, which get rewritten into the cache
|
|
1183
|
+
// and might clobber this cache update)
|
|
1184
|
+
(!diff.complete && current.networkStatus === NetworkStatus.streaming)) {
|
|
1185
|
+
this.deliverCacheDiff(diff);
|
|
1186
|
+
return;
|
|
1187
|
+
}
|
|
1188
|
+
if (diff.complete) {
|
|
1189
|
+
this.lastMissing = undefined;
|
|
1190
|
+
}
|
|
1191
|
+
else if (!lastMissing ||
|
|
1192
|
+
// If a destructive cache method has been called since the last recorded
|
|
1193
|
+
// incomplete result, there's a chance fetching this data again will
|
|
1194
|
+
// restore what was evicted, even though the cache result looks the same
|
|
1195
|
+
// as before.
|
|
1196
|
+
lastMissing.dmCount !== destructiveMethodCounts.get(this.cache) ||
|
|
1197
|
+
!equal(lastMissing.variables, this.variables) ||
|
|
1198
|
+
!equal(lastMissing.missing, diff.missing?.missing)) {
|
|
1199
|
+
this.didWarnOnFeud = false;
|
|
1200
|
+
this.lastMissing = {
|
|
1201
|
+
variables: this.variables,
|
|
1202
|
+
missing: diff.missing?.missing,
|
|
1203
|
+
dmCount: destructiveMethodCounts.get(this.cache),
|
|
1204
|
+
};
|
|
1205
|
+
}
|
|
1206
|
+
else if (
|
|
1207
|
+
// reobserveCacheFirst with cache-only fetch policy only calls
|
|
1208
|
+
// reobserve which never fetches from the network so we are ok
|
|
1209
|
+
// allowing cache-only queries to fallthrough to reobserveCacheFirst.
|
|
1210
|
+
// This also prevents the feud warning which would be confusing for a
|
|
1211
|
+
// cache-only query anyways.
|
|
1212
|
+
fetchPolicy !== "cache-only") {
|
|
1213
|
+
// If we've fallen through to this case, a cache emit has returned the
|
|
1214
|
+
// same missing fields which means at least one value on the fields we've
|
|
1215
|
+
// already delivered have changed. We are ok delivering the updated
|
|
1216
|
+
// partial result in this case to keep the result as fresh as possible. We
|
|
1217
|
+
// NEVER want to downgrade this query from a complete query to a partial
|
|
1218
|
+
// query though, so we also make sure we only deliver if the previous
|
|
1219
|
+
// result was also partial.
|
|
1220
|
+
if (current.dataState === "partial") {
|
|
1221
|
+
this.deliverCacheDiff(diff);
|
|
1151
1222
|
}
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1223
|
+
// If the (partial) result is the same as the last partial result
|
|
1224
|
+
// we recorded from a previous broadcast (and the variables match
|
|
1225
|
+
// too), avoid calling reobserveCacheFirst to refetch this query
|
|
1226
|
+
// again. If we allow refetching anytime this result becomes partial,
|
|
1227
|
+
// we risk feuds between queries competing to update the same data in
|
|
1228
|
+
// incompatible ways, which can lead to an endless cycle of cache
|
|
1229
|
+
// broadcasts and useless network requests. As with any
|
|
1230
|
+
// feud, eventually one side must step back from the brink,
|
|
1231
|
+
// letting the other side(s) have the last word(s). There may
|
|
1232
|
+
// be other points where we could break this cycle, such as
|
|
1233
|
+
// silencing the broadcast for cache.writeQuery (not a good
|
|
1234
|
+
// idea, since it just delays the feud a bit) or somehow
|
|
1235
|
+
// avoiding the network request that just happened (also bad,
|
|
1236
|
+
// because the server could return useful new data). All
|
|
1237
|
+
// options considered, returning early and stopping the
|
|
1238
|
+
// reobserveCacheFirst cycle seems to be the least damaging place to
|
|
1239
|
+
// break the cycle because it allows read functions/custom scalars to
|
|
1240
|
+
// be applied to the feuding query while avoiding the endless cycle of
|
|
1241
|
+
// requests.
|
|
1242
|
+
if (__DEV__ && !this.didWarnOnFeud) {
|
|
1243
|
+
this.didWarnOnFeud = true;
|
|
1244
|
+
warnOnFeud(this.query, diff);
|
|
1173
1245
|
}
|
|
1246
|
+
return;
|
|
1174
1247
|
}
|
|
1248
|
+
//If this diff did not come from an optimistic transaction
|
|
1249
|
+
// make the ObservableQuery "reobserve" the latest data
|
|
1250
|
+
// using a temporary fetch policy of "cache-first", so complete cache
|
|
1251
|
+
// results have a chance to be delivered without triggering additional
|
|
1252
|
+
// network requests, even when options.fetchPolicy is "network-only"
|
|
1253
|
+
// or "cache-and-network". All other fetch policies are preserved by
|
|
1254
|
+
// this method, and are handled by calling oq.reobserve(). If this
|
|
1255
|
+
// reobservation is spurious, distinctUntilChanged still has a
|
|
1256
|
+
// chance to catch it before delivery to ObservableQuery subscribers.
|
|
1257
|
+
this.reobserveCacheFirst();
|
|
1258
|
+
}
|
|
1259
|
+
deliverCacheDiff(diff) {
|
|
1260
|
+
const current = this.getCurrentResult();
|
|
1261
|
+
this.input.next({
|
|
1262
|
+
kind: "N",
|
|
1263
|
+
value: {
|
|
1264
|
+
data: diff.result,
|
|
1265
|
+
dataState: diff.dataState,
|
|
1266
|
+
networkStatus: current.networkStatus,
|
|
1267
|
+
loading: current.loading,
|
|
1268
|
+
error: undefined,
|
|
1269
|
+
partial: !diff.complete,
|
|
1270
|
+
},
|
|
1271
|
+
source: "cache",
|
|
1272
|
+
query: this.query,
|
|
1273
|
+
variables: this.variables,
|
|
1274
|
+
meta: {},
|
|
1275
|
+
});
|
|
1175
1276
|
}
|
|
1176
1277
|
activeOperations = new Set();
|
|
1177
1278
|
pushOperation(networkStatus) {
|
|
@@ -1234,6 +1335,7 @@ export class ObservableQuery {
|
|
|
1234
1335
|
// exception for cache-only queries - we reset them into a "ready" state
|
|
1235
1336
|
// as we won't trigger a refetch for them
|
|
1236
1337
|
const resetToEmpty = this.options.fetchPolicy === "cache-only";
|
|
1338
|
+
this.lastMissing = undefined;
|
|
1237
1339
|
this.setResult(resetToEmpty ? empty : uninitialized, {
|
|
1238
1340
|
shouldEmit: resetToEmpty ? 1 /* EmitBehavior.force */ : 2 /* EmitBehavior.never */,
|
|
1239
1341
|
});
|
|
@@ -1378,7 +1480,10 @@ export class ObservableQuery {
|
|
|
1378
1480
|
reobserveCacheFirst() {
|
|
1379
1481
|
const { fetchPolicy, nextFetchPolicy } = this.options;
|
|
1380
1482
|
if (fetchPolicy === "cache-and-network" || fetchPolicy === "network-only") {
|
|
1381
|
-
this.
|
|
1483
|
+
// Preserve this.lastMissing so a cache update that triggers this
|
|
1484
|
+
// reobserve doesn't reset feud detection. All user-initiated calls to
|
|
1485
|
+
// reobserve (refetch/poll/reobserve, etc) should clear it.
|
|
1486
|
+
this._reobserve({
|
|
1382
1487
|
fetchPolicy: "cache-first",
|
|
1383
1488
|
// Use a temporary nextFetchPolicy function that replaces itself with the
|
|
1384
1489
|
// previous nextFetchPolicy value and returns the original fetchPolicy.
|
|
@@ -1394,10 +1499,10 @@ export class ObservableQuery {
|
|
|
1394
1499
|
// Otherwise go back to the original this.options.fetchPolicy.
|
|
1395
1500
|
return fetchPolicy;
|
|
1396
1501
|
},
|
|
1397
|
-
});
|
|
1502
|
+
}, { keepLastMissing: true });
|
|
1398
1503
|
}
|
|
1399
1504
|
else {
|
|
1400
|
-
this.
|
|
1505
|
+
this._reobserve(undefined, { keepLastMissing: true });
|
|
1401
1506
|
}
|
|
1402
1507
|
}
|
|
1403
1508
|
getVariablesWithDefaults(variables) {
|
|
@@ -1406,7 +1511,7 @@ export class ObservableQuery {
|
|
|
1406
1511
|
}
|
|
1407
1512
|
export function logMissingFieldErrors(missing) {
|
|
1408
1513
|
if (__DEV__ && missing) {
|
|
1409
|
-
__DEV__ && invariant.debug(
|
|
1514
|
+
__DEV__ && invariant.debug(89, missing);
|
|
1410
1515
|
}
|
|
1411
1516
|
}
|
|
1412
1517
|
function isEqualQuery(a, b) {
|
|
@@ -1449,4 +1554,7 @@ function getTrackingOperatorPromise(defaultValue) {
|
|
|
1449
1554
|
});
|
|
1450
1555
|
return { promise, operator };
|
|
1451
1556
|
}
|
|
1557
|
+
function warnOnFeud(query, diff) {
|
|
1558
|
+
__DEV__ && invariant.warn(90, getOperationName(query, "(anonymous)"), diff.missing?.missing);
|
|
1559
|
+
}
|
|
1452
1560
|
//# sourceMappingURL=ObservableQuery.js.map
|