Search code examples
graphqlapolloapollo-client

Confused why returnPartialData works without a field policy in Apollo Client 3


In my application I am searching for products, then clicking into a product to see more detail about it.

I perform a GraphQL query on each page. The SEARCH query returns type [Product], and the PRODUCT query returns type Product.

// Search page
const SEARCH = gql`
  query Search($query: String!) {
    searchResults: search(query: $query) {
      id
      name
      images
      price
    }
  }
`

// ProductDetail page
const PRODUCT = gql`
  query Product($id: Int!) {
    product(id: $id) {
      id
      name
      images
      optionSetName
      options {
        id
        images
        name
      }
      price
    }
  }
`

I have enabled returnPartialData on the PRODUCT query, as some of the fields for that product already exist in the cache from the SEARCH query, and I would like to access them before the server request returns.

I thought I would also have to apply a field policy to reference the pre-existing Product, as I don't know how PRODUCT even knows what its return type is.

However, when I do the following:

const { loading, data: { product } = {} } = useQuery(
    PRODUCT,
    { variables: { id: productId, isShallow }, returnPartialData: true }
)
console.log(product)

the following is logged to console (the first is from returnPartialData, the second from server):

console

Somehow the PRODUCT query has associated itself with the existing Product, without me explicitly writing a cache redirect.

I'm confused how this has occurred? It seems like Apollo must have a reference to the GraphQL schema, and has seen the return type of PRODUCT is Product, then automatically used the id arg to reference the existing product.

Using "@apollo/client": "^3.4.1"


Solution

  • Wow, turns out I had made a field policy ages ago and forgotten about it... xD

        typePolicies: {
          Query: {
            fields: {
              product: {
                read (_, { args, toReference }) {
                  return toReference({
                    __typename: 'Product',
                    id: args.id
                  })
                }
              }
            }
          }
        }