Apollo GraphQL updateQuery auf typePolicy

Sep 01 2020

Ich schlage meinen Kopf gegen eine Wand. Ich habe auf Apollo 3 aktualisiert und kann nicht herausfinden, wie ein updateQueryzu einem migriert werden soll typePolicy. Ich mache eine grundlegende, auf Fortsetzung basierende Paginierung, und so habe ich die Ergebnisse von 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
      }
    }
  }

Ich habe versucht, das merge typePolicyselbst zu schreiben , aber es lädt ständig und wirft Fehler über doppelte Bezeichner im Apollo-Cache aus. So typePolicysieht mein Aussehen für meine Anfrage aus.

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

Antworten

DylanVester Sep 15 2020 at 14:21

So konnte ich meinen Anwendungsfall lösen. Es scheint viel schwieriger als es wirklich sein muss. Ich muss im Wesentlichen versuchen, vorhandene Elemente zu finden, die mit den eingehenden übereinstimmen, und sie überschreiben sowie neue Elemente hinzufügen, die noch nicht im Cache vorhanden sind.

Ich muss diese Logik auch nur anwenden, wenn ein Fortsetzungstoken bereitgestellt wurde, denn wenn es null oder undefiniert ist, sollte ich nur den eingehenden Wert verwenden, da dies anzeigt, dass wir ein anfängliches Laden durchführen.

Mein Dokument hat folgende Form:

{
  "items": [{ id: string, ...others }],
  "continuation": "some_token_value"
}

Ich habe eine generische Typrichtlinie erstellt, die ich für alle meine Dokumente mit ähnlicher Form verwenden kann. Hiermit kann ich den Namen der Eigenschaft items, die wichtigsten Argumente, die zwischengespeichert werden sollen, und den Namen des Typs graphql angeben.

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