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