title: Apollo GraphQL Optimistic Response and updating the store issue
body: <p>I'm running into a bit of a problem when updating the UI after a mutation using an Optimistic Response and altering the apollo cache.  I have the following Mutation: </p>
  
  <pre><code>mutation updateCart($basketId: ID!, $productId: ID!, $amount: Int!) {
    setOrderItem(
      basketId: $basketId,
      productId: $productId,
      amount: $amount
    ) {
      id
      amount
      product
    }
  }
  </code></pre>
  
  <p>And the following Query:</p>
  
  <pre><code>query cart($userId: ID!) {
    User(id: $userId) {
      id
      basket {
        id
        items {
          id
          amount
          product {
            id
            name
            price
            imageUrl
            description
          }
        }
      }
    }
  }
  </code></pre>
  
  <p>In my React component I have a button which fires the following method:</p>
  
  <pre><code>addToCart = async (product) =&gt; {
    const basketId = this.props.basketId
    const items = this.props.userCartQuery.User.basket.items
    let amount = 1
  
    for (const item of items) {
      if(item.product.id === product.id) {
        amount = item.amount + 1
      }
    }
  
    await this.props.updateCartMutation({
      variables: {
        basketId: basketId,
        productId: product.id,
        amount: amount
      },
      optimisticResponse: {
        __typename: 'Mutation',
        setOrderItem: {
          id: Math.round(Math.random() * -1000000),
          amount: amount,
          product: product,
          __typename: 'SetOrderItemPayload'
        }
      },
      update: (store, { data: { setOrderItem } }) =&gt; {
        try {
          const data = store.readQuery({
            query: USER_CART_QUERY,
            variables: {
              userId: this.props.userId,
            }
          })
          let replace = false
          for (const key in items) {
            if (items[key].product.id === product.id) {
              data.User.basket.items.splice(key, 1, setOrderItem)
              replace = true
            }
          }
          if (!replace) {
            data.User.basket.items.push(setOrderItem)
          }
          store.writeQuery({ query: USER_CART_QUERY, data })
        }
        catch(err) {
          console.log(err)
        }
      }
    })
  }
  </code></pre>
  
  <p>Here's what I expect.  addToCart will by default fire the updateCartMutation with an amount = 1 unless the product.id already exists in items, in which case it will increment amount by 1.  The optimistic response is mocked out and the update should read the USER_CART_QUERY from the store.  If the item already exists in the query we splice out the original item from the store and replace it with the setOrderItem payload.  If the item doesn't exist, we push the payload to items.  Finally we write the query to the store.  </p>
  
  <p>When I'm adding a new item to the cart, everything works perfectly.  I notice that the optimistic response is mocked and the cart query is read from the store by update.  I successfully push the payload into items and immediately my UI is updated.  Shortly after that update is called again with the response from the server.  This is pushed into items, written to the store, and everything works as expected.</p>
  
  <p>The first time that I try to add an item which already exists in items, it seems to work fine.  Also, if I attempt after a fresh refresh, everything works fine.  The second time I try to add, I get an error.  What I'm noticing is that the optimistic response is mocked out, spliced into items and then written to the store, but when update is called again with the update from the server, I get the following error:</p>
  
  <p><em>"Encountered a sub-selection on the query, but the store doesn't have an object reference. This should never happen during normal use unless you have custom code that is directly manipulating the store; please file an issue."</em></p>
  
  <p>The error is thrown in readFromtStore.js:</p>
  
  <pre><code>  export function assertIdValue(idValue) {
      if (!isIdValue(idValue)) {
          throw new Error("Encountered a sub-selection on the query, but the store doesn't have an object reference. This should never happen during normal use unless you have custom code that is directly manipulating the store; please file an issue.");
      }
    }
  </code></pre>
  
  <p>At this point, idValue is a json object representing the Product from the payload.  </p>
  
  <p>Here is setOrderItem.graphql</p>
  
  <pre><code>type SetOrderItemPayload {
    id: ID
    amount: Int!
    product: Json
  }
  
  extend type Mutation {
    setOrderItem(
      basketId: ID!
      productId: ID!
      amount: Int!
    ): SetOrderItemPayload!
  }
  </code></pre>
  
  <p>And in setOrderItem.ts I'm returning product from </p>
  
  <pre><code>product: Product(id: $productId) {
    id
    name
    price
    description
    imageUrl
    __typename
  }
  </code></pre>
  
  <p>The last thing I want to point out is that if I remove product from the return in the UPDATE_CART_MUTATION, I can add products that already exist with no issues.  The problem then is that if I try to add a product that doesn't already exist in items, when a separate component renders, the User isn't returned from the query and I get an undefined error related to a count of the items in the cart.</p>
  
  <p>This question is huge now and I may be down a hole but hopefully someone will have some idea how to help.</p>