Skip to content

Commit

Permalink
Merge pull request #8678 from apollographql/allow-directives-and-vari…
Browse files Browse the repository at this point in the history
…ables-in-field-key-policy

Allow `@directive` and `$variable` strings in field policy `keyArgs: ["arg", "@dir", "$var"]` arrays
  • Loading branch information
benjamn authored Aug 25, 2021
2 parents 698bb87 + f0cea05 commit 0f6e613
Show file tree
Hide file tree
Showing 6 changed files with 408 additions and 40 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,22 @@
- Add `updateQuery` and `updateFragment` methods to `ApolloCache`, simplifying common `readQuery`/`writeQuery` cache update patterns. <br/>
[@wassim-k](https://github.com/wassim-k) in [#8382](https://github.com/apollographql/apollo-client/pull/8382)

- Field directives and their arguments can now be included along with field argument names when using [field policy `keyArgs: [...]` notation](https://www.apollographql.com/docs/react/pagination/key-args/). For example, if you have a `Query.feed` field that takes an argument called `type` and uses a `@connection(key:...)` directive to keep `feed` data from different queries separate within the cache, you might configure both using the following `InMemoryCache` field policy:
```ts
new InMemoryCache({
typePolicies: {
Query: {
fields: {
feed: {
keyArgs: ["type", "@connection", ["key"]],
},
},
},
},
})
```
[@benjamn](https://github.com/benjamn) in [#8678](https://github.com/apollographql/apollo-client/pull/8678)

### React Refactoring

#### Bug Fixes (due to [@brainkim](https://github.com/brainkim) in [#8596](https://github.com/apollographql/apollo-client/pull/8596)):
Expand Down
69 changes: 67 additions & 2 deletions docs/source/pagination/key-args.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ const FEED_QUERY = gql`
}
`;
```
in Apollo Client, you would use the following query:
in Apollo Client, you would typically use the following query (the same query without the `@connection(...)` directive):
```js
const FEED_QUERY = gql`
query Feed($type: FeedType!, $offset: Int, $limit: Int) {
Expand Down Expand Up @@ -120,13 +120,78 @@ const cache = new InMemoryCache({
},
})
```

If the `Query.feed` field does not have an argument like `type` that you can use in `keyArgs: [...]`, then it may make sense to use the `@connection` directive after all:
```js
const FEED_QUERY = gql`
query Feed($offset: Int, $limit: Int, $feedKey: String) {
feed(offset: $offset, limit: $limit) @connection(key: $feedKey) {
edges {
node { ... }
}
pageInfo {
endCursor
hasNextPage
}
}
}
`;
```
If you execute this query with different values for the `$feedKey` variable, those feed results will be stored separately in the cache, whereas normally they would all be stored in the same list.

When choosing a `keyArgs` configuration for this `Query.feed` field, you should include the `@connection` directive as if it was an argument (the `@` tells `InMemoryCache` you mean a directive):
```js
const cache = new InMemoryCache({
typePolicies: {
Query: {
fields: {
feed: {
keyArgs: ["@connection", ["key"]],
},
},
},
},
})
```

With this configuration, your cache will use a `feed:{"@connection":{"key":...}}` key rather than just `feed` to store separate `{ edges, pageInfo }` objects within the `ROOT_QUERY` object:
```js
expect(cache.extract()).toEqual({
ROOT_QUERY: {
__typename: "Query",
'feed:{"@connection":{"key":"some feed key"}}': { edges, pageInfo },
'feed:{"@connection":{"key":"another feed key"}}': { edges, pageInfo },
'feed:{"@connection":{"key":"yet another key"}}': { edges, pageInfo },
// ...
},
})
```

The `["key"]` in `keyArgs: ["@connection", ["key"]]` means only the `key` argument to the `@connection` directive will be considered, and any other arguments (like `filter`) will be ignored. Passing just `key` to `@connection` is usually adequate, but if you are tempted to pass a `filter: ["someArg", "anotherArg"]` argument as well, you should instead include those argument names directly in `keyArgs`:
```js
const cache = new InMemoryCache({
typePolicies: {
Query: {
fields: {
feed: {
keyArgs: ["someArg", "anotherArg", "@connection", ["key"]],
},
},
},
},
})
```
If any of these arguments or directives are not provided for the current query, they will be omitted from the field key automatically, without error. This means it is generally safe to include more arguments or directives in `keyArgs` than you expect to receive in all cases.

> As mentioned above, if a `keyArgs` array is insufficient to specify your desired field keys, you can alternatively pass a function for `keyArgs`, which takes the `args` object and a `{ typename, field, fieldName, variables }` context parameter, and can either return a string or return a dynamically-generated `keyArgs` array.
Although `keyArgs` (and `@connection`) are useful for more than just paginated fields, it's worth noting that `relayStylePagination` configures `keyArgs: false` by default. You can reconfigure this `keyArgs` behavior by passing an alternate value to `relayStylePagination`:
```js
const cache = new InMemoryCache({
typePolicies: {
Query: {
fields: {
feed: relayStylePagination(["type"]),
feed: relayStylePagination(["type", "@connection", ["key"]]),
},
},
},
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
{
"name": "apollo-client",
"path": "./temp/bundlesize.min.cjs",
"maxSize": "24.75 kB"
"maxSize": "24.9 kB"
}
],
"engines": {
Expand Down
16 changes: 8 additions & 8 deletions src/cache/inmemory/__tests__/__snapshots__/policies.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -885,7 +885,7 @@ Object {
}
`;

exports[`type policies field policies can include optional arguments in keyArgs 1`] = `
exports[`type policies field policies can include optional arguments in field keyArgs policy 1`] = `
Object {
"Author:{\\"name\\":\\"Nadia Eghbal\\"}": Object {
"__typename": "Author",
Expand All @@ -907,7 +907,7 @@ Object {
}
`;

exports[`type policies field policies can include optional arguments in keyArgs 2`] = `
exports[`type policies field policies can include optional arguments in field keyArgs policy 2`] = `
Object {
"Author:{\\"name\\":\\"Nadia Eghbal\\"}": Object {
"__typename": "Author",
Expand Down Expand Up @@ -936,7 +936,7 @@ Object {
}
`;

exports[`type policies field policies can include optional arguments in keyArgs 3`] = `
exports[`type policies field policies can include optional arguments in field keyArgs policy 3`] = `
Object {
"Author:{\\"name\\":\\"Nadia Eghbal\\"}": Object {
"__typename": "Author",
Expand Down Expand Up @@ -972,7 +972,7 @@ Object {
}
`;

exports[`type policies field policies can include optional arguments in keyArgs 4`] = `
exports[`type policies field policies can include optional arguments in field keyArgs policy 4`] = `
Object {
"Author:{\\"name\\":\\"Nadia Eghbal\\"}": Object {
"__typename": "Author",
Expand Down Expand Up @@ -1015,7 +1015,7 @@ Object {
}
`;

exports[`type policies field policies can include optional arguments in keyArgs 5`] = `
exports[`type policies field policies can include optional arguments in field keyArgs policy 5`] = `
Object {
"Author:{\\"name\\":\\"Nadia Eghbal\\"}": Object {
"__typename": "Author",
Expand Down Expand Up @@ -1065,7 +1065,7 @@ Object {
}
`;

exports[`type policies field policies can include optional arguments in keyArgs 6`] = `
exports[`type policies field policies can include optional arguments in field keyArgs policy 6`] = `
Object {
"Author:{\\"name\\":\\"Nadia Eghbal\\"}": Object {
"__typename": "Author",
Expand Down Expand Up @@ -1122,7 +1122,7 @@ Object {
}
`;

exports[`type policies field policies can include optional arguments in keyArgs 7`] = `
exports[`type policies field policies can include optional arguments in field keyArgs policy 7`] = `
Object {
"Author:{\\"name\\":\\"Nadia Eghbal\\"}": Object {
"__typename": "Author",
Expand Down Expand Up @@ -1186,7 +1186,7 @@ Object {
}
`;

exports[`type policies field policies can include optional arguments in keyArgs 8`] = `
exports[`type policies field policies can include optional arguments in field keyArgs policy 8`] = `
Object {
"Author:{\\"name\\":\\"Nadia Eghbal\\"}": Object {
"__typename": "Author",
Expand Down
Loading

0 comments on commit 0f6e613

Please sign in to comment.