object.go

  1package codegen
  2
  3import (
  4	"go/types"
  5	"strconv"
  6	"strings"
  7	"unicode"
  8
  9	"github.com/99designs/gqlgen/codegen/config"
 10	"github.com/pkg/errors"
 11	"github.com/vektah/gqlparser/ast"
 12)
 13
 14type GoFieldType int
 15
 16const (
 17	GoFieldUndefined GoFieldType = iota
 18	GoFieldMethod
 19	GoFieldVariable
 20	GoFieldMap
 21)
 22
 23type Object struct {
 24	*ast.Definition
 25
 26	Type               types.Type
 27	ResolverInterface  types.Type
 28	Root               bool
 29	Fields             []*Field
 30	Implements         []*ast.Definition
 31	DisableConcurrency bool
 32	Stream             bool
 33	Directives         []*Directive
 34}
 35
 36func (b *builder) buildObject(typ *ast.Definition) (*Object, error) {
 37	dirs, err := b.getDirectives(typ.Directives)
 38	if err != nil {
 39		return nil, errors.Wrap(err, typ.Name)
 40	}
 41
 42	obj := &Object{
 43		Definition:         typ,
 44		Root:               b.Schema.Query == typ || b.Schema.Mutation == typ || b.Schema.Subscription == typ,
 45		DisableConcurrency: typ == b.Schema.Mutation,
 46		Stream:             typ == b.Schema.Subscription,
 47		Directives:         dirs,
 48		ResolverInterface: types.NewNamed(
 49			types.NewTypeName(0, b.Config.Exec.Pkg(), typ.Name+"Resolver", nil),
 50			nil,
 51			nil,
 52		),
 53	}
 54
 55	if !obj.Root {
 56		goObject, err := b.Binder.DefaultUserObject(typ.Name)
 57		if err != nil {
 58			return nil, err
 59		}
 60		obj.Type = goObject
 61	}
 62
 63	for _, intf := range b.Schema.GetImplements(typ) {
 64		obj.Implements = append(obj.Implements, b.Schema.Types[intf.Name])
 65	}
 66
 67	for _, field := range typ.Fields {
 68		if strings.HasPrefix(field.Name, "__") {
 69			continue
 70		}
 71
 72		var f *Field
 73		f, err = b.buildField(obj, field)
 74		if err != nil {
 75			return nil, err
 76		}
 77
 78		obj.Fields = append(obj.Fields, f)
 79	}
 80
 81	return obj, nil
 82}
 83
 84func (o *Object) Reference() types.Type {
 85	switch o.Type.(type) {
 86	case *types.Pointer, *types.Slice, *types.Map:
 87		return o.Type
 88	}
 89
 90	return types.NewPointer(o.Type)
 91}
 92
 93type Objects []*Object
 94
 95func (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
103func (o *Object) HasResolvers() bool {
104	for _, f := range o.Fields {
105		if f.IsResolver {
106			return true
107		}
108	}
109	return false
110}
111
112func (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
124func (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
137func (o *Object) IsConcurrent() bool {
138	for _, f := range o.Fields {
139		if f.IsConcurrent() {
140			return true
141		}
142	}
143	return false
144}
145
146func (o *Object) IsReserved() bool {
147	return strings.HasPrefix(o.Definition.Name, "__")
148}
149
150func (o *Object) Description() string {
151	return o.Definition.Description
152}
153
154func (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
163func 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}