apollographql / apollo-ios

📱  A strongly-typed, caching GraphQL client for iOS, written in Swift.
https://www.apollographql.com/docs/ios/
MIT License
3.87k stars 717 forks source link

Duplicate entries in `__mergedSources` #3321

Closed Iron-Ham closed 3 months ago

Iron-Ham commented 8 months ago

Summary

I've noticed that we occasionally get duplicate entries in merged sources of generated files. It often takes the form of:

public static var __mergedSources: [any ApolloAPI.SelectionSet.Type] { [
  UserListItemFragment.self,
  AvatarFragment.self,
  FeedItemFragment.AsFollowRecommendationFeedItem.Followee.AsUser.self,
  FeedItemFragment.AsFollowRecommendationFeedItem.Followee.AsUser.self
] }

Note that this has been a bug in some form since at least 1.2.0. In previous versions, this was a rare event. In 1.7.1, it's a certainty.

Version

1.7.1

Steps to reproduce the behavior

I've been able to reliably reproduce this by having both an in-line fragment on a member of a union type and a named fragment that relies on the same underlying type within the same selection set:

# Within a query response selection set

... on MyUnionType { # I don't know if this has to be a union type, but this seems to be the case that this is occurring in.
  ... on User { 
    # Whatever selections are needed
  }
  ... UserListItemFragment
}

In this instance:

WORKAROUND:

Instead of structuring your selection as above, structure it like so:

...on MyUnionType {
  ... on User {
    ...UserListItemFragment
  }
}

Logs

No response

Anything else?

No response

calvincestari commented 8 months ago

@Iron-Ham, did you have any luck working with the schema we spoke about last week to reproduce this yet?

Iron-Ham commented 7 months ago

So that this isn't a black-box for other impacted folks: Calvin and I have been sharing information via private channels in order to try and track down this issue.

It proved quite difficult to reproduce outside of GitHub's non-public schema, so we've been collaborating on trying down to narrow down a reproduction case. Earlier this week, Calvin shared an idea and provided a branch that includes additional debugging when it hits a duplicate. The basis is that Calvin has the hypothesis we'd like to test: given that mergedSources is an OrderedSet<IR.MergedSelections.MergedSource> it's possible that we're not getting exact duplicates – the typeInfo or fragment sources may be different, and they could be resolved to the same selection set name. This implies that we may not be resolving the selection set name correctly.

When applying that branch to a fork of 1.7.1 (as that's the current version we are using internally at GitHub), we hit some debugging logs that seem to support the general hypothesis:

1.7.1 Logs

``` [ERROR - ApolloCodegenLib:SelectionSetTemplate.swift:182] - 4 mergedSources for operation(IR.Operation) Sources: OrderedSet([[[Object - User]], fragment: UserListItemFragment on Object - User, [[Interface - Actor]], fragment: AvatarFragment on Interface - Actor, [[Union - FeedItem -> Object - FollowRecommendationFeedItem] -> [Union - Followable -> Object - User]], fragment: FeedItemFragment on Union - FeedItem, [[Union - FeedItem -> Object - FollowRecommendationFeedItem] -> [Union - Followable -> Object - User]], fragment: FeedItemFragment on Union - FeedItem]) Duplicating generated selection set name FeedItemFragment.AsFollowRecommendationFeedItem.Followee.AsUser [ERROR - ApolloCodegenLib:SelectionSetTemplate.swift:182] - 4 mergedSources for operation(IR.Operation) Sources: OrderedSet([[[Object - User]], fragment: UserListItemFragment on Object - User, [[Interface - Actor]], fragment: AvatarFragment on Interface - Actor, [[Union - FeedItem -> Object - FollowedUserFeedItem] -> [Union - Followable -> Object - User]], fragment: FeedItemFragment on Union - FeedItem, [[Union - FeedItem -> Object - FollowedUserFeedItem] -> [Union - Followable -> Object - User]], fragment: FeedItemFragment on Union - FeedItem]) Duplicating generated selection set name FeedItemFragment.AsFollowedUserFeedItem.Followee.AsUser [ERROR - ApolloCodegenLib:SelectionSetTemplate.swift:182] - 4 mergedSources for operation(IR.Operation) Sources: OrderedSet([[[Object - User]], fragment: UserListItemFragment on Object - User, [[Interface - Actor]], fragment: AvatarFragment on Interface - Actor, [[Union - FeedItem -> Object - FollowRecommendationFeedItem] -> [Union - Followable -> Object - User]], fragment: FeedItemFragment on Union - FeedItem, [[Union - FeedItem -> Object - FollowRecommendationFeedItem] -> [Union - Followable -> Object - User]], fragment: FeedItemFragment on Union - FeedItem]) Duplicating generated selection set name FeedItemFragment.AsFollowRecommendationFeedItem.Followee.AsUser [ERROR - ApolloCodegenLib:SelectionSetTemplate.swift:182] - 4 mergedSources for operation(IR.Operation) Sources: OrderedSet([[[Object - User]], fragment: UserListItemFragment on Object - User, [[Interface - Actor]], fragment: AvatarFragment on Interface - Actor, [[Union - FeedItem -> Object - FollowedUserFeedItem] -> [Union - Followable -> Object - User]], fragment: FeedItemFragment on Union - FeedItem, [[Union - FeedItem -> Object - FollowedUserFeedItem] -> [Union - Followable -> Object - User]], fragment: FeedItemFragment on Union - FeedItem]) Duplicating generated selection set name FeedItemFragment.AsFollowedUserFeedItem.Followee.AsUser ``` Examining the first error statement, and adding some new lines where I _think_ they belong (please correct me on this one if my assumptions are wrong @calvincestari), we're left with: ``` [ERROR - ApolloCodegenLib:SelectionSetTemplate.swift:182] - 4 mergedSources for operation(IR.Operation) Sources: OrderedSet([ [[Object - User]], fragment: UserListItemFragment on Object - User, [[Interface - Actor]], fragment: AvatarFragment on Interface - Actor, [[Union - FeedItem -> Object - FollowRecommendationFeedItem] -> [Union - Followable -> Object - User]], fragment: FeedItemFragment on Union - FeedItem, [[Union - FeedItem -> Object - FollowRecommendationFeedItem] -> [Union - Followable -> Object - User]], fragment: FeedItemFragment on Union - FeedItem ]) Duplicating generated selection set name FeedItemFragment.AsFollowedUserFeedItem.Followee.AsUser ```

When applied to the ApolloCodegenLib's main branch – instead of 1.7.1 – we see an identical result:

1.8.x Logs

``` [ERROR - ApolloCodegenLib:SelectionSetTemplate.swift:182] - 4 mergedSources for operation(IR.Operation) Sources: OrderedSet([[[Object - User]], fragment: UserListItemFragment on Object - User, [[Interface - Actor]], fragment: AvatarFragment on Interface - Actor, [[Union - FeedItem -> Object - FollowRecommendationFeedItem] -> [Union - Followable -> Object - User]], fragment: FeedItemFragment on Union - FeedItem, [[Union - FeedItem -> Object - FollowRecommendationFeedItem] -> [Union - Followable -> Object - User]], fragment: FeedItemFragment on Union - FeedItem]) Duplicating generated selection set name FeedItemFragment.AsFollowRecommendationFeedItem.Followee.AsUser [ERROR - ApolloCodegenLib:SelectionSetTemplate.swift:182] - 4 mergedSources for operation(IR.Operation) Sources: OrderedSet([[[Object - User]], fragment: UserListItemFragment on Object - User, [[Interface - Actor]], fragment: AvatarFragment on Interface - Actor, [[Union - FeedItem -> Object - FollowedUserFeedItem] -> [Union - Followable -> Object - User]], fragment: FeedItemFragment on Union - FeedItem, [[Union - FeedItem -> Object - FollowedUserFeedItem] -> [Union - Followable -> Object - User]], fragment: FeedItemFragment on Union - FeedItem]) Duplicating generated selection set name FeedItemFragment.AsFollowedUserFeedItem.Followee.AsUser [ERROR - ApolloCodegenLib:SelectionSetTemplate.swift:182] - 4 mergedSources for operation(IR.Operation) Sources: OrderedSet([[[Object - User]], fragment: UserListItemFragment on Object - User, [[Interface - Actor]], fragment: AvatarFragment on Interface - Actor, [[Union - FeedItem -> Object - FollowRecommendationFeedItem] -> [Union - Followable -> Object - User]], fragment: FeedItemFragment on Union - FeedItem, [[Union - FeedItem -> Object - FollowRecommendationFeedItem] -> [Union - Followable -> Object - User]], fragment: FeedItemFragment on Union - FeedItem]) Duplicating generated selection set name FeedItemFragment.AsFollowRecommendationFeedItem.Followee.AsUser [ERROR - ApolloCodegenLib:SelectionSetTemplate.swift:182] - 4 mergedSources for operation(IR.Operation) Sources: OrderedSet([[[Object - User]], fragment: UserListItemFragment on Object - User, [[Interface - Actor]], fragment: AvatarFragment on Interface - Actor, [[Union - FeedItem -> Object - FollowedUserFeedItem] -> [Union - Followable -> Object - User]], fragment: FeedItemFragment on Union - FeedItem, [[Union - FeedItem -> Object - FollowedUserFeedItem] -> [Union - Followable -> Object - User]], fragment: FeedItemFragment on Union - FeedItem]) Duplicating generated selection set name FeedItemFragment.AsFollowedUserFeedItem.Followee.AsUser ``` Adding newlines to the first output, as before, yields: ``` [ERROR - ApolloCodegenLib:SelectionSetTemplate.swift:182] - 4 mergedSources for operation(IR.Operation) Sources: OrderedSet([ [[Object - User]], fragment: UserListItemFragment on Object - User, [[Interface - Actor]], fragment: AvatarFragment on Interface - Actor, [[Union - FeedItem -> Object - FollowRecommendationFeedItem] -> [Union - Followable -> Object - User]], fragment: FeedItemFragment on Union - FeedItem, [[Union - FeedItem -> Object - FollowRecommendationFeedItem] -> [Union - Followable -> Object - User]], fragment: FeedItemFragment on Union - FeedItem ]) Duplicating generated selection set name FeedItemFragment.AsFollowRecommendationFeedItem.Followee.AsUser ```

calvincestari commented 7 months ago

Thanks @Iron-Ham.

[ERROR - ApolloCodegenLib:SelectionSetTemplate.swift:182] - 4 mergedSources for operation(IR.Operation)

Sources: OrderedSet<MergedSource>([
    [[Object - User]], fragment: UserListItemFragment on Object - User, 
    [[Interface - Actor]], fragment: AvatarFragment on Interface - Actor, 
    [[Union - FeedItem -> Object - FollowRecommendationFeedItem] -> [Union - Followable -> Object - User]], fragment: FeedItemFragment on Union - FeedItem, 
    [[Union - FeedItem -> Object - FollowRecommendationFeedItem] -> [Union - Followable -> Object - User]], fragment: FeedItemFragment on Union - FeedItem
])
Duplicating generated selection set name FeedItemFragment.AsFollowRecommendationFeedItem.Followee.AsUser

Yup, you've broken it up correctly and it looks like we are indeed getting duplicates in the set - which should not be happening!

Iron-Ham commented 7 months ago

When ran again with additional debugging, we get the following:

Logs

Cleaned first result: ``` [ERROR - ApolloCodegenLib:SelectionSetTemplate.swift:182] - 4 mergedSources for operation(IR.Operation) Sources: [ entity: IR.Entity, scopePath: [[Object - User]], fragment: rootField: UserListItemFragment: User!, definition: UserListItemFragment on Object - User, entity: IR.Entity, scopePath: [[Interface - Actor]], fragment: rootField: AvatarFragment: Actor!, definition: AvatarFragment on Interface - Actor, entity: IR.Entity, scopePath: [[Union - FeedItem -> Object - FollowRecommendationFeedItem] -> [Union - Followable -> Object - User]], fragment: rootField: FeedItemFragment: FeedItem!, definition: FeedItemFragment on Union - FeedItem, entity: IR.Entity, scopePath: [[Union - FeedItem -> Object - FollowRecommendationFeedItem] -> [Union - Followable -> Object - User]], fragment: rootField: FeedItemFragment: FeedItem!, definition: FeedItemFragment on Union - FeedItem ] Duplicating generated selection set name FeedItemFragment.AsFollowRecommendationFeedItem.Followee.AsUser ``` Full Logs: ``` [ERROR - ApolloCodegenLib:SelectionSetTemplate.swift:182] - 4 mergedSources for operation(IR.Operation) Sources: [entity: IR.Entity, scopePath: [[Object - User]], fragment: rootField: UserListItemFragment: User!, definition: UserListItemFragment on Object - User, entity: IR.Entity, scopePath: [[Interface - Actor]], fragment: rootField: AvatarFragment: Actor!, definition: AvatarFragment on Interface - Actor, entity: IR.Entity, scopePath: [[Union - FeedItem -> Object - FollowRecommendationFeedItem] -> [Union - Followable -> Object - User]], fragment: rootField: FeedItemFragment: FeedItem!, definition: FeedItemFragment on Union - FeedItem, entity: IR.Entity, scopePath: [[Union - FeedItem -> Object - FollowRecommendationFeedItem] -> [Union - Followable -> Object - User]], fragment: rootField: FeedItemFragment: FeedItem!, definition: FeedItemFragment on Union - FeedItem] Duplicating generated selection set name FeedItemFragment.AsFollowRecommendationFeedItem.Followee.AsUser [ERROR - ApolloCodegenLib:SelectionSetTemplate.swift:182] - 4 mergedSources for operation(IR.Operation) Sources: [entity: IR.Entity, scopePath: [[Object - User]], fragment: rootField: UserListItemFragment: User!, definition: UserListItemFragment on Object - User, entity: IR.Entity, scopePath: [[Interface - Actor]], fragment: rootField: AvatarFragment: Actor!, definition: AvatarFragment on Interface - Actor, entity: IR.Entity, scopePath: [[Union - FeedItem -> Object - FollowedUserFeedItem] -> [Union - Followable -> Object - User]], fragment: rootField: FeedItemFragment: FeedItem!, definition: FeedItemFragment on Union - FeedItem, entity: IR.Entity, scopePath: [[Union - FeedItem -> Object - FollowedUserFeedItem] -> [Union - Followable -> Object - User]], fragment: rootField: FeedItemFragment: FeedItem!, definition: FeedItemFragment on Union - FeedItem] Duplicating generated selection set name FeedItemFragment.AsFollowedUserFeedItem.Followee.AsUser [ERROR - ApolloCodegenLib:SelectionSetTemplate.swift:182] - 4 mergedSources for operation(IR.Operation) Sources: [entity: IR.Entity, scopePath: [[Object - User]], fragment: rootField: UserListItemFragment: User!, definition: UserListItemFragment on Object - User, entity: IR.Entity, scopePath: [[Interface - Actor]], fragment: rootField: AvatarFragment: Actor!, definition: AvatarFragment on Interface - Actor, entity: IR.Entity, scopePath: [[Union - FeedItem -> Object - FollowRecommendationFeedItem] -> [Union - Followable -> Object - User]], fragment: rootField: FeedItemFragment: FeedItem!, definition: FeedItemFragment on Union - FeedItem, entity: IR.Entity, scopePath: [[Union - FeedItem -> Object - FollowRecommendationFeedItem] -> [Union - Followable -> Object - User]], fragment: rootField: FeedItemFragment: FeedItem!, definition: FeedItemFragment on Union - FeedItem] Duplicating generated selection set name FeedItemFragment.AsFollowRecommendationFeedItem.Followee.AsUser [ERROR - ApolloCodegenLib:SelectionSetTemplate.swift:182] - 4 mergedSources for operation(IR.Operation) Sources: [entity: IR.Entity, scopePath: [[Object - User]], fragment: rootField: UserListItemFragment: User!, definition: UserListItemFragment on Object - User, entity: IR.Entity, scopePath: [[Interface - Actor]], fragment: rootField: AvatarFragment: Actor!, definition: AvatarFragment on Interface - Actor, entity: IR.Entity, scopePath: [[Union - FeedItem -> Object - FollowedUserFeedItem] -> [Union - Followable -> Object - User]], fragment: rootField: FeedItemFragment: FeedItem!, definition: FeedItemFragment on Union - FeedItem, entity: IR.Entity, scopePath: [[Union - FeedItem -> Object - FollowedUserFeedItem] -> [Union - Followable -> Object - User]], fragment: rootField: FeedItemFragment: FeedItem!, definition: FeedItemFragment on Union - FeedItem] Duplicating generated selection set name FeedItemFragment.AsFollowedUserFeedItem.Followee.AsUser ```

With these more detailed logs, we still see no difference.

AnthonyMDev commented 4 months ago

@Iron-Ham, I know we weren't able to come up with a reproduction case for this yet. Are you still experiencing this bug?

Iron-Ham commented 3 months ago

Apologies for the late response,

It's still reproducible as we haven't upgraded beyond 1.7.1 yet, but I haven't verified this behavior on the current release. I'm happy to have this closed out unless it pops up again – in case it does, future readers will see a workaround above.

calvincestari commented 3 months ago

Yeah, I'm still stumped on this one. I'll close it out and let's keep an eye on it as @AnthonyMDev works through the merged fields work since that touches much of the logic that would be responsible for this bug.

github-actions[bot] commented 3 months ago

Do you have any feedback for the maintainers? Please tell us by taking a one-minute survey. Your responses will help us understand Apollo iOS usage and allow us to serve you better.