Add support for interfaces, part 3: automatically add __typename (#56)

## Summary:
In #52, I added support for interface types, but with the simplifying
restriction (among others) that the user must request the field
`__typename`.  In this commit, I remove this restriction.

The basic idea is simple: we preprocess the query to add `__typename`.
The implementation isn't much more complicated!  Although it required
some new wiring in a few places.

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

## Test plan:
make check


Author: benjaminjkraft

Reviewers: dnerdy, aberkan, MiguelCastillo

Required Reviewers: 

Approved by: dnerdy

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

Pull request URL: https://github.com/Khan/genqlient/pull/56
This commit is contained in:
Ben Kraft
2021-08-25 11:59:45 -07:00
committed by GitHub
parent 1e87553788
commit 65f9e90f2b
16 changed files with 189 additions and 62 deletions
+5 -13
View File
@@ -259,19 +259,6 @@ func (g *generator) convertDefinition(
return nil, errorf(pos, "not implemented: %v", def.Kind)
}
// We need to request __typename so we know which concrete type to use.
hasTypename := false
for _, selection := range selectionSet {
field, ok := selection.(*ast.Field)
if ok && field.Name == "__typename" {
hasTypename = true
}
}
if !hasTypename {
// TODO(benkraft): Instead, modify the query to add __typename.
return nil, errorf(pos, "union/interface type %s must request __typename", def.Name)
}
implementationTypes := g.schema.GetPossibleTypes(def)
goType := &goInterfaceType{
GoName: name,
@@ -283,6 +270,11 @@ func (g *generator) convertDefinition(
for i, implDef := range implementationTypes {
implName, implNamePrefix := g.typeName(namePrefix, implDef)
// TODO(benkraft): In principle we should skip generating a Go
// field for __typename each of these impl-defs if you didn't
// request it (and it was automatically added by
// preprocessQueryDocument). But in practice it doesn't really
// hurt, and would be extra work to avoid, so we just leave it.
implTyp, err := g.convertDefinition(
implName, implNamePrefix, implDef, pos, selectionSet, queryOptions)
if err != nil {