genqlient
genqlient copied to clipboard
Add a way to get a shared struct from an interface
Suppose you have
query Q {
myInterface {
a b c
... on Impl1 { d }
}
}
Right now we generate (roughly)
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
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
# @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)