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

Aliasing id field prevents proper caching #10599

Closed
maclockard opened this issue Feb 24, 2023 · 7 comments
Closed

Aliasing id field prevents proper caching #10599

maclockard opened this issue Feb 24, 2023 · 7 comments

Comments

@maclockard
Copy link

maclockard commented Feb 24, 2023

Issue Description

When aliasing an id field like so:

query AllPeopleId {
  people {
    personId: id
    name
  }
}

The query ends up not being normalized in the cache nor are there individual cache entries for each Person entity.

This appears to be different behavior than expected given the id field still appears in the cache unaliased. Also from reading other issues such as apollographql/apollo-feature-requests#363 it appears as though the caching should ignore the alias.

Link to Reproduction

https://codesandbox.io/s/apollo-cache-with-id-alias-x0yhjy?file=/src/index.jsx

Reproduction Steps

As you can see rendered, the people query has not been normalized and there are no cache entries for Person.

Compare this to a version of the repro with no alias for the id field here: https://codesandbox.io/s/apollo-cache-with-no-id-alias-e8hyf5?file=/src/index.jsx. The query has been normalized as expected and there are separate cache entries for each Person entity.

@benjamn
Copy link
Member

benjamn commented Feb 24, 2023

Thanks for the reproductions!

If you add a keyFields: ["id"] configuration to your InMemoryCache for the Person type, like so

const client = new ApolloClient({
  cache: new InMemoryCache({
    typePolicies: {
      Person: {
        keyFields: ["id"]
      }
    }
  }),
  link
});

does that give the behavior you expected?

@maclockard
Copy link
Author

It looks like adding that manually results in the query being normalized. The generated cache key is a little bit different though Person:1 vs Person:{\"id\":\"1\"}.

Is there a reason why that needs to be added manually versus just making that the default behavior? I could see a lot of folks aliasing their id fields and not even realizing their cache is no longer working exactly as they expected.

If for some reason this shouldn't be done by default, is there a way to configure the cache such that this is the default caching policy unless indicated otherwise?

@benjamn
Copy link
Member

benjamn commented Feb 24, 2023

The function that automatically generates IDs like Person:1 is defaultDataIdFromObject, and the unfortunate truth is that both the formatting of those IDs and the aliasing (mis)behavior are matters of backwards compatibility at this point. For example, folks might have been using an alias to rename non-id fields to id in order to make them work seamlessly with defaultDataIdFromObject.

These behaviors could/should change in Apollo Client v4 (the next major version), but for now you can implement your own version of the dataIdFromObject function and pass it to the InMemoryCache constructor:

new InMemoryCache({
  dataIdFromObject(object, context) {
    if (object.__typename === "Person") {
      return ["id"];
    }
    return defaultDataIdFromObject(object, context);
  }
})

Returning ["id"] instead of a string tells the normalization system to use the field whose actual name is id even if it has an alias, similar to keyFields: ["id"]. Also, if no id field exists in object, an exception will be thrown, since returning ["id"] requires the field to exist for Person objects, whereas defaultDataIdFromObject classifies objects as non-normalizable if they're missing the default ID field.

You could add more __typename cases here as necessary, though I think that ends up being somewhat equivalent to registering keyFields (as above).

@maclockard
Copy link
Author

Thank you for the detailed explanation! Makes perfect sense, thank you!

@phryneas
Copy link
Member

phryneas commented Mar 2, 2023

I'm closing this here since it seems that all questions have been answered :)

@benjamn
Copy link
Member

benjamn commented Mar 8, 2023

This issue got me thinking about whether it might be possible to configure a blanket keyFields policy without having to enumerate every relevant __typename when configuring InMemoryCache.

The approach I had in mind turned out to be slightly broken, but the bug was fairly shallow, and should be fixed in Apollo Client v3.8, once this PR is merged: #10633

@github-actions
Copy link
Contributor

github-actions bot commented Apr 8, 2023

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
For general questions, we recommend using StackOverflow or our discord server.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 8, 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

No branches or pull requests

3 participants