apollo-ios: Swift error on queries with too many custom type variables

Problem Description

When a query contains a few variables with custom types, the API.swift generation may end up with a the following error:

ambiguous use of “map”

It looks like the one-liner init passing a dictionary as snapshot is the problem, I suspect it being too complex to evaluate with all the flatMap required.

Example

Assuming the following query:

query ProjectOverview(
    $projectId: ID!,
    $endDate: NaiveDateTime!
    $previousDate: NaiveDateTime!
    ) {
        project(id: $projectId) {
        id
        key
        name
        clientName

        lastProjectSourceScores(endDate: $endDate) {
            value
            source {
                id
                name
            }
        }

        previousScores:lastProjectSourceScores(endDate: $previousDate) {
            value
            source {
                id
                name
            }
        }

        events {
            value
            metadata {
                name
                content
            }
            sentAt
            source {
                name
            }
        }
    }
}

The following init will be generated, and will raise an ambiguous use of ‘map’ error:

public init(id: GraphQLID, key: String, name: String, clientName: String, lastProjectSourceScores: [LastProjectSourceScore?]? = nil, previousScores: [PreviousScore?]? = nil, events: [Event?]? = nil) {
        self.init(snapshot: ["__typename": "Project", "id": id, "key": key, "name": name, "clientName": clientName, "lastProjectSourceScores": lastProjectSourceScores.flatMap { $0.map { $0.flatMap { $0.snapshot } } }, "previousScores": previousScores.flatMap { $0.map { $0.flatMap { $0.snapshot } } }, "events": events.flatMap { $0.map { $0.flatMap { $0.snapshot } } }])
}

Workaround fix

It is possible to temporary fix the generated by extracting all the flatMap into variables, and passing those variables into the dictionary instead. That’s why I suspect the generated code being too complex.

public init(id: GraphQLID, key: String, name: String, clientName: String, lastProjectSourceScores: [LastProjectSourceScore?]? = nil, previousScores: [PreviousScore?]? = nil, events: [Event?]? = nil) {
        let lastProjectSourceScoresMap = lastProjectSourceScores.flatMap { $0.map { $0.flatMap { $0.snapshot } } }
        let previousScoresMap = previousScores.flatMap { $0.map { $0.flatMap { $0.snapshot } } }
        let eventsMap = events.flatMap { $0.map { $0.flatMap { $0.snapshot } } }
        self.init(snapshot: ["__typename": "Project", "id": id, "key": key, "name": name, "clientName": clientName, "lastProjectSourceScores": lastProjectSourceScoresMap, "previousScores": previousScoresMap, "events": eventsMap])
}

This solution is not viable, as the next build command with the Apollo Run Script will overwrite it again. The right way to do it would be to fix the code generation snippet.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 5
  • Comments: 20 (18 by maintainers)

Most upvoted comments

We also just ran into this problem.

It’s a classic case of the type system not being able to infer all the types inside map and flatMap. It can also be solved by explicitly typing out the types in the closures instead of using $0 and inferred return types.

Should definitely be solved in apollo-codegen. If all types were printed out, compile speed would increase drastically too, killing two birds with one stone. @martijnwalraven

This should be fixed in apollo-codegen 0.18.7!