Add a way to get a shared struct from an interface
- Dominant language
- Go
- Stars
- 1.3k
- Forks
- 143
- Avg merge
- 4h 50m
- Merged PRs (30d)
- 1
Description
Suppose you have
```graphql
query Q {
myInterface {
a b c
... on Impl1 { d }
}
}
```
Right now we generate (roughly)
```go
type QMyInterface interface { GetA() string; GetB() string; GetC() string }
type QMyInterfaceImpl1 struct { A, B, C, D string }
type QMyInterfaceImpl2 struct { A, B, C string }
```
We could instead generate
```go
type QMyInterface interface { GetBase() QMyInterfaceBase; GetA() string; GetB() string; GetC() string }
type QMyInterfaceBase struct { A, B, C string }
type QMyInterfaceImpl1 struct { QMyInterfaceBase; D string }
type QMyInterfaceImpl2 struct { QMyInterfaceBase }
```
Then, for the same sorts of reasons you might want `struct: true`, you can use structs here too, if you just want the shared fields. A variant approach is to say that you put `a b c` on a fragment, and then we similarly add a `GetFragment()` method.
This isn't trivial to implement. It would be sort of nice in that it somewhat more cleanly guarantees that the shared fields match up between all the implementations. But it requires rejiggering all the existing types, and I feel it's adding extra indirection in a lot of places for the sake of a more special-purpose need. I'm a little hesitant to do that work, unless it's easy, since right now our main use case for forcing a struct is to avoid updating code that was designed around another GraphQL client. (Although it's also convenient for other reasons, like that Khan's caching library doesn't want to cache interfaces.)
A variant approach based on #106 is to have you write
```graphql
# @genqlient(struct: true)
fragment F on MyInterface { a b c }
query Q {
myInterface {
...F
... on Impl1 { d }
}
}
```
and then for each such fragment we add to `QMyInterface` a method `GetF() F`. That's probably easier to implement because we don't need to change existing types, although in some ways it's more of a special case. A nice benefit is that we can also, if `F` is on some concrete type (or smaller interface) generate `GetF() (*F, bool)`
Contributor guide
Research direction
Start by reviewing the existing interface and fragment generation paths, using the two approaches described in the issue and #106 as design context. Done means an agreed approach generates shared access for interface selections through the resulting Go types.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, graphql
- Domain
- devtools
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100