...
1 package codegen
2
3 import (
4 "fmt"
5 "go/types"
6 "strconv"
7 "strings"
8 "unicode"
9
10 "github.com/vektah/gqlparser/v2/ast"
11 "golang.org/x/text/cases"
12 "golang.org/x/text/language"
13
14 "github.com/99designs/gqlgen/codegen/config"
15 )
16
17 type GoFieldType int
18
19 const (
20 GoFieldUndefined GoFieldType = iota
21 GoFieldMethod
22 GoFieldVariable
23 GoFieldMap
24 )
25
26 type Object struct {
27 *ast.Definition
28
29 Type types.Type
30 ResolverInterface types.Type
31 Root bool
32 Fields []*Field
33 Implements []*ast.Definition
34 DisableConcurrency bool
35 Stream bool
36 Directives []*Directive
37 PointersInUmarshalInput bool
38 }
39
40 func (b *builder) buildObject(typ *ast.Definition) (*Object, error) {
41 dirs, err := b.getDirectives(typ.Directives)
42 if err != nil {
43 return nil, fmt.Errorf("%s: %w", typ.Name, err)
44 }
45 caser := cases.Title(language.English, cases.NoLower)
46 obj := &Object{
47 Definition: typ,
48 Root: b.Config.IsRoot(typ),
49 DisableConcurrency: typ == b.Schema.Mutation,
50 Stream: typ == b.Schema.Subscription,
51 Directives: dirs,
52 PointersInUmarshalInput: b.Config.ReturnPointersInUmarshalInput,
53 ResolverInterface: types.NewNamed(
54 types.NewTypeName(0, b.Config.Exec.Pkg(), caser.String(typ.Name)+"Resolver", nil),
55 nil,
56 nil,
57 ),
58 }
59
60 if !obj.Root {
61 goObject, err := b.Binder.DefaultUserObject(typ.Name)
62 if err != nil {
63 return nil, err
64 }
65 obj.Type = goObject
66 }
67
68 for _, intf := range b.Schema.GetImplements(typ) {
69 obj.Implements = append(obj.Implements, b.Schema.Types[intf.Name])
70 }
71
72 for _, field := range typ.Fields {
73 if strings.HasPrefix(field.Name, "__") {
74 continue
75 }
76
77 var f *Field
78 f, err = b.buildField(obj, field)
79 if err != nil {
80 return nil, err
81 }
82
83 obj.Fields = append(obj.Fields, f)
84 }
85
86 return obj, nil
87 }
88
89 func (o *Object) Reference() types.Type {
90 if config.IsNilable(o.Type) {
91 return o.Type
92 }
93 return types.NewPointer(o.Type)
94 }
95
96 type Objects []*Object
97
98 func (o *Object) Implementors() string {
99 satisfiedBy := strconv.Quote(o.Name)
100 for _, s := range o.Implements {
101 satisfiedBy += ", " + strconv.Quote(s.Name)
102 }
103 return "[]string{" + satisfiedBy + "}"
104 }
105
106 func (o *Object) HasResolvers() bool {
107 for _, f := range o.Fields {
108 if f.IsResolver {
109 return true
110 }
111 }
112 return false
113 }
114
115 func (o *Object) HasUnmarshal() bool {
116 if o.IsMap() {
117 return false
118 }
119 for i := 0; i < o.Type.(*types.Named).NumMethods(); i++ {
120 if o.Type.(*types.Named).Method(i).Name() == "UnmarshalGQL" {
121 return true
122 }
123 }
124 return false
125 }
126
127 func (o *Object) HasDirectives() bool {
128 if len(o.Directives) > 0 {
129 return true
130 }
131 for _, f := range o.Fields {
132 if f.HasDirectives() {
133 return true
134 }
135 }
136
137 return false
138 }
139
140 func (o *Object) IsConcurrent() bool {
141 for _, f := range o.Fields {
142 if f.IsConcurrent() {
143 return true
144 }
145 }
146 return false
147 }
148
149 func (o *Object) IsReserved() bool {
150 return strings.HasPrefix(o.Definition.Name, "__")
151 }
152
153 func (o *Object) IsMap() bool {
154 return o.Type == config.MapType
155 }
156
157 func (o *Object) Description() string {
158 return o.Definition.Description
159 }
160
161 func (o *Object) HasField(name string) bool {
162 for _, f := range o.Fields {
163 if f.Name == name {
164 return true
165 }
166 }
167
168 return false
169 }
170
171 func (os Objects) ByName(name string) *Object {
172 for i, o := range os {
173 if strings.EqualFold(o.Definition.Name, name) {
174 return os[i]
175 }
176 }
177 return nil
178 }
179
180 func ucFirst(s string) string {
181 if s == "" {
182 return ""
183 }
184
185 r := []rune(s)
186 r[0] = unicode.ToUpper(r[0])
187 return string(r)
188 }
189
View as plain text