Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement InMemoryCache garbage collection and eviction. #5310

Merged
merged 11 commits into from
Sep 13, 2019
Prev Previous commit
Next Next commit
Simplify overly ceremonious Cache#evict method signature.
Per this discussion with @jbaxleyiii:
#5310 (comment)

tl;dr: This could be a breaking change for other Apollo Cache
implementations, but InMemoryCache and the Hermes cache are the only two
cache implementations we know about, and neither of them have implemented
the evict method so far.
  • Loading branch information
benjamn committed Sep 12, 2019
commit 3b659f8fd587e286b6a63bb897c938f997b76344
4 changes: 1 addition & 3 deletions src/cache/core/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ export abstract class ApolloCache<TSerialized> implements DataProxy {
): void;
public abstract diff<T>(query: Cache.DiffOptions): Cache.DiffResult<T>;
public abstract watch(watch: Cache.WatchOptions): () => void;
public abstract evict<TVariables = any>(
query: Cache.EvictOptions<TVariables>,
): Cache.EvictionResult;
public abstract evict(dataId: string): boolean;
public abstract reset(): Promise<void>;

// intializer / offline / ssr API
Expand Down
8 changes: 0 additions & 8 deletions src/cache/core/types/Cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ import { DataProxy } from './DataProxy';

export namespace Cache {
export type WatchCallback = (newData: any) => void;
export interface EvictionResult {
success: Boolean;
}

export interface ReadOptions<TVariables = any>
extends DataProxy.Query<TVariables> {
Expand All @@ -27,11 +24,6 @@ export namespace Cache {
callback: WatchCallback;
}

export interface EvictOptions<TVariables = any>
extends DataProxy.Query<TVariables> {
rootId?: string;
}

export import DiffResult = DataProxy.DiffResult;
export import WriteQueryOptions = DataProxy.WriteQueryOptions;
export import WriteFragmentOptions = DataProxy.WriteFragmentOptions;
Expand Down
21 changes: 3 additions & 18 deletions src/cache/inmemory/__tests__/entityCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -588,12 +588,7 @@ describe('EntityCache', () => {
},
});

expect(cache.evict({
rootId: "Author:J.K. Rowling",
query,
})).toEqual({
success: false,
});
expect(cache.evict("Author:J.K. Rowling")).toBe(false);

const bookAuthorFragment = gql`
fragment BookAuthor on Book {
Expand Down Expand Up @@ -661,12 +656,7 @@ describe('EntityCache', () => {

expect(cache.gc()).toEqual([]);

expect(cache.evict({
rootId: 'Author:Robert Galbraith',
query,
})).toEqual({
success: true,
});
expect(cache.evict("Author:Robert Galbraith")).toBe(true);

expect(cache.gc()).toEqual([]);

Expand Down Expand Up @@ -718,12 +708,7 @@ describe('EntityCache', () => {

// If you're ever tempted to do this, you probably want to use cache.clear()
// instead, but evicting the ROOT_QUERY should work at least.
expect(cache.evict({
rootId: "ROOT_QUERY",
query,
})).toEqual({
success: true,
});
expect(cache.evict("ROOT_QUERY")).toBe(true);

expect(cache.extract(true)).toEqual({
"Book:031648637X": {
Expand Down
10 changes: 5 additions & 5 deletions src/cache/inmemory/inMemoryCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,15 +199,15 @@ export class InMemoryCache extends ApolloCache<NormalizedCacheObject> {
return (optimistic ? this.optimisticData : this.data).release(rootId);
}

public evict(query: Cache.EvictOptions): Cache.EvictionResult {
if (this.optimisticData.has(query.rootId)) {
public evict(dataId: string): boolean {
if (this.optimisticData.has(dataId)) {
// Note that this deletion does not trigger a garbage collection, which
// is convenient in cases where you want to evict multiple entities before
// performing a single garbage collection.
this.optimisticData.delete(query.rootId);
return { success: !this.optimisticData.has(query.rootId) };
this.optimisticData.delete(dataId);
return !this.optimisticData.has(dataId);
}
return { success: false };
return false;
}

public reset(): Promise<void> {
Expand Down