1package codegen
2
3import (
4 "log"
5 "sort"
6 "strings"
7
8 "github.com/pkg/errors"
9 "github.com/vektah/gqlgen/neelance/schema"
10 "golang.org/x/tools/go/loader"
11)
12
13func (cfg *Config) buildObjects(types NamedTypes, prog *loader.Program, imports *Imports) (Objects, error) {
14 var objects Objects
15
16 for _, typ := range cfg.schema.Types {
17 switch typ := typ.(type) {
18 case *schema.Object:
19 obj, err := cfg.buildObject(types, typ)
20 if err != nil {
21 return nil, err
22 }
23
24 def, err := findGoType(prog, obj.Package, obj.GoType)
25 if err != nil {
26 return nil, err
27 }
28 if def != nil {
29 for _, bindErr := range bindObject(def.Type(), obj, imports) {
30 log.Println(bindErr.Error())
31 log.Println(" Adding resolver method")
32 }
33 }
34
35 objects = append(objects, obj)
36 }
37 }
38
39 sort.Slice(objects, func(i, j int) bool {
40 return strings.Compare(objects[i].GQLType, objects[j].GQLType) == -1
41 })
42
43 return objects, nil
44}
45
46var keywords = []string{
47 "break",
48 "default",
49 "func",
50 "interface",
51 "select",
52 "case",
53 "defer",
54 "go",
55 "map",
56 "struct",
57 "chan",
58 "else",
59 "goto",
60 "package",
61 "switch",
62 "const",
63 "fallthrough",
64 "if",
65 "range",
66 "type",
67 "continue",
68 "for",
69 "import",
70 "return",
71 "var",
72}
73
74func sanitizeGoName(name string) string {
75 for _, k := range keywords {
76 if name == k {
77 return name + "_"
78 }
79 }
80 return name
81}
82
83func (cfg *Config) buildObject(types NamedTypes, typ *schema.Object) (*Object, error) {
84 obj := &Object{NamedType: types[typ.TypeName()]}
85 typeEntry, entryExists := cfg.Models[typ.TypeName()]
86
87 for _, i := range typ.Interfaces {
88 obj.Satisfies = append(obj.Satisfies, i.Name)
89 }
90
91 for _, field := range typ.Fields {
92
93 var forceResolver bool
94 if entryExists {
95 if typeField, ok := typeEntry.Fields[field.Name]; ok {
96 forceResolver = typeField.Resolver
97 }
98 }
99
100 var args []FieldArgument
101 for _, arg := range field.Args {
102 newArg := FieldArgument{
103 GQLName: arg.Name.Name,
104 Type: types.getType(arg.Type),
105 Object: obj,
106 GoVarName: sanitizeGoName(arg.Name.Name),
107 }
108
109 if !newArg.Type.IsInput && !newArg.Type.IsScalar {
110 return nil, errors.Errorf("%s cannot be used as argument of %s.%s. only input and scalar types are allowed", arg.Type, obj.GQLType, field.Name)
111 }
112
113 if arg.Default != nil {
114 newArg.Default = arg.Default.Value(nil)
115 newArg.StripPtr()
116 }
117 args = append(args, newArg)
118 }
119
120 obj.Fields = append(obj.Fields, Field{
121 GQLName: field.Name,
122 Type: types.getType(field.Type),
123 Args: args,
124 Object: obj,
125 ForceResolver: forceResolver,
126 })
127 }
128
129 for name, typ := range cfg.schema.EntryPoints {
130 schemaObj := typ.(*schema.Object)
131 if schemaObj.TypeName() != obj.GQLType {
132 continue
133 }
134
135 obj.Root = true
136 if name == "mutation" {
137 obj.DisableConcurrency = true
138 }
139 if name == "subscription" {
140 obj.Stream = true
141 }
142 }
143 return obj, nil
144}