Apollo GraphQL updateQuery ke typePolicy

Sep 01 2020

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

DylanVester Sep 15 2020 at 14:21

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
      }
    }
  }
}