Apollo GraphQL updateQuery para typePolicy
Estou batendo minha cabeça contra a parede. Atualizei para a Apollo 3 e não consigo descobrir como migrar um updateQuerypara um typePolicy. Estou fazendo paginação básica com base em continuação e é assim que costumava mesclar os resultados de fetchMore:
await fetchMore({
query: MessagesByThreadIDQuery,
variables: {
threadId: threadId,
limit: Configuration.MessagePageSize,
continuation: token
},
updateQuery: (prev, curr) => {
// Extract our updated message page.
const last = prev.messagesByThreadId.messages ?? []
const next = curr.fetchMoreResult?.messagesByThreadId.messages ?? []
return {
messagesByThreadId: {
__typename: 'MessagesContinuation',
messages: [...last, ...next],
continuation: curr.fetchMoreResult?.messagesByThreadId.continuation
}
}
}
Eu tentei escrever o merge typePolicymesmo, mas ele carrega continuamente e lança erros sobre identificadores duplicados no cache do Apollo. Aqui está o que typePolicyparece para minha consulta.
typePolicies: {
Query: {
fields: {
messagesByThreadId: {
keyArgs: false,
merge: (existing, incoming, args): IMessagesContinuation => {
const typedExisting: IMessagesContinuation | undefined = existing
const typedIncoming: IMessagesContinuation | undefined = incoming
const existingMessages = (typedExisting?.messages ?? [])
const incomingMessages = (typedIncoming?.messages ?? [])
const result = existing ? {
__typename: 'MessageContinuation',
messages: [...existingMessages, ...incomingMessages],
continuation: typedIncoming?.continuation
} : incoming
return result
}
}
}
}
}
Respostas
Então, consegui resolver meu caso de uso. Parece muito mais difícil do que realmente precisa ser. Basicamente, tenho que tentar localizar os itens existentes que correspondem aos que chegam e sobrescrevê-los, bem como adicionar quaisquer novos itens que ainda não existam no cache.
Também tenho que aplicar essa lógica apenas se um token de continuação for fornecido, porque se for nulo ou indefinido, devo apenas usar o valor de entrada, porque isso indica que estamos fazendo um carregamento inicial.
Meu documento tem o formato deste:
{
"items": [{ id: string, ...others }],
"continuation": "some_token_value"
}
Eu criei uma política de tipo genérico que posso usar para todos os meus documentos que têm um formato semelhante. Ele me permite especificar o nome da propriedade de itens, quais são os argumentos-chave que desejo armazenar em cache e o nome do tipo graphql.
export function ContinuationPolicy(keyArgs: Array<string>, itemPropertyKey: string, typeName: string) {
return {
keyArgs,
merge(existing: any, incoming: any, args: any) {
if (!!existing && !!args.args?.continuation) {
const existingItems = (existing ? existing[itemPropertyKey] : [])
const incomingItems = (incoming ? incoming[itemPropertyKey] : [])
let items: Array<any> = [...existingItems]
for (let i = 0; i < incomingItems.length; i++) {
const current = incomingItems[i] as any
const found = items.findIndex(m => m.__ref === current.__ref)
if (found > -1) {
items[found] === current
} else {
items = [...items, current]
}
}
// This new data is a continuation of the last data.
return {
__typename: typeName,
[itemPropertyKey]: items,
continuation: incoming.continuation
}
} else {
// When we have no existing data in the cache, we'll just use the incoming data.
return incoming
}
}
}
}