Apollo GraphQL updateQuery ke typePolicy
Saya membenturkan kepala saya ke dinding. Saya telah memperbarui ke Apollo 3, dan tidak tahu cara bermigrasi updateQueryke a typePolicy. Saya melakukan paginasi berbasis lanjutan dasar, dan ini adalah cara saya menggabungkan hasil dari 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
}
}
}
Saya telah mencoba untuk menulis merge typePolicysendiri, tetapi itu terus-menerus memuat dan melempar kesalahan tentang pengenal duplikat di cache Apollo. Inilah typePolicytampilan saya untuk kueri saya.
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
}
}
}
}
}
Jawaban
Jadi saya bisa menyelesaikan kasus penggunaan saya. Tampaknya jauh lebih sulit daripada yang seharusnya. Pada dasarnya saya harus mencoba menemukan item yang ada yang cocok dengan yang masuk dan menimpanya, serta menambahkan item baru yang belum ada di cache.
Saya juga harus menerapkan logika ini hanya jika token kelanjutan disediakan, karena jika null atau tidak ditentukan, saya sebaiknya menggunakan nilai yang masuk karena itu menunjukkan bahwa kita sedang melakukan pemuatan awal.
Dokumen saya berbentuk seperti ini:
{
"items": [{ id: string, ...others }],
"continuation": "some_token_value"
}
Saya membuat kebijakan tipe generik yang dapat saya gunakan untuk semua dokumen saya yang memiliki bentuk serupa. Ini memungkinkan saya untuk menentukan nama properti items, argumen kuncinya yang ingin saya cache, dan nama tipe 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
}
}
}
}