apollographql / apollo-feature-requests

🧑‍🚀 Apollo Client Feature Requests | (no 🐛 please).
Other
130 stars 7 forks source link

Apollo 3 typePolicies - pass parent entity inside Context to generate keyArgs based on top of args + entity #243

Open ovr opened 4 years ago

ovr commented 4 years ago

Hey!

Apollo 3 introduces new mechanics called typePolicies, and it provides an api called keyArgs to generate id based on top of args & context, but sometimes it's needed to get "parent" entity too to generate id.

For example

query GetPodcastWithEpisodesQuery($id: String!) {
    podcast(id: $id) {
        id,
        title,
        episodes(order: { published: DESC }) {
            edges {
                node {
                    id,
                    title,
                    pid
                }
            },
            pageInfo {
                endCursor,
                hasNextPage,
            },
            aggregate {
                count,
            }
        }
    }
}

Problem

I am interested to create calculate keyArgs for episodes based on top of ${podcast.id}-${args.order.published}, but I am not able to do it, because keyArgs didnt pass "parent type"

return new InMemoryCache({
    typePolicies: {
        podcast: {
            fields: {
                episodes: {
                    keyArgs: (args: any, context) => {
                        // I am not able to get parent entity
                        const podcast = { id: 5 };

                        return podcast.id + buildQueryCacheFromObject(args, ['order']);
                    },
                }
            }
        }
    },
});

Thanks

ViktorShev commented 8 months ago

Bump.

Also interested in how to achieve this.

jerelmiller commented 8 months ago

Hey @ovr and @ViktorShev 👋

I'd be curious to dig into this a bit more. Is there a specific reason you need the parent as part of your keyArgs here? These fields are already cached under the parent so there is no possibility that two parent records would point to the same list. @ovr in your example, each podcast would have its own episodes field independent for each id.

Here is an example codesandbox I threw together that demonstrates that parents with different IDs that query for a list field are cached under each parent. You can also try running the example directly: https://2w4z55-3000.csb.app/. This might be easier to inspect with. Apollo Devtools if you want to look at the cache.

Here are some screenshots with the cache that show that each list has a set of independent items from each other:

Screenshot 2023-12-19 at 12 59 10 PM Screenshot 2023-12-19 at 12 59 02 PM

That being said, I'd love to know what you're running into that would warrant you needing access to the parent inside the keyArgs function. Any more info on your use case would be appreciated!

ViktorShev commented 8 months ago

Hello @jerelmiller! I had ran into an issue where I had a a type Person which contained a subfield of paymentMethods, whose id field would not be unique in the context of the flat cache, they also contained an "isDefault" field, these payment methods are only unique under the context of their parent, so because of normalization they were being merged and the isDefault field constantly changing, I had thought the solution to this problem was to create cache entries based on person_id + method_id, but then I found out about normalization, the way the cache flattens, and that I can turn this off with a type policy for PersonPaymentMethod, which solved my issue, since now every person is not storing a reference to a cached payment method object, but the actual object. What I needed was to store a certain object in the context of its parent, but as already explained, keyArgs was not the solution, for my part, I'm in no need of this feature, thanks for replying! :smile: