github.com/apipluspower/gqlgen@v0.15.2/codegen/interface.go (about) 1 package codegen 2 3 import ( 4 "fmt" 5 "go/types" 6 7 "github.com/vektah/gqlparser/v2/ast" 8 9 "github.com/apipluspower/gqlgen/codegen/config" 10 ) 11 12 type Interface struct { 13 *ast.Definition 14 Type types.Type 15 Implementors []InterfaceImplementor 16 InTypemap bool 17 } 18 19 type InterfaceImplementor struct { 20 *ast.Definition 21 22 Type types.Type 23 TakeRef bool 24 } 25 26 func (b *builder) buildInterface(typ *ast.Definition) (*Interface, error) { 27 obj, err := b.Binder.DefaultUserObject(typ.Name) 28 if err != nil { 29 panic(err) 30 } 31 32 i := &Interface{ 33 Definition: typ, 34 Type: obj, 35 InTypemap: b.Config.Models.UserDefined(typ.Name), 36 } 37 38 interfaceType, err := findGoInterface(i.Type) 39 if interfaceType == nil || err != nil { 40 return nil, fmt.Errorf("%s is not an interface", i.Type) 41 } 42 43 for _, implementor := range b.Schema.GetPossibleTypes(typ) { 44 obj, err := b.Binder.DefaultUserObject(implementor.Name) 45 if err != nil { 46 return nil, fmt.Errorf("%s has no backing go type", implementor.Name) 47 } 48 49 implementorType, err := findGoNamedType(obj) 50 if err != nil { 51 return nil, fmt.Errorf("can not find backing go type %s: %w", obj.String(), err) 52 } else if implementorType == nil { 53 return nil, fmt.Errorf("can not find backing go type %s", obj.String()) 54 } 55 56 anyValid := false 57 58 // first check if the value receiver can be nil, eg can we type switch on case Thing: 59 if types.Implements(implementorType, interfaceType) { 60 i.Implementors = append(i.Implementors, InterfaceImplementor{ 61 Definition: implementor, 62 Type: obj, 63 TakeRef: !types.IsInterface(obj), 64 }) 65 anyValid = true 66 } 67 68 // then check if the pointer receiver can be nil, eg can we type switch on case *Thing: 69 if types.Implements(types.NewPointer(implementorType), interfaceType) { 70 i.Implementors = append(i.Implementors, InterfaceImplementor{ 71 Definition: implementor, 72 Type: types.NewPointer(obj), 73 }) 74 anyValid = true 75 } 76 77 if !anyValid { 78 return nil, fmt.Errorf("%s does not satisfy the interface %s", implementorType.String(), i.Type.String()) 79 } 80 } 81 82 return i, nil 83 } 84 85 func (i *InterfaceImplementor) CanBeNil() bool { 86 return config.IsNilable(i.Type) 87 }