Skip to content

Commit

Permalink
Add tests to check that genqlient handles covariance (#203)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
benjaminjkraft committed Jun 4, 2022
1 parent 37fa3d6 commit 520532e
Show file tree
Hide file tree
Showing 4 changed files with 2,452 additions and 0 deletions.
23 changes: 23 additions & 0 deletions generate/testdata/queries/CovariantInterfaceImplementation.graphql
Original file line number Diff line number Diff line change
@@ -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 changes: 8 additions & 0 deletions generate/testdata/queries/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ interface Content {
name: String!
parent: Topic
url: String!
next: Content
related: [Content!]
}

"""An object with a duration, like a video."""
Expand All @@ -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.
Expand All @@ -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.
Expand All @@ -133,6 +139,8 @@ type Topic implements Content {
children: [Content!]!
videoChildren: [Video!]!
schoolGrade: String
next: Topic
related: [Topic!]
}

input RecursiveInput {
Expand Down
Loading

0 comments on commit 520532e

Please sign in to comment.