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