1package codegen
2
3import (
4 "fmt"
5 "go/types"
6 "os"
7 "sort"
8
9 "github.com/vektah/gqlparser/ast"
10 "golang.org/x/tools/go/loader"
11)
12
13func (cfg *Config) buildInterfaces(types NamedTypes, prog *loader.Program) []*Interface {
14 var interfaces []*Interface
15 for _, typ := range cfg.schema.Types {
16 if typ.Kind == ast.Union || typ.Kind == ast.Interface {
17 interfaces = append(interfaces, cfg.buildInterface(types, typ, prog))
18 }
19 }
20
21 sort.Slice(interfaces, func(i, j int) bool {
22 return interfaces[i].GQLType < interfaces[j].GQLType
23 })
24
25 return interfaces
26}
27
28func (cfg *Config) buildInterface(types NamedTypes, typ *ast.Definition, prog *loader.Program) *Interface {
29 i := &Interface{NamedType: types[typ.Name]}
30
31 for _, implementor := range cfg.schema.GetPossibleTypes(typ) {
32 t := types[implementor.Name]
33
34 i.Implementors = append(i.Implementors, InterfaceImplementor{
35 NamedType: t,
36 ValueReceiver: cfg.isValueReceiver(types[typ.Name], t, prog),
37 })
38 }
39
40 return i
41}
42
43func (cfg *Config) isValueReceiver(intf *NamedType, implementor *NamedType, prog *loader.Program) bool {
44 interfaceType, err := findGoInterface(prog, intf.Package, intf.GoType)
45 if interfaceType == nil || err != nil {
46 return true
47 }
48
49 implementorType, err := findGoNamedType(prog, implementor.Package, implementor.GoType)
50 if implementorType == nil || err != nil {
51 return true
52 }
53
54 for i := 0; i < interfaceType.NumMethods(); i++ {
55 intfMethod := interfaceType.Method(i)
56
57 implMethod := findMethod(implementorType, intfMethod.Name())
58 if implMethod == nil {
59 fmt.Fprintf(os.Stderr, "missing method %s on %s\n", intfMethod.Name(), implementor.GoType)
60 return false
61 }
62
63 sig := implMethod.Type().(*types.Signature)
64 if _, isPtr := sig.Recv().Type().(*types.Pointer); isPtr {
65 return false
66 }
67 }
68
69 return true
70}