input_build.go

 1package codegen
 2
 3import (
 4	"go/types"
 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) buildInputs(namedTypes NamedTypes, prog *loader.Program, imports *Imports) (Objects, error) {
14	var inputs Objects
15
16	for _, typ := range cfg.schema.Types {
17		switch typ := typ.(type) {
18		case *schema.InputObject:
19			input, err := buildInput(namedTypes, typ)
20			if err != nil {
21				return nil, err
22			}
23
24			def, err := findGoType(prog, input.Package, input.GoType)
25			if err != nil {
26				return nil, errors.Wrap(err, "cannot find type")
27			}
28			if def != nil {
29				input.Marshaler = buildInputMarshaler(typ, def)
30				bindErrs := bindObject(def.Type(), input, imports)
31				if len(bindErrs) > 0 {
32					return nil, bindErrs
33				}
34			}
35
36			inputs = append(inputs, input)
37		}
38	}
39
40	sort.Slice(inputs, func(i, j int) bool {
41		return strings.Compare(inputs[i].GQLType, inputs[j].GQLType) == -1
42	})
43
44	return inputs, nil
45}
46
47func buildInput(types NamedTypes, typ *schema.InputObject) (*Object, error) {
48	obj := &Object{NamedType: types[typ.TypeName()]}
49
50	for _, field := range typ.Values {
51		newField := Field{
52			GQLName: field.Name.Name,
53			Type:    types.getType(field.Type),
54			Object:  obj,
55		}
56
57		if field.Default != nil {
58			newField.Default = field.Default.Value(nil)
59		}
60
61		if !newField.Type.IsInput && !newField.Type.IsScalar {
62			return nil, errors.Errorf("%s cannot be used as a field of %s. only input and scalar types are allowed", newField.GQLType, obj.GQLType)
63		}
64
65		obj.Fields = append(obj.Fields, newField)
66
67	}
68	return obj, nil
69}
70
71// if user has implemented an UnmarshalGQL method on the input type manually, use it
72// otherwise we will generate one.
73func buildInputMarshaler(typ *schema.InputObject, def types.Object) *Ref {
74	switch def := def.(type) {
75	case *types.TypeName:
76		namedType := def.Type().(*types.Named)
77		for i := 0; i < namedType.NumMethods(); i++ {
78			method := namedType.Method(i)
79			if method.Name() == "UnmarshalGQL" {
80				return nil
81			}
82		}
83	}
84
85	return &Ref{GoType: typ.Name}
86}