Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge incoming fragment fields before running merge functions and updating the EntityStore #8372

Merged
merged 4 commits into from
Jun 14, 2021

Conversation

benjamn
Copy link
Member

@benjamn benjamn commented Jun 11, 2021

Fixes #8370 by postponing all context.store.merge updates until after all processSelectionSet work is done, performing the store updates at the end of StoreWriter#writeToStore, whereas previously those updates happened at the end of each StoreWriter#processSelectionSet call.

The postponement of store updates gives the StoreWriter a chance to merge together multiple partial objects representing the same logical object (possibly matched by different fragments along different query paths), before running merge functions with applyMerges.

Previously, those partial objects would be merged separately into context.store, so later objects might replace earlier objects in cases where the objects are unidentifiable/non-normalized, and there was no merge function (or merge: true shorthand) to force the objects to merge.

Of course, you could configure merge: true to explicitly permit merging unidentified objects with a given __typename. Configuring merge: true for the Container type seems to fixes the reproduction in #8370. But this explicit configuration should not be necessary when we know the objects in question represent the same logical object, because they were derived from the same incoming result object (same ID, not necessarily === objects).

In other words, this PR should wipe out a whole class of situations where we used to show Cache data may be lost... warnings, since we can now safely merge the fields of unidentifiable objects that share the same original result object, without requiring an explicit merge: true configuration to permit that mixing of fields.

benjamn added 2 commits June 11, 2021 18:43
Fixes #8370 by postponing all context.store.merge updates until after
all processSelectionSet work is done, performing the store updates at
the end of StoreWriter#writeToStore, whereas previously those updates
happened at the end of each StoreWriter#processSelectionSet call.

The postponement of store updates gives the StoreWriter a chance to
merge together multiple partial objects representing the same logical
object (possibly matched by different fragments along different query
paths), before running merge functions with applyMerges.

Previously, those partial objects would be merged separately into
context.store, so later objects might replace earlier objects in cases
where the objects are unidentifiable/non-normalized, and there is no
merge function (or merge:true) to force the objects to merge.

Of course, you could configure merge:true to explicily permit merging
unidentified objects with a given __typename. Configuring merge:true for
the 'Container' type seems to fixes the reproduction in #8370. But this
explicit configuration should not be necessary when we know the objects
in question represent the same logical object, because they were derived
from the same original result object (same ID, not necessarily ===).

In other words, this PR should wipe out a whole class of situations
where we used to show "Cache data may be lost..." warnings, since we can
now safely merge the fields of unidentifiable objects that share the
same original result object, without requiring an explicit merge:true
configuration to permit that mixing of fields.
@benjamn benjamn force-pushed the 8370-fix-fragment-merging branch from 3ba39b6 to 4935d11 Compare June 11, 2021 22:45
@benjamn benjamn changed the title Merge incoming fragment fields before applying merges. Merge incoming fragment fields before running merge functions and updating the EntityStore Jun 11, 2021
@benjamn benjamn linked an issue Jun 11, 2021 that may be closed by this pull request
Comment on lines +1405 to +1412
it('correctly merges fragment fields along multiple paths', () => {
const cache = new InMemoryCache({
typePolicies: {
Container: {
// Uncommenting this line fixes the test, but should not be necessary,
// since the Container response object in question has the same
// identity along both paths.
// merge: true,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I wrote in #8370 (comment), this merge: true configuration was going to be my answer to issue #8370, before I realized that it shouldn't be necessary (hence this PR).

Copy link
Contributor

@brainkim brainkim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don’t have the full context of writeToStore stuff but that bug should probably be fixed.

@benjamn benjamn marked this pull request as ready for review June 14, 2021 15:18
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Cache does not merge fragments correctly
3 participants