package codegen import ( "go/types" "strconv" "strings" "unicode" "github.com/99designs/gqlgen/codegen/config" "github.com/pkg/errors" "github.com/vektah/gqlparser/ast" ) type GoFieldType int const ( GoFieldUndefined GoFieldType = iota GoFieldMethod GoFieldVariable GoFieldMap ) type Object struct { *ast.Definition Type types.Type ResolverInterface types.Type Root bool Fields []*Field Implements []*ast.Definition DisableConcurrency bool Stream bool Directives []*Directive } func (b *builder) buildObject(typ *ast.Definition) (*Object, error) { dirs, err := b.getDirectives(typ.Directives) if err != nil { return nil, errors.Wrap(err, typ.Name) } obj := &Object{ Definition: typ, Root: b.Schema.Query == typ || b.Schema.Mutation == typ || b.Schema.Subscription == typ, DisableConcurrency: typ == b.Schema.Mutation, Stream: typ == b.Schema.Subscription, Directives: dirs, ResolverInterface: types.NewNamed( types.NewTypeName(0, b.Config.Exec.Pkg(), typ.Name+"Resolver", nil), nil, nil, ), } if !obj.Root { goObject, err := b.Binder.DefaultUserObject(typ.Name) if err != nil { return nil, err } obj.Type = goObject } for _, intf := range b.Schema.GetImplements(typ) { obj.Implements = append(obj.Implements, b.Schema.Types[intf.Name]) } for _, field := range typ.Fields { if strings.HasPrefix(field.Name, "__") { continue } var f *Field f, err = b.buildField(obj, field) if err != nil { return nil, err } obj.Fields = append(obj.Fields, f) } return obj, nil } func (o *Object) Reference() types.Type { switch o.Type.(type) { case *types.Pointer, *types.Slice, *types.Map: return o.Type } return types.NewPointer(o.Type) } type Objects []*Object func (o *Object) Implementors() string { satisfiedBy := strconv.Quote(o.Name) for _, s := range o.Implements { satisfiedBy += ", " + strconv.Quote(s.Name) } return "[]string{" + satisfiedBy + "}" } func (o *Object) HasResolvers() bool { for _, f := range o.Fields { if f.IsResolver { return true } } return false } func (o *Object) HasUnmarshal() bool { if o.Type == config.MapType { return true } for i := 0; i < o.Type.(*types.Named).NumMethods(); i++ { if o.Type.(*types.Named).Method(i).Name() == "UnmarshalGQL" { return true } } return false } func (o *Object) HasDirectives() bool { if len(o.Directives) > 0 { return true } for _, f := range o.Fields { if f.HasDirectives() { return true } } return false } func (o *Object) IsConcurrent() bool { for _, f := range o.Fields { if f.IsConcurrent() { return true } } return false } func (o *Object) IsReserved() bool { return strings.HasPrefix(o.Definition.Name, "__") } func (o *Object) Description() string { return o.Definition.Description } func (os Objects) ByName(name string) *Object { for i, o := range os { if strings.EqualFold(o.Definition.Name, name) { return os[i] } } return nil } func ucFirst(s string) string { if s == "" { return "" } r := []rune(s) r[0] = unicode.ToUpper(r[0]) return string(r) }