Skip to content

Commit

Permalink
Allow silencing broadcast for individual cache writes/evictions.
Browse files Browse the repository at this point in the history
  • Loading branch information
benjamn committed May 18, 2020
1 parent e84a603 commit 4699f5c
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 3 deletions.
2 changes: 2 additions & 0 deletions src/cache/core/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ export abstract class ApolloCache<TSerialized> implements DataProxy {
result: options.data,
query: options.query,
variables: options.variables,
broadcast: options.broadcast,
});
}

Expand All @@ -150,6 +151,7 @@ export abstract class ApolloCache<TSerialized> implements DataProxy {
result: options.data,
variables: options.variables,
query: this.getFragmentDoc(options.fragment, options.fragmentName),
broadcast: options.broadcast,
});
}
}
4 changes: 3 additions & 1 deletion src/cache/core/types/Cache.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { DataProxy } from './DataProxy';

export namespace Cache {
export type WatchCallback = (newData: any) => void;
export type WatchCallback = (diff: Cache.DiffResult<any>) => void;

export interface ReadOptions<TVariables = any>
extends DataProxy.Query<TVariables> {
Expand All @@ -14,6 +14,7 @@ export namespace Cache {
extends DataProxy.Query<TVariables> {
dataId: string;
result: TResult;
broadcast?: boolean;
}

export interface DiffOptions extends ReadOptions {
Expand All @@ -29,6 +30,7 @@ export namespace Cache {
id: string;
fieldName?: string;
args?: Record<string, any>;
broadcast?: boolean;
}

export import DiffResult = DataProxy.DiffResult;
Expand Down
8 changes: 8 additions & 0 deletions src/cache/core/types/DataProxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ export namespace DataProxy {
* The data you will be writing to the store.
*/
data: TData;
/**
* Whether to notify query watchers (default: true).
*/
broadcast?: boolean;
}

export interface WriteFragmentOptions<TData, TVariables>
Expand All @@ -67,6 +71,10 @@ export namespace DataProxy {
* The data you will be writing to the store.
*/
data: TData;
/**
* Whether to notify query watchers (default: true).
*/
broadcast?: boolean;
}

export type DiffResult<T> = {
Expand Down
119 changes: 119 additions & 0 deletions src/cache/inmemory/__tests__/writeToStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
} from '../../../utilities/graphql/storeUtils';
import { addTypenameToDocument } from '../../../utilities/graphql/transform';
import { cloneDeep } from '../../../utilities/common/cloneDeep';
import { itAsync } from '../../../utilities/testing/itAsync';
import { StoreWriter } from '../writeToStore';
import { defaultNormalizedCacheFactory } from '../entityStore';
import { InMemoryCache } from '../inMemoryCache';
Expand Down Expand Up @@ -2085,4 +2086,122 @@ describe('writing to the store', () => {

expect(mergeCounts).toEqual({ first: 1, second: 1, third: 1, fourth: 1 });
});

itAsync("should allow silencing broadcast of cache updates", function (resolve, reject) {
const cache = new InMemoryCache({
typePolicies: {
Counter: {
// Counter is a singleton, but we want to be able to test
// writing to it with writeFragment, so it needs to have an ID.
keyFields: [],
},
},
});

const query = gql`
query {
counter {
count
}
}
`;

const results: number[] = [];

cache.watch({
query,
optimistic: true,
callback(diff) {
results.push(diff.result);
expect(diff.result).toEqual({
counter: {
__typename: "Counter",
count: 3,
},
});
resolve();
},
});

let count = 0;

cache.writeQuery({
query,
data: {
counter: {
__typename: "Counter",
count: ++count,
},
},
broadcast: false,
});

expect(cache.extract()).toEqual({
ROOT_QUERY: {
__typename: "Query",
counter: { __ref: "Counter:{}" },
},
"Counter:{}": {
__typename: "Counter",
count: 1,
},
});

expect(results).toEqual([]);

const counterId = cache.identify({
__typename: "Counter",
})!;

cache.writeFragment({
id: counterId,
fragment: gql`fragment Count on Counter { count }`,
data: {
count: ++count,
},
broadcast: false,
});

expect(cache.extract()).toEqual({
ROOT_QUERY: {
__typename: "Query",
counter: { __ref: "Counter:{}" },
},
"Counter:{}": {
__typename: "Counter",
count: 2,
},
});

expect(results).toEqual([]);

expect(cache.evict({
id: counterId,
fieldName: "count",
broadcast: false,
})).toBe(true);

expect(cache.extract()).toEqual({
ROOT_QUERY: {
__typename: "Query",
counter: { __ref: "Counter:{}" },
},
"Counter:{}": {
__typename: "Counter",
},
});

expect(results).toEqual([]);

// Only this write should trigger a broadcast.
cache.writeQuery({
query,
data: {
counter: {
__typename: "Counter",
count: 3,
},
},
});
});
});
9 changes: 7 additions & 2 deletions src/cache/inmemory/inMemoryCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,9 @@ export class InMemoryCache extends ApolloCache<NormalizedCacheObject> {
variables: options.variables,
});

this.broadcastWatches();
if (options.broadcast !== false) {
this.broadcastWatches();
}
}

public modify(
Expand Down Expand Up @@ -235,7 +237,10 @@ export class InMemoryCache extends ApolloCache<NormalizedCacheObject> {
args,
} : idOrOptions,
);
this.broadcastWatches();
if (typeof idOrOptions === "string" ||
idOrOptions.broadcast !== false) {
this.broadcastWatches();
}
return evicted;
}

Expand Down

0 comments on commit 4699f5c

Please sign in to comment.