Cannot get relay-style paging to work with cache-first

Hi, why does my example below work fine with fetchPolicy “network-only”, but not with “cache-first”?

I’m using “relay” style cursor based paging. pageSize = 50, and I got 64 items in total. Here is my field policy:

const typePolicies: TypedTypePolicies = {
  // eslint-disable-next-line @typescript-eslint/naming-convention
  Query: {
    fields: {
      allRetailers: customRelayStylePagination(['filter'])
    }
  }
}

customRelayStylePagination is just copy-paste from relayStylePagination to debug.

Here is my function to retrieve ALL retailers:

const getAllRetailers = async (showInactiveRetailers: boolean, showInactiveMachines: boolean): Promise<Array<RetailerListItemFragment>> => {
  let myCursor = undefined;
  let hasNextPage = true;
  let result: Array<RetailerListItemFragment> = [];

  const filter = showInactiveRetailers
    ? undefined
    : {
      machineFilter: showInactiveMachines
        ? RetailerMachineFilter.HasActiveOrInactiveMachines
        : RetailerMachineFilter.HasActiveMachines,
    };

  try {
    console.log('start');
    while(hasNextPage) {
      const res: ApolloQueryResult<GetRetailerListQuery> = await apolloClient.query<
        GetRetailerListQuery,
        GetRetailerListQueryVariables
        >({
        variables: {
          cursor: myCursor,
          filter
        },
        query: GET_RETAILER_LIST,
        fetchPolicy: 'cache-first'
      });
      myCursor = res.data.allRetailers?.pageInfo.endCursor;
      hasNextPage = res.data.allRetailers?.pageInfo.hasNextPage || false;
      console.log('hasNext: ' + hasNextPage);
      result = res.data.allRetailers?.edges?.map(c => c.node) || [];
    }
    console.log('done', result);
    return result;

  } catch(err) {
    console.error(err);
    throw err;
  }
}

As mentioned this works fine for “network”, but not when using “cache-first”. I get stuck in a infinite loop where hasNextPage is always true. The first GraphQL request returns 50 items. But then it looks like it doesn’t fire the second GraphQL request when using “cache-first”. Why is that? Doesn’t it understand that I have more pages on the server?

I’m pretty sure I’m doing something wrong, but I dont know what :p:wink:

In this screenshot you can see the result from the read() function. The one on the top is when using “network”. When using “cache-first”, I see two read() where pageInfo is the same as in the bottom one.

Another question:
useQuery() vs client.Query(). What is the difference here? What is “extra” in the hook?

And does apollo handle race conditions, cancelling previous queries? If yes, both in hook and client.query?

As this question the first Google result when searching for “relayStylePagination cache-first”, I will just repost my answer to your StackOverflow question:

I think what happens is the following:

  • The cache-first fetch policy means that Apollo will first look into its cache before making a query to the GraphQL server. If it considers that all elements are present in the cache, then it will not make a request to the server.
  • When using relayStylePagination(), keyArgs is set to false. In your code, you set it to filter, but it’s all the same to Apollo: in both case it will ignore the fact that your cursor variable is different. For this reason, it will consider that all elements are present in the cache and doesn’t need to make a request to the server.

I’ve lost a few hours on this and my understanding is that relayStylePagination() simply cannot work with cache-first fetch policy*.

(*) I would definitly welcome a confirmation or refutation of this claim :).