apollo-cache-updaters
Apollo cache updater functions that make cache updates simpler and more concise.
The problem
Apollo cache updates are verbose and require an understanding of how the cache uses references and normalises data internally.
This solution
A set of declarative updaters that perform common actions automatically.
Restructuring updaters to be declarative makes cache updates more concise. This makes it possible to write complex updates inline.
Common patterns in update methods are done automatically, for instance
writeFragment
automatically generates it's fragment from data
. All automatic
behaviours are easy to disable.
Table of Contents
Installation
This module is distributed via npm which is bundled with node and
should be installed as one of your project's dependencies
:
npm install --save @pi-top/apollo-cache-updaters
The @apollo/client
package is a peerDepencency
.
Usage
This package exports updaters for the cache actions: evict
, modify
,
writeFragment
and writeQuery
. It also exports a helper called combine
(see below).
Updaters
Each updater accepts a createOptions
callback that is called with the
ExecutionResult
and the ApolloCache
as the first and second arguments
respectively. The createOptions
callback is used to create options for a cache
method, for example writeQuery
's createOptions
callback should return the
same options that would be passed cache.writeQuery
:
import { writeQuery } from '@pi-top/apollo-cache-updaters';
const update = writeQuery((result) => ({
data: result.data,
query: gql`
query GetStuff {
stuff {
id
__typename
}
}
`,
})),
createOptions
can also return an array of options, for when multiple similar
operations need to performed from a single ExecutionResult
:
import { writeQuery } from '@pi-top/apollo-cache-updaters';
const update = writeQuery((result) => result.data.stuffs.map(stuff => ({
data: { stuff },
variables: { id: stuff.id }
query: gql`
query GetStuff($id: string) {
stuff(id: $id) {
id
__typename
}
}
`,
}))
writeFragment
writeFragment
automatically generates it's fragment from the data
property
when fragment
is undefined. Note that when using this behaviour the
__typename
property is required to exist in data
:
import { writeFragment } from '@pi-top/apollo-cache-updaters';
const update = writeFragment((result) => ({
data: {
...thing,
__typename: 'Thing',
stuff: result.data.stuff
}
}))
evict
evict
automatically calls cache.gc
if there was a successful eviction. To
stop the behaviour there is an option gc
that can be set to false
import { evict } from '@pi-top/apollo-cache-updaters';
const update = evict((result, cache) => ({
id: cache.identify(result.data),
gc: false,
}))
combine
When multiple types of operation need to performed for one ExecutionResult
the
combine
method can be used:
import { combine } from '@pi-top/apollo-cache-updaters';
const update = combine(
writeFragment((result) => ({
data: {
...thing,
stuff: result.data.stuff
}
})),
writeQuery((result) => ({
data: result.data,
query: GET_STUFF,
})),
)
skipping updates
Sometimes we want to conditionally update the cache, to do this we can set the
skip
value in the updater options:
import { evict } from '@pi-top/apollo-cache-updaters'
const update = evict((result, cache) => ({
id: cache.identify(objectToDelete),
skip: !(result.data && result.data.deleted),
}));
Typescript
The project comes fully typed.
LICENSE
MIT