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		switch o.Type.(*types.Named).Method(i).Name() {
118		case "UnmarshalGQL":
119			return true
120		}
121	}
122	return false
123}
124
125func (o *Object) HasDirectives() bool {
126	if len(o.Directives) > 0 {
127		return true
128	}
129	for _, f := range o.Fields {
130		if f.HasDirectives() {
131			return true
132		}
133	}
134
135	return false
136}
137
138func (o *Object) IsConcurrent() bool {
139	for _, f := range o.Fields {
140		if f.IsConcurrent() {
141			return true
142		}
143	}
144	return false
145}
146
147func (o *Object) IsReserved() bool {
148	return strings.HasPrefix(o.Definition.Name, "__")
149}
150
151func (o *Object) Description() string {
152	return o.Definition.Description
153}
154
155func (os Objects) ByName(name string) *Object {
156	for i, o := range os {
157		if strings.EqualFold(o.Definition.Name, name) {
158			return os[i]
159		}
160	}
161	return nil
162}
163
164func ucFirst(s string) string {
165	if s == "" {
166		return ""
167	}
168
169	r := []rune(s)
170	r[0] = unicode.ToUpper(r[0])
171	return string(r)
172}