From 58ae8b8660ad16a399b0981c70abf6109ed1a3bc Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Mon, 4 Oct 2021 18:28:54 -0400 Subject: [PATCH] Make `client.{reset,clear}Store` pass `discardWatches` to `cache.reset` (#8873) --- CHANGELOG.md | 3 +++ src/core/ApolloClient.ts | 8 ++++-- src/core/QueryManager.ts | 18 +++---------- src/core/__tests__/ObservableQuery.ts | 3 ++- src/core/__tests__/QueryManager/index.ts | 32 ++++++++++++++---------- 5 files changed, 34 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed8dd86abac..18c650ba1ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,9 @@ - Avoid importing `isType` from the `graphql` package internally, to prevent bundlers from including as much as 3.4kB of unnecessary code.
[@benjamn](https://github.com/benjamn) in [#8891](https://github.com/apollographql/apollo-client/pull/8891) +- Make `client.resetStore` and `client.clearStore` pass appropriate `discardWatches` option to `cache.reset`.
+ [@benjamn](https://github.com/benjamn) in [#8873](https://github.com/apollographql/apollo-client/pull/8873) + ## Apollo Client 3.4.15 ### Bug Fixes diff --git a/src/core/ApolloClient.ts b/src/core/ApolloClient.ts index 617ba33a3c1..da86f5ee6d0 100644 --- a/src/core/ApolloClient.ts +++ b/src/core/ApolloClient.ts @@ -470,7 +470,9 @@ export class ApolloClient implements DataProxy { */ public resetStore(): Promise[] | null> { return Promise.resolve() - .then(() => this.queryManager.clearStore()) + .then(() => this.queryManager.clearStore({ + discardWatches: false, + })) .then(() => Promise.all(this.resetStoreCallbacks.map(fn => fn()))) .then(() => this.reFetchObservableQueries()); } @@ -481,7 +483,9 @@ export class ApolloClient implements DataProxy { */ public clearStore(): Promise { return Promise.resolve() - .then(() => this.queryManager.clearStore()) + .then(() => this.queryManager.clearStore({ + discardWatches: true, + })) .then(() => Promise.all(this.clearStoreCallbacks.map(fn => fn()))); } diff --git a/src/core/QueryManager.ts b/src/core/QueryManager.ts index e09911cc384..fe5f05a242a 100644 --- a/src/core/QueryManager.ts +++ b/src/core/QueryManager.ts @@ -696,7 +696,9 @@ export class QueryManager { if (queryInfo) queryInfo.stop(); } - public clearStore(): Promise { + public clearStore(options: Cache.ResetOptions = { + discardWatches: true, + }): Promise { // Before we have sent the reset action to the store, we can no longer // rely on the results returned by in-flight requests since these may // depend on values that previously existed in the data portion of the @@ -721,19 +723,7 @@ export class QueryManager { } // begin removing data from the store - return this.cache.reset(); - } - - public resetStore(): Promise[]> { - // Similarly, we have to have to refetch each of the queries currently being - // observed. We refetch instead of error'ing on these since the assumption is that - // resetting the store doesn't eliminate the need for the queries currently being - // watched. If there is an existing query in flight when the store is reset, - // the promise for it will be rejected and its results will not be written to the - // store. - return this.clearStore().then(() => { - return this.reFetchObservableQueries(); - }); + return this.cache.reset(options); } public getObservableQueries( diff --git a/src/core/__tests__/ObservableQuery.ts b/src/core/__tests__/ObservableQuery.ts index 45abeaa2ebe..3bf2794e2d3 100644 --- a/src/core/__tests__/ObservableQuery.ts +++ b/src/core/__tests__/ObservableQuery.ts @@ -15,6 +15,7 @@ import { itAsync, mockSingleLink, subscribeAndCount } from '../../testing'; import mockQueryManager from '../../utilities/testing/mocking/mockQueryManager'; import mockWatchQuery from '../../utilities/testing/mocking/mockWatchQuery'; import wrap from '../../utilities/testing/wrap'; +import { resetStore } from './QueryManager'; export const mockFetchQuery = (queryManager: QueryManager) => { const fetchQueryObservable = queryManager.fetchQueryObservable; @@ -459,7 +460,7 @@ describe('ObservableQuery', () => { expect(timesFired).toBe(1); // set policy to be cache-only but data is found await observable.setOptions({ fetchPolicy: 'cache-only' }); - await queryManager.resetStore(); + await resetStore(queryManager); } else if (handleCount === 2) { expect(result.data).toEqual({}); expect(result.loading).toBe(false); diff --git a/src/core/__tests__/QueryManager/index.ts b/src/core/__tests__/QueryManager/index.ts index cfd3e92479c..97cc6def0e0 100644 --- a/src/core/__tests__/QueryManager/index.ts +++ b/src/core/__tests__/QueryManager/index.ts @@ -47,6 +47,12 @@ interface MockedMutation { config?: ApolloReducerConfig; } +export function resetStore(qm: QueryManager) { + return qm.clearStore({ + discardWatches: false, + }).then(() => qm.reFetchObservableQueries()); +} + describe('QueryManager', () => { // Standard "get id from object" method. const dataIdFromObject = (object: any) => { @@ -3384,7 +3390,7 @@ describe('QueryManager', () => { observable.subscribe({ next: () => null }); observable2.subscribe({ next: () => null }); - return queryManager.resetStore().then(() => { + return resetStore(queryManager).then(() => { const result = getCurrentQueryResult(observable); expect(result.partial).toBe(false); expect(result.data).toEqual(dataChanged); @@ -3401,7 +3407,7 @@ describe('QueryManager', () => { link: mockSingleLink().setOnError(reject), }); - queryManager.resetStore(); + resetStore(queryManager); expect( queryManager.cache.extract(), @@ -3460,7 +3466,7 @@ describe('QueryManager', () => { expect(result.data).toEqual(data); expect(timesFired).toBe(1); // reset the store after data has returned - queryManager.resetStore(); + resetStore(queryManager); }, result => { // only refetch once and make sure data has changed @@ -3508,7 +3514,7 @@ describe('QueryManager', () => { // at this point the observable query has been torn down // because observableToPromise unsubscribe before resolving - queryManager.resetStore(); + resetStore(queryManager); setTimeout(() => { expect(timesFired).toBe(1); @@ -3560,7 +3566,7 @@ describe('QueryManager', () => { result => { expect(result.data).toEqual(data); expect(timesFired).toBe(1); - queryManager.resetStore().catch(reject); + resetStore(queryManager).catch(reject); }, result => { expect(result.data).toEqual(data); @@ -3602,7 +3608,7 @@ describe('QueryManager', () => { .catch(e => reject('Exception thrown for stopped query')); queryManager.removeQuery(queryId); - queryManager.resetStore().then(resolve, reject); + resetStore(queryManager).then(resolve, reject); }); itAsync('should throw an error on an inflight fetch query if the store is reset', (resolve, reject) => { @@ -3636,7 +3642,7 @@ describe('QueryManager', () => { }); // Need to delay the reset at least until the fetchRequest method // has had a chance to enter this request into fetchQueryRejectFns. - setTimeout(() => queryManager.resetStore(), 100); + setTimeout(() => resetStore(queryManager), 100); }); itAsync('should call refetch on a mocked Observable if the store is reset', (resolve, reject) => { @@ -3662,7 +3668,7 @@ describe('QueryManager', () => { obs.subscribe({}); obs.refetch = resolve as any; - queryManager.resetStore(); + resetStore(queryManager); }); itAsync('should not call refetch on a cache-only Observable if the store is reset', (resolve, reject) => { @@ -3693,7 +3699,7 @@ describe('QueryManager', () => { return null as never; }; - queryManager.resetStore(); + resetStore(queryManager); setTimeout(() => { expect(refetchCount).toEqual(0); @@ -3729,7 +3735,7 @@ describe('QueryManager', () => { return null as never; }; - queryManager.resetStore(); + resetStore(queryManager); setTimeout(() => { expect(refetchCount).toEqual(0); @@ -3763,7 +3769,7 @@ describe('QueryManager', () => { return null as never; }; - queryManager.resetStore(); + resetStore(queryManager); setTimeout(() => { expect(refetchCount).toEqual(0); @@ -3792,7 +3798,7 @@ describe('QueryManager', () => { () => new Observable(observer => { // reset the store as soon as we hear about the query - queryManager.resetStore(); + resetStore(queryManager); observer.next({ data }); return; }), @@ -4546,7 +4552,7 @@ describe('QueryManager', () => { expect(result.loading).toBe(false); expect(result.data).toEqual(data1); setTimeout(() => { - queryManager.resetStore(); + resetStore(queryManager); }, 0); break; case 1: