From d02d17ae1d05a2efd3915bff84153feb6497f458 Mon Sep 17 00:00:00 2001 From: creativej Date: Mon, 23 Jul 2018 13:14:07 +1000 Subject: [PATCH 1/3] Add method for generating method name from field --- codegen/object.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/codegen/object.go b/codegen/object.go index 1c03c0bae3d..17b1c875d59 100644 --- a/codegen/object.go +++ b/codegen/object.go @@ -68,11 +68,11 @@ func (f *Field) IsConcurrent() bool { return f.IsResolver() && !f.Object.DisableConcurrency } func (f *Field) ShortInvocation() string { - if !f.IsResolver() { + methodName := f.MethodName() + if methodName == "" { return "" } - shortName := strings.ToUpper(f.GQLName[:1]) + f.GQLName[1:] - res := fmt.Sprintf("%s().%s(ctx", f.Object.GQLType, shortName) + res := fmt.Sprintf("%s(ctx", methodName) if !f.Object.Root { res += fmt.Sprintf(", obj") } @@ -82,6 +82,15 @@ func (f *Field) ShortInvocation() string { res += ")" return res } +func (f *Field) MethodName() string { + if !f.IsResolver() { + return "" + } + shortName := strings.ToUpper(f.GQLName[:1]) + f.GQLName[1:] + + return fmt.Sprintf("%s().%s", f.Object.GQLType, shortName) +} + func (f *Field) ShortResolverDeclaration() string { if !f.IsResolver() { return "" From 3870896111fe12e5320880a0f1baf65a1baa3776 Mon Sep 17 00:00:00 2001 From: creativej Date: Mon, 23 Jul 2018 13:21:05 +1000 Subject: [PATCH 2/3] Stop generating two types of resolvers In recent refactor we introduced a new pattern of resolvers which is better structured and more readable. To keep Gqlgen backward compatible we started generate two styles of resolvers side by side. It is now time to sunset the old resolver. This commit removes the old resolver and update the generation code to use the new resolver directly. --- codegen/object.go | 18 ++--------------- codegen/templates/data.go | 4 ++-- codegen/templates/field.gotpl | 4 ++-- codegen/templates/generated.gotpl | 33 +++---------------------------- 4 files changed, 9 insertions(+), 50 deletions(-) diff --git a/codegen/object.go b/codegen/object.go index 17b1c875d59..5b673e510fc 100644 --- a/codegen/object.go +++ b/codegen/object.go @@ -67,28 +67,14 @@ func (f *Field) IsResolver() bool { func (f *Field) IsConcurrent() bool { return f.IsResolver() && !f.Object.DisableConcurrency } + func (f *Field) ShortInvocation() string { - methodName := f.MethodName() - if methodName == "" { - return "" - } - res := fmt.Sprintf("%s(ctx", methodName) - if !f.Object.Root { - res += fmt.Sprintf(", obj") - } - for _, arg := range f.Args { - res += fmt.Sprintf(", %s", arg.GoVarName) - } - res += ")" - return res -} -func (f *Field) MethodName() string { if !f.IsResolver() { return "" } shortName := strings.ToUpper(f.GQLName[:1]) + f.GQLName[1:] - return fmt.Sprintf("%s().%s", f.Object.GQLType, shortName) + return fmt.Sprintf("%s().%s(%s)", f.Object.GQLType, shortName, f.CallArgs()) } func (f *Field) ShortResolverDeclaration() string { diff --git a/codegen/templates/data.go b/codegen/templates/data.go index c7d750d7a0c..0892b29418c 100644 --- a/codegen/templates/data.go +++ b/codegen/templates/data.go @@ -2,8 +2,8 @@ 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.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() *ast.Schema {\n\treturn parsedSchema\n}\n\nfunc (e *executableSchema) Query(ctx context.Context, op *ast.OperationDefinition) *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.SelectionSet)\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 *ast.OperationDefinition) *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.SelectionSet)\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 *ast.OperationDefinition) 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.SelectionSet)\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\treturn introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name])\n}\n\nvar parsedSchema = gqlparser.MustLoadSchema(\n\t&ast.Source{Name: {{.SchemaFilename|quote}}, Input: {{.SchemaRaw|rawQuote}}},\n)\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.{{ $field.ShortInvocation }}\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.{{ $field.ShortInvocation }}\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// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.\nfunc NewExecutableSchema(resolvers ResolverRoot) graphql.ExecutableSchema {\n\treturn &executableSchema{resolvers: resolvers}\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 executableSchema struct {\n\tresolvers ResolverRoot\n}\n\nfunc (e *executableSchema) Schema() *ast.Schema {\n\treturn parsedSchema\n}\n\nfunc (e *executableSchema) Query(ctx context.Context, op *ast.OperationDefinition) *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.SelectionSet)\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 *ast.OperationDefinition) *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.SelectionSet)\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 *ast.OperationDefinition) 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.SelectionSet)\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 ResolverRoot\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\treturn introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name])\n}\n\nvar parsedSchema = gqlparser.MustLoadSchema(\n\t&ast.Source{Name: {{.SchemaFilename|quote}}, Input: {{.SchemaRaw|rawQuote}}},\n)\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 ast.SelectionSet, 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", "models.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{{ range $model := .Models }}\n\t{{- if .IsInterface }}\n\t\ttype {{.GoType}} interface {}\n\t{{- else }}\n\t\ttype {{.GoType}} struct {\n\t\t\t{{- range $field := .Fields }}\n\t\t\t\t{{- if $field.GoVarName }}\n\t\t\t\t\t{{ $field.GoVarName }} {{$field.Signature}} `json:\"{{$field.GQLName}}\"`\n\t\t\t\t{{- else }}\n\t\t\t\t\t{{ $field.GoFKName }} {{$field.GoFKType}}\n\t\t\t\t{{- end }}\n\t\t\t{{- end }}\n\t\t}\n\t{{- end }}\n{{- end}}\n\n{{ range $enum := .Enums }}\n\ttype {{.GoType}} string\n\tconst (\n\t{{ range $value := .Values -}}\n\t\t{{with .Description}} {{.|prefixLines \"// \"}} {{end}}\n\t\t{{$enum.GoType}}{{ .Name|toCamel }} {{$enum.GoType}} = {{.Name|quote}}\n\t{{- end }}\n\t)\n\n\tfunc (e {{.GoType}}) IsValid() bool {\n\t\tswitch e {\n\t\tcase {{ range $index, $element := .Values}}{{if $index}},{{end}}{{ $enum.GoType }}{{ $element.Name|toCamel }}{{end}}:\n\t\t\treturn true\n\t\t}\n\t\treturn false\n\t}\n\n\tfunc (e {{.GoType}}) String() string {\n\t\treturn string(e)\n\t}\n\n\tfunc (e *{{.GoType}}) UnmarshalGQL(v interface{}) error {\n\t\tstr, ok := v.(string)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"enums must be strings\")\n\t\t}\n\n\t\t*e = {{.GoType}}(str)\n\t\tif !e.IsValid() {\n\t\t\treturn fmt.Errorf(\"%s is not a valid {{.GQLType}}\", str)\n\t\t}\n\t\treturn nil\n\t}\n\n\tfunc (e {{.GoType}}) MarshalGQL(w io.Writer) {\n\t\tfmt.Fprint(w, strconv.Quote(e.String()))\n\t}\n\n{{- end }}\n", diff --git a/codegen/templates/field.gotpl b/codegen/templates/field.gotpl index 4279ad8eaea..64596057662 100644 --- a/codegen/templates/field.gotpl +++ b/codegen/templates/field.gotpl @@ -5,7 +5,7 @@ func (ec *executionContext) _{{$object.GQLType}}_{{$field.GQLName}}(ctx context.Context, field graphql.CollectedField) func() graphql.Marshaler { {{- template "args.gotpl" $field.Args }} ctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{Field: field}) - results, err := ec.resolvers.{{ $object.GQLType }}_{{ $field.GQLName }}({{ $field.CallArgs }}) + results, err := ec.resolvers.{{ $field.ShortInvocation }} if err != nil { ec.Error(ctx, err) return nil @@ -49,7 +49,7 @@ {{- if $field.IsResolver }} resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.{{ $object.GQLType }}_{{ $field.GQLName }}({{ $field.CallArgs }}) + return ec.resolvers.{{ $field.ShortInvocation }} }) if err != nil { ec.Error(ctx, err) diff --git a/codegen/templates/generated.gotpl b/codegen/templates/generated.gotpl index daeece7a4eb..415e5d42e48 100644 --- a/codegen/templates/generated.gotpl +++ b/codegen/templates/generated.gotpl @@ -8,22 +8,9 @@ import ( {{ end }} ) -// MakeExecutableSchema creates an ExecutableSchema from the Resolvers interface. -func MakeExecutableSchema(resolvers Resolvers) graphql.ExecutableSchema { - return &executableSchema{resolvers: resolvers} -} - // NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface. func NewExecutableSchema(resolvers ResolverRoot) graphql.ExecutableSchema { - return MakeExecutableSchema(shortMapper{r: resolvers}) -} - -type Resolvers interface { -{{- range $object := .Objects -}} - {{ range $field := $object.Fields -}} - {{ $field.ResolverDeclaration }} - {{ end }} -{{- end }} + return &executableSchema{resolvers: resolvers} } type ResolverRoot interface { @@ -44,22 +31,8 @@ type ResolverRoot interface { {{- end }} {{- end }} -type shortMapper struct { - r ResolverRoot -} - -{{- range $object := .Objects -}} - {{ range $field := $object.Fields -}} - {{- if $field.IsResolver }} - func (s shortMapper) {{ $field.ResolverDeclaration }} { - return s.r.{{$field.ShortInvocation}} - } - {{- end }} - {{ end }} -{{- end }} - type executableSchema struct { - resolvers Resolvers + resolvers ResolverRoot } func (e *executableSchema) Schema() *ast.Schema { @@ -141,7 +114,7 @@ func (e *executableSchema) Subscription(ctx context.Context, op *ast.OperationDe type executionContext struct { *graphql.RequestContext - resolvers Resolvers + resolvers ResolverRoot } {{- range $object := .Objects }} From 1ba61fcb262123cefb506c899160292fc1dab542 Mon Sep 17 00:00:00 2001 From: creativej Date: Mon, 23 Jul 2018 13:26:53 +1000 Subject: [PATCH 3/3] Update test & examples to use new resolver pattern * chat * dataloader * scalar * selection * starwars * todo --- example/chat/chat_test.go | 2 +- example/chat/generated.go | 40 ++------ example/chat/resolvers.go | 34 +++++-- example/chat/server/server.go | 2 +- example/dataloader/dataloader_test.go | 2 +- example/dataloader/generated.go | 54 ++--------- example/dataloader/resolvers.go | 34 +++++-- example/dataloader/server/server.go | 2 +- example/scalars/generated.go | 47 ++------- example/scalars/resolvers.go | 20 +++- example/scalars/scalar_test.go | 2 +- example/scalars/server/server.go | 2 +- example/selection/generated.go | 25 +---- example/selection/selection.go | 10 +- example/selection/selection_test.go | 2 +- example/selection/server/server.go | 2 +- example/starwars/generated.go | 135 ++++---------------------- example/starwars/resolvers.go | 120 +++++++++++++++-------- example/starwars/server/server.go | 2 +- example/starwars/starwars_test.go | 2 +- example/todo/generated.go | 53 ++-------- test/generated.go | 75 +++----------- test/resolvers_test.go | 60 ++++++++---- 23 files changed, 267 insertions(+), 460 deletions(-) diff --git a/example/chat/chat_test.go b/example/chat/chat_test.go index 4b63fd0526c..409edf2db4d 100644 --- a/example/chat/chat_test.go +++ b/example/chat/chat_test.go @@ -10,7 +10,7 @@ import ( ) func TestChat(t *testing.T) { - srv := httptest.NewServer(handler.GraphQL(MakeExecutableSchema(New()))) + srv := httptest.NewServer(handler.GraphQL(NewExecutableSchema(New()))) c := client.New(srv.URL) t.Run("subscribe to chat events", func(t *testing.T) { diff --git a/example/chat/generated.go b/example/chat/generated.go index a78511caf40..ddc98dd012c 100644 --- a/example/chat/generated.go +++ b/example/chat/generated.go @@ -13,21 +13,9 @@ import ( ast "github.com/vektah/gqlparser/ast" ) -// MakeExecutableSchema creates an ExecutableSchema from the Resolvers interface. -func MakeExecutableSchema(resolvers Resolvers) graphql.ExecutableSchema { - return &executableSchema{resolvers: resolvers} -} - // NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface. func NewExecutableSchema(resolvers ResolverRoot) graphql.ExecutableSchema { - return MakeExecutableSchema(shortMapper{r: resolvers}) -} - -type Resolvers interface { - Mutation_post(ctx context.Context, text string, username string, roomName string) (Message, error) - Query_room(ctx context.Context, name string) (*Chatroom, error) - - Subscription_messageAdded(ctx context.Context, roomName string) (<-chan Message, error) + return &executableSchema{resolvers: resolvers} } type ResolverRoot interface { @@ -45,24 +33,8 @@ type SubscriptionResolver interface { MessageAdded(ctx context.Context, roomName string) (<-chan Message, error) } -type shortMapper struct { - r ResolverRoot -} - -func (s shortMapper) Mutation_post(ctx context.Context, text string, username string, roomName string) (Message, error) { - return s.r.Mutation().Post(ctx, text, username, roomName) -} - -func (s shortMapper) Query_room(ctx context.Context, name string) (*Chatroom, error) { - return s.r.Query().Room(ctx, name) -} - -func (s shortMapper) Subscription_messageAdded(ctx context.Context, roomName string) (<-chan Message, error) { - return s.r.Subscription().MessageAdded(ctx, roomName) -} - type executableSchema struct { - resolvers Resolvers + resolvers ResolverRoot } func (e *executableSchema) Schema() *ast.Schema { @@ -132,7 +104,7 @@ func (e *executableSchema) Subscription(ctx context.Context, op *ast.OperationDe type executionContext struct { *graphql.RequestContext - resolvers Resolvers + resolvers ResolverRoot } var chatroomImplementors = []string{"Chatroom"} @@ -330,7 +302,7 @@ func (ec *executionContext) _Mutation_post(ctx context.Context, field graphql.Co 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)) + return ec.resolvers.Mutation().Post(ctx, args["text"].(string), args["username"].(string), args["roomName"].(string)) }) if err != nil { ec.Error(ctx, err) @@ -401,7 +373,7 @@ func (ec *executionContext) _Query_room(ctx context.Context, field graphql.Colle }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Query_room(ctx, args["name"].(string)) + return ec.resolvers.Query().Room(ctx, args["name"].(string)) }) if err != nil { ec.Error(ctx, err) @@ -491,7 +463,7 @@ func (ec *executionContext) _Subscription_messageAdded(ctx context.Context, fiel } args["roomName"] = arg0 ctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{Field: field}) - results, err := ec.resolvers.Subscription_messageAdded(ctx, args["roomName"].(string)) + results, err := ec.resolvers.Subscription().MessageAdded(ctx, args["roomName"].(string)) if err != nil { ec.Error(ctx, err) return nil diff --git a/example/chat/resolvers.go b/example/chat/resolvers.go index 6bbb0a60dc6..f9f8ee3f083 100644 --- a/example/chat/resolvers.go +++ b/example/chat/resolvers.go @@ -9,13 +9,25 @@ import ( "time" ) -type resolvers struct { +type resolver struct { Rooms map[string]*Chatroom - mu sync.Mutex + mu sync.Mutex // nolint: structcheck } -func New() *resolvers { - return &resolvers{ +func (r *resolver) Mutation() MutationResolver { + return &mutationResolver{r} +} + +func (r *resolver) Query() QueryResolver { + return &queryResolver{r} +} + +func (r *resolver) Subscription() SubscriptionResolver { + return &subscriptionResolver{r} +} + +func New() *resolver { + return &resolver{ Rooms: map[string]*Chatroom{}, } } @@ -26,7 +38,9 @@ type Chatroom struct { Observers map[string]chan Message } -func (r *resolvers) Mutation_post(ctx context.Context, text string, userName string, roomName string) (Message, error) { +type mutationResolver struct{ *resolver } + +func (r *mutationResolver) Post(ctx context.Context, text string, username string, roomName string) (Message, error) { r.mu.Lock() room := r.Rooms[roomName] if room == nil { @@ -39,7 +53,7 @@ func (r *resolvers) Mutation_post(ctx context.Context, text string, userName str ID: randString(8), CreatedAt: time.Now(), Text: text, - CreatedBy: userName, + CreatedBy: username, } room.Messages = append(room.Messages, message) @@ -51,7 +65,9 @@ func (r *resolvers) Mutation_post(ctx context.Context, text string, userName str return message, nil } -func (r *resolvers) Query_room(ctx context.Context, name string) (*Chatroom, error) { +type queryResolver struct{ *resolver } + +func (r *queryResolver) Room(ctx context.Context, name string) (*Chatroom, error) { r.mu.Lock() room := r.Rooms[name] if room == nil { @@ -63,7 +79,9 @@ func (r *resolvers) Query_room(ctx context.Context, name string) (*Chatroom, err return room, nil } -func (r *resolvers) Subscription_messageAdded(ctx context.Context, roomName string) (<-chan Message, error) { +type subscriptionResolver struct{ *resolver } + +func (r *subscriptionResolver) MessageAdded(ctx context.Context, roomName string) (<-chan Message, error) { r.mu.Lock() room := r.Rooms[roomName] if room == nil { diff --git a/example/chat/server/server.go b/example/chat/server/server.go index 1a163996378..6bb56ea98b4 100644 --- a/example/chat/server/server.go +++ b/example/chat/server/server.go @@ -20,7 +20,7 @@ func main() { startAppdashServer() http.Handle("/", handler.Playground("Todo", "/query")) - http.Handle("/query", handler.GraphQL(chat.MakeExecutableSchema(chat.New()), + http.Handle("/query", handler.GraphQL(chat.NewExecutableSchema(chat.New()), handler.ResolverMiddleware(gqlopentracing.ResolverMiddleware()), handler.RequestMiddleware(gqlopentracing.RequestMiddleware()), handler.WebsocketUpgrader(websocket.Upgrader{ diff --git a/example/dataloader/dataloader_test.go b/example/dataloader/dataloader_test.go index c10bb574724..4948feacc48 100644 --- a/example/dataloader/dataloader_test.go +++ b/example/dataloader/dataloader_test.go @@ -11,7 +11,7 @@ import ( ) func TestTodo(t *testing.T) { - srv := httptest.NewServer(LoaderMiddleware(handler.GraphQL(MakeExecutableSchema(&Resolver{})))) + srv := httptest.NewServer(LoaderMiddleware(handler.GraphQL(NewExecutableSchema(&Resolver{})))) c := client.New(srv.URL) t.Run("create a new todo", func(t *testing.T) { diff --git a/example/dataloader/generated.go b/example/dataloader/generated.go index 7695566c644..fff48520fd6 100644 --- a/example/dataloader/generated.go +++ b/example/dataloader/generated.go @@ -13,23 +13,9 @@ import ( ast "github.com/vektah/gqlparser/ast" ) -// MakeExecutableSchema creates an ExecutableSchema from the Resolvers interface. -func MakeExecutableSchema(resolvers Resolvers) graphql.ExecutableSchema { - return &executableSchema{resolvers: resolvers} -} - // NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface. func NewExecutableSchema(resolvers ResolverRoot) graphql.ExecutableSchema { - return MakeExecutableSchema(shortMapper{r: resolvers}) -} - -type Resolvers interface { - Customer_address(ctx context.Context, obj *Customer) (*Address, error) - Customer_orders(ctx context.Context, obj *Customer) ([]Order, error) - - Order_items(ctx context.Context, obj *Order) ([]Item, error) - Query_customers(ctx context.Context) ([]Customer, error) - Query_torture(ctx context.Context, customerIds [][]int) ([][]Customer, error) + return &executableSchema{resolvers: resolvers} } type ResolverRoot interface { @@ -49,32 +35,8 @@ type QueryResolver interface { Torture(ctx context.Context, customerIds [][]int) ([][]Customer, error) } -type shortMapper struct { - r ResolverRoot -} - -func (s shortMapper) Customer_address(ctx context.Context, obj *Customer) (*Address, error) { - return s.r.Customer().Address(ctx, obj) -} - -func (s shortMapper) Customer_orders(ctx context.Context, obj *Customer) ([]Order, error) { - return s.r.Customer().Orders(ctx, obj) -} - -func (s shortMapper) Order_items(ctx context.Context, obj *Order) ([]Item, error) { - return s.r.Order().Items(ctx, obj) -} - -func (s shortMapper) Query_customers(ctx context.Context) ([]Customer, error) { - return s.r.Query().Customers(ctx) -} - -func (s shortMapper) Query_torture(ctx context.Context, customerIds [][]int) ([][]Customer, error) { - return s.r.Query().Torture(ctx, customerIds) -} - type executableSchema struct { - resolvers Resolvers + resolvers ResolverRoot } func (e *executableSchema) Schema() *ast.Schema { @@ -108,7 +70,7 @@ func (e *executableSchema) Subscription(ctx context.Context, op *ast.OperationDe type executionContext struct { *graphql.RequestContext - resolvers Resolvers + resolvers ResolverRoot } var addressImplementors = []string{"Address"} @@ -238,7 +200,7 @@ func (ec *executionContext) _Customer_address(ctx context.Context, field graphql }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Customer_address(ctx, obj) + return ec.resolvers.Customer().Address(ctx, obj) }) if err != nil { ec.Error(ctx, err) @@ -271,7 +233,7 @@ func (ec *executionContext) _Customer_orders(ctx context.Context, field graphql. }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Customer_orders(ctx, obj) + return ec.resolvers.Customer().Orders(ctx, obj) }) if err != nil { ec.Error(ctx, err) @@ -406,7 +368,7 @@ func (ec *executionContext) _Order_items(ctx context.Context, field graphql.Coll }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Order_items(ctx, obj) + return ec.resolvers.Order().Items(ctx, obj) }) if err != nil { ec.Error(ctx, err) @@ -478,7 +440,7 @@ func (ec *executionContext) _Query_customers(ctx context.Context, field graphql. }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Query_customers(ctx) + return ec.resolvers.Query().Customers(ctx) }) if err != nil { ec.Error(ctx, err) @@ -546,7 +508,7 @@ func (ec *executionContext) _Query_torture(ctx context.Context, field graphql.Co }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Query_torture(ctx, args["customerIds"].([][]int)) + return ec.resolvers.Query().Torture(ctx, args["customerIds"].([][]int)) }) if err != nil { ec.Error(ctx, err) diff --git a/example/dataloader/resolvers.go b/example/dataloader/resolvers.go index 2bd93c95ba5..77765e03bb4 100644 --- a/example/dataloader/resolvers.go +++ b/example/dataloader/resolvers.go @@ -22,19 +22,37 @@ type Order struct { type Resolver struct{} -func (r *Resolver) Customer_address(ctx context.Context, it *Customer) (*Address, error) { - return ctxLoaders(ctx).addressByID.Load(it.AddressID) +func (r *Resolver) Customer() CustomerResolver { + return &customerResolver{r} } -func (r *Resolver) Customer_orders(ctx context.Context, it *Customer) ([]Order, error) { - return ctxLoaders(ctx).ordersByCustomer.Load(it.ID) +func (r *Resolver) Order() OrderResolver { + return &orderResolver{r} } -func (r *Resolver) Order_items(ctx context.Context, it *Order) ([]Item, error) { - return ctxLoaders(ctx).itemsByOrder.Load(it.ID) +func (r *Resolver) Query() QueryResolver { + return &queryResolver{r} } -func (r *Resolver) Query_customers(ctx context.Context) ([]Customer, error) { +type customerResolver struct{ *Resolver } + +func (r *customerResolver) Address(ctx context.Context, obj *Customer) (*Address, error) { + return ctxLoaders(ctx).addressByID.Load(obj.AddressID) +} + +func (r *customerResolver) Orders(ctx context.Context, obj *Customer) ([]Order, error) { + return ctxLoaders(ctx).ordersByCustomer.Load(obj.ID) +} + +type orderResolver struct{ *Resolver } + +func (r *orderResolver) Items(ctx context.Context, obj *Order) ([]Item, error) { + return ctxLoaders(ctx).itemsByOrder.Load(obj.ID) +} + +type queryResolver struct{ *Resolver } + +func (r *queryResolver) Customers(ctx context.Context) ([]Customer, error) { fmt.Println("SELECT * FROM customer") time.Sleep(5 * time.Millisecond) @@ -47,7 +65,7 @@ func (r *Resolver) Query_customers(ctx context.Context) ([]Customer, error) { } // this method is here to test code generation of nested arrays -func (r *Resolver) Query_torture(ctx context.Context, customerIds [][]int) ([][]Customer, error) { +func (r *queryResolver) Torture(ctx context.Context, customerIds [][]int) ([][]Customer, error) { result := make([][]Customer, len(customerIds)) for i := range customerIds { inner := make([]Customer, len(customerIds[i])) diff --git a/example/dataloader/server/server.go b/example/dataloader/server/server.go index 22b3b214e51..5f1a501fa4a 100644 --- a/example/dataloader/server/server.go +++ b/example/dataloader/server/server.go @@ -26,7 +26,7 @@ func main() { router.Handle("/", handler.Playground("Dataloader", "/query")) router.Handle("/query", handler.GraphQL( - dataloader.MakeExecutableSchema(&dataloader.Resolver{}), + dataloader.NewExecutableSchema(&dataloader.Resolver{}), handler.ResolverMiddleware(gqlopentracing.ResolverMiddleware()), handler.RequestMiddleware(gqlopentracing.RequestMiddleware()), )) diff --git a/example/scalars/generated.go b/example/scalars/generated.go index c9c6314c804..93b6b50910d 100644 --- a/example/scalars/generated.go +++ b/example/scalars/generated.go @@ -16,22 +16,9 @@ import ( ast "github.com/vektah/gqlparser/ast" ) -// MakeExecutableSchema creates an ExecutableSchema from the Resolvers interface. -func MakeExecutableSchema(resolvers Resolvers) graphql.ExecutableSchema { - return &executableSchema{resolvers: resolvers} -} - // NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface. func NewExecutableSchema(resolvers ResolverRoot) graphql.ExecutableSchema { - return MakeExecutableSchema(shortMapper{r: resolvers}) -} - -type Resolvers interface { - Query_user(ctx context.Context, id external.ObjectID) (*model.User, error) - Query_search(ctx context.Context, input model.SearchArgs) ([]model.User, error) - - User_primitiveResolver(ctx context.Context, obj *model.User) (string, error) - User_customResolver(ctx context.Context, obj *model.User) (model.Point, error) + return &executableSchema{resolvers: resolvers} } type ResolverRoot interface { @@ -47,28 +34,8 @@ type UserResolver interface { CustomResolver(ctx context.Context, obj *model.User) (model.Point, error) } -type shortMapper struct { - r ResolverRoot -} - -func (s shortMapper) Query_user(ctx context.Context, id external.ObjectID) (*model.User, error) { - return s.r.Query().User(ctx, id) -} - -func (s shortMapper) Query_search(ctx context.Context, input model.SearchArgs) ([]model.User, error) { - return s.r.Query().Search(ctx, input) -} - -func (s shortMapper) User_primitiveResolver(ctx context.Context, obj *model.User) (string, error) { - return s.r.User().PrimitiveResolver(ctx, obj) -} - -func (s shortMapper) User_customResolver(ctx context.Context, obj *model.User) (model.Point, error) { - return s.r.User().CustomResolver(ctx, obj) -} - type executableSchema struct { - resolvers Resolvers + resolvers ResolverRoot } func (e *executableSchema) Schema() *ast.Schema { @@ -102,7 +69,7 @@ func (e *executableSchema) Subscription(ctx context.Context, op *ast.OperationDe type executionContext struct { *graphql.RequestContext - resolvers Resolvers + resolvers ResolverRoot } var addressImplementors = []string{"Address"} @@ -215,7 +182,7 @@ func (ec *executionContext) _Query_user(ctx context.Context, field graphql.Colle }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Query_user(ctx, args["id"].(external.ObjectID)) + return ec.resolvers.Query().User(ctx, args["id"].(external.ObjectID)) }) if err != nil { ec.Error(ctx, err) @@ -268,7 +235,7 @@ func (ec *executionContext) _Query_search(ctx context.Context, field graphql.Col }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Query_search(ctx, args["input"].(model.SearchArgs)) + return ec.resolvers.Query().Search(ctx, args["input"].(model.SearchArgs)) }) if err != nil { ec.Error(ctx, err) @@ -427,7 +394,7 @@ func (ec *executionContext) _User_primitiveResolver(ctx context.Context, field g }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.User_primitiveResolver(ctx, obj) + return ec.resolvers.User().PrimitiveResolver(ctx, obj) }) if err != nil { ec.Error(ctx, err) @@ -457,7 +424,7 @@ func (ec *executionContext) _User_customResolver(ctx context.Context, field grap }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.User_customResolver(ctx, obj) + return ec.resolvers.User().CustomResolver(ctx, obj) }) if err != nil { ec.Error(ctx, err) diff --git a/example/scalars/resolvers.go b/example/scalars/resolvers.go index 8b45f80246c..3f001bdcd32 100644 --- a/example/scalars/resolvers.go +++ b/example/scalars/resolvers.go @@ -14,7 +14,17 @@ import ( type Resolver struct { } -func (r *Resolver) Query_user(ctx context.Context, id external.ObjectID) (*model.User, error) { +func (r *Resolver) Query() QueryResolver { + return &queryResolver{r} +} + +func (r *Resolver) User() UserResolver { + return &userResolver{r} +} + +type queryResolver struct{ *Resolver } + +func (r *queryResolver) User(ctx context.Context, id external.ObjectID) (*model.User, error) { return &model.User{ ID: id, Name: fmt.Sprintf("Test User %d", id), @@ -24,7 +34,7 @@ func (r *Resolver) Query_user(ctx context.Context, id external.ObjectID) (*model }, nil } -func (r *Resolver) Query_search(ctx context.Context, input model.SearchArgs) ([]model.User, error) { +func (r *queryResolver) Search(ctx context.Context, input model.SearchArgs) ([]model.User, error) { location := model.Point{1, 2} if input.Location != nil { location = *input.Location @@ -53,10 +63,12 @@ func (r *Resolver) Query_search(ctx context.Context, input model.SearchArgs) ([] }, nil } -func (r *Resolver) User_primitiveResolver(ctx context.Context, obj *model.User) (string, error) { +type userResolver struct{ *Resolver } + +func (r *userResolver) PrimitiveResolver(ctx context.Context, obj *model.User) (string, error) { return "test", nil } -func (r *Resolver) User_customResolver(ctx context.Context, obj *model.User) (model.Point, error) { +func (r *userResolver) CustomResolver(ctx context.Context, obj *model.User) (model.Point, error) { return model.Point{5, 1}, nil } diff --git a/example/scalars/scalar_test.go b/example/scalars/scalar_test.go index 96a3eee409c..7e07e096858 100644 --- a/example/scalars/scalar_test.go +++ b/example/scalars/scalar_test.go @@ -22,7 +22,7 @@ type RawUser struct { } func TestScalars(t *testing.T) { - srv := httptest.NewServer(handler.GraphQL(MakeExecutableSchema(&Resolver{}))) + srv := httptest.NewServer(handler.GraphQL(NewExecutableSchema(&Resolver{}))) c := client.New(srv.URL) t.Run("marshaling", func(t *testing.T) { diff --git a/example/scalars/server/server.go b/example/scalars/server/server.go index 22805f22244..748213b97ec 100644 --- a/example/scalars/server/server.go +++ b/example/scalars/server/server.go @@ -10,7 +10,7 @@ import ( func main() { http.Handle("/", handler.Playground("Starwars", "/query")) - http.Handle("/query", handler.GraphQL(scalars.MakeExecutableSchema(&scalars.Resolver{}))) + http.Handle("/query", handler.GraphQL(scalars.NewExecutableSchema(&scalars.Resolver{}))) log.Fatal(http.ListenAndServe(":8084", nil)) } diff --git a/example/selection/generated.go b/example/selection/generated.go index e46fbd0c97b..c001c2d6694 100644 --- a/example/selection/generated.go +++ b/example/selection/generated.go @@ -14,18 +14,9 @@ import ( ast "github.com/vektah/gqlparser/ast" ) -// MakeExecutableSchema creates an ExecutableSchema from the Resolvers interface. -func MakeExecutableSchema(resolvers Resolvers) graphql.ExecutableSchema { - return &executableSchema{resolvers: resolvers} -} - // NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface. func NewExecutableSchema(resolvers ResolverRoot) graphql.ExecutableSchema { - return MakeExecutableSchema(shortMapper{r: resolvers}) -} - -type Resolvers interface { - Query_events(ctx context.Context) ([]Event, error) + return &executableSchema{resolvers: resolvers} } type ResolverRoot interface { @@ -35,16 +26,8 @@ type QueryResolver interface { Events(ctx context.Context) ([]Event, error) } -type shortMapper struct { - r ResolverRoot -} - -func (s shortMapper) Query_events(ctx context.Context) ([]Event, error) { - return s.r.Query().Events(ctx) -} - type executableSchema struct { - resolvers Resolvers + resolvers ResolverRoot } func (e *executableSchema) Schema() *ast.Schema { @@ -78,7 +61,7 @@ func (e *executableSchema) Subscription(ctx context.Context, op *ast.OperationDe type executionContext struct { *graphql.RequestContext - resolvers Resolvers + resolvers ResolverRoot } var likeImplementors = []string{"Like", "Event"} @@ -310,7 +293,7 @@ func (ec *executionContext) _Query_events(ctx context.Context, field graphql.Col }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Query_events(ctx) + return ec.resolvers.Query().Events(ctx) }) if err != nil { ec.Error(ctx, err) diff --git a/example/selection/selection.go b/example/selection/selection.go index 7d11be04572..be4486f6b6b 100644 --- a/example/selection/selection.go +++ b/example/selection/selection.go @@ -11,9 +11,15 @@ import ( "github.com/vektah/gqlparser/ast" ) -type SelectionResolver struct{} +type Resolver struct{} -func (r *SelectionResolver) Query_events(ctx context.Context) ([]Event, error) { +func (r *Resolver) Query() QueryResolver { + return &queryResolver{r} +} + +type queryResolver struct{ *Resolver } + +func (r *queryResolver) Events(ctx context.Context) ([]Event, error) { var sels []string reqCtx := graphql.GetRequestContext(ctx) diff --git a/example/selection/selection_test.go b/example/selection/selection_test.go index 4c1829a3aaa..dc3a199549e 100644 --- a/example/selection/selection_test.go +++ b/example/selection/selection_test.go @@ -11,7 +11,7 @@ import ( ) func TestSelection(t *testing.T) { - srv := httptest.NewServer(handler.GraphQL(MakeExecutableSchema(&SelectionResolver{}))) + srv := httptest.NewServer(handler.GraphQL(NewExecutableSchema(&Resolver{}))) c := client.New(srv.URL) query := `{ diff --git a/example/selection/server/server.go b/example/selection/server/server.go index e8982e8bd1d..84e291cb5db 100644 --- a/example/selection/server/server.go +++ b/example/selection/server/server.go @@ -10,6 +10,6 @@ import ( func main() { http.Handle("/", handler.Playground("Selection Demo", "/query")) - http.Handle("/query", handler.GraphQL(selection.MakeExecutableSchema(&selection.SelectionResolver{}))) + http.Handle("/query", handler.GraphQL(selection.NewExecutableSchema(&selection.Resolver{}))) log.Fatal(http.ListenAndServe(":8086", nil)) } diff --git a/example/starwars/generated.go b/example/starwars/generated.go index fc0036b3a82..d83d60303c0 100644 --- a/example/starwars/generated.go +++ b/example/starwars/generated.go @@ -15,38 +15,9 @@ import ( ast "github.com/vektah/gqlparser/ast" ) -// MakeExecutableSchema creates an ExecutableSchema from the Resolvers interface. -func MakeExecutableSchema(resolvers Resolvers) graphql.ExecutableSchema { - return &executableSchema{resolvers: resolvers} -} - // NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface. func NewExecutableSchema(resolvers ResolverRoot) graphql.ExecutableSchema { - return MakeExecutableSchema(shortMapper{r: resolvers}) -} - -type Resolvers interface { - Droid_friends(ctx context.Context, obj *Droid) ([]Character, error) - Droid_friendsConnection(ctx context.Context, obj *Droid, first *int, after *string) (FriendsConnection, error) - - FriendsConnection_edges(ctx context.Context, obj *FriendsConnection) ([]FriendsEdge, error) - FriendsConnection_friends(ctx context.Context, obj *FriendsConnection) ([]Character, error) - - Human_friends(ctx context.Context, obj *Human) ([]Character, error) - Human_friendsConnection(ctx context.Context, obj *Human, first *int, after *string) (FriendsConnection, error) - - Human_starships(ctx context.Context, obj *Human) ([]Starship, error) - Mutation_createReview(ctx context.Context, episode Episode, review Review) (*Review, error) - - Query_hero(ctx context.Context, episode Episode) (Character, error) - Query_reviews(ctx context.Context, episode Episode, since *time.Time) ([]Review, error) - Query_search(ctx context.Context, text string) ([]SearchResult, error) - Query_character(ctx context.Context, id string) (Character, error) - 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) + return &executableSchema{resolvers: resolvers} } type ResolverRoot interface { @@ -87,76 +58,8 @@ type StarshipResolver interface { Length(ctx context.Context, obj *Starship, unit LengthUnit) (float64, error) } -type shortMapper struct { - r ResolverRoot -} - -func (s shortMapper) Droid_friends(ctx context.Context, obj *Droid) ([]Character, error) { - return s.r.Droid().Friends(ctx, obj) -} - -func (s shortMapper) Droid_friendsConnection(ctx context.Context, obj *Droid, first *int, after *string) (FriendsConnection, error) { - return s.r.Droid().FriendsConnection(ctx, obj, first, after) -} - -func (s shortMapper) FriendsConnection_edges(ctx context.Context, obj *FriendsConnection) ([]FriendsEdge, error) { - return s.r.FriendsConnection().Edges(ctx, obj) -} - -func (s shortMapper) FriendsConnection_friends(ctx context.Context, obj *FriendsConnection) ([]Character, error) { - return s.r.FriendsConnection().Friends(ctx, obj) -} - -func (s shortMapper) Human_friends(ctx context.Context, obj *Human) ([]Character, error) { - return s.r.Human().Friends(ctx, obj) -} - -func (s shortMapper) Human_friendsConnection(ctx context.Context, obj *Human, first *int, after *string) (FriendsConnection, error) { - return s.r.Human().FriendsConnection(ctx, obj, first, after) -} - -func (s shortMapper) Human_starships(ctx context.Context, obj *Human) ([]Starship, error) { - return s.r.Human().Starships(ctx, obj) -} - -func (s shortMapper) Mutation_createReview(ctx context.Context, episode Episode, review Review) (*Review, error) { - return s.r.Mutation().CreateReview(ctx, episode, review) -} - -func (s shortMapper) Query_hero(ctx context.Context, episode Episode) (Character, error) { - return s.r.Query().Hero(ctx, episode) -} - -func (s shortMapper) Query_reviews(ctx context.Context, episode Episode, since *time.Time) ([]Review, error) { - return s.r.Query().Reviews(ctx, episode, since) -} - -func (s shortMapper) Query_search(ctx context.Context, text string) ([]SearchResult, error) { - return s.r.Query().Search(ctx, text) -} - -func (s shortMapper) Query_character(ctx context.Context, id string) (Character, error) { - return s.r.Query().Character(ctx, id) -} - -func (s shortMapper) Query_droid(ctx context.Context, id string) (*Droid, error) { - return s.r.Query().Droid(ctx, id) -} - -func (s shortMapper) Query_human(ctx context.Context, id string) (*Human, error) { - return s.r.Query().Human(ctx, id) -} - -func (s shortMapper) Query_starship(ctx context.Context, id string) (*Starship, error) { - 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 + resolvers ResolverRoot } func (e *executableSchema) Schema() *ast.Schema { @@ -202,7 +105,7 @@ func (e *executableSchema) Subscription(ctx context.Context, op *ast.OperationDe type executionContext struct { *graphql.RequestContext - resolvers Resolvers + resolvers ResolverRoot } var droidImplementors = []string{"Droid", "Character"} @@ -276,7 +179,7 @@ func (ec *executionContext) _Droid_friends(ctx context.Context, field graphql.Co }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Droid_friends(ctx, obj) + return ec.resolvers.Droid().Friends(ctx, obj) }) if err != nil { ec.Error(ctx, err) @@ -346,7 +249,7 @@ func (ec *executionContext) _Droid_friendsConnection(ctx context.Context, field }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Droid_friendsConnection(ctx, obj, args["first"].(*int), args["after"].(*string)) + return ec.resolvers.Droid().FriendsConnection(ctx, obj, args["first"].(*int), args["after"].(*string)) }) if err != nil { ec.Error(ctx, err) @@ -447,7 +350,7 @@ func (ec *executionContext) _FriendsConnection_edges(ctx context.Context, field }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.FriendsConnection_edges(ctx, obj) + return ec.resolvers.FriendsConnection().Edges(ctx, obj) }) if err != nil { ec.Error(ctx, err) @@ -486,7 +389,7 @@ func (ec *executionContext) _FriendsConnection_friends(ctx context.Context, fiel }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.FriendsConnection_friends(ctx, obj) + return ec.resolvers.FriendsConnection().Friends(ctx, obj) }) if err != nil { ec.Error(ctx, err) @@ -684,7 +587,7 @@ func (ec *executionContext) _Human_friends(ctx context.Context, field graphql.Co }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Human_friends(ctx, obj) + return ec.resolvers.Human().Friends(ctx, obj) }) if err != nil { ec.Error(ctx, err) @@ -754,7 +657,7 @@ func (ec *executionContext) _Human_friendsConnection(ctx context.Context, field }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Human_friendsConnection(ctx, obj, args["first"].(*int), args["after"].(*string)) + return ec.resolvers.Human().FriendsConnection(ctx, obj, args["first"].(*int), args["after"].(*string)) }) if err != nil { ec.Error(ctx, err) @@ -804,7 +707,7 @@ func (ec *executionContext) _Human_starships(ctx context.Context, field graphql. }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Human_starships(ctx, obj) + return ec.resolvers.Human().Starships(ctx, obj) }) if err != nil { ec.Error(ctx, err) @@ -883,7 +786,7 @@ func (ec *executionContext) _Mutation_createReview(ctx context.Context, field gr 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)) + return ec.resolvers.Mutation().CreateReview(ctx, args["episode"].(Episode), args["review"].(Review)) }) if err != nil { ec.Error(ctx, err) @@ -1038,7 +941,7 @@ func (ec *executionContext) _Query_hero(ctx context.Context, field graphql.Colle }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Query_hero(ctx, args["episode"].(Episode)) + return ec.resolvers.Query().Hero(ctx, args["episode"].(Episode)) }) if err != nil { ec.Error(ctx, err) @@ -1094,7 +997,7 @@ func (ec *executionContext) _Query_reviews(ctx context.Context, field graphql.Co }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Query_reviews(ctx, args["episode"].(Episode), args["since"].(*time.Time)) + return ec.resolvers.Query().Reviews(ctx, args["episode"].(Episode), args["since"].(*time.Time)) }) if err != nil { ec.Error(ctx, err) @@ -1144,7 +1047,7 @@ func (ec *executionContext) _Query_search(ctx context.Context, field graphql.Col }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Query_search(ctx, args["text"].(string)) + return ec.resolvers.Query().Search(ctx, args["text"].(string)) }) if err != nil { ec.Error(ctx, err) @@ -1194,7 +1097,7 @@ func (ec *executionContext) _Query_character(ctx context.Context, field graphql. }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Query_character(ctx, args["id"].(string)) + return ec.resolvers.Query().Character(ctx, args["id"].(string)) }) if err != nil { ec.Error(ctx, err) @@ -1235,7 +1138,7 @@ func (ec *executionContext) _Query_droid(ctx context.Context, field graphql.Coll }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Query_droid(ctx, args["id"].(string)) + return ec.resolvers.Query().Droid(ctx, args["id"].(string)) }) if err != nil { ec.Error(ctx, err) @@ -1279,7 +1182,7 @@ func (ec *executionContext) _Query_human(ctx context.Context, field graphql.Coll }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Query_human(ctx, args["id"].(string)) + return ec.resolvers.Query().Human(ctx, args["id"].(string)) }) if err != nil { ec.Error(ctx, err) @@ -1323,7 +1226,7 @@ func (ec *executionContext) _Query_starship(ctx context.Context, field graphql.C }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Query_starship(ctx, args["id"].(string)) + return ec.resolvers.Query().Starship(ctx, args["id"].(string)) }) if err != nil { ec.Error(ctx, err) @@ -1529,7 +1432,7 @@ func (ec *executionContext) _Starship_length(ctx context.Context, field graphql. }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Starship_length(ctx, obj, args["unit"].(LengthUnit)) + return ec.resolvers.Starship().Length(ctx, obj, args["unit"].(LengthUnit)) }) if err != nil { ec.Error(ctx, err) diff --git a/example/starwars/resolvers.go b/example/starwars/resolvers.go index 7113401d923..8cf78469aa1 100644 --- a/example/starwars/resolvers.go +++ b/example/starwars/resolvers.go @@ -16,84 +16,117 @@ type Resolver struct { reviews map[Episode][]Review } -func (r *Resolver) resolveCharacters(ctx context.Context, ids []string) ([]Character, error) { - var result []Character - for _, id := range ids { - char, err := r.Query_character(ctx, id) - if err != nil { - return nil, err - } - result = append(result, char) - } - return result, nil +func (r *Resolver) Droid() DroidResolver { + return &droidResolver{r} } -func (r *Resolver) Human_friends(ctx context.Context, it *Human) ([]Character, error) { - return r.resolveCharacters(ctx, it.FriendIds) +func (r *Resolver) FriendsConnection() FriendsConnectionResolver { + return &friendsConnectionResolver{r} } -func (r *Resolver) Human_friendsConnection(ctx context.Context, it *Human, first *int, after *string) (FriendsConnection, error) { - return r.resolveFriendConnection(ctx, it.FriendIds, first, after) +func (r *Resolver) Human() HumanResolver { + return &humanResolver{r} } -func (r *Resolver) Human_starships(ctx context.Context, it *Human) ([]Starship, error) { - var result []Starship - for _, id := range it.StarshipIds { - char, err := r.Query_starship(ctx, id) +func (r *Resolver) Mutation() MutationResolver { + return &mutationResolver{r} +} + +func (r *Resolver) Query() QueryResolver { + return &queryResolver{r} +} + +func (r *Resolver) Starship() StarshipResolver { + return &starshipResolver{r} +} + +func (r *Resolver) resolveCharacters(ctx context.Context, ids []string) ([]Character, error) { + var result []Character + for _, id := range ids { + char, err := r.Query().Character(ctx, id) if err != nil { return nil, err } - if char != nil { - result = append(result, *char) - } + result = append(result, char) } return result, nil } -func (r *Resolver) Droid_friends(ctx context.Context, it *Droid) ([]Character, error) { - return r.resolveCharacters(ctx, it.FriendIds) +type droidResolver struct{ *Resolver } + +func (r *droidResolver) Friends(ctx context.Context, obj *Droid) ([]Character, error) { + return r.resolveCharacters(ctx, obj.FriendIds) } -func (r *Resolver) Droid_friendsConnection(ctx context.Context, it *Droid, first *int, after *string) (FriendsConnection, error) { - return r.resolveFriendConnection(ctx, it.FriendIds, first, after) +func (r *droidResolver) FriendsConnection(ctx context.Context, obj *Droid, first *int, after *string) (FriendsConnection, error) { + return r.resolveFriendConnection(ctx, obj.FriendIds, first, after) } -func (r *Resolver) FriendsConnection_edges(ctx context.Context, it *FriendsConnection) ([]FriendsEdge, error) { - friends, err := r.resolveCharacters(ctx, it.ids) +type friendsConnectionResolver struct{ *Resolver } + +func (r *friendsConnectionResolver) Edges(ctx context.Context, obj *FriendsConnection) ([]FriendsEdge, error) { + friends, err := r.resolveCharacters(ctx, obj.ids) if err != nil { return nil, err } - edges := make([]FriendsEdge, it.to-it.from) + edges := make([]FriendsEdge, obj.to-obj.from) for i := range edges { edges[i] = FriendsEdge{ - Cursor: encodeCursor(it.from + i), + Cursor: encodeCursor(obj.from + i), Node: friends[i], } } return edges, nil } -// A list of the friends, as a convenience when edges are not needed. -func (r *Resolver) FriendsConnection_friends(ctx context.Context, it *FriendsConnection) ([]Character, error) { - return r.resolveCharacters(ctx, it.ids) +func (r *friendsConnectionResolver) Friends(ctx context.Context, obj *FriendsConnection) ([]Character, error) { + return r.resolveCharacters(ctx, obj.ids) +} + +type humanResolver struct{ *Resolver } + +func (r *humanResolver) Friends(ctx context.Context, obj *Human) ([]Character, error) { + return r.resolveCharacters(ctx, obj.FriendIds) +} + +func (r *humanResolver) FriendsConnection(ctx context.Context, obj *Human, first *int, after *string) (FriendsConnection, error) { + return r.resolveFriendConnection(ctx, obj.FriendIds, first, after) } -func (r *Resolver) Mutation_createReview(ctx context.Context, episode Episode, review Review) (*Review, error) { +func (r *humanResolver) Starships(ctx context.Context, obj *Human) ([]Starship, error) { + var result []Starship + for _, id := range obj.StarshipIds { + char, err := r.Query().Starship(ctx, id) + if err != nil { + return nil, err + } + if char != nil { + result = append(result, *char) + } + } + return result, nil +} + +type mutationResolver struct{ *Resolver } + +func (r *mutationResolver) CreateReview(ctx context.Context, episode Episode, review Review) (*Review, error) { review.Time = time.Now() time.Sleep(1 * time.Second) r.reviews[episode] = append(r.reviews[episode], review) return &review, nil } -func (r *Resolver) Query_hero(ctx context.Context, episode Episode) (Character, error) { +type queryResolver struct{ *Resolver } + +func (r *queryResolver) Hero(ctx context.Context, episode Episode) (Character, error) { if episode == EpisodeEmpire { return r.humans["1000"], nil } return r.droid["2001"], nil } -func (r *Resolver) Query_reviews(ctx context.Context, episode Episode, since *time.Time) ([]Review, error) { +func (r *queryResolver) Reviews(ctx context.Context, episode Episode, since *time.Time) ([]Review, error) { if since == nil { return r.reviews[episode], nil } @@ -107,7 +140,7 @@ func (r *Resolver) Query_reviews(ctx context.Context, episode Episode, since *ti return filtered, nil } -func (r *Resolver) Query_search(ctx context.Context, text string) ([]SearchResult, error) { +func (r *queryResolver) Search(ctx context.Context, text string) ([]SearchResult, error) { var l []SearchResult for _, h := range r.humans { if strings.Contains(h.Name, text) { @@ -127,7 +160,7 @@ func (r *Resolver) Query_search(ctx context.Context, text string) ([]SearchResul return l, nil } -func (r *Resolver) Query_character(ctx context.Context, id string) (Character, error) { +func (r *queryResolver) Character(ctx context.Context, id string) (Character, error) { if h, ok := r.humans[id]; ok { return &h, nil } @@ -136,26 +169,31 @@ func (r *Resolver) Query_character(ctx context.Context, id string) (Character, e } return nil, nil } -func (r *Resolver) Query_droid(ctx context.Context, id string) (*Droid, error) { + +func (r *queryResolver) Droid(ctx context.Context, id string) (*Droid, error) { if d, ok := r.droid[id]; ok { return &d, nil } return nil, nil } -func (r *Resolver) Query_human(ctx context.Context, id string) (*Human, error) { + +func (r *queryResolver) Human(ctx context.Context, id string) (*Human, error) { if h, ok := r.humans[id]; ok { return &h, nil } return nil, nil } -func (r *Resolver) Query_starship(ctx context.Context, id string) (*Starship, error) { + +func (r *queryResolver) Starship(ctx context.Context, id string) (*Starship, error) { if s, ok := r.starships[id]; ok { return &s, nil } return nil, nil } -func (r *Resolver) Starship_length(ctx context.Context, obj *Starship, unit LengthUnit) (float64, error) { +type starshipResolver struct{ *Resolver } + +func (r *starshipResolver) Length(ctx context.Context, obj *Starship, unit LengthUnit) (float64, error) { switch unit { case LengthUnitMeter, "": return obj.Length, nil diff --git a/example/starwars/server/server.go b/example/starwars/server/server.go index 86bdbdc5468..b27404f0490 100644 --- a/example/starwars/server/server.go +++ b/example/starwars/server/server.go @@ -13,7 +13,7 @@ import ( func main() { http.Handle("/", handler.Playground("Starwars", "/query")) - http.Handle("/query", handler.GraphQL(starwars.MakeExecutableSchema(starwars.NewResolver()), + http.Handle("/query", handler.GraphQL(starwars.NewExecutableSchema(starwars.NewResolver()), handler.ResolverMiddleware(func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) { rc := graphql.GetResolverContext(ctx) fmt.Println("Entered", rc.Object, rc.Field.Name) diff --git a/example/starwars/starwars_test.go b/example/starwars/starwars_test.go index 8fbb54547bf..fc35f0b416f 100644 --- a/example/starwars/starwars_test.go +++ b/example/starwars/starwars_test.go @@ -11,7 +11,7 @@ import ( ) func TestStarwars(t *testing.T) { - srv := httptest.NewServer(handler.GraphQL(MakeExecutableSchema(NewResolver()))) + srv := httptest.NewServer(handler.GraphQL(NewExecutableSchema(NewResolver()))) c := client.New(srv.URL) t.Run("Lukes starships", func(t *testing.T) { diff --git a/example/todo/generated.go b/example/todo/generated.go index 142f9f79545..135cff5dace 100644 --- a/example/todo/generated.go +++ b/example/todo/generated.go @@ -13,22 +13,9 @@ import ( ast "github.com/vektah/gqlparser/ast" ) -// MakeExecutableSchema creates an ExecutableSchema from the Resolvers interface. -func MakeExecutableSchema(resolvers Resolvers) graphql.ExecutableSchema { - return &executableSchema{resolvers: resolvers} -} - // NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface. func NewExecutableSchema(resolvers ResolverRoot) graphql.ExecutableSchema { - return MakeExecutableSchema(shortMapper{r: resolvers}) -} - -type Resolvers interface { - MyMutation_createTodo(ctx context.Context, todo TodoInput) (Todo, error) - MyMutation_updateTodo(ctx context.Context, id int, changes map[string]interface{}) (*Todo, error) - MyQuery_todo(ctx context.Context, id int) (*Todo, error) - MyQuery_lastTodo(ctx context.Context) (*Todo, error) - MyQuery_todos(ctx context.Context) ([]Todo, error) + return &executableSchema{resolvers: resolvers} } type ResolverRoot interface { @@ -45,32 +32,8 @@ type MyQueryResolver interface { Todos(ctx context.Context) ([]Todo, error) } -type shortMapper struct { - r ResolverRoot -} - -func (s shortMapper) MyMutation_createTodo(ctx context.Context, todo TodoInput) (Todo, error) { - return s.r.MyMutation().CreateTodo(ctx, todo) -} - -func (s shortMapper) MyMutation_updateTodo(ctx context.Context, id int, changes map[string]interface{}) (*Todo, error) { - return s.r.MyMutation().UpdateTodo(ctx, id, changes) -} - -func (s shortMapper) MyQuery_todo(ctx context.Context, id int) (*Todo, error) { - return s.r.MyQuery().Todo(ctx, id) -} - -func (s shortMapper) MyQuery_lastTodo(ctx context.Context) (*Todo, error) { - return s.r.MyQuery().LastTodo(ctx) -} - -func (s shortMapper) MyQuery_todos(ctx context.Context) ([]Todo, error) { - return s.r.MyQuery().Todos(ctx) -} - type executableSchema struct { - resolvers Resolvers + resolvers ResolverRoot } func (e *executableSchema) Schema() *ast.Schema { @@ -116,7 +79,7 @@ func (e *executableSchema) Subscription(ctx context.Context, op *ast.OperationDe type executionContext struct { *graphql.RequestContext - resolvers Resolvers + resolvers ResolverRoot } var myMutationImplementors = []string{"MyMutation"} @@ -167,7 +130,7 @@ func (ec *executionContext) _MyMutation_createTodo(ctx context.Context, field gr 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)) + return ec.resolvers.MyMutation().CreateTodo(ctx, args["todo"].(TodoInput)) }) if err != nil { ec.Error(ctx, err) @@ -209,7 +172,7 @@ func (ec *executionContext) _MyMutation_updateTodo(ctx context.Context, field gr 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{})) + return ec.resolvers.MyMutation().UpdateTodo(ctx, args["id"].(int), args["changes"].(map[string]interface{})) }) if err != nil { ec.Error(ctx, err) @@ -287,7 +250,7 @@ func (ec *executionContext) _MyQuery_todo(ctx context.Context, field graphql.Col }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.MyQuery_todo(ctx, args["id"].(int)) + return ec.resolvers.MyQuery().Todo(ctx, args["id"].(int)) }) if err != nil { ec.Error(ctx, err) @@ -320,7 +283,7 @@ func (ec *executionContext) _MyQuery_lastTodo(ctx context.Context, field graphql }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.MyQuery_lastTodo(ctx) + return ec.resolvers.MyQuery().LastTodo(ctx) }) if err != nil { ec.Error(ctx, err) @@ -353,7 +316,7 @@ func (ec *executionContext) _MyQuery_todos(ctx context.Context, field graphql.Co }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.MyQuery_todos(ctx) + return ec.resolvers.MyQuery().Todos(ctx) }) if err != nil { ec.Error(ctx, err) diff --git a/test/generated.go b/test/generated.go index 240b8961e06..59019126358 100644 --- a/test/generated.go +++ b/test/generated.go @@ -15,26 +15,9 @@ import ( ast "github.com/vektah/gqlparser/ast" ) -// MakeExecutableSchema creates an ExecutableSchema from the Resolvers interface. -func MakeExecutableSchema(resolvers Resolvers) graphql.ExecutableSchema { - return &executableSchema{resolvers: resolvers} -} - // NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface. func NewExecutableSchema(resolvers ResolverRoot) graphql.ExecutableSchema { - return MakeExecutableSchema(shortMapper{r: resolvers}) -} - -type Resolvers interface { - Element_child(ctx context.Context, obj *models.Element) (models.Element, error) - Element_error(ctx context.Context, obj *models.Element) (bool, error) - Element_mismatched(ctx context.Context, obj *models.Element) ([]bool, error) - Query_path(ctx context.Context) ([]*models.Element, error) - Query_date(ctx context.Context, filter models.DateFilter) (bool, error) - Query_viewer(ctx context.Context) (*models.Viewer, error) - Query_jsonEncoding(ctx context.Context) (string, error) - - User_likes(ctx context.Context, obj *remote_api.User) ([]string, error) + return &executableSchema{resolvers: resolvers} } type ResolverRoot interface { @@ -57,44 +40,8 @@ type UserResolver interface { Likes(ctx context.Context, obj *remote_api.User) ([]string, error) } -type shortMapper struct { - r ResolverRoot -} - -func (s shortMapper) Element_child(ctx context.Context, obj *models.Element) (models.Element, error) { - return s.r.Element().Child(ctx, obj) -} - -func (s shortMapper) Element_error(ctx context.Context, obj *models.Element) (bool, error) { - return s.r.Element().Error(ctx, obj) -} - -func (s shortMapper) Element_mismatched(ctx context.Context, obj *models.Element) ([]bool, error) { - return s.r.Element().Mismatched(ctx, obj) -} - -func (s shortMapper) Query_path(ctx context.Context) ([]*models.Element, error) { - return s.r.Query().Path(ctx) -} - -func (s shortMapper) Query_date(ctx context.Context, filter models.DateFilter) (bool, error) { - return s.r.Query().Date(ctx, filter) -} - -func (s shortMapper) Query_viewer(ctx context.Context) (*models.Viewer, error) { - return s.r.Query().Viewer(ctx) -} - -func (s shortMapper) Query_jsonEncoding(ctx context.Context) (string, error) { - return s.r.Query().JsonEncoding(ctx) -} - -func (s shortMapper) User_likes(ctx context.Context, obj *remote_api.User) ([]string, error) { - return s.r.User().Likes(ctx, obj) -} - type executableSchema struct { - resolvers Resolvers + resolvers ResolverRoot } func (e *executableSchema) Schema() *ast.Schema { @@ -128,7 +75,7 @@ func (e *executableSchema) Subscription(ctx context.Context, op *ast.OperationDe type executionContext struct { *graphql.RequestContext - resolvers Resolvers + resolvers ResolverRoot } var elementImplementors = []string{"Element"} @@ -174,7 +121,7 @@ func (ec *executionContext) _Element_child(ctx context.Context, field graphql.Co }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Element_child(ctx, obj) + return ec.resolvers.Element().Child(ctx, obj) }) if err != nil { ec.Error(ctx, err) @@ -204,7 +151,7 @@ func (ec *executionContext) _Element_error(ctx context.Context, field graphql.Co }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Element_error(ctx, obj) + return ec.resolvers.Element().Error(ctx, obj) }) if err != nil { ec.Error(ctx, err) @@ -234,7 +181,7 @@ func (ec *executionContext) _Element_mismatched(ctx context.Context, field graph }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Element_mismatched(ctx, obj) + return ec.resolvers.Element().Mismatched(ctx, obj) }) if err != nil { ec.Error(ctx, err) @@ -310,7 +257,7 @@ func (ec *executionContext) _Query_path(ctx context.Context, field graphql.Colle }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Query_path(ctx) + return ec.resolvers.Query().Path(ctx) }) if err != nil { ec.Error(ctx, err) @@ -363,7 +310,7 @@ func (ec *executionContext) _Query_date(ctx context.Context, field graphql.Colle }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Query_date(ctx, args["filter"].(models.DateFilter)) + return ec.resolvers.Query().Date(ctx, args["filter"].(models.DateFilter)) }) if err != nil { ec.Error(ctx, err) @@ -393,7 +340,7 @@ func (ec *executionContext) _Query_viewer(ctx context.Context, field graphql.Col }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Query_viewer(ctx) + return ec.resolvers.Query().Viewer(ctx) }) if err != nil { ec.Error(ctx, err) @@ -426,7 +373,7 @@ func (ec *executionContext) _Query_jsonEncoding(ctx context.Context, field graph }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.Query_jsonEncoding(ctx) + return ec.resolvers.Query().JsonEncoding(ctx) }) if err != nil { ec.Error(ctx, err) @@ -531,7 +478,7 @@ func (ec *executionContext) _User_likes(ctx context.Context, field graphql.Colle }() resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) { - return ec.resolvers.User_likes(ctx, obj) + return ec.resolvers.User().Likes(ctx, obj) }) if err != nil { ec.Error(ctx, err) diff --git a/test/resolvers_test.go b/test/resolvers_test.go index 9cada0eb004..c8ab3acfeb7 100644 --- a/test/resolvers_test.go +++ b/test/resolvers_test.go @@ -21,8 +21,8 @@ import ( ) func TestCustomErrorPresenter(t *testing.T) { - resolvers := &testResolvers{} - srv := httptest.NewServer(handler.GraphQL(MakeExecutableSchema(resolvers), + resolvers := &testResolver{} + srv := httptest.NewServer(handler.GraphQL(NewExecutableSchema(resolvers), handler.ErrorPresenter(func(i context.Context, e error) *gqlerror.Error { if _, ok := errors.Cause(e).(*specialErr); ok { return &gqlerror.Error{Message: "override special error message"} @@ -62,7 +62,7 @@ func TestCustomErrorPresenter(t *testing.T) { } func TestErrorPath(t *testing.T) { - srv := httptest.NewServer(handler.GraphQL(MakeExecutableSchema(&testResolvers{err: fmt.Errorf("boom")}))) + srv := httptest.NewServer(handler.GraphQL(NewExecutableSchema(&testResolver{err: fmt.Errorf("boom")}))) c := client.New(srv.URL) var resp struct{} @@ -73,7 +73,7 @@ func TestErrorPath(t *testing.T) { func TestInputDefaults(t *testing.T) { called := false - srv := httptest.NewServer(handler.GraphQL(MakeExecutableSchema(&testResolvers{ + srv := httptest.NewServer(handler.GraphQL(NewExecutableSchema(&testResolver{ queryDate: func(ctx context.Context, filter models.DateFilter) (bool, error) { assert.Equal(t, "asdf", filter.Value) assert.Equal(t, "UTC", *filter.Timezone) @@ -96,7 +96,7 @@ func TestInputDefaults(t *testing.T) { } func TestJsonEncoding(t *testing.T) { - srv := httptest.NewServer(handler.GraphQL(MakeExecutableSchema(&testResolvers{}))) + srv := httptest.NewServer(handler.GraphQL(NewExecutableSchema(&testResolver{}))) c := client.New(srv.URL) var resp struct { @@ -108,45 +108,63 @@ func TestJsonEncoding(t *testing.T) { require.Equal(t, "\U000fe4ed", resp.JsonEncoding) } -type testResolvers struct { +type testResolver struct { err error queryDate func(ctx context.Context, filter models.DateFilter) (bool, error) } -func (r *testResolvers) Query_jsonEncoding(ctx context.Context) (string, error) { - return "\U000fe4ed", nil +func (r *testResolver) Element() ElementResolver { + return &elementResolver{r} } -func (r *testResolvers) Query_viewer(ctx context.Context) (*models.Viewer, error) { - return &models.Viewer{ - User: &remote_api.User{Name: "Bob"}, - }, nil +func (r *testResolver) Query() QueryResolver { + return &queryResolver{r} } -func (r *testResolvers) Query_date(ctx context.Context, filter models.DateFilter) (bool, error) { - return r.queryDate(ctx, filter) +func (r *testResolver) User() UserResolver { + return &userResolver{r} } -func (r *testResolvers) Query_path(ctx context.Context) ([]*models.Element, error) { - return []*models.Element{{1}, {2}, {3}, {4}}, nil -} +type elementResolver struct{ *testResolver } -func (r *testResolvers) Element_child(ctx context.Context, obj *models.Element) (models.Element, error) { +func (r *elementResolver) Child(ctx context.Context, obj *models.Element) (models.Element, error) { return models.Element{obj.ID * 10}, nil } -func (r *testResolvers) Element_error(ctx context.Context, obj *models.Element) (bool, error) { +func (r *elementResolver) Error(ctx context.Context, obj *models.Element) (bool, error) { // A silly hack to make the result order stable time.Sleep(time.Duration(obj.ID) * 10 * time.Millisecond) return false, r.err } -func (r *testResolvers) Element_mismatched(ctx context.Context, obj *models.Element) ([]bool, error) { +func (r *elementResolver) Mismatched(ctx context.Context, obj *models.Element) ([]bool, error) { return []bool{true}, nil } -func (r *testResolvers) User_likes(ctx context.Context, obj *remote_api.User) ([]string, error) { +type queryResolver struct{ *testResolver } + +func (r *queryResolver) Path(ctx context.Context) ([]*models.Element, error) { + return []*models.Element{{1}, {2}, {3}, {4}}, nil +} + +func (r *queryResolver) Date(ctx context.Context, filter models.DateFilter) (bool, error) { + return r.queryDate(ctx, filter) +} + +func (r *queryResolver) Viewer(ctx context.Context) (*models.Viewer, error) { + return &models.Viewer{ + User: &remote_api.User{Name: "Bob"}, + }, nil +} + +func (r *queryResolver) JsonEncoding(ctx context.Context) (string, error) { + return "\U000fe4ed", nil +} + +type userResolver struct{ *testResolver } + +func (r *userResolver) Likes(ctx context.Context, obj *remote_api.User) ([]string, error) { return obj.Likes, nil }