Skip to content

Nested objects with no ids and different selection sets returns no data #7315

Open
@ford-outreach

Description

@ford-outreach

Intended outcome:
With returnPartialData false, requesting non-matching selection sets from nested, denormalized objects (with no id), should alert me that there is data loss, and therefore complete data can never be achieved.

In this case, our User has a set of Preferences, and under preferences there are CalendarPreferences. Neither Preferences nor CalendarPreferences has their own id.

Take this very contrived query (I promise there's a realistic query with the same symptoms)

query {
  userWithPreferenceOne: user(id: 1) {
    id
    preferences {
      calendarPreferences {
        preferenceOne
      }
   }
  userWithPreferenceTwo: user(id: 1) {
    id
    preferences {
      calendarPreferences {
        preferenceTwo
      }
   }
 }
}

Apollo Client should alert me that because there is no custom merge function defined for Preferences or CalendarPreferences, and because there are no ids, it won't merge them, and therefore either userWithPreferenceOne or userWithPreferenceTwo will never have complete data.

At the very least, warnAboutDataLoss should fire,
however in a case like this where data will never resolve, an error seems appropriate.

Actual outcome:
When a query like the one above is made using the useQuery hook. The results are

error: undefined,
data: undefined,
loading: false

There are no errors or warnings logged, so there is no indication that anything failed. However the query is 'finished' and yet there is no data and no error.

With returnPartialData on, the incomplete data is returned (turning this on is undesirable, we need all the data).
Turning on partialRefetch leads to an infinite loop of trying to load the complete data and failing.

I stepped through the warnAboutDataLoss function and the problematic object (preferences, in the above example) early returns on this condition:

if (Object.keys(existing).every(
key => store.getFieldValue(incoming, key) !== void 0)) {
return;
}

Since it is only checking top level properties, it verifies that 'existing' and 'incoming' both have 'calendarPreferences' fields, but it does not catch that one only has preferenceOne and one only has preferenceTwo.

How to reproduce the issue:
I have created a reproduction here: https://github.com/ford-outreach/react-apollo-error-template
Here is the diff (apologies that it's a little noisy, prettier went to town): apollographql/react-apollo-error-template@master...ford-outreach:master

Versions
3.0.2 in our app
3.2.5 in the reproduction

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions