Add tests to check that genqlient handles covariance (#203)
I didn't realize until today that implementations of GraphQL interfaces are actually allowed to be covariant: if the interface has a field `f: T`, then the implementations may have fields `f: U` where `U` is a subtype of `T` (for example `U` may be an implementation of the interface `T`, or `U` may be `T!` if `T` is non-nullable. (I thought it had to be `f: T` exactly.) So I figured I'd add a test and see what breaks. Surprisingly, and despite the fact that Go interfaces do *not* allow covariance, everything... worked? There's at least one place where it's possible we could ideally use a more specific type [1], but for now I just wanted to make sure we at least write something that builds and is vaguely reasonable. Of course I'm not sure if there's anything I've missed (some day I need to find a fuzzing engine that can fuzz GraphQL). [1] Specifically, the field `CovariantInterfaceImplementationRandomItemTopic.Next` might ideally have type `...NextContentTopic`, not `...NextContent`; we know it's a topic. This doesn't directly cause covariance problems in Go: the method `GetNext` still returns `...NextContent` so the interface matches. But that trick doesn't work for the sibling field `.Related` which is slice-typed: or rather, we'd need the method to copy the slice to the correct type. (Not to mention the implemention of any change here would require a bunch of plumbing because the AST doesn't quite have what we want.) So it's probably best to just keep this as-is for simplicity and consistency. Test plan: make check
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
query CovariantInterfaceImplementation {
|
||||
randomItem {
|
||||
id
|
||||
next { ...ContentFields }
|
||||
related { ...ContentFields }
|
||||
}
|
||||
root {
|
||||
...ContentFields
|
||||
...TopicFields
|
||||
next { ...TopicFields }
|
||||
related { ...TopicFields }
|
||||
}
|
||||
}
|
||||
|
||||
fragment ContentFields on Content {
|
||||
next { id }
|
||||
related { id }
|
||||
}
|
||||
|
||||
fragment TopicFields on Topic {
|
||||
next { id }
|
||||
related { id }
|
||||
}
|
||||
+8
@@ -84,6 +84,8 @@ interface Content {
|
||||
name: String!
|
||||
parent: Topic
|
||||
url: String!
|
||||
next: Content
|
||||
related: [Content!]
|
||||
}
|
||||
|
||||
"""An object with a duration, like a video."""
|
||||
@@ -102,6 +104,8 @@ type Article implements Content {
|
||||
url: String!
|
||||
text: String!
|
||||
thumbnail: StuffThumbnail
|
||||
next: Content
|
||||
related: [Content!]
|
||||
}
|
||||
|
||||
type StuffThumbnail { # for articles, but let's give the name-generator a hard time.
|
||||
@@ -117,6 +121,8 @@ type Video implements Content & HasDuration {
|
||||
url: String!
|
||||
duration: Int!
|
||||
thumbnail: Thumbnail
|
||||
next: Content
|
||||
related: [Content!]
|
||||
}
|
||||
|
||||
type Thumbnail { # for videos, but let's give the name-generator a hard time.
|
||||
@@ -133,6 +139,8 @@ type Topic implements Content {
|
||||
children: [Content!]!
|
||||
videoChildren: [Video!]!
|
||||
schoolGrade: String
|
||||
next: Topic
|
||||
related: [Topic!]
|
||||
}
|
||||
|
||||
input RecursiveInput {
|
||||
|
||||
+2412
File diff suppressed because it is too large
Load Diff
+9
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"operations": [
|
||||
{
|
||||
"operationName": "CovariantInterfaceImplementation",
|
||||
"query": "\nquery CovariantInterfaceImplementation {\n\trandomItem {\n\t\t__typename\n\t\tid\n\t\tnext {\n\t\t\t__typename\n\t\t\t... ContentFields\n\t\t}\n\t\trelated {\n\t\t\t__typename\n\t\t\t... ContentFields\n\t\t}\n\t}\n\troot {\n\t\t... ContentFields\n\t\t... TopicFields\n\t\tnext {\n\t\t\t... TopicFields\n\t\t}\n\t\trelated {\n\t\t\t... TopicFields\n\t\t}\n\t}\n}\nfragment ContentFields on Content {\n\tnext {\n\t\t__typename\n\t\tid\n\t}\n\trelated {\n\t\t__typename\n\t\tid\n\t}\n}\nfragment TopicFields on Topic {\n\tnext {\n\t\tid\n\t}\n\trelated {\n\t\tid\n\t}\n}\n",
|
||||
"sourceLocation": "testdata/queries/CovariantInterfaceImplementation.graphql"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user