Skip to content

Instantly share code, notes, and snippets.

@ngryman
Created June 29, 2019 17:24
Show Gist options
  • Save ngryman/6856c7eb8f9a15b1095032a6ba478c5c to your computer and use it in GitHub Desktop.
Save ngryman/6856c7eb8f9a15b1095032a6ba478c5c to your computer and use it in GitHub Desktop.
Updating cached data from multiple parameterized queries after a mutation (hacky solution)
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)
}
@riccoski
Copy link

Interesting, does it only add filters (from the @connection directive) as that could be a better approach

@eric-burel
Copy link

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"

@eric-burel
Copy link

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.

@nihey
Copy link

nihey commented May 21, 2020

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