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

Restrict field name over-invalidation to fields without keyArgs. #7351

Merged
merged 5 commits into from
Nov 21, 2020
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Test that fields with keyArgs are not over-invalidated.
  • Loading branch information
benjamn committed Nov 20, 2020
commit 1f2ff40686551383d07bfaf76360e70e74bb82ee
139 changes: 139 additions & 0 deletions src/cache/inmemory/__tests__/entityStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { InMemoryCache } from '../inMemoryCache';
import { DocumentNode } from 'graphql';
import { StoreObject } from '../types';
import { ApolloCache } from '../../core/cache';
import { Cache } from '../../core/types/Cache';
import { Reference, makeReference, isReference } from '../../../utilities/graphql/storeUtils';
import { MissingFieldError } from '../..';

Expand Down Expand Up @@ -2277,4 +2278,142 @@ describe('EntityStore', () => {
favorited: false,
}});
});

it("should not over-invalidate fields with keyArgs", () => {
const isbnsWeHaveRead: string[] = [];

const cache = new InMemoryCache({
typePolicies: {
Query: {
fields: {
book: {
// The presence of this keyArgs configuration permits the
// cache to track result caching dependencies at the level
// of individual Books, so writing one Book does not
// invalidate other Books with different ISBNs. If the cache
// doesn't know which arguments are "important," it can't
// make any assumptions about the relationships between
// field values with the same field name but different
// arguments, so it has to err on the side of invalidating
// all Query.book data whenever any Book is written.
keyArgs: ["isbn"],

read(book, { args, toReference }) {
isbnsWeHaveRead.push(args!.isbn);
return book || toReference({
__typename: "Book",
isbn: args!.isbn,
});
},
},
},
},
},
});

const query = gql`
query Book($isbn: string) {
book(isbn: $isbn) {
title
isbn
author {
name
}
}
}
`;

const diffs: Cache.DiffResult<any>[] = [];
cache.watch({
query,
optimistic: true,
variables: {
isbn: "1449373321",
},
callback(diff) {
diffs.push(diff);
},
});

const ddiaData = {
book: {
__typename: "Book",
isbn: "1449373321",
title: "Designing Data-Intensive Applications",
author: {
__typename: "Author",
name: "Martin Kleppmann",
},
},
};

expect(isbnsWeHaveRead).toEqual([]);

cache.writeQuery({
query,
variables: {
isbn: "1449373321",
},
data: ddiaData,
});

expect(isbnsWeHaveRead).toEqual([
"1449373321",
]);

expect(diffs).toEqual([
{
complete: true,
result: ddiaData,
},
]);

const theEndData = {
book: {
__typename: "Book",
isbn: "1982103558",
title: "The End of Everything",
author: {
__typename: "Author",
name: "Katie Mack",
},
},
};

cache.writeQuery({
query,
variables: {
isbn: "1982103558",
},
data: theEndData,
});

// This list does not include the book we just wrote, because the
// cache.watch we started above only depends on the Query.book field
// value corresponding to the 1449373321 ISBN.
expect(diffs).toEqual([
{
complete: true,
result: ddiaData,
},
]);

// Likewise, this list is unchanged, because we did not need to read
// the 1449373321 Book again after writing the 1982103558 data.
expect(isbnsWeHaveRead).toEqual([
"1449373321",
]);

expect(cache.readQuery({
query,
variables: {
isbn: "1982103558",
},
})).toEqual(theEndData);

expect(isbnsWeHaveRead).toEqual([
"1449373321",
"1982103558",
]);
});
});