├── .gitignore ├── .travis.yml ├── Makefile ├── README.md ├── cmd ├── generate.go ├── root.go ├── version.go └── version_gen.go ├── codegen ├── codegen.go ├── codegen_test.go ├── fixtures │ ├── basic │ │ ├── config.hcl │ │ ├── pageinfo_gen.go │ │ └── schema.graphql │ ├── custom_field_types │ │ ├── barfoo_gen.go │ │ ├── config.hcl │ │ ├── foobar_gen.go │ │ └── schema.graphql │ ├── httpget │ │ ├── config.hcl │ │ ├── conversation_gen.go │ │ ├── coversation.go │ │ ├── http_test.go │ │ ├── message_gen.go │ │ ├── query_gen.go │ │ ├── resolver_gen.go │ │ ├── schema.graphql │ │ └── user_gen.go │ ├── list_of_lists │ │ ├── config.hcl │ │ ├── listtype_gen.go │ │ └── schema.graphql │ └── starwars │ │ ├── character_gen.go │ │ ├── config.hcl │ │ ├── droid_gen.go │ │ ├── episode_gen.go │ │ ├── friendsconnection_gen.go │ │ ├── friendsedge_gen.go │ │ ├── human_gen.go │ │ ├── lengthunit_gen.go │ │ ├── mutation_gen.go │ │ ├── pageinfo_gen.go │ │ ├── query_gen.go │ │ ├── resolver_gen.go │ │ ├── review_gen.go │ │ ├── reviewinput_gen.go │ │ ├── schema.graphql │ │ ├── searchresult_gen.go │ │ └── starship_gen.go ├── formatcode.go └── testhelpers.go ├── config ├── config.go ├── parse.go └── parse_test.go ├── main.go └── template ├── assets.go ├── field.go ├── property ├── custom │ ├── config.hcl │ ├── field.tmpl │ └── method.tmpl ├── default │ ├── config.hcl │ ├── field.tmpl │ └── method.tmpl └── http_resolver │ ├── config.hcl │ ├── field.tmpl │ └── method.tmpl ├── type.go └── type └── default ├── config.hcl └── type.tmpl /.gitignore: -------------------------------------------------------------------------------- 1 | test_output/ 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - tip 4 | install: 5 | - make setup 6 | - make generate 7 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | setup: 3 | go get -u github.com/jteeuwen/go-bindata/... 4 | .PHONY: setup 5 | 6 | generate: 7 | go generate github.com/Applifier/graphql-codegen/template 8 | .PHONY: generate 9 | 10 | test: generate 11 | go test ./... 12 | .PHONY: test 13 | 14 | record: generate 15 | RECORD_FIXTURES=yes go test ./... 16 | .PHONY: record 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.com/Applifier/graphql-codegen.svg?token=jeWt6weUpeDp6aNSSaST&branch=master)](https://travis-ci.com/Applifier/graphql-codegen) 2 | 3 | # graphql-codegen 4 | 5 | This tool generates boilerplate code for [graphql-go](https://github.com/neelance/graphql-go) based on a provided graphql.schema file. Additional config file can be provided to customize output. 6 | 7 | ```sh 8 | go install github.com/Applifier/graphql-codegen 9 | ``` 10 | 11 | ## TODO 12 | - [ ] Allow custom templates (without rebuilding) 13 | 14 | ## example 15 | 16 | Example below generates code for [schema.graphql](https://github.com/Applifier/graphql-codegen/blob/master/codegen/fixtures/httpget/schema.graphql). Optional config [config.hcl](https://github.com/Applifier/graphql-codegen/blob/master/codegen/fixtures/httpget/config.hcl) file is provided to tell the codegen where and how to fetch the data for the resolvers. 17 | 18 | ```sh 19 | graphql-codegen generate -s=codegen/fixtures/httpget/schema.graphql -c=codegen/fixtures/httpget/config.hcl -p=httpget -o=test_output/ 20 | ``` 21 | 22 | Example of the generated code (_gen.go files) can be found under [/codegen/fixtures/httpget](https://github.com/Applifier/graphql-codegen/tree/master/codegen/fixtures/httpget) 23 | 24 | - More examples under [codegen/fixtures](https://github.com/Applifier/graphql-codegen/tree/master/codegen/fixtures) 25 | 26 | ## templates 27 | 28 | ### default 29 | Resolve field based on a struct property with the same name as the schema type field 30 | 31 | ### custom 32 | Skips code generation for the field 33 | 34 | Check example [config](https://github.com/Applifier/graphql-codegen/blob/master/codegen/fixtures/httpget/config.hcl#L35) and [conversation.go](https://github.com/Applifier/graphql-codegen/blob/master/codegen/fixtures/httpget/coversation.go#L12) 35 | 36 | ### http_resolver 37 | Resolve field with a http GET request to a server 38 | ```hcl 39 | type "Query" { 40 | field "user" { 41 | imports = ["\"fmt\""] 42 | template "http_resolver" { 43 | url = "fmt.Sprintf(\"https://static.everyplay.com/developer-quiz/data/users/%s\", args.ID)" 44 | } 45 | } 46 | } 47 | ``` 48 | -------------------------------------------------------------------------------- /cmd/generate.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "io/ioutil" 5 | "path" 6 | 7 | "github.com/Applifier/graphql-codegen/codegen" 8 | "github.com/Applifier/graphql-codegen/config" 9 | "github.com/spf13/cobra" 10 | ) 11 | 12 | func init() { 13 | var schemaFile string 14 | var configFile string 15 | var packageName string 16 | var outputDir string 17 | 18 | var generateCmd = &cobra.Command{ 19 | Use: "generate", 20 | Short: "Generate go code for a graphql schema", 21 | Long: "Generate go code for a graphql schema", 22 | Run: func(cmd *cobra.Command, args []string) { 23 | var conf config.Config 24 | conf.Package = packageName 25 | 26 | if configFile != "" { 27 | fileBytes, err := ioutil.ReadFile(configFile) 28 | if err != nil { 29 | panic(err) 30 | } 31 | conf, err = config.Parse(string(fileBytes)) 32 | if err != nil { 33 | panic(err) 34 | } 35 | } 36 | 37 | schemaBytes, err := ioutil.ReadFile(schemaFile) 38 | if err != nil { 39 | panic(err) 40 | } 41 | 42 | cg := codegen.NewCodeGen(string(schemaBytes), conf) 43 | fileMap, err := cg.Generate() 44 | if err != nil { 45 | panic(err) 46 | } 47 | 48 | for filename, fileContent := range fileMap { 49 | err := ioutil.WriteFile(path.Join(outputDir, filename), []byte(fileContent), 0644) 50 | if err != nil { 51 | panic(err) 52 | } 53 | } 54 | }, 55 | } 56 | 57 | RootCmd.AddCommand(generateCmd) 58 | 59 | // Here you will define your flags and configuration settings. 60 | 61 | // Cobra supports Persistent Flags which will work for this command 62 | // and all subcommands, e.g.: 63 | generateCmd.PersistentFlags().StringVarP(&schemaFile, "schema", "s", "graphql.schema", "graphql.schema file") 64 | generateCmd.PersistentFlags().StringVarP(&configFile, "config", "c", "", "Optional configuration file. Default options are used if path is not defined") 65 | generateCmd.PersistentFlags().StringVarP(&packageName, "package", "p", "main", "Package name for generated files") 66 | generateCmd.PersistentFlags().StringVarP(&outputDir, "output", "o", ".", "Output directory. Defaults to current working directory") 67 | 68 | // Cobra supports local flags which will only run when this command 69 | // is called directly, e.g.: 70 | // generateCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") 71 | 72 | } 73 | -------------------------------------------------------------------------------- /cmd/root.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/spf13/cobra" 8 | "github.com/spf13/viper" 9 | ) 10 | 11 | var cfgFile string 12 | 13 | // RootCmd represents the base command when called without any subcommands 14 | var RootCmd = &cobra.Command{ 15 | Use: "graphql-codegen", 16 | Short: "A brief description of your application", 17 | Long: `A longer description that spans multiple lines and likely contains 18 | examples and usage of using your application. For example: 19 | 20 | Cobra is a CLI library for Go that empowers applications. 21 | This application is a tool to generate the needed files 22 | to quickly create a Cobra application.`, 23 | // Uncomment the following line if your bare application 24 | // has an action associated with it: 25 | // Run: func(cmd *cobra.Command, args []string) { }, 26 | } 27 | 28 | // Execute adds all child commands to the root command sets flags appropriately. 29 | // This is called by main.main(). It only needs to happen once to the rootCmd. 30 | func Execute() { 31 | if err := RootCmd.Execute(); err != nil { 32 | fmt.Println(err) 33 | os.Exit(-1) 34 | } 35 | } 36 | 37 | func init() { 38 | cobra.OnInitialize(initConfig) 39 | 40 | // Here you will define your flags and configuration settings. 41 | // Cobra supports Persistent Flags, which, if defined here, 42 | // will be global for your application. 43 | 44 | RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.graphql-codegen.yaml)") 45 | // Cobra also supports local flags, which will only run 46 | // when this action is called directly. 47 | RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") 48 | } 49 | 50 | // initConfig reads in config file and ENV variables if set. 51 | func initConfig() { 52 | if cfgFile != "" { // enable ability to specify config file via flag 53 | viper.SetConfigFile(cfgFile) 54 | } 55 | 56 | viper.SetConfigName(".graphql-codegen") // name of config file (without extension) 57 | viper.AddConfigPath("$HOME") // adding home directory as first search path 58 | viper.AutomaticEnv() // read in environment variables that match 59 | 60 | // If a config file is found, read it in. 61 | if err := viper.ReadInConfig(); err == nil { 62 | fmt.Println("Using config file:", viper.ConfigFileUsed()) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /cmd/version.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/spf13/cobra" 7 | ) 8 | 9 | // versionCmd represents the version command 10 | var versionCmd = &cobra.Command{ 11 | Use: "version", 12 | Short: "graphql-codegen version", 13 | Long: `graphql-codegen version`, 14 | Run: func(cmd *cobra.Command, args []string) { 15 | fmt.Println(VERSION) 16 | }, 17 | } 18 | 19 | func init() { 20 | RootCmd.AddCommand(versionCmd) 21 | } 22 | -------------------------------------------------------------------------------- /cmd/version_gen.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | const VERSION = "1.0.0" 4 | -------------------------------------------------------------------------------- /codegen/codegen.go: -------------------------------------------------------------------------------- 1 | package codegen 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "log" 7 | "strings" 8 | "text/template" 9 | 10 | "github.com/Applifier/graphql-codegen/config" 11 | codegenTemplate "github.com/Applifier/graphql-codegen/template" 12 | graphql "github.com/neelance/graphql-go" 13 | "github.com/neelance/graphql-go/introspection" 14 | ) 15 | 16 | type typeConfig struct { 17 | ignore bool 18 | goType string 19 | importPath string 20 | } 21 | 22 | var ( 23 | internalTypeConfig = map[string]typeConfig{ 24 | "SCALAR": typeConfig{ 25 | true, 26 | "", 27 | "", 28 | }, 29 | "Boolean": typeConfig{ 30 | true, 31 | "bool", 32 | "", 33 | }, 34 | "Float": typeConfig{ 35 | true, 36 | "float64", 37 | "", 38 | }, 39 | "Int": typeConfig{ 40 | true, 41 | "int32", 42 | "", 43 | }, 44 | "ID": typeConfig{ 45 | true, 46 | "graphql.ID", 47 | "graphql \"github.com/neelance/graphql-go\"", 48 | }, 49 | "String": typeConfig{ 50 | true, 51 | "string", 52 | "", 53 | }, 54 | } 55 | ) 56 | 57 | type CodeGen struct { 58 | graphSchema string 59 | conf config.Config 60 | mutationName string 61 | queryName string 62 | } 63 | 64 | func NewCodeGen(graphSchema string, conf config.Config) *CodeGen { 65 | return &CodeGen{graphSchema, conf, "", ""} 66 | } 67 | 68 | func (g *CodeGen) Generate() (map[string]string, error) { 69 | graphSchema := g.graphSchema 70 | conf := g.conf 71 | 72 | sch, err := graphql.ParseSchema(graphSchema, nil) 73 | if err != nil { 74 | return nil, err 75 | } 76 | 77 | ins := sch.Inspect() 78 | 79 | if ins.MutationType() != nil { 80 | g.mutationName = g.returnString(ins.MutationType().Name()) 81 | } 82 | 83 | if ins.QueryType() != nil { 84 | g.queryName = g.returnString(ins.QueryType().Name()) 85 | } 86 | 87 | results := map[string]string{} 88 | 89 | var entryPoint = false 90 | 91 | for _, qlType := range ins.Types() { 92 | name := *qlType.Name() 93 | if strings.HasPrefix(name, "_") { 94 | continue 95 | } 96 | 97 | if internalTypeConfig[name].ignore { 98 | continue 99 | } 100 | 101 | if g.isEntryPoint(name) { 102 | entryPoint = true 103 | } 104 | 105 | fileName := fmt.Sprintf("%s_gen.go", strings.ToLower(name)) 106 | 107 | log.Printf("Generating Go code for %s %s", qlType.Kind(), name) 108 | 109 | var code string 110 | code, err = g.generateType(qlType, conf) 111 | if err != nil { 112 | return nil, err 113 | } 114 | 115 | results[fileName] = code 116 | } 117 | 118 | // Generate entry point 119 | if entryPoint { 120 | entry, err := g.generateEntryPoint(conf) 121 | if err != nil { 122 | return nil, err 123 | } 124 | results["resolver_gen.go"] = entry 125 | } 126 | 127 | return results, nil 128 | } 129 | 130 | func (g *CodeGen) returnString(strPtr *string) string { 131 | if strPtr != nil { 132 | return *strPtr 133 | } 134 | return "" 135 | } 136 | 137 | func (g *CodeGen) generateEntryPoint(conf config.Config) (string, error) { 138 | // TODO figure out if this needs to be configurable 139 | typeTemplate, err := codegenTemplate.GetTypeTemplate("default") 140 | if err != nil { 141 | return "", err 142 | } 143 | 144 | tmpl, err := template.New("default").Funcs(g.templateFuncMap()).Parse(strings.Trim(typeTemplate.TypeTemplate, " \t")) 145 | if err != nil { 146 | return "", err 147 | } 148 | 149 | buf := &bytes.Buffer{} 150 | tmpl.Execute(buf, map[string]interface{}{ 151 | "Kind": "RESOLVER", 152 | "TypeName": "Resolver", 153 | "TypeDescription": "Resolver is the main resolver for all queries", 154 | "Config": conf, 155 | }) 156 | 157 | b, err := FormatCode(string(buf.Bytes())) 158 | return string(b), err 159 | } 160 | 161 | func (g *CodeGen) generateType(tp *introspection.Type, conf config.Config) (code string, err error) { 162 | name := *tp.Name() 163 | typeConf := conf.Type[name] 164 | 165 | buf := &bytes.Buffer{} 166 | 167 | if len(typeConf.Template) == 0 { 168 | typeConf.Template = map[string]map[string]interface{}{} 169 | typeConf.Template["default"] = map[string]interface{}{} 170 | } 171 | 172 | for templateName, templateConfig := range typeConf.Template { 173 | typeTemplate, err := codegenTemplate.GetTypeTemplate(templateName) 174 | if err != nil { 175 | return "", err 176 | } 177 | 178 | tmpl, err := template.New(templateName).Funcs(g.templateFuncMap()).Parse(strings.Trim(typeTemplate.TypeTemplate, " \t")) 179 | if err != nil { 180 | return "", err 181 | } 182 | 183 | // Move this to a util func (g *CodeGen) 184 | var ifields []*introspection.Field 185 | if tp.Fields(&struct{ IncludeDeprecated bool }{true}) != nil { 186 | ifields = *tp.Fields(&struct{ IncludeDeprecated bool }{true}) 187 | } 188 | 189 | fields := make([]string, len(ifields)) 190 | methods := make([]string, len(ifields)) 191 | imports := []string{} 192 | for i, fp := range ifields { 193 | fieldCode, methodCode, fieldImports, err := g.generateField(fp, tp, typeConf, conf) 194 | if err != nil { 195 | return "", err 196 | } 197 | fields[i] = fieldCode 198 | methods[i] = methodCode 199 | 200 | imports = append(imports, fieldImports...) 201 | } 202 | 203 | var inputFields []string 204 | if tp.InputFields() != nil { 205 | for _, ip := range *tp.InputFields() { 206 | inputField, inputFieldImports, err := g.generateInputValue(ip, tp, typeConf, conf) 207 | if err != nil { 208 | return "", err 209 | } 210 | imports = append(imports, inputFieldImports...) 211 | inputFields = append(inputFields, inputField) 212 | } 213 | } 214 | 215 | possibleTypes := []string{} 216 | 217 | if tp.PossibleTypes() != nil { 218 | for _, tp := range *tp.PossibleTypes() { 219 | possibleTypes = append(possibleTypes, *tp.Name()) 220 | } 221 | } 222 | 223 | enumValues := []string{} 224 | if tp.EnumValues(&struct{ IncludeDeprecated bool }{true}) != nil { 225 | for _, value := range *tp.EnumValues(&struct{ IncludeDeprecated bool }{true}) { 226 | enumValues = append(enumValues, value.Name()) 227 | } 228 | } 229 | 230 | imports = append(imports, typeTemplate.Config.Imports...) 231 | if val, ok := templateConfig["imports"]; ok { 232 | if arr, ok := val.([]string); ok { 233 | imports = append(imports, arr...) 234 | } 235 | } 236 | 237 | imports = append(imports, typeConf.Imports...) 238 | 239 | tmpl.Execute(buf, map[string]interface{}{ 240 | "Kind": tp.Kind(), 241 | "PossibleTypes": possibleTypes, 242 | "EnumValues": enumValues, 243 | "TypeName": name, 244 | "TypeDescription": g.removeLineBreaks(g.returnString(tp.Description())), 245 | "Config": conf, 246 | "Fields": fields, 247 | "InputFields": inputFields, 248 | "Methods": methods, 249 | "Imports": g.removeDuplicates(imports), 250 | "TemplateConfig": templateConfig, 251 | }) 252 | } 253 | //println(string(buf.Bytes())) 254 | b, err := FormatCode(string(buf.Bytes())) 255 | return string(b), err 256 | } 257 | 258 | func (g *CodeGen) generateInputValue(ip *introspection.InputValue, tp *introspection.Type, typeConf config.TypeConfig, conf config.Config) (string, []string, error) { 259 | name := ip.Name() 260 | propConf := typeConf.Field[name] 261 | fieldCode := &bytes.Buffer{} 262 | imports := []string{} 263 | 264 | if len(propConf.Template) == 0 { 265 | propConf.Template = map[string]map[string]interface{}{} 266 | propConf.Template["default"] = map[string]interface{}{} 267 | } 268 | 269 | for templateName, templateConfig := range propConf.Template { 270 | propTemplate, err := codegenTemplate.GetPropertyTemplate(templateName) 271 | if err != nil { 272 | return "", nil, err 273 | } 274 | 275 | tmpl, err := template.New(templateName).Funcs(g.templateFuncMap()).Parse(strings.Trim(propTemplate.FieldTemplate, " \t")) 276 | if err != nil { 277 | return "", nil, err 278 | } 279 | 280 | fieldTypeName := g.getTypeName(ip.Type(), conf, false) 281 | 282 | tmpl.Execute(fieldCode, map[string]interface{}{ 283 | "TypeKind": tp.Kind(), 284 | "FieldName": name, 285 | "FieldDescription": g.removeLineBreaks(g.returnString(ip.Description())), 286 | "FieldType": fieldTypeName, 287 | "Config": conf, 288 | "TemplateConfig": templateConfig, 289 | }) 290 | 291 | imports = append(imports, g.getImports(ip.Type(), conf)...) 292 | imports = append(imports, propConf.Imports...) 293 | imports = append(imports, propTemplate.Config.Imports...) 294 | if val, ok := templateConfig["imports"]; ok { 295 | if arr, ok := val.([]string); ok { 296 | imports = append(imports, arr...) 297 | } 298 | } 299 | } 300 | 301 | return string(fieldCode.Bytes()), imports, nil 302 | } 303 | 304 | func (g *CodeGen) generateField(fp *introspection.Field, tp *introspection.Type, typeConf config.TypeConfig, conf config.Config) (string, string, []string, error) { 305 | name := fp.Name() 306 | typeName := *tp.Name() 307 | propConf := typeConf.Field[name] 308 | fieldCode := &bytes.Buffer{} 309 | methodCode := &bytes.Buffer{} 310 | imports := []string{} 311 | 312 | if len(propConf.Template) == 0 { 313 | propConf.Template = map[string]map[string]interface{}{} 314 | propConf.Template["default"] = map[string]interface{}{} 315 | } 316 | 317 | for templateName, templateConfig := range propConf.Template { 318 | propTemplate, err := codegenTemplate.GetPropertyTemplate(templateName) 319 | if err != nil { 320 | return "", "", nil, err 321 | } 322 | 323 | tmpl, err := template.New(templateName).Funcs(g.templateFuncMap()).Parse(strings.Trim(propTemplate.FieldTemplate, " \t")) 324 | if err != nil { 325 | return "", "", nil, err 326 | } 327 | 328 | fieldTypeName := g.getTypeName(fp.Type(), conf, false) 329 | 330 | type fieldArgument struct { 331 | Name string 332 | Type string 333 | } 334 | fieldArguments := make([]fieldArgument, 0, len(fp.Args())) 335 | 336 | for _, field := range fp.Args() { 337 | fieldArguments = append(fieldArguments, fieldArgument{ 338 | Name: field.Name(), 339 | Type: g.getTypeName(field.Type(), conf, true), 340 | }) 341 | imports = append(imports, g.getImports(field.Type(), conf)...) 342 | } 343 | 344 | tmpl.Execute(fieldCode, map[string]interface{}{ 345 | "TypeKind": tp.Kind(), 346 | "FieldName": name, 347 | "FieldDescription": g.removeLineBreaks(g.returnString(fp.Description())), 348 | "FieldType": fieldTypeName, 349 | "Config": conf, 350 | "TemplateConfig": templateConfig, 351 | }) 352 | 353 | tmpl, err = template.New(templateName).Funcs(g.templateFuncMap()).Parse(propTemplate.MethodTemplate) 354 | if err != nil { 355 | return "", "", nil, err 356 | } 357 | 358 | tmpl.Execute(methodCode, map[string]interface{}{ 359 | "TypeKind": tp.Kind(), 360 | "TypeName": typeName, 361 | "MethodArguments": fieldArguments, 362 | "MethodDescription": g.removeLineBreaks(g.returnString(fp.Description())), 363 | "MethodName": name, 364 | "MethodReturnType": fieldTypeName, 365 | "MethodReturn": name, 366 | "Config": conf, 367 | "TemplateConfig": templateConfig, 368 | }) 369 | 370 | imports = append(imports, g.getImports(fp.Type(), conf)...) 371 | imports = append(imports, propTemplate.Config.Imports...) 372 | imports = append(imports, propConf.Imports...) 373 | if val, ok := templateConfig["imports"]; ok { 374 | if arr, ok := val.([]string); ok { 375 | imports = append(imports, arr...) 376 | } 377 | } 378 | } 379 | 380 | return string(fieldCode.Bytes()), string(methodCode.Bytes()), imports, nil 381 | } 382 | 383 | func (g *CodeGen) getPointer(typeName string, fp *introspection.Field) string { 384 | if fp.Type().Kind() == "NON_NULL" { 385 | return typeName 386 | } 387 | return "*" + typeName 388 | } 389 | 390 | func (g *CodeGen) getImports(tp *introspection.Type, conf config.Config) []string { 391 | name := tp.Name() 392 | if name != nil { 393 | if val, ok := internalTypeConfig[*name]; ok { 394 | return []string{val.importPath} 395 | } 396 | } 397 | 398 | if tp.OfType() != nil { 399 | return g.getImports(tp.OfType(), conf) 400 | } 401 | 402 | return []string{} 403 | } 404 | 405 | func (g *CodeGen) getTypeName(tp *introspection.Type, conf config.Config, input bool) (typ string) { 406 | check: 407 | if tp.Kind() == "NON_NULL" { 408 | tp = tp.OfType() 409 | } else { 410 | typ = typ + "*" 411 | } 412 | 413 | if tp.Kind() == "LIST" { 414 | tp = tp.OfType() 415 | typ = typ + "[]" 416 | goto check 417 | } 418 | 419 | name := tp.Name() 420 | if val, ok := internalTypeConfig[*name]; ok { 421 | return typ + val.goType 422 | } 423 | 424 | if tp.Kind() == "ENUM" { 425 | typ = typ + *name 426 | } else if tp.Kind() != "INPUT_OBJECT" { 427 | if len(typ) > 0 { 428 | if typ[len(typ)-1] != '*' { 429 | typ = typ + "*" 430 | } 431 | } else if tp.Kind() != "SCALAR" { 432 | typ = "*" 433 | } 434 | typ = typ + *name + "Resolver" 435 | } else { 436 | typ = typ + *name 437 | } 438 | 439 | if typ[0] != '*' && tp.Kind() == "INPUT_OBJECT" { 440 | typ = "*" + typ 441 | } 442 | 443 | return 444 | } 445 | 446 | func (g *CodeGen) removeDuplicates(a []string) []string { 447 | result := []string{} 448 | seen := map[string]string{} 449 | for _, val := range a { 450 | val = strings.TrimSpace(val) 451 | if _, ok := seen[val]; !ok { 452 | result = append(result, val) 453 | seen[val] = val 454 | } 455 | } 456 | return result 457 | } 458 | 459 | func (g *CodeGen) isEntryPoint(a string) bool { 460 | return a == g.mutationName || a == g.queryName 461 | } 462 | 463 | func (g *CodeGen) removeLineBreaks(a string) string { 464 | return strings.Replace(a, "\n", " ", -1) 465 | } 466 | 467 | func (g *CodeGen) capitalise(str string) string { 468 | if strings.ToLower(str) == "id" { 469 | return "ID" 470 | } 471 | return strings.ToUpper(string(str[0])) + str[1:] 472 | } 473 | 474 | func (g *CodeGen) unCapitalise(str string) string { 475 | return strings.ToLower(string(str[0])) + str[1:] 476 | } 477 | 478 | func (g *CodeGen) subTemplate(str string, val interface{}) string { 479 | tmpl, err := template.New("sub_template").Funcs(g.templateFuncMap()).Parse(str) 480 | if err != nil { 481 | panic(err) 482 | } 483 | 484 | buf := &bytes.Buffer{} 485 | tmpl.Execute(buf, val) 486 | 487 | return string(buf.Bytes()) 488 | } 489 | 490 | func (g *CodeGen) includesString(strings []string, str string) bool { 491 | for _, val := range strings { 492 | if val == str { 493 | return true 494 | } 495 | } 496 | 497 | return false 498 | } 499 | 500 | func (g *CodeGen) templateFuncMap() template.FuncMap { 501 | return template.FuncMap{ 502 | "capitalize": g.capitalise, 503 | "uncapitalize": g.unCapitalise, 504 | "is_entry": g.isEntryPoint, 505 | "remove_line_breaks": g.removeLineBreaks, 506 | "sub_template": g.subTemplate, 507 | "sprintf": fmt.Sprintf, 508 | "includes_string": g.includesString, 509 | } 510 | } 511 | -------------------------------------------------------------------------------- /codegen/codegen_test.go: -------------------------------------------------------------------------------- 1 | package codegen 2 | 3 | import ( 4 | "io/ioutil" 5 | "os" 6 | "path" 7 | "strings" 8 | "testing" 9 | 10 | "github.com/Applifier/graphql-codegen/config" 11 | ) 12 | 13 | const fixtureDir = "fixtures" 14 | 15 | func TestCodegen(t *testing.T) { 16 | testDirs, err := ioutil.ReadDir(fixtureDir) 17 | if err != nil { 18 | t.Fatal(err) 19 | } 20 | for _, testDir := range testDirs { 21 | if strings.HasPrefix(testDir.Name(), "_") && os.Getenv("UNSTABLE_TEST") != "yes" { 22 | continue 23 | } 24 | 25 | schemaBytes, _ := ioutil.ReadFile(path.Join(fixtureDir, testDir.Name(), "schema.graphql")) 26 | confBytes, _ := ioutil.ReadFile(path.Join(fixtureDir, testDir.Name(), "config.hcl")) 27 | exectedFiles, _ := ioutil.ReadDir(path.Join(fixtureDir, testDir.Name())) 28 | exectedFilesMap := map[string]string{} 29 | 30 | for _, f := range exectedFiles { 31 | if strings.HasSuffix(f.Name(), ".go") { 32 | expectedBytes, _ := ioutil.ReadFile(path.Join(fixtureDir, testDir.Name(), f.Name())) 33 | exectedFilesMap[f.Name()] = string(expectedBytes) 34 | } 35 | } 36 | 37 | cfg, err := config.Parse(string(confBytes)) 38 | if err != nil { 39 | t.Fatal(err) 40 | } 41 | 42 | fileMap := RunTest(string(schemaBytes), cfg, exectedFilesMap, t) 43 | if os.Getenv("RECORD_FIXTURES") == "yes" { 44 | for filename, data := range fileMap { 45 | ioutil.WriteFile(path.Join(fixtureDir, testDir.Name(), filename), []byte(data), 0644) 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /codegen/fixtures/basic/config.hcl: -------------------------------------------------------------------------------- 1 | package = "basic" 2 | -------------------------------------------------------------------------------- /codegen/fixtures/basic/pageinfo_gen.go: -------------------------------------------------------------------------------- 1 | // This code is genereated by graphql-codegen 2 | // DO NOT EDIT! 3 | 4 | package basic 5 | 6 | import ( 7 | "encoding/json" 8 | 9 | graphql "github.com/neelance/graphql-go" 10 | ) 11 | 12 | // PageInfo Information for paginating this connection 13 | type PageInfo struct { 14 | // StartCursor 15 | StartCursor *graphql.ID `json:"startCursor"` 16 | // EndCursor 17 | EndCursor *graphql.ID `json:"endCursor"` 18 | // HasNextPage 19 | HasNextPage bool `json:"hasNextPage"` 20 | } 21 | 22 | // PageInfoResolver resolver for PageInfo 23 | type PageInfoResolver struct { 24 | PageInfo 25 | } 26 | 27 | // StartCursor 28 | func (r *PageInfoResolver) StartCursor() *graphql.ID { 29 | return r.PageInfo.StartCursor 30 | } 31 | 32 | // EndCursor 33 | func (r *PageInfoResolver) EndCursor() *graphql.ID { 34 | return r.PageInfo.EndCursor 35 | } 36 | 37 | // HasNextPage 38 | func (r *PageInfoResolver) HasNextPage() bool { 39 | return r.PageInfo.HasNextPage 40 | } 41 | 42 | func (r *PageInfoResolver) MarshalJSON() ([]byte, error) { 43 | return json.Marshal(&r.PageInfo) 44 | } 45 | 46 | func (r *PageInfoResolver) UnmarshalJSON(data []byte) error { 47 | return json.Unmarshal(data, &r.PageInfo) 48 | } 49 | -------------------------------------------------------------------------------- /codegen/fixtures/basic/schema.graphql: -------------------------------------------------------------------------------- 1 | # Information for paginating this connection 2 | type PageInfo { 3 | startCursor: ID 4 | endCursor: ID 5 | hasNextPage: Boolean! 6 | } 7 | -------------------------------------------------------------------------------- /codegen/fixtures/custom_field_types/barfoo_gen.go: -------------------------------------------------------------------------------- 1 | // This code is genereated by graphql-codegen 2 | // DO NOT EDIT! 3 | 4 | package custom_field_types 5 | 6 | import ( 7 | "encoding/json" 8 | 9 | graphql "github.com/neelance/graphql-go" 10 | ) 11 | 12 | // BarFoo 13 | type BarFoo struct { 14 | // StartCursor 15 | StartCursor *graphql.ID `json:"startCursor"` 16 | // EndCursor 17 | EndCursor *graphql.ID `json:"endCursor"` 18 | // HasNextPage 19 | HasNextPage bool `json:"hasNextPage"` 20 | } 21 | 22 | // BarFooResolver resolver for BarFoo 23 | type BarFooResolver struct { 24 | BarFoo 25 | } 26 | 27 | // StartCursor 28 | func (r *BarFooResolver) StartCursor() *graphql.ID { 29 | return r.BarFoo.StartCursor 30 | } 31 | 32 | // EndCursor 33 | func (r *BarFooResolver) EndCursor() *graphql.ID { 34 | return r.BarFoo.EndCursor 35 | } 36 | 37 | // HasNextPage 38 | func (r *BarFooResolver) HasNextPage() bool { 39 | return r.BarFoo.HasNextPage 40 | } 41 | 42 | func (r *BarFooResolver) MarshalJSON() ([]byte, error) { 43 | return json.Marshal(&r.BarFoo) 44 | } 45 | 46 | func (r *BarFooResolver) UnmarshalJSON(data []byte) error { 47 | return json.Unmarshal(data, &r.BarFoo) 48 | } 49 | -------------------------------------------------------------------------------- /codegen/fixtures/custom_field_types/config.hcl: -------------------------------------------------------------------------------- 1 | package = "custom_field_types" 2 | -------------------------------------------------------------------------------- /codegen/fixtures/custom_field_types/foobar_gen.go: -------------------------------------------------------------------------------- 1 | // This code is genereated by graphql-codegen 2 | // DO NOT EDIT! 3 | 4 | package custom_field_types 5 | 6 | import ( 7 | "encoding/json" 8 | ) 9 | 10 | // FooBar 11 | type FooBar struct { 12 | // BarFoo 13 | BarFoo *BarFooResolver `json:"barFoo"` 14 | } 15 | 16 | // FooBarResolver resolver for FooBar 17 | type FooBarResolver struct { 18 | FooBar 19 | } 20 | 21 | // BarFoo 22 | func (r *FooBarResolver) BarFoo() *BarFooResolver { 23 | return r.FooBar.BarFoo 24 | } 25 | 26 | func (r *FooBarResolver) MarshalJSON() ([]byte, error) { 27 | return json.Marshal(&r.FooBar) 28 | } 29 | 30 | func (r *FooBarResolver) UnmarshalJSON(data []byte) error { 31 | return json.Unmarshal(data, &r.FooBar) 32 | } 33 | -------------------------------------------------------------------------------- /codegen/fixtures/custom_field_types/schema.graphql: -------------------------------------------------------------------------------- 1 | type BarFoo { 2 | startCursor: ID 3 | endCursor: ID 4 | hasNextPage: Boolean! 5 | } 6 | 7 | type FooBar { 8 | barFoo: BarFoo 9 | } 10 | -------------------------------------------------------------------------------- /codegen/fixtures/httpget/config.hcl: -------------------------------------------------------------------------------- 1 | package = "httpget" 2 | 3 | type "User" { 4 | } 5 | 6 | type "Message" { 7 | field "from" { 8 | imports = ["\"fmt\""] 9 | template "http_resolver" { 10 | fields = [ 11 | { 12 | field_name = "from_user_id" 13 | field_type = "string" 14 | } 15 | ] 16 | url = "fmt.Sprintf(\"https://static.everyplay.com/developer-quiz/data/users/%s\", r.{{.TypeName}}.From_user_id)" 17 | } 18 | } 19 | 20 | field "conversation" { 21 | imports = ["\"fmt\""] 22 | template "http_resolver" { 23 | fields = [ 24 | { 25 | field_name = "conversation_id" 26 | field_type = "string" 27 | } 28 | ] 29 | url = "fmt.Sprintf(\"https://static.everyplay.com/developer-quiz/data/conversations/%s\", r.{{.TypeName}}.Conversation_id)" 30 | } 31 | } 32 | } 33 | 34 | type "Conversation" { 35 | field "title" { 36 | template "custom" {} 37 | } 38 | field "with_user" { 39 | imports = ["\"fmt\""] 40 | template "http_resolver" { 41 | fields = [ 42 | { 43 | field_name = "with_user_id" 44 | field_type = "string" 45 | } 46 | ] 47 | url = "fmt.Sprintf(\"https://static.everyplay.com/developer-quiz/data/users/%s\", r.{{.TypeName}}.With_user_id)" 48 | } 49 | } 50 | 51 | field "messages" { 52 | imports = ["\"fmt\""] 53 | template "http_resolver" { 54 | url = "fmt.Sprintf(\"https://static.everyplay.com/developer-quiz/data/conversations/%s/messages\", r.{{.TypeName}}.ID)" 55 | } 56 | } 57 | } 58 | 59 | type "Query" { 60 | field "user" { 61 | imports = ["\"fmt\""] 62 | template "http_resolver" { 63 | url = "fmt.Sprintf(\"https://static.everyplay.com/developer-quiz/data/users/%s\", args.ID)" 64 | } 65 | } 66 | 67 | field "conversation" { 68 | imports = ["\"fmt\""] 69 | template "http_resolver" { 70 | url = "fmt.Sprintf(\"https://static.everyplay.com/developer-quiz/data/conversations/%s\", args.ID)" 71 | } 72 | } 73 | 74 | field "conversations" { 75 | imports = ["\"fmt\""] 76 | template "http_resolver" { 77 | url = "\"https://static.everyplay.com/developer-quiz/data/conversations\"" 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /codegen/fixtures/httpget/conversation_gen.go: -------------------------------------------------------------------------------- 1 | // This code is genereated by graphql-codegen 2 | // DO NOT EDIT! 3 | 4 | package httpget 5 | 6 | import ( 7 | graphql "github.com/neelance/graphql-go" 8 | 9 | "net/http" 10 | 11 | "encoding/json" 12 | 13 | "fmt" 14 | ) 15 | 16 | // Conversation 17 | type Conversation struct { 18 | // ID 19 | ID graphql.ID `json:"id"` 20 | 21 | With_user_id string `json:"with_user_id"` 22 | } 23 | 24 | // ConversationResolver resolver for Conversation 25 | type ConversationResolver struct { 26 | Conversation 27 | } 28 | 29 | // ID 30 | func (r *ConversationResolver) ID() graphql.ID { 31 | return r.Conversation.ID 32 | } 33 | 34 | // With_user 35 | func (r *ConversationResolver) With_user() (*UserResolver, error) { 36 | var result *UserResolver 37 | resp, err := http.Get(fmt.Sprintf("https://static.everyplay.com/developer-quiz/data/users/%s", r.Conversation.With_user_id)) 38 | if err != nil { 39 | return nil, err 40 | } 41 | defer resp.Body.Close() 42 | 43 | err = json.NewDecoder(resp.Body).Decode(&result) 44 | return result, err 45 | } 46 | 47 | // Messages 48 | func (r *ConversationResolver) Messages() ([]*MessageResolver, error) { 49 | var result []*MessageResolver 50 | resp, err := http.Get(fmt.Sprintf("https://static.everyplay.com/developer-quiz/data/conversations/%s/messages", r.Conversation.ID)) 51 | if err != nil { 52 | return nil, err 53 | } 54 | defer resp.Body.Close() 55 | 56 | err = json.NewDecoder(resp.Body).Decode(&result) 57 | return result, err 58 | } 59 | 60 | func (r *ConversationResolver) MarshalJSON() ([]byte, error) { 61 | return json.Marshal(&r.Conversation) 62 | } 63 | 64 | func (r *ConversationResolver) UnmarshalJSON(data []byte) error { 65 | return json.Unmarshal(data, &r.Conversation) 66 | } 67 | -------------------------------------------------------------------------------- /codegen/fixtures/httpget/coversation.go: -------------------------------------------------------------------------------- 1 | package httpget 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "net/http" 7 | ) 8 | 9 | // This file contains custom definitions for ConversationResolver 10 | 11 | // Title returns a title for the conversation 12 | func (r *ConversationResolver) Title() (string, error) { 13 | var user *UserResolver 14 | resp, err := http.Get(fmt.Sprintf("https://static.everyplay.com/developer-quiz/data/users/%s", r.Conversation.With_user_id)) 15 | if err != nil { 16 | return "", err 17 | } 18 | defer resp.Body.Close() 19 | 20 | if err = json.NewDecoder(resp.Body).Decode(&user); err != nil { 21 | return "", err 22 | } 23 | 24 | return fmt.Sprintf("Conversation between you and %s", user.Username()), err 25 | } 26 | -------------------------------------------------------------------------------- /codegen/fixtures/httpget/http_test.go: -------------------------------------------------------------------------------- 1 | package httpget 2 | 3 | import ( 4 | "io/ioutil" 5 | "testing" 6 | 7 | graphql "github.com/neelance/graphql-go" 8 | ) 9 | 10 | func TestHTTPSchema(t *testing.T) { 11 | schema, err := ioutil.ReadFile("schema.graphql") 12 | if err != nil { 13 | t.Fatal(err) 14 | } 15 | 16 | resolver := &Resolver{} 17 | 18 | graphql.RunTests(t, []*graphql.Test{ 19 | { 20 | Schema: graphql.MustParseSchema(string(schema), resolver), 21 | Query: ` 22 | { 23 | user(id: "1") { 24 | username, 25 | avatar_url 26 | } 27 | } 28 | `, 29 | ExpectedResult: ` 30 | { 31 | "user": { 32 | "username": "John", 33 | "avatar_url": "http://placekitten.com/g/300/300" 34 | } 35 | } 36 | `, 37 | }, 38 | { 39 | Schema: graphql.MustParseSchema(string(schema), resolver), 40 | Query: ` 41 | { 42 | conversations { 43 | id, 44 | with_user { 45 | id, 46 | username, 47 | avatar_url, 48 | }, 49 | } 50 | } 51 | `, 52 | ExpectedResult: ` 53 | { 54 | "conversations":[ 55 | { 56 | "id":"1", 57 | "with_user":{ 58 | "avatar_url":"http://placekitten.com/g/301/301", 59 | "id":"2", 60 | "username":"Amy" 61 | } 62 | }, 63 | { 64 | "id":"2", 65 | "with_user":{ 66 | "avatar_url":"http://placekitten.com/g/302/302", 67 | "id":"3", 68 | "username":"Jeremy" 69 | } 70 | }, 71 | { 72 | "id":"3", 73 | "with_user":{ 74 | "avatar_url":"http://placekitten.com/g/303/303", 75 | "id":"4", 76 | "username":"Hannah" 77 | } 78 | }, 79 | { 80 | "id":"4", 81 | "with_user":{ 82 | "avatar_url":"http://placekitten.com/g/304/304", 83 | "id":"5", 84 | "username":"Charles" 85 | } 86 | }, 87 | { 88 | "id":"5", 89 | "with_user":{ 90 | "avatar_url":"http://placekitten.com/g/305/305", 91 | "id":"6", 92 | "username":"George" 93 | } 94 | } 95 | ] 96 | } 97 | `, 98 | }, 99 | { 100 | Schema: graphql.MustParseSchema(string(schema), resolver), 101 | Query: ` 102 | { 103 | conversation(id: "1") { 104 | id, 105 | title, 106 | with_user { 107 | id, 108 | username, 109 | avatar_url, 110 | }, 111 | messages { 112 | id, 113 | body, 114 | from { 115 | username 116 | } 117 | } 118 | } 119 | } 120 | `, 121 | ExpectedResult: ` 122 | { 123 | "conversation":{ 124 | "id":"1", 125 | "title": "Conversation between you and Amy", 126 | "messages":[ 127 | { 128 | "body":"Moi!", 129 | "from":{ 130 | "username":"John" 131 | }, 132 | "id":"1" 133 | } 134 | ], 135 | "with_user":{ 136 | "avatar_url":"http://placekitten.com/g/301/301", 137 | "id":"2", 138 | "username":"Amy" 139 | } 140 | } 141 | } 142 | `, 143 | }, 144 | }) 145 | } 146 | -------------------------------------------------------------------------------- /codegen/fixtures/httpget/message_gen.go: -------------------------------------------------------------------------------- 1 | // This code is genereated by graphql-codegen 2 | // DO NOT EDIT! 3 | 4 | package httpget 5 | 6 | import ( 7 | graphql "github.com/neelance/graphql-go" 8 | 9 | "net/http" 10 | 11 | "encoding/json" 12 | 13 | "fmt" 14 | ) 15 | 16 | // Message 17 | type Message struct { 18 | // ID 19 | ID graphql.ID `json:"id"` 20 | 21 | Conversation_id string `json:"conversation_id"` 22 | 23 | From_user_id string `json:"from_user_id"` 24 | 25 | // Body dasadssadsad 26 | Body string `json:"body"` 27 | // Created_at 28 | Created_at string `json:"created_at"` 29 | } 30 | 31 | // MessageResolver resolver for Message 32 | type MessageResolver struct { 33 | Message 34 | } 35 | 36 | // ID 37 | func (r *MessageResolver) ID() graphql.ID { 38 | return r.Message.ID 39 | } 40 | 41 | // Conversation 42 | func (r *MessageResolver) Conversation() (*ConversationResolver, error) { 43 | var result *ConversationResolver 44 | resp, err := http.Get(fmt.Sprintf("https://static.everyplay.com/developer-quiz/data/conversations/%s", r.Message.Conversation_id)) 45 | if err != nil { 46 | return nil, err 47 | } 48 | defer resp.Body.Close() 49 | 50 | err = json.NewDecoder(resp.Body).Decode(&result) 51 | return result, err 52 | } 53 | 54 | // From user blalala 55 | func (r *MessageResolver) From() (*UserResolver, error) { 56 | var result *UserResolver 57 | resp, err := http.Get(fmt.Sprintf("https://static.everyplay.com/developer-quiz/data/users/%s", r.Message.From_user_id)) 58 | if err != nil { 59 | return nil, err 60 | } 61 | defer resp.Body.Close() 62 | 63 | err = json.NewDecoder(resp.Body).Decode(&result) 64 | return result, err 65 | } 66 | 67 | // Body dasadssadsad 68 | func (r *MessageResolver) Body() string { 69 | return r.Message.Body 70 | } 71 | 72 | // Created_at 73 | func (r *MessageResolver) Created_at() string { 74 | return r.Message.Created_at 75 | } 76 | 77 | func (r *MessageResolver) MarshalJSON() ([]byte, error) { 78 | return json.Marshal(&r.Message) 79 | } 80 | 81 | func (r *MessageResolver) UnmarshalJSON(data []byte) error { 82 | return json.Unmarshal(data, &r.Message) 83 | } 84 | -------------------------------------------------------------------------------- /codegen/fixtures/httpget/query_gen.go: -------------------------------------------------------------------------------- 1 | // This code is genereated by graphql-codegen 2 | // DO NOT EDIT! 3 | 4 | package httpget 5 | 6 | import ( 7 | graphql "github.com/neelance/graphql-go" 8 | 9 | "net/http" 10 | 11 | "encoding/json" 12 | 13 | "fmt" 14 | ) 15 | 16 | // User 17 | func (r *Resolver) User(args *struct { 18 | ID graphql.ID 19 | }) (*UserResolver, error) { 20 | var result *UserResolver 21 | resp, err := http.Get(fmt.Sprintf("https://static.everyplay.com/developer-quiz/data/users/%s", args.ID)) 22 | if err != nil { 23 | return nil, err 24 | } 25 | defer resp.Body.Close() 26 | 27 | err = json.NewDecoder(resp.Body).Decode(&result) 28 | return result, err 29 | } 30 | 31 | // Conversation 32 | func (r *Resolver) Conversation(args *struct { 33 | ID graphql.ID 34 | }) (*ConversationResolver, error) { 35 | var result *ConversationResolver 36 | resp, err := http.Get(fmt.Sprintf("https://static.everyplay.com/developer-quiz/data/conversations/%s", args.ID)) 37 | if err != nil { 38 | return nil, err 39 | } 40 | defer resp.Body.Close() 41 | 42 | err = json.NewDecoder(resp.Body).Decode(&result) 43 | return result, err 44 | } 45 | 46 | // Conversations 47 | func (r *Resolver) Conversations() ([]*ConversationResolver, error) { 48 | var result []*ConversationResolver 49 | resp, err := http.Get("https://static.everyplay.com/developer-quiz/data/conversations") 50 | if err != nil { 51 | return nil, err 52 | } 53 | defer resp.Body.Close() 54 | 55 | err = json.NewDecoder(resp.Body).Decode(&result) 56 | return result, err 57 | } 58 | -------------------------------------------------------------------------------- /codegen/fixtures/httpget/resolver_gen.go: -------------------------------------------------------------------------------- 1 | // This code is genereated by graphql-codegen 2 | // DO NOT EDIT! 3 | 4 | package httpget 5 | 6 | // Resolver Resolver is the main resolver for all queries 7 | type Resolver struct { 8 | } 9 | -------------------------------------------------------------------------------- /codegen/fixtures/httpget/schema.graphql: -------------------------------------------------------------------------------- 1 | type User { 2 | id: ID! 3 | username: String! 4 | avatar_url: String! 5 | } 6 | 7 | type Conversation { 8 | id: ID! 9 | with_user: User! 10 | messages: [Message!]! 11 | title: String! 12 | } 13 | 14 | type Message { 15 | id: ID! 16 | conversation: Conversation! 17 | # user blalala 18 | from: User! 19 | # dasadssadsad 20 | body: String! 21 | created_at: String! 22 | } 23 | 24 | type Query { 25 | user(id: ID!): User 26 | conversation(id: ID!): Conversation 27 | conversations: [Conversation!]! 28 | } 29 | 30 | schema { 31 | query: Query 32 | } 33 | -------------------------------------------------------------------------------- /codegen/fixtures/httpget/user_gen.go: -------------------------------------------------------------------------------- 1 | // This code is genereated by graphql-codegen 2 | // DO NOT EDIT! 3 | 4 | package httpget 5 | 6 | import ( 7 | "encoding/json" 8 | 9 | graphql "github.com/neelance/graphql-go" 10 | ) 11 | 12 | // User 13 | type User struct { 14 | // ID 15 | ID graphql.ID `json:"id"` 16 | // Username 17 | Username string `json:"username"` 18 | // Avatar_url 19 | Avatar_url string `json:"avatar_url"` 20 | } 21 | 22 | // UserResolver resolver for User 23 | type UserResolver struct { 24 | User 25 | } 26 | 27 | // ID 28 | func (r *UserResolver) ID() graphql.ID { 29 | return r.User.ID 30 | } 31 | 32 | // Username 33 | func (r *UserResolver) Username() string { 34 | return r.User.Username 35 | } 36 | 37 | // Avatar_url 38 | func (r *UserResolver) Avatar_url() string { 39 | return r.User.Avatar_url 40 | } 41 | 42 | func (r *UserResolver) MarshalJSON() ([]byte, error) { 43 | return json.Marshal(&r.User) 44 | } 45 | 46 | func (r *UserResolver) UnmarshalJSON(data []byte) error { 47 | return json.Unmarshal(data, &r.User) 48 | } 49 | -------------------------------------------------------------------------------- /codegen/fixtures/list_of_lists/config.hcl: -------------------------------------------------------------------------------- 1 | package = "list_of_lists" 2 | -------------------------------------------------------------------------------- /codegen/fixtures/list_of_lists/listtype_gen.go: -------------------------------------------------------------------------------- 1 | // This code is genereated by graphql-codegen 2 | // DO NOT EDIT! 3 | 4 | package list_of_lists 5 | 6 | import ( 7 | "encoding/json" 8 | ) 9 | 10 | // ListType Information for paginating this connection 11 | type ListType struct { 12 | // List 13 | List *[]*string `json:"list"` 14 | // ListOfList 15 | ListOfList *[]*[]*string `json:"listOfList"` 16 | // NonNullListOfList 17 | NonNullListOfList [][]string `json:"nonNullListOfList"` 18 | } 19 | 20 | // ListTypeResolver resolver for ListType 21 | type ListTypeResolver struct { 22 | ListType 23 | } 24 | 25 | // List 26 | func (r *ListTypeResolver) List() *[]*string { 27 | return r.ListType.List 28 | } 29 | 30 | // ListOfList 31 | func (r *ListTypeResolver) ListOfList() *[]*[]*string { 32 | return r.ListType.ListOfList 33 | } 34 | 35 | // NonNullListOfList 36 | func (r *ListTypeResolver) NonNullListOfList() [][]string { 37 | return r.ListType.NonNullListOfList 38 | } 39 | 40 | func (r *ListTypeResolver) MarshalJSON() ([]byte, error) { 41 | return json.Marshal(&r.ListType) 42 | } 43 | 44 | func (r *ListTypeResolver) UnmarshalJSON(data []byte) error { 45 | return json.Unmarshal(data, &r.ListType) 46 | } 47 | -------------------------------------------------------------------------------- /codegen/fixtures/list_of_lists/schema.graphql: -------------------------------------------------------------------------------- 1 | # Information for paginating this connection 2 | type ListType { 3 | list: [String] 4 | listOfList: [[String]] 5 | nonNullListOfList: [[String!]!]! 6 | } 7 | -------------------------------------------------------------------------------- /codegen/fixtures/starwars/character_gen.go: -------------------------------------------------------------------------------- 1 | // This code is genereated by graphql-codegen 2 | // DO NOT EDIT! 3 | 4 | package starwars 5 | 6 | import ( 7 | graphql "github.com/neelance/graphql-go" 8 | ) 9 | 10 | // Character A character from the Star Wars universe 11 | type Character interface { 12 | 13 | // ID The ID of the character 14 | ID() graphql.ID 15 | 16 | // Name The name of the character 17 | Name() string 18 | 19 | // Friends The friends of the character, or an empty list if they have none 20 | Friends() *[]*CharacterResolver 21 | 22 | // FriendsConnection The friends of the character exposed as a connection with edges 23 | FriendsConnection(args *struct { 24 | First *int32 25 | After *graphql.ID 26 | }) *FriendsConnectionResolver 27 | 28 | // AppearsIn The movies this character appears in 29 | AppearsIn() []Episode 30 | } 31 | 32 | // CharacterResolver resolver for Character 33 | type CharacterResolver struct { 34 | Character 35 | } 36 | 37 | func (r *CharacterResolver) ToHuman() (*HumanResolver, bool) { 38 | c, ok := r.Character.(*HumanResolver) 39 | return c, ok 40 | } 41 | 42 | func (r *CharacterResolver) ToDroid() (*DroidResolver, bool) { 43 | c, ok := r.Character.(*DroidResolver) 44 | return c, ok 45 | } 46 | -------------------------------------------------------------------------------- /codegen/fixtures/starwars/config.hcl: -------------------------------------------------------------------------------- 1 | package = "starwars" 2 | -------------------------------------------------------------------------------- /codegen/fixtures/starwars/droid_gen.go: -------------------------------------------------------------------------------- 1 | // This code is genereated by graphql-codegen 2 | // DO NOT EDIT! 3 | 4 | package starwars 5 | 6 | import ( 7 | "encoding/json" 8 | 9 | graphql "github.com/neelance/graphql-go" 10 | ) 11 | 12 | // Droid An autonomous mechanical character in the Star Wars universe 13 | type Droid struct { 14 | // ID The ID of the droid 15 | ID graphql.ID `json:"id"` 16 | // Name What others call this droid 17 | Name string `json:"name"` 18 | // Friends This droid's friends, or an empty list if they have none 19 | Friends *[]*CharacterResolver `json:"friends"` 20 | // FriendsConnection The friends of the droid exposed as a connection with edges 21 | FriendsConnection *FriendsConnectionResolver `json:"friendsConnection"` 22 | // AppearsIn The movies this droid appears in 23 | AppearsIn []Episode `json:"appearsIn"` 24 | // PrimaryFunction This droid's primary function 25 | PrimaryFunction *string `json:"primaryFunction"` 26 | } 27 | 28 | // DroidResolver resolver for Droid 29 | type DroidResolver struct { 30 | Droid 31 | } 32 | 33 | // ID The ID of the droid 34 | func (r *DroidResolver) ID() graphql.ID { 35 | return r.Droid.ID 36 | } 37 | 38 | // Name What others call this droid 39 | func (r *DroidResolver) Name() string { 40 | return r.Droid.Name 41 | } 42 | 43 | // Friends This droid's friends, or an empty list if they have none 44 | func (r *DroidResolver) Friends() *[]*CharacterResolver { 45 | return r.Droid.Friends 46 | } 47 | 48 | // FriendsConnection The friends of the droid exposed as a connection with edges 49 | func (r *DroidResolver) FriendsConnection(args *struct { 50 | First *int32 51 | After *graphql.ID 52 | }) *FriendsConnectionResolver { 53 | return r.Droid.FriendsConnection 54 | } 55 | 56 | // AppearsIn The movies this droid appears in 57 | func (r *DroidResolver) AppearsIn() []Episode { 58 | return r.Droid.AppearsIn 59 | } 60 | 61 | // PrimaryFunction This droid's primary function 62 | func (r *DroidResolver) PrimaryFunction() *string { 63 | return r.Droid.PrimaryFunction 64 | } 65 | 66 | func (r *DroidResolver) MarshalJSON() ([]byte, error) { 67 | return json.Marshal(&r.Droid) 68 | } 69 | 70 | func (r *DroidResolver) UnmarshalJSON(data []byte) error { 71 | return json.Unmarshal(data, &r.Droid) 72 | } 73 | -------------------------------------------------------------------------------- /codegen/fixtures/starwars/episode_gen.go: -------------------------------------------------------------------------------- 1 | // This code is genereated by graphql-codegen 2 | // DO NOT EDIT! 3 | 4 | package starwars 5 | 6 | // Episode The episodes in the Star Wars trilogy 7 | type Episode string 8 | 9 | const ( 10 | 11 | // EpisodeNEWHOPE The episodes in the Star Wars trilogy 12 | EpisodeNEWHOPE = Episode("NEWHOPE") 13 | 14 | // EpisodeEMPIRE The episodes in the Star Wars trilogy 15 | EpisodeEMPIRE = Episode("EMPIRE") 16 | 17 | // EpisodeJEDI The episodes in the Star Wars trilogy 18 | EpisodeJEDI = Episode("JEDI") 19 | ) 20 | -------------------------------------------------------------------------------- /codegen/fixtures/starwars/friendsconnection_gen.go: -------------------------------------------------------------------------------- 1 | // This code is genereated by graphql-codegen 2 | // DO NOT EDIT! 3 | 4 | package starwars 5 | 6 | import ( 7 | "encoding/json" 8 | ) 9 | 10 | // FriendsConnection A connection object for a character's friends 11 | type FriendsConnection struct { 12 | // TotalCount The total number of friends 13 | TotalCount int32 `json:"totalCount"` 14 | // Edges The edges for each of the character's friends. 15 | Edges *[]*FriendsEdgeResolver `json:"edges"` 16 | // Friends A list of the friends, as a convenience when edges are not needed. 17 | Friends *[]*CharacterResolver `json:"friends"` 18 | // PageInfo Information for paginating this connection 19 | PageInfo *PageInfoResolver `json:"pageInfo"` 20 | } 21 | 22 | // FriendsConnectionResolver resolver for FriendsConnection 23 | type FriendsConnectionResolver struct { 24 | FriendsConnection 25 | } 26 | 27 | // TotalCount The total number of friends 28 | func (r *FriendsConnectionResolver) TotalCount() int32 { 29 | return r.FriendsConnection.TotalCount 30 | } 31 | 32 | // Edges The edges for each of the character's friends. 33 | func (r *FriendsConnectionResolver) Edges() *[]*FriendsEdgeResolver { 34 | return r.FriendsConnection.Edges 35 | } 36 | 37 | // Friends A list of the friends, as a convenience when edges are not needed. 38 | func (r *FriendsConnectionResolver) Friends() *[]*CharacterResolver { 39 | return r.FriendsConnection.Friends 40 | } 41 | 42 | // PageInfo Information for paginating this connection 43 | func (r *FriendsConnectionResolver) PageInfo() *PageInfoResolver { 44 | return r.FriendsConnection.PageInfo 45 | } 46 | 47 | func (r *FriendsConnectionResolver) MarshalJSON() ([]byte, error) { 48 | return json.Marshal(&r.FriendsConnection) 49 | } 50 | 51 | func (r *FriendsConnectionResolver) UnmarshalJSON(data []byte) error { 52 | return json.Unmarshal(data, &r.FriendsConnection) 53 | } 54 | -------------------------------------------------------------------------------- /codegen/fixtures/starwars/friendsedge_gen.go: -------------------------------------------------------------------------------- 1 | // This code is genereated by graphql-codegen 2 | // DO NOT EDIT! 3 | 4 | package starwars 5 | 6 | import ( 7 | "encoding/json" 8 | 9 | graphql "github.com/neelance/graphql-go" 10 | ) 11 | 12 | // FriendsEdge An edge object for a character's friends 13 | type FriendsEdge struct { 14 | // Cursor A cursor used for pagination 15 | Cursor graphql.ID `json:"cursor"` 16 | // Node The character represented by this friendship edge 17 | Node *CharacterResolver `json:"node"` 18 | } 19 | 20 | // FriendsEdgeResolver resolver for FriendsEdge 21 | type FriendsEdgeResolver struct { 22 | FriendsEdge 23 | } 24 | 25 | // Cursor A cursor used for pagination 26 | func (r *FriendsEdgeResolver) Cursor() graphql.ID { 27 | return r.FriendsEdge.Cursor 28 | } 29 | 30 | // Node The character represented by this friendship edge 31 | func (r *FriendsEdgeResolver) Node() *CharacterResolver { 32 | return r.FriendsEdge.Node 33 | } 34 | 35 | func (r *FriendsEdgeResolver) MarshalJSON() ([]byte, error) { 36 | return json.Marshal(&r.FriendsEdge) 37 | } 38 | 39 | func (r *FriendsEdgeResolver) UnmarshalJSON(data []byte) error { 40 | return json.Unmarshal(data, &r.FriendsEdge) 41 | } 42 | -------------------------------------------------------------------------------- /codegen/fixtures/starwars/human_gen.go: -------------------------------------------------------------------------------- 1 | // This code is genereated by graphql-codegen 2 | // DO NOT EDIT! 3 | 4 | package starwars 5 | 6 | import ( 7 | "encoding/json" 8 | 9 | graphql "github.com/neelance/graphql-go" 10 | ) 11 | 12 | // Human A humanoid creature from the Star Wars universe 13 | type Human struct { 14 | // ID The ID of the human 15 | ID graphql.ID `json:"id"` 16 | // Name What this human calls themselves 17 | Name string `json:"name"` 18 | // Height Height in the preferred unit, default is meters 19 | Height float64 `json:"height"` 20 | // Mass Mass in kilograms, or null if unknown 21 | Mass *float64 `json:"mass"` 22 | // Friends This human's friends, or an empty list if they have none 23 | Friends *[]*CharacterResolver `json:"friends"` 24 | // FriendsConnection The friends of the human exposed as a connection with edges 25 | FriendsConnection *FriendsConnectionResolver `json:"friendsConnection"` 26 | // AppearsIn The movies this human appears in 27 | AppearsIn []Episode `json:"appearsIn"` 28 | // Starships A list of starships this person has piloted, or an empty list if none 29 | Starships *[]*StarshipResolver `json:"starships"` 30 | } 31 | 32 | // HumanResolver resolver for Human 33 | type HumanResolver struct { 34 | Human 35 | } 36 | 37 | // ID The ID of the human 38 | func (r *HumanResolver) ID() graphql.ID { 39 | return r.Human.ID 40 | } 41 | 42 | // Name What this human calls themselves 43 | func (r *HumanResolver) Name() string { 44 | return r.Human.Name 45 | } 46 | 47 | // Height Height in the preferred unit, default is meters 48 | func (r *HumanResolver) Height(args *struct { 49 | Unit *LengthUnit 50 | }) float64 { 51 | return r.Human.Height 52 | } 53 | 54 | // Mass Mass in kilograms, or null if unknown 55 | func (r *HumanResolver) Mass() *float64 { 56 | return r.Human.Mass 57 | } 58 | 59 | // Friends This human's friends, or an empty list if they have none 60 | func (r *HumanResolver) Friends() *[]*CharacterResolver { 61 | return r.Human.Friends 62 | } 63 | 64 | // FriendsConnection The friends of the human exposed as a connection with edges 65 | func (r *HumanResolver) FriendsConnection(args *struct { 66 | First *int32 67 | After *graphql.ID 68 | }) *FriendsConnectionResolver { 69 | return r.Human.FriendsConnection 70 | } 71 | 72 | // AppearsIn The movies this human appears in 73 | func (r *HumanResolver) AppearsIn() []Episode { 74 | return r.Human.AppearsIn 75 | } 76 | 77 | // Starships A list of starships this person has piloted, or an empty list if none 78 | func (r *HumanResolver) Starships() *[]*StarshipResolver { 79 | return r.Human.Starships 80 | } 81 | 82 | func (r *HumanResolver) MarshalJSON() ([]byte, error) { 83 | return json.Marshal(&r.Human) 84 | } 85 | 86 | func (r *HumanResolver) UnmarshalJSON(data []byte) error { 87 | return json.Unmarshal(data, &r.Human) 88 | } 89 | -------------------------------------------------------------------------------- /codegen/fixtures/starwars/lengthunit_gen.go: -------------------------------------------------------------------------------- 1 | // This code is genereated by graphql-codegen 2 | // DO NOT EDIT! 3 | 4 | package starwars 5 | 6 | // LengthUnit Units of height 7 | type LengthUnit string 8 | 9 | const ( 10 | 11 | // LengthUnitMETER Units of height 12 | LengthUnitMETER = LengthUnit("METER") 13 | 14 | // LengthUnitFOOT Units of height 15 | LengthUnitFOOT = LengthUnit("FOOT") 16 | ) 17 | -------------------------------------------------------------------------------- /codegen/fixtures/starwars/mutation_gen.go: -------------------------------------------------------------------------------- 1 | // This code is genereated by graphql-codegen 2 | // DO NOT EDIT! 3 | 4 | package starwars 5 | 6 | // CreateReview 7 | func (r *Resolver) CreateReview(args *struct { 8 | Episode Episode 9 | Review *ReviewInput 10 | }) *ReviewResolver { 11 | return nil 12 | } 13 | -------------------------------------------------------------------------------- /codegen/fixtures/starwars/pageinfo_gen.go: -------------------------------------------------------------------------------- 1 | // This code is genereated by graphql-codegen 2 | // DO NOT EDIT! 3 | 4 | package starwars 5 | 6 | import ( 7 | "encoding/json" 8 | 9 | graphql "github.com/neelance/graphql-go" 10 | ) 11 | 12 | // PageInfo Information for paginating this connection 13 | type PageInfo struct { 14 | // StartCursor 15 | StartCursor *graphql.ID `json:"startCursor"` 16 | // EndCursor 17 | EndCursor *graphql.ID `json:"endCursor"` 18 | // HasNextPage 19 | HasNextPage bool `json:"hasNextPage"` 20 | } 21 | 22 | // PageInfoResolver resolver for PageInfo 23 | type PageInfoResolver struct { 24 | PageInfo 25 | } 26 | 27 | // StartCursor 28 | func (r *PageInfoResolver) StartCursor() *graphql.ID { 29 | return r.PageInfo.StartCursor 30 | } 31 | 32 | // EndCursor 33 | func (r *PageInfoResolver) EndCursor() *graphql.ID { 34 | return r.PageInfo.EndCursor 35 | } 36 | 37 | // HasNextPage 38 | func (r *PageInfoResolver) HasNextPage() bool { 39 | return r.PageInfo.HasNextPage 40 | } 41 | 42 | func (r *PageInfoResolver) MarshalJSON() ([]byte, error) { 43 | return json.Marshal(&r.PageInfo) 44 | } 45 | 46 | func (r *PageInfoResolver) UnmarshalJSON(data []byte) error { 47 | return json.Unmarshal(data, &r.PageInfo) 48 | } 49 | -------------------------------------------------------------------------------- /codegen/fixtures/starwars/query_gen.go: -------------------------------------------------------------------------------- 1 | // This code is genereated by graphql-codegen 2 | // DO NOT EDIT! 3 | 4 | package starwars 5 | 6 | import ( 7 | graphql "github.com/neelance/graphql-go" 8 | ) 9 | 10 | // Hero 11 | func (r *Resolver) Hero(args *struct { 12 | Episode *Episode 13 | }) *CharacterResolver { 14 | return nil 15 | } 16 | 17 | // Reviews 18 | func (r *Resolver) Reviews(args *struct { 19 | Episode Episode 20 | }) []*ReviewResolver { 21 | return nil 22 | } 23 | 24 | // Search 25 | func (r *Resolver) Search(args *struct { 26 | Text string 27 | }) []*SearchResultResolver { 28 | return nil 29 | } 30 | 31 | // Character 32 | func (r *Resolver) Character(args *struct { 33 | ID graphql.ID 34 | }) *CharacterResolver { 35 | return nil 36 | } 37 | 38 | // Droid 39 | func (r *Resolver) Droid(args *struct { 40 | ID graphql.ID 41 | }) *DroidResolver { 42 | return nil 43 | } 44 | 45 | // Human 46 | func (r *Resolver) Human(args *struct { 47 | ID graphql.ID 48 | }) *HumanResolver { 49 | return nil 50 | } 51 | 52 | // Starship 53 | func (r *Resolver) Starship(args *struct { 54 | ID graphql.ID 55 | }) *StarshipResolver { 56 | return nil 57 | } 58 | -------------------------------------------------------------------------------- /codegen/fixtures/starwars/resolver_gen.go: -------------------------------------------------------------------------------- 1 | // This code is genereated by graphql-codegen 2 | // DO NOT EDIT! 3 | 4 | package starwars 5 | 6 | // Resolver Resolver is the main resolver for all queries 7 | type Resolver struct { 8 | } 9 | -------------------------------------------------------------------------------- /codegen/fixtures/starwars/review_gen.go: -------------------------------------------------------------------------------- 1 | // This code is genereated by graphql-codegen 2 | // DO NOT EDIT! 3 | 4 | package starwars 5 | 6 | import ( 7 | "encoding/json" 8 | ) 9 | 10 | // Review Represents a review for a movie 11 | type Review struct { 12 | // Stars The number of stars this review gave, 1-5 13 | Stars int32 `json:"stars"` 14 | // Commentary Comment about the movie 15 | Commentary *string `json:"commentary"` 16 | } 17 | 18 | // ReviewResolver resolver for Review 19 | type ReviewResolver struct { 20 | Review 21 | } 22 | 23 | // Stars The number of stars this review gave, 1-5 24 | func (r *ReviewResolver) Stars() int32 { 25 | return r.Review.Stars 26 | } 27 | 28 | // Commentary Comment about the movie 29 | func (r *ReviewResolver) Commentary() *string { 30 | return r.Review.Commentary 31 | } 32 | 33 | func (r *ReviewResolver) MarshalJSON() ([]byte, error) { 34 | return json.Marshal(&r.Review) 35 | } 36 | 37 | func (r *ReviewResolver) UnmarshalJSON(data []byte) error { 38 | return json.Unmarshal(data, &r.Review) 39 | } 40 | -------------------------------------------------------------------------------- /codegen/fixtures/starwars/reviewinput_gen.go: -------------------------------------------------------------------------------- 1 | // This code is genereated by graphql-codegen 2 | // DO NOT EDIT! 3 | 4 | package starwars 5 | 6 | // ReviewInput The input object sent when someone is creating a new review 7 | type ReviewInput struct { 8 | // Stars 0-5 stars 9 | Stars int32 `json:"stars"` 10 | // Commentary Comment about the movie, optional 11 | Commentary *string `json:"commentary"` 12 | } 13 | -------------------------------------------------------------------------------- /codegen/fixtures/starwars/schema.graphql: -------------------------------------------------------------------------------- 1 | schema { 2 | query: Query 3 | mutation: Mutation 4 | } 5 | # The query type, represents all of the entry points into our object graph 6 | type Query { 7 | hero(episode: Episode = NEWHOPE): Character 8 | reviews(episode: Episode!): [Review]! 9 | search(text: String!): [SearchResult]! 10 | character(id: ID!): Character 11 | droid(id: ID!): Droid 12 | human(id: ID!): Human 13 | starship(id: ID!): Starship 14 | } 15 | 16 | # The mutation type, represents all updates we can make to our data 17 | type Mutation { 18 | createReview(episode: Episode!, review: ReviewInput!): Review 19 | } 20 | 21 | # The episodes in the Star Wars trilogy 22 | enum Episode { 23 | # Star Wars Episode IV: A New Hope, released in 1977. 24 | NEWHOPE 25 | # Star Wars Episode V: The Empire Strikes Back, released in 1980. 26 | EMPIRE 27 | # Star Wars Episode VI: Return of the Jedi, released in 1983. 28 | JEDI 29 | } 30 | 31 | # A character from the Star Wars universe 32 | interface Character { 33 | # The ID of the character 34 | id: ID! 35 | # The name of the character 36 | name: String! 37 | # The friends of the character, or an empty list if they have none 38 | friends: [Character] 39 | # The friends of the character exposed as a connection with edges 40 | friendsConnection(first: Int, after: ID): FriendsConnection! 41 | # The movies this character appears in 42 | appearsIn: [Episode!]! 43 | } 44 | 45 | # Units of height 46 | enum LengthUnit { 47 | # The standard unit around the world 48 | METER 49 | # Primarily used in the United States 50 | FOOT 51 | } 52 | 53 | # A humanoid creature from the Star Wars universe 54 | type Human implements Character { 55 | # The ID of the human 56 | id: ID! 57 | # What this human calls themselves 58 | name: String! 59 | # Height in the preferred unit, default is meters 60 | height(unit: LengthUnit = METER): Float! 61 | # Mass in kilograms, or null if unknown 62 | mass: Float 63 | # This human's friends, or an empty list if they have none 64 | friends: [Character] 65 | # The friends of the human exposed as a connection with edges 66 | friendsConnection(first: Int, after: ID): FriendsConnection! 67 | # The movies this human appears in 68 | appearsIn: [Episode!]! 69 | # A list of starships this person has piloted, or an empty list if none 70 | starships: [Starship] 71 | } 72 | 73 | # An autonomous mechanical character in the Star Wars universe 74 | type Droid implements Character { 75 | # The ID of the droid 76 | id: ID! 77 | # What others call this droid 78 | name: String! 79 | # This droid's friends, or an empty list if they have none 80 | friends: [Character] 81 | # The friends of the droid exposed as a connection with edges 82 | friendsConnection(first: Int, after: ID): FriendsConnection! 83 | # The movies this droid appears in 84 | appearsIn: [Episode!]! 85 | # This droid's primary function 86 | primaryFunction: String 87 | } 88 | 89 | # A connection object for a character's friends 90 | type FriendsConnection { 91 | # The total number of friends 92 | totalCount: Int! 93 | # The edges for each of the character's friends. 94 | edges: [FriendsEdge] 95 | # A list of the friends, as a convenience when edges are not needed. 96 | friends: [Character] 97 | # Information for paginating this connection 98 | pageInfo: PageInfo! 99 | } 100 | 101 | # An edge object for a character's friends 102 | type FriendsEdge { 103 | # A cursor used for pagination 104 | cursor: ID! 105 | # The character represented by this friendship edge 106 | node: Character 107 | } 108 | 109 | # Information for paginating this connection 110 | type PageInfo { 111 | startCursor: ID 112 | endCursor: ID 113 | hasNextPage: Boolean! 114 | } 115 | 116 | # Represents a review for a movie 117 | type Review { 118 | # The number of stars this review gave, 1-5 119 | stars: Int! 120 | # Comment about the movie 121 | commentary: String 122 | } 123 | 124 | # The input object sent when someone is creating a new review 125 | input ReviewInput { 126 | # 0-5 stars 127 | stars: Int! 128 | # Comment about the movie, optional 129 | commentary: String 130 | } 131 | 132 | type Starship { 133 | # The ID of the starship 134 | id: ID! 135 | # The name of the starship 136 | name: String! 137 | # Length of the starship, along the longest axis 138 | length(unit: LengthUnit = METER): Float! 139 | } 140 | 141 | union SearchResult = Human | Droid | Starship 142 | -------------------------------------------------------------------------------- /codegen/fixtures/starwars/searchresult_gen.go: -------------------------------------------------------------------------------- 1 | // This code is genereated by graphql-codegen 2 | // DO NOT EDIT! 3 | 4 | package starwars 5 | 6 | // SearchResultResolver resolver for SearchResult 7 | type SearchResultResolver struct { 8 | searchResult interface{} 9 | } 10 | 11 | func (r *SearchResultResolver) ToHuman() (*HumanResolver, bool) { 12 | c, ok := r.searchResult.(*HumanResolver) 13 | return c, ok 14 | } 15 | 16 | func (r *SearchResultResolver) ToDroid() (*DroidResolver, bool) { 17 | c, ok := r.searchResult.(*DroidResolver) 18 | return c, ok 19 | } 20 | 21 | func (r *SearchResultResolver) ToStarship() (*StarshipResolver, bool) { 22 | c, ok := r.searchResult.(*StarshipResolver) 23 | return c, ok 24 | } 25 | -------------------------------------------------------------------------------- /codegen/fixtures/starwars/starship_gen.go: -------------------------------------------------------------------------------- 1 | // This code is genereated by graphql-codegen 2 | // DO NOT EDIT! 3 | 4 | package starwars 5 | 6 | import ( 7 | "encoding/json" 8 | 9 | graphql "github.com/neelance/graphql-go" 10 | ) 11 | 12 | // Starship 13 | type Starship struct { 14 | // ID The ID of the starship 15 | ID graphql.ID `json:"id"` 16 | // Name The name of the starship 17 | Name string `json:"name"` 18 | // Length Length of the starship, along the longest axis 19 | Length float64 `json:"length"` 20 | } 21 | 22 | // StarshipResolver resolver for Starship 23 | type StarshipResolver struct { 24 | Starship 25 | } 26 | 27 | // ID The ID of the starship 28 | func (r *StarshipResolver) ID() graphql.ID { 29 | return r.Starship.ID 30 | } 31 | 32 | // Name The name of the starship 33 | func (r *StarshipResolver) Name() string { 34 | return r.Starship.Name 35 | } 36 | 37 | // Length Length of the starship, along the longest axis 38 | func (r *StarshipResolver) Length(args *struct { 39 | Unit *LengthUnit 40 | }) float64 { 41 | return r.Starship.Length 42 | } 43 | 44 | func (r *StarshipResolver) MarshalJSON() ([]byte, error) { 45 | return json.Marshal(&r.Starship) 46 | } 47 | 48 | func (r *StarshipResolver) UnmarshalJSON(data []byte) error { 49 | return json.Unmarshal(data, &r.Starship) 50 | } 51 | -------------------------------------------------------------------------------- /codegen/formatcode.go: -------------------------------------------------------------------------------- 1 | package codegen 2 | 3 | import ( 4 | "bytes" 5 | "os" 6 | "os/exec" 7 | "strings" 8 | ) 9 | 10 | func FormatCode(code string) ([]byte, error) { 11 | fmtCmd := exec.Command("gofmt", "-s") 12 | fmtCmd.Stdin = strings.NewReader(code) 13 | var out bytes.Buffer 14 | fmtCmd.Stdout = &out 15 | fmtCmd.Stderr = os.Stderr 16 | if err := fmtCmd.Run(); err != nil { 17 | return []byte(code), err 18 | } 19 | 20 | if out.Len() == 0 { 21 | return []byte(code), nil 22 | } 23 | 24 | return out.Bytes(), nil 25 | } 26 | -------------------------------------------------------------------------------- /codegen/testhelpers.go: -------------------------------------------------------------------------------- 1 | package codegen 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Applifier/graphql-codegen/config" 7 | ) 8 | 9 | func RunTest(schema string, conf config.Config, expected map[string]string, t *testing.T) map[string]string { 10 | fileMap, err := NewCodeGen(schema, conf).Generate() 11 | if err != nil { 12 | t.Log("Schema parsing failed") 13 | t.Fatal(err) 14 | } 15 | 16 | for file, resultingCode := range fileMap { 17 | code, err := FormatCode(expected[file]) 18 | if err != nil { 19 | t.Fatal(err) 20 | } 21 | 22 | if string(code) != resultingCode { 23 | t.Errorf("Generated file %s content\n%s\n\nshould have matched\n\n%s", file, resultingCode, code) 24 | } 25 | } 26 | 27 | return fileMap 28 | } 29 | -------------------------------------------------------------------------------- /config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | type FieldConfig struct { 4 | Template map[string]map[string]interface{} 5 | Imports []string 6 | } 7 | 8 | type TypeConfig struct { 9 | Template map[string]map[string]interface{} 10 | Field map[string]FieldConfig 11 | Imports []string 12 | } 13 | 14 | type Config struct { 15 | Package string 16 | Type map[string]TypeConfig 17 | } 18 | -------------------------------------------------------------------------------- /config/parse.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import "github.com/hashicorp/hcl" 4 | 5 | // Parse parses codegen config 6 | func Parse(config string) (cfg Config, err error) { 7 | err = hcl.Decode(&cfg, config) 8 | return 9 | } 10 | -------------------------------------------------------------------------------- /config/parse_test.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | func TestConfigParse(t *testing.T) { 9 | tests := []struct { 10 | conf string 11 | expected Config 12 | }{ 13 | { 14 | conf: ` 15 | package = "main" 16 | `, 17 | expected: Config{ 18 | Package: "main", 19 | }, 20 | }, 21 | { 22 | conf: ` 23 | package = "main" 24 | 25 | type "SomeType" { 26 | field "someField" { 27 | template "some_template" { 28 | arg1 = "arg1" 29 | } 30 | } 31 | } 32 | 33 | type "SomeOtherType" { 34 | field "someOtherField" { 35 | template "some_template" { 36 | arg1 = "arg1" 37 | } 38 | } 39 | 40 | field "someOtherField2" { 41 | template "some_template" { 42 | arg1 = "arg1" 43 | } 44 | } 45 | } 46 | `, 47 | expected: Config{ 48 | Package: "main", 49 | Type: map[string]TypeConfig{ 50 | "SomeType": TypeConfig{ 51 | Field: map[string]FieldConfig{ 52 | "someField": { 53 | Template: map[string]map[string]interface{}{ 54 | "some_template": map[string]interface{}{ 55 | "arg1": "arg1", 56 | }, 57 | }, 58 | }, 59 | }, 60 | }, 61 | "SomeOtherType": TypeConfig{ 62 | Field: map[string]FieldConfig{ 63 | "someOtherField": { 64 | Template: map[string]map[string]interface{}{ 65 | "some_template": map[string]interface{}{ 66 | "arg1": "arg1", 67 | }, 68 | }, 69 | }, 70 | "someOtherField2": { 71 | Template: map[string]map[string]interface{}{ 72 | "some_template": map[string]interface{}{ 73 | "arg1": "arg1", 74 | }, 75 | }, 76 | }, 77 | }, 78 | }, 79 | }, 80 | }, 81 | }, 82 | } 83 | 84 | for _, test := range tests { 85 | cfg, err := Parse(test.conf) 86 | if err != nil { 87 | t.Fatal(err) 88 | } 89 | 90 | if !reflect.DeepEqual(cfg, test.expected) { 91 | t.Errorf("Expected\n%+v\nto equal\n%+v", cfg, test.expected) 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/Applifier/graphql-codegen/cmd" 4 | 5 | func main() { 6 | cmd.Execute() 7 | } 8 | -------------------------------------------------------------------------------- /template/assets.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-bindata. 2 | // sources: 3 | // property/custom/config.hcl 4 | // property/custom/field.tmpl 5 | // property/custom/method.tmpl 6 | // property/default/config.hcl 7 | // property/default/field.tmpl 8 | // property/default/method.tmpl 9 | // property/http_resolver/config.hcl 10 | // property/http_resolver/field.tmpl 11 | // property/http_resolver/method.tmpl 12 | // type/default/config.hcl 13 | // type/default/type.tmpl 14 | // DO NOT EDIT! 15 | 16 | package template 17 | 18 | import ( 19 | "bytes" 20 | "compress/gzip" 21 | "fmt" 22 | "io" 23 | "io/ioutil" 24 | "os" 25 | "path/filepath" 26 | "strings" 27 | "time" 28 | ) 29 | 30 | func bindataRead(data []byte, name string) ([]byte, error) { 31 | gz, err := gzip.NewReader(bytes.NewBuffer(data)) 32 | if err != nil { 33 | return nil, fmt.Errorf("Read %q: %v", name, err) 34 | } 35 | 36 | var buf bytes.Buffer 37 | _, err = io.Copy(&buf, gz) 38 | clErr := gz.Close() 39 | 40 | if err != nil { 41 | return nil, fmt.Errorf("Read %q: %v", name, err) 42 | } 43 | if clErr != nil { 44 | return nil, err 45 | } 46 | 47 | return buf.Bytes(), nil 48 | } 49 | 50 | type asset struct { 51 | bytes []byte 52 | info os.FileInfo 53 | } 54 | 55 | type bindataFileInfo struct { 56 | name string 57 | size int64 58 | mode os.FileMode 59 | modTime time.Time 60 | } 61 | 62 | func (fi bindataFileInfo) Name() string { 63 | return fi.name 64 | } 65 | func (fi bindataFileInfo) Size() int64 { 66 | return fi.size 67 | } 68 | func (fi bindataFileInfo) Mode() os.FileMode { 69 | return fi.mode 70 | } 71 | func (fi bindataFileInfo) ModTime() time.Time { 72 | return fi.modTime 73 | } 74 | func (fi bindataFileInfo) IsDir() bool { 75 | return false 76 | } 77 | func (fi bindataFileInfo) Sys() interface{} { 78 | return nil 79 | } 80 | 81 | var _propertyCustomConfigHcl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x4a\xcb\x4c\xcd\x49\x51\xb0\x55\x50\x02\x33\xf4\x4a\x72\x0b\x72\x94\xb8\x72\x53\x4b\x32\xf2\xc1\xa2\x10\x16\x54\x18\x10\x00\x00\xff\xff\xda\x37\xa8\x72\x2c\x00\x00\x00") 82 | 83 | func propertyCustomConfigHclBytes() ([]byte, error) { 84 | return bindataRead( 85 | _propertyCustomConfigHcl, 86 | "property/custom/config.hcl", 87 | ) 88 | } 89 | 90 | func propertyCustomConfigHcl() (*asset, error) { 91 | bytes, err := propertyCustomConfigHclBytes() 92 | if err != nil { 93 | return nil, err 94 | } 95 | 96 | info := bindataFileInfo{name: "property/custom/config.hcl", size: 44, mode: os.FileMode(420), modTime: time.Unix(1488801363, 0)} 97 | a := &asset{bytes: bytes, info: info} 98 | return a, nil 99 | } 100 | 101 | var _propertyCustomFieldTmpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xaa\xae\x2e\x4a\xcc\x4b\x4f\x55\xd0\x0b\x49\xcd\x2d\xc8\x49\x2c\x49\x75\xce\xcf\x4b\xcb\x4c\xd7\x4b\xcb\x4c\xcd\x49\x29\xae\xad\xe5\x52\x50\xa8\xae\x4e\x4e\x2c\xc8\x2c\x49\xcc\xc9\xac\x02\xaa\x03\x4b\xc4\xe7\x25\xe6\xa6\xd6\xd6\x02\xa5\xa0\xfc\x92\xca\x02\x10\x3f\x21\xab\x38\x3f\xcf\x4a\x09\x2e\x0c\x51\xa6\x94\xc0\x55\x5d\x9d\x9a\x97\x02\x34\x0d\x10\x00\x00\xff\xff\x68\x48\x08\x80\x6f\x00\x00\x00") 102 | 103 | func propertyCustomFieldTmplBytes() ([]byte, error) { 104 | return bindataRead( 105 | _propertyCustomFieldTmpl, 106 | "property/custom/field.tmpl", 107 | ) 108 | } 109 | 110 | func propertyCustomFieldTmpl() (*asset, error) { 111 | bytes, err := propertyCustomFieldTmplBytes() 112 | if err != nil { 113 | return nil, err 114 | } 115 | 116 | info := bindataFileInfo{name: "property/custom/field.tmpl", size: 111, mode: os.FileMode(420), modTime: time.Unix(1488801393, 0)} 117 | a := &asset{bytes: bytes, info: info} 118 | return a, nil 119 | } 120 | 121 | var _propertyCustomMethodTmpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x01\x00\x00\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00") 122 | 123 | func propertyCustomMethodTmplBytes() ([]byte, error) { 124 | return bindataRead( 125 | _propertyCustomMethodTmpl, 126 | "property/custom/method.tmpl", 127 | ) 128 | } 129 | 130 | func propertyCustomMethodTmpl() (*asset, error) { 131 | bytes, err := propertyCustomMethodTmplBytes() 132 | if err != nil { 133 | return nil, err 134 | } 135 | 136 | info := bindataFileInfo{name: "property/custom/method.tmpl", size: 0, mode: os.FileMode(420), modTime: time.Unix(1488801374, 0)} 137 | a := &asset{bytes: bytes, info: info} 138 | return a, nil 139 | } 140 | 141 | var _propertyDefaultConfigHcl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x4a\xcb\x4c\xcd\x49\x51\xb0\x55\x50\x02\x33\xf4\x4a\x72\x0b\x72\x94\xb8\x72\x53\x4b\x32\xf2\xc1\xa2\x10\x16\x54\x18\x10\x00\x00\xff\xff\xda\x37\xa8\x72\x2c\x00\x00\x00") 142 | 143 | func propertyDefaultConfigHclBytes() ([]byte, error) { 144 | return bindataRead( 145 | _propertyDefaultConfigHcl, 146 | "property/default/config.hcl", 147 | ) 148 | } 149 | 150 | func propertyDefaultConfigHcl() (*asset, error) { 151 | bytes, err := propertyDefaultConfigHclBytes() 152 | if err != nil { 153 | return nil, err 154 | } 155 | 156 | info := bindataFileInfo{name: "property/default/config.hcl", size: 44, mode: os.FileMode(420), modTime: time.Unix(1488374780, 0)} 157 | a := &asset{bytes: bytes, info: info} 158 | return a, nil 159 | } 160 | 161 | var _propertyDefaultFieldTmpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xd2\xd7\x57\xa8\xae\x4e\x4e\x2c\xc8\x2c\x49\xcc\xc9\xac\x4a\x55\xd0\x73\xcb\x4c\xcd\x49\xf1\x4b\xcc\x4d\xad\xad\x05\xca\x40\xb8\x2e\xa9\xc5\xc9\x45\x99\x05\x25\x99\xf9\x79\xb5\xb5\x5c\x84\xd5\x87\x54\x16\x80\xb8\x09\x59\xc5\xf9\x79\x56\x4a\x30\x51\x88\x22\xa5\x04\x2e\x40\x00\x00\x00\xff\xff\x1c\x2b\xdd\xa2\x74\x00\x00\x00") 162 | 163 | func propertyDefaultFieldTmplBytes() ([]byte, error) { 164 | return bindataRead( 165 | _propertyDefaultFieldTmpl, 166 | "property/default/field.tmpl", 167 | ) 168 | } 169 | 170 | func propertyDefaultFieldTmpl() (*asset, error) { 171 | bytes, err := propertyDefaultFieldTmplBytes() 172 | if err != nil { 173 | return nil, err 174 | } 175 | 176 | info := bindataFileInfo{name: "property/default/field.tmpl", size: 116, mode: os.FileMode(420), modTime: time.Unix(1488485204, 0)} 177 | a := &asset{bytes: bytes, info: info} 178 | return a, nil 179 | } 180 | 181 | var _propertyDefaultMethodTmpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xc4\x51\xcb\x4e\xeb\x30\x10\xdd\xf7\x2b\x46\xd1\x5d\xb4\x5d\xb8\x77\x8d\xc4\xa2\x94\x22\x01\xa2\x48\x55\xf7\xc8\x4a\x27\xa9\x25\xc7\x09\xb6\x83\x54\x5c\xff\x3b\x13\x3b\xa9\x1b\x04\x2c\x61\xe7\xc7\x99\x33\xe7\xe1\x1c\xec\xb1\x10\x0a\x21\xe3\xba\x6c\x2b\x54\xd6\x64\xe0\x3d\x5d\x0c\xcc\x8d\xd5\x6d\x6e\xdd\x04\xc0\x39\xcd\x55\x89\xc0\xbc\x77\x8e\x6d\x78\x85\x70\x82\x9c\x37\xc2\x72\x29\xde\xd1\x7b\x42\xb0\xdd\xb1\xa1\x53\x40\xa3\xda\xd3\x89\xb0\x40\x27\xe2\x9b\x38\x37\xec\xd1\x98\xa3\x78\x43\x9d\x75\x54\xa2\x00\x61\x5e\x68\xab\x3e\x02\x23\xdc\x16\x4d\x2d\xe9\x93\x18\xa4\xc1\xb0\x6c\xf4\xd8\xd1\x0e\xec\x61\x1a\x5f\x21\xec\x7d\x14\xb4\x27\x7b\xbe\x79\x58\xaf\x76\x59\xf8\xfc\x77\xe0\x66\x39\x78\x82\xab\x6b\x28\x2d\x4c\xd9\x13\xda\x43\xbd\x4f\xef\x27\x90\xa8\x66\xf0\x9f\x46\x16\x0b\x12\x9e\x3c\x41\x8f\xed\xcc\x46\x7f\xf1\x7e\x8b\x26\xd7\xa2\xb1\xa2\x56\x34\x54\xb4\x2a\x87\xa9\x86\xb9\x73\x16\xab\x46\x72\x7b\x69\x31\x6a\x8b\x0c\xb3\x1f\xd8\xa7\xc1\xcb\x48\x71\xe7\x33\x31\x5e\x94\xf3\xd9\xc2\x39\x90\x59\xd2\xb8\x45\xdb\x6a\x15\xfb\x80\xd8\xdf\x28\xe9\xa4\x4a\x07\x24\x28\x21\x87\xc8\xfb\x17\xcd\xfa\x46\x23\x8e\x7d\x25\x3e\xae\x49\x8d\x74\xb1\x7f\xdb\xcd\xfd\x66\xb7\xde\xde\x2d\x57\xeb\xdf\xac\xe7\x6f\x22\x3f\xc7\xf0\x11\x00\x00\xff\xff\xa5\x2d\xa9\x13\x5f\x03\x00\x00") 182 | 183 | func propertyDefaultMethodTmplBytes() ([]byte, error) { 184 | return bindataRead( 185 | _propertyDefaultMethodTmpl, 186 | "property/default/method.tmpl", 187 | ) 188 | } 189 | 190 | func propertyDefaultMethodTmpl() (*asset, error) { 191 | bytes, err := propertyDefaultMethodTmplBytes() 192 | if err != nil { 193 | return nil, err 194 | } 195 | 196 | info := bindataFileInfo{name: "property/default/method.tmpl", size: 863, mode: os.FileMode(420), modTime: time.Unix(1488485204, 0)} 197 | a := &asset{bytes: bytes, info: info} 198 | return a, nil 199 | } 200 | 201 | var _propertyHttp_resolverConfigHcl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x4a\xcb\x4c\xcd\x49\x51\xb0\x55\x50\x02\x33\xf4\x4a\x72\x0b\x72\x94\xb8\x72\x53\x4b\x32\xf2\xc1\xa2\x10\x16\x54\x38\x33\xb7\x20\xbf\xa8\xa4\x18\x28\x1e\xad\x14\xa3\x94\x97\x5a\xa2\x9f\x51\x52\x52\x10\xa3\xa4\xa4\xa3\x00\xe4\xa7\xe6\x25\xe7\xa7\x64\xe6\xa5\xeb\x67\x15\xe7\xe7\x01\x05\x63\xb9\x00\x01\x00\x00\xff\xff\x59\x8a\x5b\x6d\x5c\x00\x00\x00") 202 | 203 | func propertyHttp_resolverConfigHclBytes() ([]byte, error) { 204 | return bindataRead( 205 | _propertyHttp_resolverConfigHcl, 206 | "property/http_resolver/config.hcl", 207 | ) 208 | } 209 | 210 | func propertyHttp_resolverConfigHcl() (*asset, error) { 211 | bytes, err := propertyHttp_resolverConfigHclBytes() 212 | if err != nil { 213 | return nil, err 214 | } 215 | 216 | info := bindataFileInfo{name: "property/http_resolver/config.hcl", size: 92, mode: os.FileMode(420), modTime: time.Unix(1488545767, 0)} 217 | a := &asset{bytes: bytes, info: info} 218 | return a, nil 219 | } 220 | 221 | var _propertyHttp_resolverFieldTmpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xaa\xae\x2e\x4a\xcc\x4b\x4f\x55\xd0\x0b\x49\xcd\x2d\xc8\x49\x2c\x49\x75\xce\xcf\x4b\xcb\x4c\xd7\x4b\xcb\x4c\xcd\x49\x29\xae\xad\xe5\x52\x50\xa8\xae\x4e\x4e\x2c\xc8\x2c\x49\xcc\xc9\xac\x02\xaa\x03\x4b\xc4\xe7\x25\xe6\xa6\xd6\xd6\x02\xa5\xa0\xfc\x92\xca\x02\x10\x3f\x21\xab\x38\x3f\xcf\x4a\x09\x2e\x0c\x51\xa6\x94\xc0\x55\x5d\x9d\x9a\x97\x02\x34\x0d\x10\x00\x00\xff\xff\x68\x48\x08\x80\x6f\x00\x00\x00") 222 | 223 | func propertyHttp_resolverFieldTmplBytes() ([]byte, error) { 224 | return bindataRead( 225 | _propertyHttp_resolverFieldTmpl, 226 | "property/http_resolver/field.tmpl", 227 | ) 228 | } 229 | 230 | func propertyHttp_resolverFieldTmpl() (*asset, error) { 231 | bytes, err := propertyHttp_resolverFieldTmplBytes() 232 | if err != nil { 233 | return nil, err 234 | } 235 | 236 | info := bindataFileInfo{name: "property/http_resolver/field.tmpl", size: 111, mode: os.FileMode(420), modTime: time.Unix(1488552731, 0)} 237 | a := &asset{bytes: bytes, info: info} 238 | return a, nil 239 | } 240 | 241 | var _propertyHttp_resolverMethodTmpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x7c\x51\xcd\x8e\xda\x30\x10\x3e\x37\x4f\x31\x45\x55\x95\xa0\xca\xf4\x5c\x89\x43\x0b\x52\x4f\xe5\x80\xb8\x23\x37\x99\x04\x57\xc6\x8e\xc6\x0e\x15\x6b\xf2\xee\x3b\xb6\x21\xc0\x6a\xb5\xb7\xf1\xcc\x37\xdf\xcf\x38\x04\x68\xb0\x55\x06\x61\x26\xa9\x1b\x8e\x68\xbc\x9b\xc1\x38\xf2\xc3\xc1\xdc\x79\x1a\x6a\x1f\x0a\x80\x10\x48\x9a\x0e\x41\x8c\x63\x08\x62\x23\x8f\x08\x17\xa8\x65\xaf\xbc\xd4\xea\x05\xc7\x91\x11\x62\x77\xee\xb9\x4a\x68\x34\x0d\x57\x8c\x05\xae\x98\xaf\x08\xe1\xa6\x43\x58\xa3\x3a\x21\xcd\x22\x95\x6a\x41\xb9\x3d\xab\xd2\x19\x04\xe3\xb6\xe8\xac\xe6\x21\x33\x68\x87\x49\xec\xa9\x19\x69\x6f\xec\x21\x7c\x39\x48\xf7\xf3\x66\x1b\x7e\x2c\xa1\xf3\x50\x8a\x3f\xe8\x0f\xb6\xb9\xf7\x2f\xa0\xd1\x54\xf0\x9d\x57\x16\x0b\xf6\x76\xb7\x0d\x57\x6c\xcc\x93\x23\xe4\xf7\x1a\x5d\x4d\xaa\xf7\xca\x1a\x5e\x6a\x07\x53\x43\x49\x30\x0f\xc1\xe3\xb1\xd7\xd2\x3f\xa6\x80\x14\x3b\x33\x54\x1f\xb0\x97\x29\xec\x93\xe3\x18\xe5\xce\xf8\x70\xff\xb7\x11\xa6\xcc\x15\x94\x93\xc9\x2d\xfa\x81\x4c\xbe\xf9\x37\x40\x22\x4b\xac\xcf\xd7\x3f\x49\x02\x42\x37\x68\x0f\xef\x82\x19\xc2\xe3\x3e\xed\xc4\xa3\x1d\xbc\xef\xc5\x6f\xf4\x4c\xed\x86\xbf\xfb\xc9\x91\xd8\x5d\xab\x95\x35\xad\xea\xc4\x40\x3a\xfe\x7f\xc5\xfb\x9c\x24\x2e\x7f\x5e\x82\x51\x3a\x89\x7e\xa2\xa4\x10\xdf\x89\x98\x5b\x51\x88\x3f\x1d\x93\x9b\x5e\xfc\xb2\xcd\x59\xac\xb4\x75\x58\x56\x05\x8f\x22\xc1\x12\xfe\x39\x6b\xc4\x06\xff\xaf\xb1\xb6\x0d\x52\x39\x41\x2b\x91\x5b\xe5\xd7\x9c\xa5\x4a\xb6\x93\x46\x6e\x64\x99\xb1\x78\x0d\x00\x00\xff\xff\x98\x78\x89\x36\xc3\x02\x00\x00") 242 | 243 | func propertyHttp_resolverMethodTmplBytes() ([]byte, error) { 244 | return bindataRead( 245 | _propertyHttp_resolverMethodTmpl, 246 | "property/http_resolver/method.tmpl", 247 | ) 248 | } 249 | 250 | func propertyHttp_resolverMethodTmpl() (*asset, error) { 251 | bytes, err := propertyHttp_resolverMethodTmplBytes() 252 | if err != nil { 253 | return nil, err 254 | } 255 | 256 | info := bindataFileInfo{name: "property/http_resolver/method.tmpl", size: 707, mode: os.FileMode(420), modTime: time.Unix(1488542641, 0)} 257 | a := &asset{bytes: bytes, info: info} 258 | return a, nil 259 | } 260 | 261 | var _typeDefaultConfigHcl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x2a\xa9\x2c\x48\x55\xb0\x55\x50\x02\xd1\x7a\x25\xb9\x05\x39\x4a\x5c\x80\x00\x00\x00\xff\xff\x3a\x12\xfd\xa1\x13\x00\x00\x00") 262 | 263 | func typeDefaultConfigHclBytes() ([]byte, error) { 264 | return bindataRead( 265 | _typeDefaultConfigHcl, 266 | "type/default/config.hcl", 267 | ) 268 | } 269 | 270 | func typeDefaultConfigHcl() (*asset, error) { 271 | bytes, err := typeDefaultConfigHclBytes() 272 | if err != nil { 273 | return nil, err 274 | } 275 | 276 | info := bindataFileInfo{name: "type/default/config.hcl", size: 19, mode: os.FileMode(420), modTime: time.Unix(1488546073, 0)} 277 | a := &asset{bytes: bytes, info: info} 278 | return a, nil 279 | } 280 | 281 | var _typeDefaultTypeTmpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xd4\x56\x41\x73\xda\x3a\x10\x3e\x3f\xff\x8a\x7d\x9e\xcc\x1b\x9c\xe1\x39\xf7\x76\x72\x48\x89\xd3\x21\x4d\x20\x05\x93\x4b\xd3\xc9\x08\x23\x40\x8d\x90\x1c\x59\xce\x0c\x75\xfd\xdf\x2b\x59\xb6\x91\xc1\x84\x66\x9a\x4c\xa7\x27\xf0\xee\x6a\xbf\x4f\xfb\xed\x7a\x7d\x72\x02\xe1\x92\x24\x10\xf1\x19\x06\xf5\xbb\xc0\x0c\x0b\x8c\x24\x9e\xc1\x74\x0d\x0b\x81\xe2\xe5\x23\xfd\x5f\x7b\x95\xc7\x51\xd1\xe7\x43\x18\x0c\x43\x08\xce\xfb\xe1\xbf\x8e\x13\xa3\xe8\x01\x2d\x30\x64\x99\xdf\xe3\x6c\x4e\x16\xfe\x8d\xb1\xe4\xf9\x7b\xc7\x71\xc8\x2a\xe6\x42\x42\xc7\xc9\x32\x32\x07\xfc\x08\xfe\x27\xc2\x66\xe0\x0e\x3f\x5c\x06\xbd\xd0\xcd\x73\x07\xa0\x70\x31\xae\xa2\x48\x72\x8f\x99\x14\x6b\xf0\xc3\x75\x8c\x07\x68\x85\x3d\xd8\x0e\x61\x11\x4d\x67\x38\xb9\x4f\xa4\x20\x6c\x01\x7e\xbf\x40\x48\xc0\xbd\x73\x31\x53\x34\x95\xf1\xe4\x5b\xc2\xd9\x9d\xeb\x7a\x79\xde\xb4\xb9\x59\x86\xd9\xac\xcc\x68\xfe\xd9\x16\x81\x98\xba\x49\x95\xb1\x30\x6a\xb3\xdf\x38\xe0\xed\xbf\xca\xc1\x8b\xa8\xea\xa9\x74\x95\x29\xcf\xab\xa7\x73\x9c\x44\x82\xc4\x92\x70\xa6\xa2\xa4\xb2\x6c\xc5\xa9\xcb\xa6\x91\x84\xcc\xa6\x79\x41\x30\x9d\x29\x96\x05\xc1\x8a\x5d\xee\xec\x80\x8c\x70\xc2\xe9\x13\x16\x20\xaa\x3f\x73\x2e\x9a\x21\x2d\x90\xf5\xa9\x06\xb4\x7d\x66\x53\xbb\x9a\xd2\x35\x96\x4b\x5e\x73\xb2\xfc\x07\xea\x32\x4f\x59\x04\x1d\x01\xc7\xad\x14\x3c\xb8\x46\x22\x59\x22\x7a\x39\x1e\x0e\x3a\x1e\x74\xbe\x7c\x9d\xae\x25\xee\x02\x16\x82\x2b\xaf\xa6\x26\xb0\x4c\x05\x03\x2d\xb2\x5f\x46\x77\xfe\x13\x7e\x23\x9f\xa7\xab\x73\x08\x6a\xc2\x56\x16\xd8\x0c\x49\x04\x06\xce\x33\x70\x3b\x68\xf5\x81\x22\xb8\x0b\x6d\xa8\xdb\xcd\xb6\xdd\x42\xfd\x41\x18\x8c\x2e\xce\x7a\x81\xfb\x3b\x4d\x42\x98\xc4\x62\x8e\x22\xdc\xec\x93\xa6\x28\x7f\xa8\x51\xe0\x48\x96\x06\x78\x77\xba\x51\x1f\xac\xee\x39\x8a\x79\x92\x90\x29\xc5\xda\x59\x44\xdd\x58\x06\x33\x8e\x96\x7a\x75\x42\x5b\xbd\x90\x2b\x87\x9d\x27\xcf\x75\xc3\x1c\xef\x58\xab\x23\x5d\x98\x72\x4e\x4d\x0f\x01\x44\x5d\xe0\x0f\x1a\x5a\x6b\x68\x01\xf8\xcf\x64\xf0\x9c\x7f\xa0\xee\x88\x22\x81\x4a\xd5\x90\xba\x5d\xf3\xc9\xa0\x3f\x1c\xb4\xe9\xfd\x26\x32\xc0\x0f\x50\xa5\x43\x31\x91\x88\x92\xef\x8d\x6e\xc9\xfe\x7e\x85\x76\x6e\xf7\x16\x82\x05\x83\xc9\xb5\x79\xcb\x3f\x5b\x2a\xe3\xb4\x86\xb5\x8e\xb1\x6d\x2f\x9d\x73\xab\x96\x60\x36\x9f\x13\x71\x96\x98\xcd\x5a\xaa\xf3\x84\x68\x6a\x18\x05\x2c\x5d\xdd\xea\x27\xa3\x49\x81\x64\x65\x50\x0f\x45\x6c\x81\xb9\x4d\xb7\x5c\x76\xed\xe1\xa7\x4d\x4f\xc7\xdd\xf8\x5c\xcf\xb1\x57\xe4\xbe\x17\xdd\xcd\x24\xbc\xdf\x6c\xcc\x57\x5d\x88\x7d\x16\xa7\x72\xcf\x56\xdc\x47\x68\x14\x8c\x87\x57\xb7\xc1\xe8\x75\xc8\xec\xc7\x19\xf7\xce\xae\xce\x5a\x51\xea\xc1\xfd\x45\xb4\xb6\x41\x37\xca\x37\x27\xfa\xe0\xa6\x53\x9f\x39\x14\xaf\xd4\x3a\x4e\x3e\xea\x8f\xbc\xcf\x57\x3a\xa8\xc3\x74\x23\x9b\x0e\xf3\x8a\xc9\x2b\x07\xaf\x9c\x97\x39\xa2\x09\x7e\xd1\x1e\x2d\x93\xab\x0f\x37\xa5\x8e\xcd\xd1\x5e\xa8\xaa\x28\xe3\x08\x51\x75\x02\x18\x56\x5f\x9e\x92\xc3\x54\x5d\xa8\x62\xa8\x2c\x2b\xc4\x52\x44\xe9\x5a\x6f\x5f\xdf\xdc\xf7\x14\x8a\x9c\x9b\x7d\xcc\x08\x75\xac\x01\xfe\x19\x00\x00\xff\xff\xf0\x2a\xe7\xfa\xda\x0a\x00\x00") 282 | 283 | func typeDefaultTypeTmplBytes() ([]byte, error) { 284 | return bindataRead( 285 | _typeDefaultTypeTmpl, 286 | "type/default/type.tmpl", 287 | ) 288 | } 289 | 290 | func typeDefaultTypeTmpl() (*asset, error) { 291 | bytes, err := typeDefaultTypeTmplBytes() 292 | if err != nil { 293 | return nil, err 294 | } 295 | 296 | info := bindataFileInfo{name: "type/default/type.tmpl", size: 2778, mode: os.FileMode(420), modTime: time.Unix(1488546839, 0)} 297 | a := &asset{bytes: bytes, info: info} 298 | return a, nil 299 | } 300 | 301 | // Asset loads and returns the asset for the given name. 302 | // It returns an error if the asset could not be found or 303 | // could not be loaded. 304 | func Asset(name string) ([]byte, error) { 305 | cannonicalName := strings.Replace(name, "\\", "/", -1) 306 | if f, ok := _bindata[cannonicalName]; ok { 307 | a, err := f() 308 | if err != nil { 309 | return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) 310 | } 311 | return a.bytes, nil 312 | } 313 | return nil, fmt.Errorf("Asset %s not found", name) 314 | } 315 | 316 | // MustAsset is like Asset but panics when Asset would return an error. 317 | // It simplifies safe initialization of global variables. 318 | func MustAsset(name string) []byte { 319 | a, err := Asset(name) 320 | if err != nil { 321 | panic("asset: Asset(" + name + "): " + err.Error()) 322 | } 323 | 324 | return a 325 | } 326 | 327 | // AssetInfo loads and returns the asset info for the given name. 328 | // It returns an error if the asset could not be found or 329 | // could not be loaded. 330 | func AssetInfo(name string) (os.FileInfo, error) { 331 | cannonicalName := strings.Replace(name, "\\", "/", -1) 332 | if f, ok := _bindata[cannonicalName]; ok { 333 | a, err := f() 334 | if err != nil { 335 | return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) 336 | } 337 | return a.info, nil 338 | } 339 | return nil, fmt.Errorf("AssetInfo %s not found", name) 340 | } 341 | 342 | // AssetNames returns the names of the assets. 343 | func AssetNames() []string { 344 | names := make([]string, 0, len(_bindata)) 345 | for name := range _bindata { 346 | names = append(names, name) 347 | } 348 | return names 349 | } 350 | 351 | // _bindata is a table, holding each asset generator, mapped to its name. 352 | var _bindata = map[string]func() (*asset, error){ 353 | "property/custom/config.hcl": propertyCustomConfigHcl, 354 | "property/custom/field.tmpl": propertyCustomFieldTmpl, 355 | "property/custom/method.tmpl": propertyCustomMethodTmpl, 356 | "property/default/config.hcl": propertyDefaultConfigHcl, 357 | "property/default/field.tmpl": propertyDefaultFieldTmpl, 358 | "property/default/method.tmpl": propertyDefaultMethodTmpl, 359 | "property/http_resolver/config.hcl": propertyHttp_resolverConfigHcl, 360 | "property/http_resolver/field.tmpl": propertyHttp_resolverFieldTmpl, 361 | "property/http_resolver/method.tmpl": propertyHttp_resolverMethodTmpl, 362 | "type/default/config.hcl": typeDefaultConfigHcl, 363 | "type/default/type.tmpl": typeDefaultTypeTmpl, 364 | } 365 | 366 | // AssetDir returns the file names below a certain 367 | // directory embedded in the file by go-bindata. 368 | // For example if you run go-bindata on data/... and data contains the 369 | // following hierarchy: 370 | // data/ 371 | // foo.txt 372 | // img/ 373 | // a.png 374 | // b.png 375 | // then AssetDir("data") would return []string{"foo.txt", "img"} 376 | // AssetDir("data/img") would return []string{"a.png", "b.png"} 377 | // AssetDir("foo.txt") and AssetDir("notexist") would return an error 378 | // AssetDir("") will return []string{"data"}. 379 | func AssetDir(name string) ([]string, error) { 380 | node := _bintree 381 | if len(name) != 0 { 382 | cannonicalName := strings.Replace(name, "\\", "/", -1) 383 | pathList := strings.Split(cannonicalName, "/") 384 | for _, p := range pathList { 385 | node = node.Children[p] 386 | if node == nil { 387 | return nil, fmt.Errorf("Asset %s not found", name) 388 | } 389 | } 390 | } 391 | if node.Func != nil { 392 | return nil, fmt.Errorf("Asset %s not found", name) 393 | } 394 | rv := make([]string, 0, len(node.Children)) 395 | for childName := range node.Children { 396 | rv = append(rv, childName) 397 | } 398 | return rv, nil 399 | } 400 | 401 | type bintree struct { 402 | Func func() (*asset, error) 403 | Children map[string]*bintree 404 | } 405 | var _bintree = &bintree{nil, map[string]*bintree{ 406 | "property": &bintree{nil, map[string]*bintree{ 407 | "custom": &bintree{nil, map[string]*bintree{ 408 | "config.hcl": &bintree{propertyCustomConfigHcl, map[string]*bintree{}}, 409 | "field.tmpl": &bintree{propertyCustomFieldTmpl, map[string]*bintree{}}, 410 | "method.tmpl": &bintree{propertyCustomMethodTmpl, map[string]*bintree{}}, 411 | }}, 412 | "default": &bintree{nil, map[string]*bintree{ 413 | "config.hcl": &bintree{propertyDefaultConfigHcl, map[string]*bintree{}}, 414 | "field.tmpl": &bintree{propertyDefaultFieldTmpl, map[string]*bintree{}}, 415 | "method.tmpl": &bintree{propertyDefaultMethodTmpl, map[string]*bintree{}}, 416 | }}, 417 | "http_resolver": &bintree{nil, map[string]*bintree{ 418 | "config.hcl": &bintree{propertyHttp_resolverConfigHcl, map[string]*bintree{}}, 419 | "field.tmpl": &bintree{propertyHttp_resolverFieldTmpl, map[string]*bintree{}}, 420 | "method.tmpl": &bintree{propertyHttp_resolverMethodTmpl, map[string]*bintree{}}, 421 | }}, 422 | }}, 423 | "type": &bintree{nil, map[string]*bintree{ 424 | "default": &bintree{nil, map[string]*bintree{ 425 | "config.hcl": &bintree{typeDefaultConfigHcl, map[string]*bintree{}}, 426 | "type.tmpl": &bintree{typeDefaultTypeTmpl, map[string]*bintree{}}, 427 | }}, 428 | }}, 429 | }} 430 | 431 | // RestoreAsset restores an asset under the given directory 432 | func RestoreAsset(dir, name string) error { 433 | data, err := Asset(name) 434 | if err != nil { 435 | return err 436 | } 437 | info, err := AssetInfo(name) 438 | if err != nil { 439 | return err 440 | } 441 | err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) 442 | if err != nil { 443 | return err 444 | } 445 | err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) 446 | if err != nil { 447 | return err 448 | } 449 | err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) 450 | if err != nil { 451 | return err 452 | } 453 | return nil 454 | } 455 | 456 | // RestoreAssets restores an asset under the given directory recursively 457 | func RestoreAssets(dir, name string) error { 458 | children, err := AssetDir(name) 459 | // File 460 | if err != nil { 461 | return RestoreAsset(dir, name) 462 | } 463 | // Dir 464 | for _, child := range children { 465 | err = RestoreAssets(dir, filepath.Join(name, child)) 466 | if err != nil { 467 | return err 468 | } 469 | } 470 | return nil 471 | } 472 | 473 | func _filePath(dir, name string) string { 474 | cannonicalName := strings.Replace(name, "\\", "/", -1) 475 | return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) 476 | } 477 | 478 | -------------------------------------------------------------------------------- /template/field.go: -------------------------------------------------------------------------------- 1 | package template 2 | 3 | import ( 4 | "errors" 5 | "path" 6 | 7 | "github.com/hashicorp/hcl" 8 | ) 9 | 10 | //go:generate go-bindata -pkg template -ignore=\.go -o assets.go ./... 11 | 12 | type PropertyTemplateConfig struct { 13 | Field string 14 | Method string 15 | Imports []string 16 | } 17 | 18 | type PropertyTemplate struct { 19 | Config PropertyTemplateConfig 20 | FieldTemplate string 21 | MethodTemplate string 22 | } 23 | 24 | func parseConfig(str string) (config PropertyTemplateConfig, err error) { 25 | err = hcl.Decode(&config, str) 26 | return 27 | } 28 | 29 | func loadStoredTemplate(template string) (*PropertyTemplate, bool, error) { 30 | cfgStr, err := Asset(template + "/config.hcl") 31 | if err != nil { 32 | return nil, false, nil 33 | } 34 | 35 | cfg, err := parseConfig(string(cfgStr)) 36 | if err != nil { 37 | return nil, false, err 38 | } 39 | 40 | fieldTemplateString, err := Asset(path.Join(template, cfg.Field)) 41 | if err != nil { 42 | return nil, false, err 43 | } 44 | 45 | methodTemplateString, err := Asset(path.Join(template, cfg.Method)) 46 | if err != nil { 47 | return nil, false, err 48 | } 49 | 50 | return &PropertyTemplate{ 51 | Config: cfg, 52 | FieldTemplate: string(fieldTemplateString), 53 | MethodTemplate: string(methodTemplateString), 54 | }, true, nil 55 | } 56 | 57 | func GetPropertyTemplate(templateName string) (template *PropertyTemplate, err error) { 58 | template, ok, err := loadStoredTemplate("property/" + templateName) 59 | // if ok false read file from the directory 60 | if !ok { 61 | return nil, errors.New("Fail") 62 | } 63 | return 64 | } 65 | -------------------------------------------------------------------------------- /template/property/custom/config.hcl: -------------------------------------------------------------------------------- 1 | field = "field.tmpl" 2 | method = "method.tmpl" 3 | -------------------------------------------------------------------------------- /template/property/custom/field.tmpl: -------------------------------------------------------------------------------- 1 | {{range .TemplateConfig.fields}} 2 | {{capitalize .field_name}} {{.field_type}} `json:"{{.field_name}}"` 3 | {{end}} 4 | -------------------------------------------------------------------------------- /template/property/custom/method.tmpl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Applifier/graphql-codegen/f07b1d6fc68b1339a05abf489a6a2b98585551d4/template/property/custom/method.tmpl -------------------------------------------------------------------------------- /template/property/default/config.hcl: -------------------------------------------------------------------------------- 1 | field = "field.tmpl" 2 | method = "method.tmpl" 3 | -------------------------------------------------------------------------------- /template/property/default/field.tmpl: -------------------------------------------------------------------------------- 1 | // {{capitalize .FieldName}} {{.FieldDescription}} 2 | {{capitalize .FieldName}} {{.FieldType}} `json:"{{.FieldName}}"` 3 | -------------------------------------------------------------------------------- /template/property/default/method.tmpl: -------------------------------------------------------------------------------- 1 | {{ define "arguments" }}args *struct{ 2 | {{range .}}{{.Name | capitalize}} {{.Type}} 3 | {{end}} 4 | }{{ end }} 5 | {{define "receiver"}}{{if is_entry . }}Resolver{{else}}{{.}}Resolver{{end}}{{end}} 6 | {{if eq .TypeKind "OBJECT"}} 7 | {{$hasArguments := gt (.MethodArguments | len) 0}} 8 | // {{capitalize .MethodName}} {{.MethodDescription}} 9 | func (r *{{template "receiver" .TypeName}}) {{capitalize .MethodName}}({{if $hasArguments}}{{template "arguments" .MethodArguments}}{{end}}) {{.MethodReturnType}} { 10 | {{if is_entry .TypeName}}return nil{{else}}return r.{{.TypeName}}.{{capitalize .MethodReturn}}{{end}} 11 | } 12 | {{end}} 13 | {{if eq .TypeKind "INTERFACE"}} 14 | {{$hasArguments := gt (.MethodArguments | len) 0}} 15 | // {{capitalize .MethodName}} {{.MethodDescription}} 16 | {{capitalize .MethodName}}({{if $hasArguments}}{{template "arguments" .MethodArguments}}{{end}}) {{.MethodReturnType}} 17 | {{end}} 18 | -------------------------------------------------------------------------------- /template/property/http_resolver/config.hcl: -------------------------------------------------------------------------------- 1 | field = "field.tmpl" 2 | method = "method.tmpl" 3 | imports = ["\"net/http\"", "\"encoding/json\""] 4 | -------------------------------------------------------------------------------- /template/property/http_resolver/field.tmpl: -------------------------------------------------------------------------------- 1 | {{range .TemplateConfig.fields}} 2 | {{capitalize .field_name}} {{.field_type}} `json:"{{.field_name}}"` 3 | {{end}} 4 | -------------------------------------------------------------------------------- /template/property/http_resolver/method.tmpl: -------------------------------------------------------------------------------- 1 | {{ define "arguments" }}args *struct{ 2 | {{range .}}{{.Name | capitalize}} {{.Type}} 3 | {{end}} 4 | }{{ end }} 5 | {{define "receiver"}}{{if is_entry . }}Resolver{{else}}{{.}}Resolver{{end}}{{end}} 6 | {{$hasArguments := gt (.MethodArguments | len) 0}} 7 | // {{capitalize .MethodName}} {{.MethodDescription}} 8 | func (r *{{template "receiver" .TypeName}}) {{capitalize .MethodName}}({{if $hasArguments}}{{template "arguments" .MethodArguments}}{{end}}) ({{.MethodReturnType}}, error) { 9 | var result {{.MethodReturnType}} 10 | resp, err := http.Get({{sub_template .TemplateConfig.url .}}) 11 | if err != nil { 12 | return nil, err 13 | } 14 | defer resp.Body.Close() 15 | 16 | err = json.NewDecoder(resp.Body).Decode(&result) 17 | return result, err 18 | } 19 | -------------------------------------------------------------------------------- /template/type.go: -------------------------------------------------------------------------------- 1 | package template 2 | 3 | import ( 4 | "errors" 5 | "path" 6 | 7 | "github.com/hashicorp/hcl" 8 | ) 9 | 10 | //go:generate go-bindata -pkg template -ignore=\.go -o assets.go ./... 11 | 12 | type TypeTemplateConfig struct { 13 | Type string 14 | Imports []string 15 | } 16 | 17 | type TypeTemplate struct { 18 | Config TypeTemplateConfig 19 | TypeTemplate string 20 | } 21 | 22 | func parseTypeConfig(str string) (config TypeTemplateConfig, err error) { 23 | err = hcl.Decode(&config, str) 24 | return 25 | } 26 | 27 | func loadStoredTypeTemplate(template string) (*TypeTemplate, bool, error) { 28 | cfgStr, err := Asset(template + "/config.hcl") 29 | if err != nil { 30 | return nil, false, nil 31 | } 32 | 33 | cfg, err := parseTypeConfig(string(cfgStr)) 34 | if err != nil { 35 | return nil, false, err 36 | } 37 | 38 | templateString, err := Asset(path.Join(template, cfg.Type)) 39 | if err != nil { 40 | return nil, false, err 41 | } 42 | 43 | return &TypeTemplate{ 44 | Config: cfg, 45 | TypeTemplate: string(templateString), 46 | }, true, nil 47 | } 48 | 49 | func GetTypeTemplate(templateName string) (template *TypeTemplate, err error) { 50 | template, ok, err := loadStoredTypeTemplate("type/" + templateName) 51 | // if ok false read file from the directory 52 | if !ok { 53 | return nil, errors.New("Fail") 54 | } 55 | return 56 | } 57 | -------------------------------------------------------------------------------- /template/type/default/config.hcl: -------------------------------------------------------------------------------- 1 | type = "type.tmpl" 2 | -------------------------------------------------------------------------------- /template/type/default/type.tmpl: -------------------------------------------------------------------------------- 1 | // This code is genereated by graphql-codegen 2 | // DO NOT EDIT! 3 | 4 | package {{.Config.Package}}; 5 | 6 | 7 | import ( 8 | {{if eq .Kind "OBJECT"}} 9 | {{if not (is_entry .TypeName) }} 10 | {{if not (includes_string .Imports "\"encoding/json\"")}}"encoding/json"{{end}} 11 | {{end}} 12 | {{end}} 13 | {{range .Imports}} 14 | {{.}} 15 | {{end}} 16 | ) 17 | {{if eq .Kind "OBJECT"}} 18 | {{if not (is_entry .TypeName) }} 19 | // {{.TypeName}} {{.TypeDescription}} 20 | type {{.TypeName}} struct { 21 | {{range .Fields}}{{.}}{{end}} 22 | } 23 | 24 | // {{.TypeName}}Resolver resolver for {{.TypeName}} 25 | type {{.TypeName}}Resolver struct { 26 | {{.TypeName}} 27 | } 28 | {{end}} 29 | {{range .Methods}}{{.}} 30 | {{end}} 31 | {{if not (is_entry .TypeName) }} 32 | func (r *{{.TypeName}}Resolver) MarshalJSON() ([]byte, error) { 33 | return json.Marshal(&r.{{.TypeName}}) 34 | } 35 | 36 | func (r *{{.TypeName}}Resolver) UnmarshalJSON(data []byte) error { 37 | return json.Unmarshal(data, &r.{{.TypeName}}) 38 | } 39 | {{end}} 40 | {{end}} 41 | 42 | {{if eq .Kind "INTERFACE"}} 43 | // {{.TypeName}} {{.TypeDescription}} 44 | type {{.TypeName}} interface { 45 | {{range .Methods}}{{.}}{{end}} 46 | } 47 | 48 | // {{.TypeName}}Resolver resolver for {{.TypeName}} 49 | type {{.TypeName}}Resolver struct { 50 | {{.TypeName}} 51 | } 52 | {{ $typeName := .TypeName }} 53 | {{range $possibleType := .PossibleTypes}} 54 | func (r *{{$typeName}}Resolver) To{{$possibleType}}() (*{{$possibleType}}Resolver, bool) { 55 | c, ok := r.{{$typeName}}.(*{{$possibleType}}Resolver) 56 | return c, ok 57 | } 58 | {{end}} 59 | 60 | {{end}} 61 | 62 | {{if eq .Kind "UNION"}} 63 | // {{.TypeName}}Resolver resolver for {{.TypeName}} 64 | type {{.TypeName}}Resolver struct { 65 | {{.TypeName | uncapitalize}} interface{} 66 | } 67 | {{ $typeName := .TypeName }} 68 | {{range $possibleType := .PossibleTypes}} 69 | func (r *{{$typeName}}Resolver) To{{$possibleType}}() (*{{$possibleType}}Resolver, bool) { 70 | c, ok := r.{{$typeName | uncapitalize}}.(*{{$possibleType}}Resolver) 71 | return c, ok 72 | } 73 | {{end}} 74 | 75 | {{end}} 76 | 77 | {{if eq .Kind "ENUM"}} 78 | {{ $typeName := .TypeName }} 79 | {{ $typeDescription := .TypeDescription }} 80 | // {{.TypeName}} {{.TypeDescription}} 81 | type {{$typeName}} string 82 | const ( 83 | {{range $value := .EnumValues}} 84 | // {{$typeName}}{{$value}} {{$typeDescription}} 85 | {{$typeName}}{{$value}} = {{$typeName}}("{{$value}}") 86 | {{end}} 87 | ) 88 | {{end}} 89 | 90 | {{if eq .Kind "INPUT_OBJECT"}} 91 | // {{.TypeName}} {{.TypeDescription}} 92 | type {{.TypeName}} struct { 93 | {{range .InputFields}}{{.}}{{end}} 94 | } 95 | {{end}} 96 | 97 | {{if eq .Kind "RESOLVER"}} 98 | // {{.TypeName}} {{.TypeDescription}} 99 | type {{.TypeName}} struct { 100 | } 101 | {{end}} 102 | 103 | {{if eq .Kind "SCALAR"}} 104 | // {{.TypeName}}Resolver {{.TypeDescription}} 105 | type {{.TypeName}}Resolver struct { 106 | value interface{} 107 | } 108 | 109 | func (r *{{.TypeName}}Resolver) ImplementsGraphQLType(name string) bool { 110 | return false 111 | } 112 | 113 | func (r *{{.TypeName}}Resolver) UnmarshalGraphQL(input interface{}) error { 114 | // Scalars need to be implemented manually 115 | r.value = input 116 | return nil 117 | } 118 | 119 | {{end}} 120 | --------------------------------------------------------------------------------