-
-
Save ngryman/6856c7eb8f9a15b1095032a6ba478c5c to your computer and use it in GitHub Desktop.
| 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 }) | |
| } | |
| } | |
| }) |
| 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) | |
| } |
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"
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.valueInstead of:
const queryName = query.definitions[0].name.valueEven 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);
};
Interesting, does it only add filters (from the @connection directive) as that could be a better approach