diff --git a/codegen/codegen.go b/codegen/codegen.go index cad1e4f3339..789ef2ecb05 100644 --- a/codegen/codegen.go +++ b/codegen/codegen.go @@ -38,15 +38,15 @@ func Generate(cfg Config) error { return err } for _, model := range modelsBuild.Models { - cfg.Models[model.GQLType] = TypeMapEntry{ - Model: cfg.Model.ImportPath() + "." + model.GoType, - } + modelCfg := cfg.Models[model.GQLType] + modelCfg.Model = cfg.Model.ImportPath() + "." + model.GoType + cfg.Models[model.GQLType] = modelCfg } for _, enum := range modelsBuild.Enums { - cfg.Models[enum.GQLType] = TypeMapEntry{ - Model: cfg.Model.ImportPath() + "." + enum.GoType, - } + modelCfg := cfg.Models[enum.GQLType] + modelCfg.Model = cfg.Model.ImportPath() + "." + enum.GoType + cfg.Models[enum.GQLType] = modelCfg } } diff --git a/codegen/config.go b/codegen/config.go index 01eb87cad05..3c23b98d460 100644 --- a/codegen/config.go +++ b/codegen/config.go @@ -148,9 +148,6 @@ func (tm TypeMap) Exists(typeName string) bool { func (tm TypeMap) Check() error { for typeName, entry := range tm { - if entry.Model == "" { - return fmt.Errorf("model %s: entityPath is not defined", typeName) - } if strings.LastIndex(entry.Model, ".") < strings.LastIndex(entry.Model, "/") { return fmt.Errorf("model %s: invalid type specifier \"%s\" - you need to specify a struct to map to", typeName, entry.Model) } diff --git a/codegen/templates/data.go b/codegen/templates/data.go index c024d322106..407f4f25e60 100644 --- a/codegen/templates/data.go +++ b/codegen/templates/data.go @@ -2,7 +2,7 @@ package templates var data = map[string]string{ "args.gotpl": "\t{{- if . }}args := map[string]interface{}{} {{end}}\n\t{{- range $i, $arg := . }}\n\t\tvar arg{{$i}} {{$arg.Signature }}\n\t\tif tmp, ok := field.Args[{{$arg.GQLName|quote}}]; ok {\n\t\t\tvar err error\n\t\t\t{{$arg.Unmarshal (print \"arg\" $i) \"tmp\" }}\n\t\t\tif err != nil {\n\t\t\t\tec.Error(ctx, err)\n\t\t\t\t{{- if $arg.Object.Stream }}\n\t\t\t\t\treturn nil\n\t\t\t\t{{- else }}\n\t\t\t\t\treturn graphql.Null\n\t\t\t\t{{- end }}\n\t\t\t}\n\t\t} {{ if $arg.Default }} else {\n\t\t\tvar tmp interface{} = {{ $arg.Default | dump }}\n\t\t\tvar err error\n\t\t\t{{$arg.Unmarshal (print \"arg\" $i) \"tmp\" }}\n\t\t\tif err != nil {\n\t\t\t\tec.Error(ctx, err)\n\t\t\t\t{{- if $arg.Object.Stream }}\n\t\t\t\t\treturn nil\n\t\t\t\t{{- else }}\n\t\t\t\t\treturn graphql.Null\n\t\t\t\t{{- end }}\n\t\t\t}\n\t\t}\n\t\t{{end }}\n\t\targs[{{$arg.GQLName|quote}}] = arg{{$i}}\n\t{{- end -}}\n", - "field.gotpl": "{{ $field := . }}\n{{ $object := $field.Object }}\n\n{{- if $object.Stream }}\n\tfunc (ec *executionContext) _{{$object.GQLType}}_{{$field.GQLName}}(ctx context.Context, field graphql.CollectedField) func() graphql.Marshaler {\n\t\t{{- template \"args.gotpl\" $field.Args }}\n\t\tctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{Field: field})\n\t\tresults, err := ec.resolvers.{{ $object.GQLType }}_{{ $field.GQLName }}({{ $field.CallArgs }})\n\t\tif err != nil {\n\t\t\tec.Error(ctx, err)\n\t\t\treturn nil\n\t\t}\n\t\treturn func() graphql.Marshaler {\n\t\t\tres, ok := <-results\n\t\t\tif !ok {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tvar out graphql.OrderedMap\n\t\t\tout.Add(field.Alias, func() graphql.Marshaler { {{ $field.WriteJson }} }())\n\t\t\treturn &out\n\t\t}\n\t}\n{{ else }}\n\tfunc (ec *executionContext) _{{$object.GQLType}}_{{$field.GQLName}}(ctx context.Context, field graphql.CollectedField, {{if not $object.Root}}obj *{{$object.FullName}}{{end}}) graphql.Marshaler {\n\t\t{{- template \"args.gotpl\" $field.Args }}\n\n\t\t{{- if $field.IsConcurrent }}\n\t\t\tctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{\n\t\t\t\tObject: {{$object.GQLType|quote}},\n\t\t\t\tArgs: {{if $field.Args }}args{{else}}nil{{end}},\n\t\t\t\tField: field,\n\t\t\t})\n\t\t\treturn graphql.Defer(func() (ret graphql.Marshaler) {\n\t\t\t\tdefer func() {\n\t\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\t\tuserErr := ec.Recover(ctx, r)\n\t\t\t\t\t\tec.Error(ctx, userErr)\n\t\t\t\t\t\tret = graphql.Null\n\t\t\t\t\t}\n\t\t\t\t}()\n\t\t{{ else }}\n\t\t\trctx := graphql.GetResolverContext(ctx)\n\t\t\trctx.Object = {{$object.GQLType|quote}}\n\t\t\trctx.Args = {{if $field.Args }}args{{else}}nil{{end}}\n\t\t\trctx.Field = field\n\t\t\trctx.PushField(field.Alias)\n\t\t\tdefer rctx.Pop()\n\t\t{{- end }}\n\n\t\t\t{{- if $field.GoVarName }}\n\t\t\t\tres := obj.{{$field.GoVarName}}\n\t\t\t{{- else if $field.GoMethodName }}\n\t\t\t\t{{- if $field.NoErr }}\n\t\t\t\t\tres := {{$field.GoMethodName}}({{ $field.CallArgs }})\n\t\t\t\t{{- else }}\n\t\t\t\t\tres, err := {{$field.GoMethodName}}({{ $field.CallArgs }})\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tec.Error(ctx, err)\n\t\t\t\t\t\treturn graphql.Null\n\t\t\t\t\t}\n\t\t\t\t{{- end }}\n\t\t\t{{- else }}\n\n\t\t\t\tresTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) {\n\t\t\t\t\treturn ec.resolvers.{{ $object.GQLType }}_{{ $field.GQLName }}({{ $field.CallArgs }})\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\tec.Error(ctx, err)\n\t\t\t\t\treturn graphql.Null\n\t\t\t\t}\n\t\t\t\tif resTmp == nil {\n\t\t\t\t\treturn graphql.Null\n\t\t\t\t}\n\t\t\t\tres := resTmp.({{$field.Signature}})\n\t\t\t{{- end }}\n\t\t\t{{ $field.WriteJson }}\n\t\t{{- if $field.IsConcurrent }}\n\t\t\t})\n\t\t{{- end }}\n\t}\n{{ end }}\n", + "field.gotpl": "{{ $field := . }}\n{{ $object := $field.Object }}\n\n{{- if $object.Stream }}\n\tfunc (ec *executionContext) _{{$object.GQLType}}_{{$field.GQLName}}(ctx context.Context, field graphql.CollectedField) func() graphql.Marshaler {\n\t\t{{- template \"args.gotpl\" $field.Args }}\n\t\tctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{Field: field})\n\t\tresults, err := ec.resolvers.{{ $object.GQLType }}_{{ $field.GQLName }}({{ $field.CallArgs }})\n\t\tif err != nil {\n\t\t\tec.Error(ctx, err)\n\t\t\treturn nil\n\t\t}\n\t\treturn func() graphql.Marshaler {\n\t\t\tres, ok := <-results\n\t\t\tif !ok {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tvar out graphql.OrderedMap\n\t\t\tout.Add(field.Alias, func() graphql.Marshaler { {{ $field.WriteJson }} }())\n\t\t\treturn &out\n\t\t}\n\t}\n{{ else }}\n\tfunc (ec *executionContext) _{{$object.GQLType}}_{{$field.GQLName}}(ctx context.Context, field graphql.CollectedField, {{if not $object.Root}}obj *{{$object.FullName}}{{end}}) graphql.Marshaler {\n\t\t{{- template \"args.gotpl\" $field.Args }}\n\n\t\t{{- if $field.IsConcurrent }}\n\t\t\tctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{\n\t\t\t\tObject: {{$object.GQLType|quote}},\n\t\t\t\tArgs: {{if $field.Args }}args{{else}}nil{{end}},\n\t\t\t\tField: field,\n\t\t\t})\n\t\t\treturn graphql.Defer(func() (ret graphql.Marshaler) {\n\t\t\t\tdefer func() {\n\t\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\t\tuserErr := ec.Recover(ctx, r)\n\t\t\t\t\t\tec.Error(ctx, userErr)\n\t\t\t\t\t\tret = graphql.Null\n\t\t\t\t\t}\n\t\t\t\t}()\n\t\t{{ else }}\n\t\t\trctx := graphql.GetResolverContext(ctx)\n\t\t\trctx.Object = {{$object.GQLType|quote}}\n\t\t\trctx.Args = {{if $field.Args }}args{{else}}nil{{end}}\n\t\t\trctx.Field = field\n\t\t\trctx.PushField(field.Alias)\n\t\t\tdefer rctx.Pop()\n\t\t{{- end }}\n\n\t\t\t{{- if $field.IsResolver }}\n\t\t\t\tresTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) {\n\t\t\t\t\treturn ec.resolvers.{{ $object.GQLType }}_{{ $field.GQLName }}({{ $field.CallArgs }})\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\tec.Error(ctx, err)\n\t\t\t\t\treturn graphql.Null\n\t\t\t\t}\n\t\t\t\tif resTmp == nil {\n\t\t\t\t\treturn graphql.Null\n\t\t\t\t}\n\t\t\t\tres := resTmp.({{$field.Signature}})\n\t\t\t{{- else if $field.GoVarName }}\n\t\t\t\tres := obj.{{$field.GoVarName}}\n\t\t\t{{- else if $field.GoMethodName }}\n\t\t\t\t{{- if $field.NoErr }}\n\t\t\t\t\tres := {{$field.GoMethodName}}({{ $field.CallArgs }})\n\t\t\t\t{{- else }}\n\t\t\t\t\tres, err := {{$field.GoMethodName}}({{ $field.CallArgs }})\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tec.Error(ctx, err)\n\t\t\t\t\t\treturn graphql.Null\n\t\t\t\t\t}\n\t\t\t\t{{- end }}\n\t\t\t{{- end }}\n\t\t\t{{ $field.WriteJson }}\n\t\t{{- if $field.IsConcurrent }}\n\t\t\t})\n\t\t{{- end }}\n\t}\n{{ end }}\n", "generated.gotpl": "// Code generated by github.com/vektah/gqlgen, DO NOT EDIT.\n\npackage {{ .PackageName }}\n\nimport (\n{{- range $import := .Imports }}\n\t{{- $import.Write }}\n{{ end }}\n)\n\n// MakeExecutableSchema creates an ExecutableSchema from the Resolvers interface.\nfunc MakeExecutableSchema(resolvers Resolvers) graphql.ExecutableSchema {\n\treturn &executableSchema{resolvers: resolvers}\n}\n\n// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.\nfunc NewExecutableSchema(resolvers ResolverRoot) graphql.ExecutableSchema {\n\treturn MakeExecutableSchema(shortMapper{r: resolvers})\n}\n\ntype Resolvers interface {\n{{- range $object := .Objects -}}\n\t{{ range $field := $object.Fields -}}\n\t\t{{ $field.ResolverDeclaration }}\n\t{{ end }}\n{{- end }}\n}\n\ntype ResolverRoot interface {\n{{- range $object := .Objects -}}\n\t{{ if $object.HasResolvers -}}\n\t\t{{$object.GQLType}}() {{$object.GQLType}}Resolver\n\t{{ end }}\n{{- end }}\n}\n\n{{- range $object := .Objects -}}\n\t{{ if $object.HasResolvers }}\n\t\ttype {{$object.GQLType}}Resolver interface {\n\t\t{{ range $field := $object.Fields -}}\n\t\t\t{{ $field.ShortResolverDeclaration }}\n\t\t{{ end }}\n\t\t}\n\t{{- end }}\n{{- end }}\n\ntype shortMapper struct {\n\tr ResolverRoot\n}\n\n{{- range $object := .Objects -}}\n\t{{ range $field := $object.Fields -}}\n\t\t{{- if $field.IsResolver }}\n\t\t\tfunc (s shortMapper) {{ $field.ResolverDeclaration }} {\n\t\t\t\treturn s.r.{{$field.ShortInvocation}}\n\t\t\t}\n\t\t{{- end }}\n\t{{ end }}\n{{- end }}\n\ntype executableSchema struct {\n\tresolvers Resolvers\n}\n\nfunc (e *executableSchema) Schema() *schema.Schema {\n\treturn parsedSchema\n}\n\nfunc (e *executableSchema) Query(ctx context.Context, op *query.Operation) *graphql.Response {\n\t{{- if .QueryRoot }}\n\t\tec := executionContext{graphql.GetRequestContext(ctx), e.resolvers}\n\n\t\tbuf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte {\n\t\t\tdata := ec._{{.QueryRoot.GQLType}}(ctx, op.Selections)\n\t\t\tvar buf bytes.Buffer\n\t\t\tdata.MarshalGQL(&buf)\n\t\t\treturn buf.Bytes()\n\t\t})\n\n\t\treturn &graphql.Response{\n\t\t\tData: buf,\n\t\t\tErrors: ec.Errors,\n\t\t}\n\t{{- else }}\n\t\treturn graphql.ErrorResponse(ctx, \"queries are not supported\")\n\t{{- end }}\n}\n\nfunc (e *executableSchema) Mutation(ctx context.Context, op *query.Operation) *graphql.Response {\n\t{{- if .MutationRoot }}\n\t\tec := executionContext{graphql.GetRequestContext(ctx), e.resolvers}\n\n\t\tbuf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte {\n\t\t\tdata := ec._{{.MutationRoot.GQLType}}(ctx, op.Selections)\n\t\t\tvar buf bytes.Buffer\n\t\t\tdata.MarshalGQL(&buf)\n\t\t\treturn buf.Bytes()\n\t\t})\n\n\t\treturn &graphql.Response{\n\t\t\tData: buf,\n\t\t\tErrors: ec.Errors,\n\t\t}\n\t{{- else }}\n\t\treturn graphql.ErrorResponse(ctx, \"mutations are not supported\")\n\t{{- end }}\n}\n\nfunc (e *executableSchema) Subscription(ctx context.Context, op *query.Operation) func() *graphql.Response {\n\t{{- if .SubscriptionRoot }}\n\t\tec := executionContext{graphql.GetRequestContext(ctx), e.resolvers}\n\n\t\tnext := ec._{{.SubscriptionRoot.GQLType}}(ctx, op.Selections)\n\t\tif ec.Errors != nil {\n\t\t\treturn graphql.OneShot(&graphql.Response{Data: []byte(\"null\"), Errors: ec.Errors})\n\t\t}\n\n\t\tvar buf bytes.Buffer\n\t\treturn func() *graphql.Response {\n\t\t\tbuf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte {\n\t\t\t\tbuf.Reset()\n\t\t\t\tdata := next()\n\n\t\t\t\tif data == nil {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\tdata.MarshalGQL(&buf)\n\t\t\t\treturn buf.Bytes()\n\t\t\t})\n\n\t\t\treturn &graphql.Response{\n\t\t\t\tData: buf,\n\t\t\t\tErrors: ec.Errors,\n\t\t\t}\n\t\t}\n\t{{- else }}\n\t\treturn graphql.OneShot(graphql.ErrorResponse(ctx, \"subscriptions are not supported\"))\n\t{{- end }}\n}\n\ntype executionContext struct {\n\t*graphql.RequestContext\n\n\tresolvers Resolvers\n}\n\n{{- range $object := .Objects }}\n\t{{ template \"object.gotpl\" $object }}\n\n\t{{- range $field := $object.Fields }}\n\t\t{{ template \"field.gotpl\" $field }}\n\t{{ end }}\n{{- end}}\n\n{{- range $interface := .Interfaces }}\n\t{{ template \"interface.gotpl\" $interface }}\n{{- end }}\n\n{{- range $input := .Inputs }}\n\t{{ template \"input.gotpl\" $input }}\n{{- end }}\n\nfunc (ec *executionContext) introspectSchema() *introspection.Schema {\n\treturn introspection.WrapSchema(parsedSchema)\n}\n\nfunc (ec *executionContext) introspectType(name string) *introspection.Type {\n\tt := parsedSchema.Resolve(name)\n\tif t == nil {\n\t\treturn nil\n\t}\n\treturn introspection.WrapType(t)\n}\n\nvar parsedSchema = schema.MustParse({{.SchemaRaw|rawQuote}})\n", "input.gotpl": "\t{{- if .IsMarshaled }}\n\tfunc Unmarshal{{ .GQLType }}(v interface{}) ({{.FullName}}, error) {\n\t\tvar it {{.FullName}}\n\t\tvar asMap = v.(map[string]interface{})\n\t\t{{ range $field := .Fields}}\n\t\t\t{{- if $field.Default}}\n\t\t\t\tif _, present := asMap[{{$field.GQLName|quote}}] ; !present {\n\t\t\t\t\tasMap[{{$field.GQLName|quote}}] = {{ $field.Default | dump }}\n\t\t\t\t}\n\t\t\t{{- end}}\n\t\t{{- end }}\n\n\t\tfor k, v := range asMap {\n\t\t\tswitch k {\n\t\t\t{{- range $field := .Fields }}\n\t\t\tcase {{$field.GQLName|quote}}:\n\t\t\t\tvar err error\n\t\t\t\t{{ $field.Unmarshal (print \"it.\" $field.GoVarName) \"v\" }}\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn it, err\n\t\t\t\t}\n\t\t\t{{- end }}\n\t\t\t}\n\t\t}\n\n\t\treturn it, nil\n\t}\n\t{{- end }}\n", "interface.gotpl": "{{- $interface := . }}\n\nfunc (ec *executionContext) _{{$interface.GQLType}}(ctx context.Context, sel []query.Selection, obj *{{$interface.FullName}}) graphql.Marshaler {\n\tswitch obj := (*obj).(type) {\n\tcase nil:\n\t\treturn graphql.Null\n\t{{- range $implementor := $interface.Implementors }}\n\t\t{{- if $implementor.ValueReceiver }}\n\t\t\tcase {{$implementor.FullName}}:\n\t\t\t\treturn ec._{{$implementor.GQLType}}(ctx, sel, &obj)\n\t\t{{- end}}\n\t\tcase *{{$implementor.FullName}}:\n\t\t\treturn ec._{{$implementor.GQLType}}(ctx, sel, obj)\n\t{{- end }}\n\tdefault:\n\t\tpanic(fmt.Errorf(\"unexpected type %T\", obj))\n\t}\n}\n", diff --git a/codegen/templates/field.gotpl b/codegen/templates/field.gotpl index 87f9611c0c1..4279ad8eaea 100644 --- a/codegen/templates/field.gotpl +++ b/codegen/templates/field.gotpl @@ -47,20 +47,7 @@ defer rctx.Pop() {{- end }} - {{- if $field.GoVarName }} - res := obj.{{$field.GoVarName}} - {{- else if $field.GoMethodName }} - {{- if $field.NoErr }} - res := {{$field.GoMethodName}}({{ $field.CallArgs }}) - {{- else }} - res, err := {{$field.GoMethodName}}({{ $field.CallArgs }}) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - {{- end }} - {{- else }} - + {{- if $field.IsResolver }} resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { return ec.resolvers.{{ $object.GQLType }}_{{ $field.GQLName }}({{ $field.CallArgs }}) }) @@ -72,6 +59,18 @@ return graphql.Null } res := resTmp.({{$field.Signature}}) + {{- else if $field.GoVarName }} + res := obj.{{$field.GoVarName}} + {{- else if $field.GoMethodName }} + {{- if $field.NoErr }} + res := {{$field.GoMethodName}}({{ $field.CallArgs }}) + {{- else }} + res, err := {{$field.GoMethodName}}({{ $field.CallArgs }}) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + {{- end }} {{- end }} {{ $field.WriteJson }} {{- if $field.IsConcurrent }} diff --git a/codegen/type_build.go b/codegen/type_build.go index 76426a2745b..d157b84fd6c 100644 --- a/codegen/type_build.go +++ b/codegen/type_build.go @@ -16,17 +16,12 @@ func (cfg *Config) buildNamedTypes() NamedTypes { for _, schemaType := range cfg.schema.Types { t := namedTypeFromSchema(schemaType) - userType := "" - if userEntry, ok := cfg.Models[t.GQLType]; ok { - userType = userEntry.Model - } - t.IsUserDefined = userType != "" - if userType == "" && t.IsScalar { - userType = "github.com/vektah/gqlgen/graphql.String" - } - - if userType != "" { - t.Package, t.GoType = pkgAndType(userType) + if userEntry, ok := cfg.Models[t.GQLType]; ok && userEntry.Model != "" { + t.IsUserDefined = true + t.Package, t.GoType = pkgAndType(userEntry.Model) + } else if t.IsScalar { + t.Package = "github.com/vektah/gqlgen/graphql" + t.GoType = "String" } types[t.GQLType] = t diff --git a/example/chat/generated.go b/example/chat/generated.go index 2dc437e2c1e..ea16d4cd235 100644 --- a/example/chat/generated.go +++ b/example/chat/generated.go @@ -329,7 +329,6 @@ func (ec *executionContext) _Mutation_post(ctx context.Context, field graphql.Co rctx.Field = field rctx.PushField(field.Alias) defer rctx.Pop() - resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { return ec.resolvers.Mutation_post(ctx, args["text"].(string), args["username"].(string), args["roomName"].(string)) }) diff --git a/example/starwars/.gqlgen.yml b/example/starwars/.gqlgen.yml index 01193161cd8..877f6197026 100644 --- a/example/starwars/.gqlgen.yml +++ b/example/starwars/.gqlgen.yml @@ -3,8 +3,6 @@ models: model: github.com/vektah/gqlgen/example/starwars.Droid FriendsConnection: model: github.com/vektah/gqlgen/example/starwars.FriendsConnection - FriendsEdge: - model: github.com/vektah/gqlgen/example/starwars.FriendsEdge Human: model: github.com/vektah/gqlgen/example/starwars.Human Review: @@ -12,4 +10,6 @@ models: ReviewInput: model: github.com/vektah/gqlgen/example/starwars.Review Starship: - model: github.com/vektah/gqlgen/example/starwars.Starship + fields: + length: + resolver: true diff --git a/example/starwars/generated.go b/example/starwars/generated.go index e5c04858143..aa10cb366ed 100644 --- a/example/starwars/generated.go +++ b/example/starwars/generated.go @@ -45,6 +45,8 @@ type Resolvers interface { Query_droid(ctx context.Context, id string) (*Droid, error) Query_human(ctx context.Context, id string) (*Human, error) Query_starship(ctx context.Context, id string) (*Starship, error) + + Starship_length(ctx context.Context, obj *Starship, unit LengthUnit) (float64, error) } type ResolverRoot interface { @@ -53,6 +55,7 @@ type ResolverRoot interface { Human() HumanResolver Mutation() MutationResolver Query() QueryResolver + Starship() StarshipResolver } type DroidResolver interface { Friends(ctx context.Context, obj *Droid) ([]Character, error) @@ -80,6 +83,9 @@ type QueryResolver interface { Human(ctx context.Context, id string) (*Human, error) Starship(ctx context.Context, id string) (*Starship, error) } +type StarshipResolver interface { + Length(ctx context.Context, obj *Starship, unit LengthUnit) (float64, error) +} type shortMapper struct { r ResolverRoot @@ -145,6 +151,10 @@ func (s shortMapper) Query_starship(ctx context.Context, id string) (*Starship, return s.r.Query().Starship(ctx, id) } +func (s shortMapper) Starship_length(ctx context.Context, obj *Starship, unit LengthUnit) (float64, error) { + return s.r.Starship().Length(ctx, obj, unit) +} + type executableSchema struct { resolvers Resolvers } @@ -872,7 +882,6 @@ func (ec *executionContext) _Mutation_createReview(ctx context.Context, field gr rctx.Field = field rctx.PushField(field.Alias) defer rctx.Pop() - resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { return ec.resolvers.Mutation_createReview(ctx, args["episode"].(Episode), args["review"].(Review)) }) @@ -1505,14 +1514,33 @@ func (ec *executionContext) _Starship_length(ctx context.Context, field graphql. } args["unit"] = arg0 - rctx := graphql.GetResolverContext(ctx) - rctx.Object = "Starship" - rctx.Args = args - rctx.Field = field - rctx.PushField(field.Alias) - defer rctx.Pop() - res := obj.Length(args["unit"].(LengthUnit)) - return graphql.MarshalFloat(res) + ctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{ + Object: "Starship", + Args: args, + Field: field, + }) + return graphql.Defer(func() (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + userErr := ec.Recover(ctx, r) + ec.Error(ctx, userErr) + ret = graphql.Null + } + }() + + resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { + return ec.resolvers.Starship_length(ctx, obj, args["unit"].(LengthUnit)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(float64) + return graphql.MarshalFloat(res) + }) } func (ec *executionContext) _Starship_history(ctx context.Context, field graphql.CollectedField, obj *Starship) graphql.Marshaler { diff --git a/example/starwars/model.go b/example/starwars/model.go index c06bcbbbfee..557f59a8472 100644 --- a/example/starwars/model.go +++ b/example/starwars/model.go @@ -34,24 +34,6 @@ func (h *Human) Height(unit LengthUnit) float64 { } } -type Starship struct { - ID string - Name string - History [][]int - lengthMeters float64 -} - -func (s *Starship) Length(unit LengthUnit) float64 { - switch unit { - case "METER", "": - return s.lengthMeters - case "FOOT": - return s.lengthMeters * 3.28084 - default: - panic("invalid unit") - } -} - type Review struct { Stars int Commentary *string @@ -113,8 +95,3 @@ func (f *FriendsConnection) PageInfo() PageInfo { func encodeCursor(i int) string { return base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("cursor%d", i+1))) } - -type FriendsEdge struct { - Cursor string - Node Character -} diff --git a/example/starwars/models_gen.go b/example/starwars/models_gen.go index f1982cac111..03aec369f5f 100644 --- a/example/starwars/models_gen.go +++ b/example/starwars/models_gen.go @@ -9,12 +9,22 @@ import ( ) type Character interface{} +type FriendsEdge struct { + Cursor string `json:"cursor"` + Node Character `json:"node"` +} type PageInfo struct { StartCursor string `json:"startCursor"` EndCursor string `json:"endCursor"` HasNextPage bool `json:"hasNextPage"` } type SearchResult interface{} +type Starship struct { + ID string `json:"id"` + Name string `json:"name"` + Length float64 `json:"length"` + History [][]int `json:"history"` +} type Episode string diff --git a/example/starwars/resolvers.go b/example/starwars/resolvers.go index 038ce15ef92..7113401d923 100644 --- a/example/starwars/resolvers.go +++ b/example/starwars/resolvers.go @@ -4,6 +4,7 @@ package starwars import ( "context" + "errors" "strings" "time" ) @@ -154,6 +155,17 @@ func (r *Resolver) Query_starship(ctx context.Context, id string) (*Starship, er return nil, nil } +func (r *Resolver) Starship_length(ctx context.Context, obj *Starship, unit LengthUnit) (float64, error) { + switch unit { + case LengthUnitMeter, "": + return obj.Length, nil + case LengthUnitFoot: + return obj.Length * 3.28084, nil + default: + return 0, errors.New("invalid unit") + } +} + func NewResolver() *Resolver { r := Resolver{} r.humans = map[string]Human{ @@ -243,7 +255,7 @@ func NewResolver() *Resolver { {1, 2}, {3, 2}, }, - lengthMeters: 34.37, + Length: 34.37, }, "3001": { ID: "3001", @@ -254,7 +266,7 @@ func NewResolver() *Resolver { {2, 3}, {5, 1}, }, - lengthMeters: 12.5, + Length: 12.5, }, "3002": { ID: "3002", @@ -265,7 +277,7 @@ func NewResolver() *Resolver { {6, 4}, {3, 2}, }, - lengthMeters: 9.2, + Length: 9.2, }, "3003": { ID: "3003", @@ -276,7 +288,7 @@ func NewResolver() *Resolver { {5, 3}, {7, 1}, }, - lengthMeters: 20, + Length: 20, }, } diff --git a/example/todo/generated.go b/example/todo/generated.go index 20498008159..edcc028460d 100644 --- a/example/todo/generated.go +++ b/example/todo/generated.go @@ -166,7 +166,6 @@ func (ec *executionContext) _MyMutation_createTodo(ctx context.Context, field gr rctx.Field = field rctx.PushField(field.Alias) defer rctx.Pop() - resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { return ec.resolvers.MyMutation_createTodo(ctx, args["todo"].(TodoInput)) }) @@ -209,7 +208,6 @@ func (ec *executionContext) _MyMutation_updateTodo(ctx context.Context, field gr rctx.Field = field rctx.PushField(field.Alias) defer rctx.Pop() - resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { return ec.resolvers.MyMutation_updateTodo(ctx, args["id"].(int), args["changes"].(map[string]interface{})) }) diff --git a/test/generated.go b/test/generated.go index 612bc6fc33f..bbc95e81f97 100644 --- a/test/generated.go +++ b/test/generated.go @@ -480,7 +480,17 @@ func (ec *executionContext) _User_likes(ctx context.Context, field graphql.Colle } }() - res := obj.Likes + resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { + return ec.resolvers.User_likes(ctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]string) arr1 := graphql.Array{} for idx1 := range res { arr1 = append(arr1, func() graphql.Marshaler {