Add a new option to treat an interface like an object (#97)

## Summary:
The basic idea here is if you only request interface fields (no
fragments) you may not care about the concrete type, and so we could
just generate a struct as if it were an object.  I don't think it's a
good idea to do that by default, because then if you later add a
fragment all your code totally changes, but it's quite reasonable as an
option!

Most of the code involved is just wiring and validation; the
core implementation is literally just: treat it like an object.

Issue: https://github.com/Khan/genqlient/issues/85

## Test plan:
make check


Author: benjaminjkraft

Reviewers: csilvers, StevenACoffman, benjaminjkraft, aberkan, dnerdy, jvoll, mahtabsabet, MiguelCastillo

Required Reviewers: 

Approved By: StevenACoffman

Checks:  Test (1.17),  Test (1.16),  Test (1.15),  Test (1.14),  Lint,  Test (1.17),  Test (1.16),  Test (1.15),  Test (1.14),  Lint

Pull Request URL: https://github.com/Khan/genqlient/pull/97
This commit is contained in:
Ben Kraft
2021-09-15 18:00:22 -07:00
committed by GitHub
parent 463cffdede
commit 5211442843
14 changed files with 477 additions and 9 deletions
+22
View File
@@ -183,6 +183,28 @@ if novel, ok := resp.Favorite.(*GetBooksFavoriteNovel); ok {
The interface-type's GoDoc will include a list of its implementations, for your convenience.
If you only want to request shared fields of the interface (i.e. no fragments), this may seem like a lot of ceremony. If you prefer, you can instead add `# @genqlient(struct: true)` to the field, and genqlient will just generate a struct, like it does for GraphQL object types. For example, given:
```graphql
query GetBooks {
# @genqlient(struct: true)
favorite {
title
}
}
```
genqlient will generate just:
```go
type GetBooksFavoriteBook struct {
Title string
}
```
Keep in mind that if you later want to add fragments to your selection, you won't be able to use `struct` anymore; when you remove it you may need to update your code to replace `.Title` with `.GetTitle()` and so on.
### … documentation on the output types?
For any GraphQL types or fields with documentation in the GraphQL schema, genqlient automatically includes that documentation in the generated code's GoDoc. To add additional information to genqlient entrypoints, you can put comments in the GraphQL source:
+16
View File
@@ -54,6 +54,22 @@ directive genqlient(
# zero value and null (for nullable fields).
pointer: Boolean
# If set, this field will use a struct type in Go, even if it's an interface.
#
# This is useful when you have a query like
# query MyQuery {
# myInterface { myField }
# }
# where you are requesting only shared fields of an interface. By default,
# genqlient still generates an interface type, for consistency. But this
# isn't necessary: a struct would do just fine since there are no
# type-specific fields. Setting `struct: true` tells genqlient to do that.
#
# Note that this is only allowed when there are no fragments in play, such
# that all fields are on the interface type. Note that if you later add a
# fragment, you'll have to remove this option, and the types will change.
struct: Boolean
# If set, this argument or field will use the given Go type instead of a
# genqlient-generated type.
#