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

Multiple (3) lines of defense against merging { __ref } objects into normalized StoreObject entities #8505

Merged
merged 3 commits into from
Jul 16, 2021

Conversation

benjamn
Copy link
Member

@benjamn benjamn commented Jul 16, 2021

PR #7778 (first released in @apollo/client@3.4.0-beta.12) allowed merge: true to combine Reference objects (which refer to normalized StoreObject entities by ID) with non-normalized StoreObject objects.

When these mixed Reference/StoreObject merges happen (e.g. in the mergeObjects function), the StoreWriter#applyMerges method returns a Reference rather than a StoreObject, which was a new possibility not adequately handled by the calling code in PR #7778. In particular, applyMerges returning a Reference could result in calling store.merge(dataId, fields) when isReference(fields), allowing __ref properties to end up as fields in the normalized StoreObject. These stray __ref properties could later confuse the EntityStore garbage collector into not traversing the other properties of the StoreObject (because the object appears to be a Reference), potentially misidentifying any unreached references as unreachable, and thus inappropriately deleting them from the store.

This PR solves these problems in three independent ways:

  1. When StoreWriter#applyMerges returns a Reference, we now assume its fields have already been updated in the store, and avoid merging the Reference object using store.merge(dataId, fields).
  2. Fix EntityStore#findChildRefIds to continue traversing other properties of objects that appear to have __ref properties, just in case there has been an accidental merge.
  3. Tolerate surprise Reference arguments in EntityStore#merge by converting them to their string IDs, which are well-handled by the merge method already. This shouldn't happen now thanks to 1, but provides a foolproof backup plan.

@benjamn benjamn added this to the MM-2021-07 milestone Jul 16, 2021
@benjamn benjamn requested a review from brainkim July 16, 2021 17:21
@benjamn benjamn self-assigned this Jul 16, 2021
@benjamn benjamn changed the title Multiple (3) lines of defense against merging { __ref } objects into entity objects Multiple (3) lines of defense against merging { __ref } objects into StoreObject entity objects Jul 16, 2021
@benjamn benjamn changed the title Multiple (3) lines of defense against merging { __ref } objects into StoreObject entity objects Multiple (3) lines of defense against merging { __ref } objects into normalized StoreObject entities Jul 16, 2021
@brainkim
Copy link
Contributor

No test case?

@benjamn
Copy link
Member Author

benjamn commented Jul 16, 2021

@brainkim Working on a test! Let me know if you have any reproductions from your investigation yesterday, and I'll try to include them as regression tests.

@brainkim
Copy link
Contributor

Sorry I don’t have a handle on the exact schema query/eviction pattern from Apollo Studio which was causing the Account to be a reference or whatever. If you’d like me to figure that out, let me know.

@benjamn
Copy link
Member Author

benjamn commented Jul 16, 2021

@brainkim Studio isn't doing anything wrong! Ultimately, Studio will benefit from #7778 because they have code that previously (using AC v3.3.7) would replace an existing { __ref: "Account:..." } reference object with an incoming StoreObject. After #7778, the reference and the object should be appropriately merged in the EntityStore, with no fields lost in the process, and no stray __ref properties. However, #7778 was incomplete, containing some bugs/oversights that this PR aims to fix. With this PR is applied, I can no longer reproduce the problem locally in Studio.

@benjamn benjamn force-pushed the avoid-mistaking-references-for-entity-objects branch from f93f4f1 to 4832e87 Compare July 16, 2021 19:10
@benjamn
Copy link
Member Author

benjamn commented Jul 16, 2021

@brainkim Alright, I've added separate regression tests to each commit.

@benjamn benjamn merged commit 6fe0d66 into release-3.4 Jul 16, 2021
@benjamn benjamn deleted the avoid-mistaking-references-for-entity-objects branch July 16, 2021 22:06
@hwillson hwillson removed this from the MM-2021-07 milestone Jul 29, 2021
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 15, 2023
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.

3 participants