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