github.com/matiasanaya/gqlgen@v0.6.0/codegen/object_build.go (about) 1 package codegen 2 3 import ( 4 "log" 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) buildObjects(types NamedTypes, prog *loader.Program, imports *Imports) (Objects, error) { 13 var objects Objects 14 15 for _, typ := range cfg.schema.Types { 16 if typ.Kind != ast.Object { 17 continue 18 } 19 20 obj, err := cfg.buildObject(types, typ, imports) 21 if err != nil { 22 return nil, err 23 } 24 25 def, err := findGoType(prog, obj.Package, obj.GoType) 26 if err != nil { 27 return nil, err 28 } 29 if def != nil { 30 for _, bindErr := range bindObject(def.Type(), obj, imports, cfg.StructTag) { 31 log.Println(bindErr.Error()) 32 log.Println(" Adding resolver method") 33 } 34 } 35 36 objects = append(objects, obj) 37 } 38 39 sort.Slice(objects, func(i, j int) bool { 40 return objects[i].GQLType < objects[j].GQLType 41 }) 42 43 return objects, nil 44 } 45 46 var 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 74 // sanitizeArgName prevents collisions with go keywords for arguments to resolver functions 75 func sanitizeArgName(name string) string { 76 for _, k := range keywords { 77 if name == k { 78 return name + "Arg" 79 } 80 } 81 return name 82 } 83 84 func (cfg *Config) buildObject(types NamedTypes, typ *ast.Definition, imports *Imports) (*Object, error) { 85 obj := &Object{NamedType: types[typ.Name]} 86 typeEntry, entryExists := cfg.Models[typ.Name] 87 88 imp := imports.findByPath(cfg.Exec.ImportPath()) 89 obj.ResolverInterface = &Ref{GoType: obj.GQLType + "Resolver", Import: imp} 90 91 if typ == cfg.schema.Query { 92 obj.Root = true 93 } 94 95 if typ == cfg.schema.Mutation { 96 obj.Root = true 97 obj.DisableConcurrency = true 98 } 99 100 if typ == cfg.schema.Subscription { 101 obj.Root = true 102 obj.Stream = true 103 } 104 105 obj.Satisfies = append(obj.Satisfies, typ.Interfaces...) 106 107 for _, intf := range cfg.schema.GetImplements(typ) { 108 obj.Implements = append(obj.Implements, types[intf.Name]) 109 } 110 111 for _, field := range typ.Fields { 112 if typ == cfg.schema.Query && field.Name == "__type" { 113 obj.Fields = append(obj.Fields, Field{ 114 Type: &Type{types["__Schema"], []string{modPtr}, ast.NamedType("__Schema", nil), nil}, 115 GQLName: "__schema", 116 NoErr: true, 117 GoFieldType: GoFieldMethod, 118 GoReceiverName: "ec", 119 GoFieldName: "introspectSchema", 120 Object: obj, 121 Description: field.Description, 122 }) 123 continue 124 } 125 if typ == cfg.schema.Query && field.Name == "__schema" { 126 obj.Fields = append(obj.Fields, Field{ 127 Type: &Type{types["__Type"], []string{modPtr}, ast.NamedType("__Schema", nil), nil}, 128 GQLName: "__type", 129 NoErr: true, 130 GoFieldType: GoFieldMethod, 131 GoReceiverName: "ec", 132 GoFieldName: "introspectType", 133 Args: []FieldArgument{ 134 {GQLName: "name", Type: &Type{types["String"], []string{}, ast.NamedType("String", nil), nil}, Object: &Object{}}, 135 }, 136 Object: obj, 137 }) 138 continue 139 } 140 141 var forceResolver bool 142 var goName string 143 if entryExists { 144 if typeField, ok := typeEntry.Fields[field.Name]; ok { 145 goName = typeField.FieldName 146 forceResolver = typeField.Resolver 147 } 148 } 149 150 var args []FieldArgument 151 for _, arg := range field.Arguments { 152 newArg := FieldArgument{ 153 GQLName: arg.Name, 154 Type: types.getType(arg.Type), 155 Object: obj, 156 GoVarName: sanitizeArgName(arg.Name), 157 } 158 159 if !newArg.Type.IsInput && !newArg.Type.IsScalar { 160 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) 161 } 162 163 if arg.DefaultValue != nil { 164 var err error 165 newArg.Default, err = arg.DefaultValue.Value(nil) 166 if err != nil { 167 return nil, errors.Errorf("default value for %s.%s is not valid: %s", typ.Name, field.Name, err.Error()) 168 } 169 } 170 args = append(args, newArg) 171 } 172 173 obj.Fields = append(obj.Fields, Field{ 174 GQLName: field.Name, 175 Type: types.getType(field.Type), 176 Args: args, 177 Object: obj, 178 GoFieldName: goName, 179 ForceResolver: forceResolver, 180 }) 181 } 182 183 return obj, nil 184 }