Updating multiple queries with `cache.writeQuery` with `keyArgs`
Hi,
Is there a way to get a list of queries by name in the cache? I have an issue where I'm unable to update a cached query because I don't know what variables have been used to fetch it.
Example:
- Query to get a list of cards (paginated)
- Query accepts sort/filter options
- Query uses
keyArgsin type policy to cache queries separately - Mutation to create a card
- Add card to list using
cache.writeQueryin the mutationupdatecallback
Here's what my field policy looks like:
const cardsPagination: FieldPolicy<CardCollection> = {
keyArgs(args) {
const variables = args as GetCardsQueryVariables;
return variables.input ? `${variables.input.order_by}${variables.input.order_by_dir}` : '';
},
merge(existing, incoming, { readField }) {
if (!existing) {
return incoming;
}
const pageInfo = { ...existing.pageInfo, ...incoming.pageInfo };
const edges = uniqueBy([...existing.edges, ...incoming.edges], (edge) =>
readField('idx', edge.node),
);
return { __typename: 'CardCollection', pageInfo, edges };
},
};
and the mutation update:
update(cache, { data }) {
const card = data?.cardCreate;
if (!card) {
return;
}
cache.writeQuery<GetCardsQuery, GetCardsQueryVariables>({
query: getCardsQuery,
// Should have variables here...
data: {
cards: {
__typename: 'CardCollection',
pageInfo: pageInfoStub,
edges: [{ node: card, cursor: Date.now().toString() }],
},
},
});
},
My current solution is to call cache.writeQuery with all possible variable combinations, but this isn't ideal. Using refetchQueries is not something I consider a "solution", it's a work-around.
Thanks.
Hi @mitchheddles, unfortunately, right now, there's no really good solution for this.
You could call getObservableQueries, but that would only give you all currently active observable queries back, not past queries that might have written into your cache.
This is a shortcoming that we're aware of and at some point during 4.x we want to get a solution for it in place that will allow you to access the variables that were used to write a cache field - but as of right now, you'll probably have to stick to your workaround.
Thanks @phryneas, but this kinda sucks. Is there a recommended approach for storing the variables/queries besides my own cache or context? It feels like a really shit workaround right now, especially for something thats's already stored somewhere in the client...
I understand it's not as simple as making it the loopup public, or adding a new api, but at this point I'm kinda useless for optimistic updates.
Hm, the closest to get would be an approach like this:
In your merge function, you could track the variables in storage and then later access them from cache.modify.
const cache = new InMemoryCache({
typePolicies: {
Query: {
fields: {
cards: {
merge(existing = [], incoming, { storage, variables }) {
storage.variables = variables;
// actual merge logic
return [...existing, ...incoming];
},
},
},
},
},
});
cache.modify({
fields: {
cards(existing = [], { storage }) {
const variables = storage.variables;
// do your modification here instead of `client.writeQuery`
return existing;
},
},
});