object_build.go

  1package codegen
  2
  3import (
  4	"log"
  5	"sort"
  6	"strings"
  7
  8	"github.com/pkg/errors"
  9	"github.com/vektah/gqlgen/neelance/schema"
 10	"golang.org/x/tools/go/loader"
 11)
 12
 13func (cfg *Config) buildObjects(types NamedTypes, prog *loader.Program, imports *Imports) (Objects, error) {
 14	var objects Objects
 15
 16	for _, typ := range cfg.schema.Types {
 17		switch typ := typ.(type) {
 18		case *schema.Object:
 19			obj, err := cfg.buildObject(types, typ)
 20			if err != nil {
 21				return nil, err
 22			}
 23
 24			def, err := findGoType(prog, obj.Package, obj.GoType)
 25			if err != nil {
 26				return nil, err
 27			}
 28			if def != nil {
 29				for _, bindErr := range bindObject(def.Type(), obj, imports) {
 30					log.Println(bindErr.Error())
 31					log.Println("  Adding resolver method")
 32				}
 33			}
 34
 35			objects = append(objects, obj)
 36		}
 37	}
 38
 39	sort.Slice(objects, func(i, j int) bool {
 40		return strings.Compare(objects[i].GQLType, objects[j].GQLType) == -1
 41	})
 42
 43	return objects, nil
 44}
 45
 46var keywords = []string{
 47	"break",
 48	"default",
 49	"func",
 50	"interface",
 51	"select",
 52	"case",
 53	"defer",
 54	"go",
 55	"map",
 56	"struct",
 57	"chan",
 58	"else",
 59	"goto",
 60	"package",
 61	"switch",
 62	"const",
 63	"fallthrough",
 64	"if",
 65	"range",
 66	"type",
 67	"continue",
 68	"for",
 69	"import",
 70	"return",
 71	"var",
 72}
 73
 74func sanitizeGoName(name string) string {
 75	for _, k := range keywords {
 76		if name == k {
 77			return name + "_"
 78		}
 79	}
 80	return name
 81}
 82
 83func (cfg *Config) buildObject(types NamedTypes, typ *schema.Object) (*Object, error) {
 84	obj := &Object{NamedType: types[typ.TypeName()]}
 85	typeEntry, entryExists := cfg.Models[typ.TypeName()]
 86
 87	for _, i := range typ.Interfaces {
 88		obj.Satisfies = append(obj.Satisfies, i.Name)
 89	}
 90
 91	for _, field := range typ.Fields {
 92
 93		var forceResolver bool
 94		if entryExists {
 95			if typeField, ok := typeEntry.Fields[field.Name]; ok {
 96				forceResolver = typeField.Resolver
 97			}
 98		}
 99
100		var args []FieldArgument
101		for _, arg := range field.Args {
102			newArg := FieldArgument{
103				GQLName:   arg.Name.Name,
104				Type:      types.getType(arg.Type),
105				Object:    obj,
106				GoVarName: sanitizeGoName(arg.Name.Name),
107			}
108
109			if !newArg.Type.IsInput && !newArg.Type.IsScalar {
110				return nil, errors.Errorf("%s cannot be used as argument of %s.%s. only input and scalar types are allowed", arg.Type, obj.GQLType, field.Name)
111			}
112
113			if arg.Default != nil {
114				newArg.Default = arg.Default.Value(nil)
115				newArg.StripPtr()
116			}
117			args = append(args, newArg)
118		}
119
120		obj.Fields = append(obj.Fields, Field{
121			GQLName:       field.Name,
122			Type:          types.getType(field.Type),
123			Args:          args,
124			Object:        obj,
125			ForceResolver: forceResolver,
126		})
127	}
128
129	for name, typ := range cfg.schema.EntryPoints {
130		schemaObj := typ.(*schema.Object)
131		if schemaObj.TypeName() != obj.GQLType {
132			continue
133		}
134
135		obj.Root = true
136		if name == "mutation" {
137			obj.DisableConcurrency = true
138		}
139		if name == "subscription" {
140			obj.Stream = true
141		}
142	}
143	return obj, nil
144}