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 1c03c0bae3..17b1c875d5 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 17b1c875d5..5b673e510f 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 c7d750d7a0..0892b29418 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 4279ad8eae..6459605766 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 daeece7a4e..415e5d42e4 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 4b63fd0526..409edf2db4 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 a78511caf4..ddc98dd012 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 6bbb0a60dc..f9f8ee3f08 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 1a16399637..6bb56ea98b 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 c10bb57472..4948feacc4 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 7695566c64..fff48520fd 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 2bd93c95ba..77765e03bb 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 22b3b214e5..5f1a501fa4 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 c9c6314c80..93b6b50910 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 8b45f80246..3f001bdcd3 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 96a3eee409..7e07e09685 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 22805f2224..748213b97e 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 e46fbd0c97..c001c2d669 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 7d11be0457..be4486f6b6 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 4c1829a3aa..dc3a199549 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 e8982e8bd1..84e291cb5d 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 fc0036b3a8..d83d60303c 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 7113401d92..8cf78469aa 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 86bdbdc546..b27404f049 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 8fbb54547b..fc35f0b416 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 142f9f7954..135cff5dac 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 240b8961e0..5901912635 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 9cada0eb00..c8ab3acfeb 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 }