## Summary:
One common use of fragment spreads is as the entirety of a field's
selection, e.g.
```graphql
query MyQuery {
myField {
...MyFragment
}
}
```
In this case, by default, genqlient generates a wrapper type
`MyQueryMyFieldMyType`, which just embeds `MyFragment`. This makes
sense if you later want to add more fields in addition to the fragment
spread. But if you don't -- and you did the fragment because you want
to share types, it's an extra layer of indirection. (Which becomes
especially onerous if `myField` has list type (`[MyType!]`), such that
it's not just an extra attribute-access to get to `MyFragment`.)
The new option `# @genqlient(flatten: true)` simplifies this situation:
if applied to `myField` is skips the wrapper type;
`MyQueryResponse.MyField` will simply have type `MyFragment` (or
`[]MyFragment`, or whatever). This should hopefully make the `typename`
option, which has more limitations, less necessary.
Note that in #30 the initial idea was to support this for fields as
well. This would require significant additional complexity in the
JSON-(un)marshaling code, and has proven less necessary, so I
implemented this option only for fragment-spreads for now. With that
restriction, it was shockingly simple; we have to hook into a bunch of
different places, but they're all quite simple, since the structure of
the Go types still matches the structure in GraphQL.
Issue: https://github.com/Khan/genqlient/issues/30
## Test plan:
make check
Author: benjaminjkraft
Reviewers: csilvers, dnerdy, aberkan, jvoll, mahtabsabet, MiguelCastillo, StevenACoffman
Required Reviewers:
Approved By: csilvers, dnerdy
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/121
89 lines
1.5 KiB
Go
89 lines
1.5 KiB
Go
// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
|
|
|
|
package server
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"strconv"
|
|
)
|
|
|
|
type Being interface {
|
|
IsBeing()
|
|
}
|
|
|
|
type Lucky interface {
|
|
IsLucky()
|
|
}
|
|
|
|
type Animal struct {
|
|
ID string `json:"id"`
|
|
Name string `json:"name"`
|
|
Species Species `json:"species"`
|
|
Owner Being `json:"owner"`
|
|
Hair *BeingsHair `json:"hair"`
|
|
}
|
|
|
|
func (Animal) IsBeing() {}
|
|
|
|
type BeingsHair struct {
|
|
HasHair bool `json:"hasHair"`
|
|
}
|
|
|
|
type Hair struct {
|
|
Color *string `json:"color"`
|
|
}
|
|
|
|
type User struct {
|
|
ID string `json:"id"`
|
|
Name string `json:"name"`
|
|
LuckyNumber *int `json:"luckyNumber"`
|
|
Hair *Hair `json:"hair"`
|
|
Birthdate *string `json:"birthdate"`
|
|
Friends []*User `json:"friends"`
|
|
}
|
|
|
|
func (User) IsBeing() {}
|
|
func (User) IsLucky() {}
|
|
|
|
type Species string
|
|
|
|
const (
|
|
SpeciesDog Species = "DOG"
|
|
SpeciesCoelacanth Species = "COELACANTH"
|
|
)
|
|
|
|
var AllSpecies = []Species{
|
|
SpeciesDog,
|
|
SpeciesCoelacanth,
|
|
}
|
|
|
|
func (e Species) IsValid() bool {
|
|
switch e {
|
|
case SpeciesDog, SpeciesCoelacanth:
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (e Species) String() string {
|
|
return string(e)
|
|
}
|
|
|
|
func (e *Species) UnmarshalGQL(v interface{}) error {
|
|
str, ok := v.(string)
|
|
if !ok {
|
|
return fmt.Errorf("enums must be strings")
|
|
}
|
|
|
|
*e = Species(str)
|
|
if !e.IsValid() {
|
|
return fmt.Errorf("%s is not a valid Species", str)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (e Species) MarshalGQL(w io.Writer) {
|
|
fmt.Fprint(w, strconv.Quote(e.String()))
|
|
}
|