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 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 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) | |
} |
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:
query multiCustomersQuery {
customers {
}
}
In this case I need to match customers
which is in the cache, but your code will match multiCustomersQuery
.
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.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Awesome, I am trying this out. First remark, the
startsWith
is not the best strategy because it could match more queries than expected. Instead a regex could allow to match more precisely, eg "customers" would match "customers({ foobar })" but not "customersSpecificQueryYouDontWantToMatch"