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

Support cache.identify(entity) for computing entity ID strings. #5642

Merged
merged 3 commits into from
Dec 3, 2019

Conversation

benjamn
Copy link
Member

@benjamn benjamn commented Dec 2, 2019

After you've specified accurate keyFields policies for your types, the last thing you want is for application code to reimplement that logic just to compute IDs to use with methods like InMemoryCache#evict.

This commit introduces a method called InMemoryCache#identify, which takes a result object and computes its ID based on its __typename and primary key fields, so that you can do cache.evict(cache.identify(entity)) to evict an object from the cache, without any manual string manipulation.

After you've specified accurate keyFields policies for your types, the
last thing you want is for application code to reimplement that logic just
to compute an ID to use with methods like InMemoryCache#evict.

This commit introduces a method called InMemoryCache#identify, which takes
a result object and computes its ID based on its __typename and primary
key fields, so that you can do cache.evict(cache.identify(entity)) to
evict an object from the cache, without any manual string manipulation.
@benjamn benjamn added this to the Release 3.0 milestone Dec 2, 2019
@benjamn benjamn requested a review from hwillson December 2, 2019 19:56
@benjamn benjamn self-assigned this Dec 2, 2019
Comment on lines 861 to 865
const rootSelectionSet = getOperationDefinition(query).selectionSet;
const abcsSelectionSet = (rootSelectionSet.selections[0] as FieldNode).selectionSet;
const fragmentMap = createFragmentMap(getFragmentDefinitions(query));

expect(cache.identify(object, abcsSelectionSet, fragmentMap)).toBe(
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 was typing out this part of the test, I found myself wondering whether anyone will ever go to the trouble of passing a SelectionSet and a FragmentMap as additional arguments to cache.identify. Those arguments are important for the underlying policies.identify method, since we do have the selection set available when we're writing results to the cache, and it's important to handle field aliasing correctly, but I wonder if we should limit this public API to accepting just the StoreObject, and assume that its fields have not been renamed by aliasing? For what it's worth, cache.identify will throw if any of the keyFields are missing (as I'm testing just above).

Copy link
Member

Choose a reason for hiding this comment

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

@benjamn I'm okay with either approach, but leaving it like this does add extra flexibility.

Copy link
Contributor

Choose a reason for hiding this comment

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

@benjamn I'm in favor of only having the StoreObject as it is the piece they will have readily available within their application. Passing in additional selectionSet/fragmentMap would require keeping additional state about the graph accessible in places where I don't think it should really be found

Copy link
Contributor

Choose a reason for hiding this comment

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

I think a picture of where/how this will be used when using aliases to evict data would be helpful to know if it is useable without the selection set part

Copy link
Member Author

@benjamn benjamn Dec 3, 2019

Choose a reason for hiding this comment

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

Yeah, the alternative is just to tell folks to make sure they're not renaming any of the primary key fields in the object they pass to cache.identify. Even in the rare cases where someone actually does need to rename an aliased field in a result object before passing it to cache.identify, that's a lot easier to do by hand in a few places than finding the relevant selection set and computing a fragment map. I'm comfortable telling people that the reason their normalization is broken is because of aliasing. Also, once they start using keyFields, cache.identify will throw if any of the necessary fields are missing, so it shouldn't be that much of a mystery.

@benjamn benjamn changed the title Support cache.identify(object) for computing entity ID strings. Support cache.identify(entity) for computing entity ID strings. Dec 2, 2019
Copy link
Member

@hwillson hwillson left a comment

Choose a reason for hiding this comment

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

Looks great @benjamn!

Comment on lines 861 to 865
const rootSelectionSet = getOperationDefinition(query).selectionSet;
const abcsSelectionSet = (rootSelectionSet.selections[0] as FieldNode).selectionSet;
const fragmentMap = createFragmentMap(getFragmentDefinitions(query));

expect(cache.identify(object, abcsSelectionSet, fragmentMap)).toBe(
Copy link
Member

Choose a reason for hiding this comment

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

@benjamn I'm okay with either approach, but leaving it like this does add extra flexibility.

Comment on lines 861 to 865
const rootSelectionSet = getOperationDefinition(query).selectionSet;
const abcsSelectionSet = (rootSelectionSet.selections[0] as FieldNode).selectionSet;
const fragmentMap = createFragmentMap(getFragmentDefinitions(query));

expect(cache.identify(object, abcsSelectionSet, fragmentMap)).toBe(
Copy link
Contributor

Choose a reason for hiding this comment

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

@benjamn I'm in favor of only having the StoreObject as it is the piece they will have readily available within their application. Passing in additional selectionSet/fragmentMap would require keeping additional state about the graph accessible in places where I don't think it should really be found

Comment on lines 861 to 865
const rootSelectionSet = getOperationDefinition(query).selectionSet;
const abcsSelectionSet = (rootSelectionSet.selections[0] as FieldNode).selectionSet;
const fragmentMap = createFragmentMap(getFragmentDefinitions(query));

expect(cache.identify(object, abcsSelectionSet, fragmentMap)).toBe(
Copy link
Contributor

Choose a reason for hiding this comment

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

I think a picture of where/how this will be used when using aliases to evict data would be helpful to know if it is useable without the selection set part

@benjamn benjamn mentioned this pull request Dec 3, 2019
31 tasks
@benjamn benjamn merged commit 32f1201 into release-3.0 Dec 3, 2019
@benjamn benjamn deleted the cache.identify branch December 3, 2019 20:24
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 16, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants