Created
June 29, 2019 17:24
-
-
Save ngryman/6856c7eb8f9a15b1095032a6ba478c5c to your computer and use it in GitHub Desktop.
Updating cached data from multiple parameterized queries after a mutation (hacky solution)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
addTask({ | |
variables: { input }, | |
optimisticResponse: { | |
addTask: { | |
__typename: 'Task', | |
id, | |
...input | |
} | |
}, | |
update: (proxy: any, { data: { addTask } }: any) => { | |
const query = Queries.tasks | |
const variablesList = getVariablesListFromCache(proxy, query) | |
for (const variables of variablesList) { | |
const data = proxy.readQuery({ query, variables }) | |
data.tasks.push(addTask) | |
proxy.writeQuery({ query, data }) | |
} | |
} | |
}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const getVariablesListFromCache = (proxy: any, query: any) => { | |
const queryName = query.definitions[0].name.value | |
const rootQuery = proxy.data.data.ROOT_QUERY | |
// XXX: When using `optimisticResponse`, `proxy.data.data` resolves to | |
// another cache that doesn't contain the root query. | |
if (!rootQuery) return [] | |
const matchQueryReducer = (names: string[], name: string) => { | |
if (name.startsWith(queryName)) { | |
names.push(name) | |
} | |
return names | |
} | |
const parseQueryNameToVariables = (name: string) => | |
JSON.parse((name.match(/{.*}/) as string[])[0]) | |
return Object.keys(rootQuery) | |
.reduce(matchQueryReducer, []) | |
.map(parseQueryNameToVariables) | |
} |
In this case I need to match customers which is in the cache, but your code will match multiCustomersQuery.
@eric-burel I've felt this exact same thing, for me the solution that works best would be to use:
const queryName = query.definitions[0].selectionSet.selections[0].name.value
Instead of:
const queryName = query.definitions[0].name.value
Even with this, it would not handle queries that contains multiple subqueries below it:
query multiCustomersQuery {
customers {
}
anotherThing {
}
}
For my use case there are no such cases, so I do not need to worry, but it is good to warn about it.
In case it helps someone, I used the selectionSet
since I use different names than the declared in the resolvers for the queries in the frontend. To avoid updating queries that are not the ones that I want I ended up using a simple regex, for example, if the query is lead
, but I also have leads
, I only want lead
. This works for me:
const getVariablesListFromCache = (proxy: any, query: any) => {
const queryName =
query.definitions[0].selectionSet.selections[0].name.value;
const rootQuery = proxy.data.data.ROOT_QUERY;
if (!rootQuery) return [];
const matchQueryReducer = (names: string[], name: string) => {
const regex = new RegExp(`${queryName}\\(.*`);
if (regex.test(name)) {
names.push(name);
}
return names;
};
const parseQueryNameToVariables = (name: string) =>
JSON.parse((name.match(/{.*}/) as string[])[0]);
return Object.keys(rootQuery)
.reduce(matchQueryReducer, [])
.map(parseQueryNameToVariables);
};
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Also I don't know why but in the cache, it's not the query name that is used but the underlying result :
Simplified example:
In this case I need to match
customers
which is in the cache, but your code will matchmultiCustomersQuery
.