apollo-feature-requests
apollo-feature-requests copied to clipboard
cache.modify - Expose args passed to field modified fields
cache.modify - Expose args passed to field modified fields
What I am hoping to accomplish with this feature request may already exist in some form and maybe I am just misunderstanding how to do it or need to rely on a field merge policy or just the exposed storeFieldName
The problem I am hoping to solve is that when an entity within the cache is updated there could be any number, sometimes even double-digit queries that need to be updated on the client. Unfourtionatley in our apps uses case, even without considering extra round trips to the server, invalidating queries will not work because sometimes the data on the backend is not updated for 5 or more seconds. Eventual consistency issues.
With Apollo Client 3.0 we now have cache.modify
which seems vastly simpler than the previous ways we've tried to use readQuery
and writeQuery
to update all the necessary queries.
However, I was a bit surprised when I noticed that I don't have access to the variables for a query field from within cache.modify
except for in a serialized form.
const [addBook] = useMutation(
gql`
mutation AddBook {
addNewBook {
id
name
description
likes
}
}
`,
{
update(client, { data }) {
const book = data.addNewBook;
const newBookRef = client.writeFragment({
data: book,
fragment: gql`
fragment NewBook on Book {
id
name
description
}
`,
});
client.modify({
fields: {
books(existing, { args, storeFieldName, fieldName, }) {
args // undefined
fieldName // "books"
storeFieldName // first query - "books:{"sort":"normal"}", second query -"books:{"sort":"reverse"}",
if (storeFieldName === 'books:{"sort":"reverse"}') {
return [newBookRef, ...existing];
}
if (storeFieldName === 'books:{"sort":"normal"}') {
return [...existing, newBookRef];
}
},
},
});
},
}
);
This seems to work, but I was wondering if we could just expose could add an args property there that could be constructed by deserializing the variables used for storeFeildName
, or maybe there is an existing cache utility that is exported to serialize an object into the storeFieldName
? Just to make sure that we stay consistent with the cache.
Another thing that seems to work, if my modify
field function returns nothing, it seems like it falls back to the merge
function defined in the field's type policy.
client.modify({
fields: {
books(existing, { args, storeFieldName, fieldName }) {},
},
});
cache: new InMemoryCache({
typePolicies: {
Book: {
keyFields: ["id"],
fields: {},
},
Query: {
fields: {
books: {
keyArgs: ["sort"],
merge(existing = [], incoming, { args }) {
args // { sort: 'reverse' | 'normal' }
if (args.sort === "reverse") {
return [...incoming, ...existing];
}
if (args.sort === "normal") {
return [...existing, ...incoming];
}
},
},
...
Am I missing something? is there a better way to orchestrate some of these cache updates? Is there a reason that args
or variables
couldn't be included as part of the parameters for the cache.modify
field updater like it is available in the merge/read type policies?
Anyway, really appreciate the work you all have done with maintaining and working on this library! I'm really excited about the version 3 release and hope to get through upgrading our current project to be using it in production soon!
It would be great if the args were exposed. Currently you can parse the storedFieldName as follows
const args = JSON.parse(storeFieldName.replace(`${fieldName}:`, ''))
but it would be much better if there was a supported way of doing this.
Related to https://github.com/apollographql/apollo-feature-requests/issues/238
Here's my current thinking about this idea: https://github.com/apollographql/apollo-client/issues/7129