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)
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
andflatMap
. 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. @martijnwalravenThis should be fixed in
apollo-codegen
0.18.7!