github.com/galaxy-book/gqlgen@v0.7.2/codegen/input_build.go (about) 1 package codegen 2 3 import ( 4 "go/types" 5 "sort" 6 7 "github.com/pkg/errors" 8 "github.com/vektah/gqlparser/ast" 9 "golang.org/x/tools/go/loader" 10 ) 11 12 func (cfg *Config) buildInputs(namedTypes NamedTypes, prog *loader.Program) (Objects, error) { 13 var inputs Objects 14 15 for _, typ := range cfg.schema.Types { 16 switch typ.Kind { 17 case ast.InputObject: 18 input, err := cfg.buildInput(namedTypes, typ) 19 if err != nil { 20 return nil, err 21 } 22 23 def, err := findGoType(prog, input.Package, input.GoType) 24 if err != nil { 25 return nil, errors.Wrap(err, "cannot find type") 26 } 27 if def != nil { 28 input.Marshaler = buildInputMarshaler(typ, def) 29 bindErrs := bindObject(def.Type(), input, cfg.StructTag) 30 if len(bindErrs) > 0 { 31 return nil, bindErrs 32 } 33 } 34 35 inputs = append(inputs, input) 36 } 37 } 38 39 sort.Slice(inputs, func(i, j int) bool { 40 return inputs[i].GQLType < inputs[j].GQLType 41 }) 42 43 return inputs, nil 44 } 45 46 func (cfg *Config) buildInput(types NamedTypes, typ *ast.Definition) (*Object, error) { 47 obj := &Object{NamedType: types[typ.Name]} 48 typeEntry, entryExists := cfg.Models[typ.Name] 49 50 for _, field := range typ.Fields { 51 newField := Field{ 52 GQLName: field.Name, 53 Type: types.getType(field.Type), 54 Object: obj, 55 } 56 57 if entryExists { 58 if typeField, ok := typeEntry.Fields[field.Name]; ok { 59 newField.GoFieldName = typeField.FieldName 60 } 61 } 62 63 if field.DefaultValue != nil { 64 var err error 65 newField.Default, err = field.DefaultValue.Value(nil) 66 if err != nil { 67 return nil, errors.Errorf("default value for %s.%s is not valid: %s", typ.Name, field.Name, err.Error()) 68 } 69 } 70 71 if !newField.Type.IsInput && !newField.Type.IsScalar { 72 return nil, errors.Errorf("%s cannot be used as a field of %s. only input and scalar types are allowed", newField.GQLType, obj.GQLType) 73 } 74 75 obj.Fields = append(obj.Fields, newField) 76 77 } 78 return obj, nil 79 } 80 81 // if user has implemented an UnmarshalGQL method on the input type manually, use it 82 // otherwise we will generate one. 83 func buildInputMarshaler(typ *ast.Definition, def types.Object) *Ref { 84 switch def := def.(type) { 85 case *types.TypeName: 86 namedType := def.Type().(*types.Named) 87 for i := 0; i < namedType.NumMethods(); i++ { 88 method := namedType.Method(i) 89 if method.Name() == "UnmarshalGQL" { 90 return nil 91 } 92 } 93 } 94 95 return &Ref{GoType: typ.Name} 96 }