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  }