-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
StoreWriter: Fragment selection not fully merged with other selections #8057
Comments
@czabaj The problem here is that your However, that merging is not something the cache can safely do by default, since the positions of the elements in the two arrays don't give the cache any information about the logical identities of the objects. Instead, since you seem to know it's safe to merge these array elements by index, you can/should configure that behavior with a new InMemoryCache({
typePolicies: {
OrderItem: {
fields: {
rewards: {
merge(existing: any[] | undefined, incoming: any[], { mergeObjects }) {
if (existing) {
// Merge object elements that have the same index:
const merged = existing.map((e, i) => mergeObjects(e, incoming[i]));
// In case incoming.length > existing.length:
const additional = incoming.slice(existing.length);
return [ ...merged, ...additional ];
}
return incoming;
},
},
},
},
},
}) I've opened a PR with an adaptation of your regression test (thanks!), showing both the initial failure and also that adding the While the You still might want to define a |
Thank you for your very nice explanation! The "unofficial rule of thumb" is very helpful for future API design. Coincidentally, I assign a synthetic Anyway, using the merge function for the field is brilliant. I'm also think about setting |
As the behavior proved not to be a bug, I'm closing this issue. |
@czabaj I've given this some thought before, and while I think it might not be fundamentally impossible, I can confirm it will not work right now. Specifically, if you try to define a |
Sorry for opening another issue, I searched carefully but did not found a similar issue.
I encountered this bug when I attempt to mimic Relay style components and fragment organization, where each component defines its data needs as its own set of fragments, which parent screen component compose into screen query to gather all necessary data in one request. This could lead to queries with many overlapping fragments, some of which are deeply nested.
One such screen query ended in a weird state, where
loading
is false, buterrors
anddata
are bothundefined
. After some travel in the call stack, I found a silent "Can't find field..." error inreadFromStore
(described in #6375). Curiously, the field was returned from the server but was not stored in the cache.After some more traveling in the call stack, I found out, that the field is lost in
StoreWriter#writeToStore
. I don't know the precise cause yet, but the problem is caused by fragment selection nested in another fragment selection -- the Query and parent Fragment selections are processed first and entities are stored in EntityStore, but then the nested fragment for an entity (with identity -id
field - which seems to be related), is processed and its limited selection overwrites some entities. As the fragment selection does not fully overlap with other selections, the fragment simply omits some fields from the EntityStore.I tried setting the merge functions for cache
typePolicies
per documentation in hope that it is matter of merge functions, but even settingmerge: true
for all types in query had no effect and even if it did, it would still smell like a bug in implementation to me.I created a minimal reproducible example (MRE) in CodeSandbox. It is a failed test there and I hope the comments in code will help explain all the necessary details.
Intended outcome:
All fragment selections in a single query are merged into the EntityStore during
StoreWriter#writeToStore
, thus theEntityStore
contains all the data returned from the server.Actual outcome:
Deeply nested fragments in some cases (see a minimal reproducible example for details) overwrites record for a certain entity in EntityStore, which, in case the fragment selection does not fully overlap with other selections, leads to (silent) "Can't find field..." error in
readFromStore
.How to reproduce the issue:
Open the MRE https://codesandbox.io/s/apollo-cache-error-bnu9w?file=/src/index.test.js
Versions
The text was updated successfully, but these errors were encountered: