Retrieve already cached list item from cache with similar query field

Hey guys, I’m using the @neo4j/graphql library that auto-generates queries and mutations from my schema’s type definitions.

I have a list of posts in my app from the following query:

  const POSTS = gql`
    query posts($limit:Int) {
      posts(
        options: {
          limit: $limit
        }
      ) {
        title
        text
      }
    }

  `

Which gives me a list of posts and stores them in the cache.

When a user clicks on the post, he gets redirected to the post’s page where he can see the post’s comments.

Here, I’d like to retrieve the post from the cache with a similar query field:

  const POST = gql`
    query post($postId:String , $limit:Int) {
      posts(
        where: {postId:$postId}
        options: {
          limit: $limit
        }
      ) {
        title
        text
      }
    }

  `

Even though this is the same posts query field, adding the where: {postId:$postId} argument returns an array with only one post. But using this query, apollo doesn’t know how to find the post in the cache.

Therefore I need to define a typePolicy such as:

export const cache = new InMemoryCache({
  typePolicies: {
    Query: {
      fields: {
        posts : {
          read(_, { args, toReference }) {
            return toReference({
              __typename: 'Post',
              id: args.id,
            });
          }
        },
      }
    }
  }
})

But here the posts query field is used both to query the list of posts and individual posts. Resulting in an error.

Is there any way around this? Maybe with the name of the query?

Can you return an array from the read function? And maybe also add in a condition to return existing cache data for the list view. And also you’ll need to get the id from args.where.postId, not args.id.

export const cache = new InMemoryCache({
  typePolicies: {
    Query: {
      fields: {
        posts : {
          read(existing, { args, toReference }) {
            if (args?.where?.postId != null) {
              return [toReference({ __typename: 'Post', id: args.where.postId })];
            }
            return existing;
          }
        },
      }
    }
  }
})

Does this work?
Edit: updated to access postId argument correctly

Oh and one more thing: make sure your queries are actually querying the id field. I don’t see it in your example queries.

Thanks @Dylan_Wulf! Your solution works for the use case I’ve discribed when a user clicks on a post to get to the post’s page. I had actually included the id field in the selection set, just forgot to include it in my example.

And I also forgot to mention that users can also end up on the post page from the url. I guess it’s possible to achieve as well with the posts query, but I found a way to create another PostById query with @neo4j/graphql, thus avoiding naming conflicts, and everything is working fine with it.

Still thanks for the help! I understand type policies better now :upside_down_face:

1 Like