Skip to content

Commit

Permalink
Add getCacheKey to context for cache resolver (#2998)
Browse files Browse the repository at this point in the history
* Added getCacheKey method on the context for cache resolvers

Test cleanup

Add a comment

* Fixed test

* Added getContextKey to cacheResolver context, fixed tests

* Fixed test, added PR to changelog

* Bundle bump :(

* Guard against undefined config
  • Loading branch information
peggyrayzis authored and James Baxley committed Feb 14, 2018
1 parent ee03beb commit 6eec674
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 2 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
{
"name": "apollo-client",
"path": "./packages/apollo-client/lib/bundle.min.js",
"maxSize": "11.7 kB"
"maxSize": "11.8 kB"
},
{
"name": "apollo-client-preset",
Expand Down
1 change: 1 addition & 0 deletions packages/apollo-cache-inmemory/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Change log

### vNEXT
- Added `getCacheKey` function to cacheResolver context [#2998](https://github.com/apollographql/apollo-client/pull/2998)

### 1.1.8
- dependency updates
Expand Down
7 changes: 6 additions & 1 deletion packages/apollo-cache-inmemory/src/readFromStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
getQueryDefinition,
isJsonValue,
isIdValue,
toIdValue,
getStoreKeyName,
} from 'apollo-utilities';
import { Cache } from 'apollo-cache';
Expand Down Expand Up @@ -83,7 +84,10 @@ const readStoreResolver: Resolver = (
// Look for the field in the custom resolver map
const resolver = type[fieldName];
if (resolver) {
fieldValue = resolver(obj, args);
fieldValue = resolver(obj, args, {
getCacheKey: (obj: { __typename: string; id: string | number }) =>
toIdValue(context.dataIdFromObject(obj)),
});
}
}
}
Expand Down Expand Up @@ -161,6 +165,7 @@ export function diffQueryAgainstStore<T>({
// Global settings
store,
returnPartialData,
dataIdFromObject: (config && config.dataIdFromObject) || null,
cacheResolvers: (config && config.cacheResolvers) || {},
// Flag set during execution
hasMissingField: false,
Expand Down
2 changes: 2 additions & 0 deletions packages/apollo-cache-inmemory/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ export type ReadStoreContext = {
returnPartialData: boolean;
hasMissingField: boolean;
cacheResolvers: CacheResolverMap;
dataIdFromObject?: IdGetter;
};

export interface FragmentMatcherInterface {
Expand Down Expand Up @@ -122,6 +123,7 @@ export type IntrospectionResultData = {
export type CacheResolver = (
rootValue: any,
args: { [argName: string]: any },
context: any,
) => any;

export type CacheResolverMap = {
Expand Down
1 change: 1 addition & 0 deletions packages/apollo-client/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# Change log

### vNEXT
- Added `getCacheKey` function to the link context for use in state-link [PR#2998](https://github.com/apollographql/apollo-client/pull/2998)

### 2.2.3
- dependency updates
Expand Down
12 changes: 12 additions & 0 deletions packages/apollo-client/src/core/QueryManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1193,6 +1193,7 @@ export class QueryManager<TStore> {
extraContext?: any,
) {
const cache = this.dataStore.getCache();

return {
query: cache.transformForLink
? cache.transformForLink(document)
Expand All @@ -1202,6 +1203,17 @@ export class QueryManager<TStore> {
context: {
...extraContext,
cache,
// getting an entry's cache key is useful for cacheResolvers & state-link
getCacheKey: (obj: { __typename: string; id: string | number }) => {
if ((cache as any).config) {
// on the link, we just want the id string, not the full id value from toIdValue
return (cache as any).config.dataIdFromObject(obj);
} else {
throw new Error(
'To use context.getCacheKey, you need to use a cache that has a configurable dataIdFromObject, like apollo-cache-inmemory.',
);
}
},
},
};
}
Expand Down
65 changes: 65 additions & 0 deletions packages/apollo-client/src/core/__tests__/QueryManager/links.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,4 +310,69 @@ describe('Link interactions', () => {
// fire off first result
mockLink.simulateResult({ result: { data: initialData } });
});
it('includes getCacheKey function on the context for cache resolvers', async () => {
const query = gql`
{
books {
id
title
}
}
`;

const shouldHitCacheResolver = gql`
{
book(id: 1) {
title
}
}
`;

const bookData = {
books: [
{ id: 1, title: 'Woo', __typename: 'Book' },
{ id: 2, title: 'Foo', __typename: 'Book' },
],
};

const link = new ApolloLink((operation, forward) => {
const { getCacheKey } = operation.getContext();
expect(getCacheKey).toBeDefined();
expect(getCacheKey({ id: 1, __typename: 'Book' })).toEqual('Book:1');
return Observable.of({ data: bookData });
});

const queryManager = new QueryManager({
link,
store: new DataStore(
new InMemoryCache({
cacheResolvers: {
Query: {
book: (_, { id }, context) => {
expect(context.getCacheKey).toBeDefined();
const cacheKey = context.getCacheKey({
id,
__typename: 'Book',
});
expect(cacheKey.id).toEqual(`Book:${id}`);
return cacheKey;
},
},
},
}),
),
});

await queryManager.query({ query });

return queryManager
.query({ query: shouldHitCacheResolver })
.then(({ data }) => {
expect({
...data,
}).toMatchObject({
book: { title: 'Woo', __typename: 'Book' },
});
});
});
});

0 comments on commit 6eec674

Please sign in to comment.