Skip to content

Commit

Permalink
Improve ResolverImplementer.Implment (#2850)
Browse files Browse the repository at this point in the history
* improve resolver implement render

* add error when multiple implementors

* add initial test
  • Loading branch information
roneli authored Dec 3, 2023
1 parent cb3c1c8 commit bd9657f
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 28 deletions.
5 changes: 2 additions & 3 deletions plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
package plugin

import (
"github.com/vektah/gqlparser/v2/ast"

"github.com/99designs/gqlgen/codegen"
"github.com/99designs/gqlgen/codegen/config"
"github.com/vektah/gqlparser/v2/ast"
)

type Plugin interface {
Expand All @@ -31,7 +30,7 @@ type LateSourceInjector interface {
InjectSourceLate(schema *ast.Schema) *ast.Source
}

// Implementer is used to generate code inside resolvers
// ResolverImplementer is used to generate code inside resolvers
type ResolverImplementer interface {
Implement(field *codegen.Field) string
}
51 changes: 27 additions & 24 deletions plugin/resolvergen/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func (m *Plugin) generateSingleFile(data *codegen.Data) error {
continue
}

resolver := Resolver{o, f, nil, "", `panic("not implemented")`}
resolver := Resolver{o, f, nil, "", `panic("not implemented")`, nil}
file.Resolvers = append(file.Resolvers, &resolver)
}
}
Expand Down Expand Up @@ -130,29 +130,24 @@ func (m *Plugin) generatePerSchema(data *codegen.Data) error {

structName := templates.LcFirst(o.Name) + templates.UcFirst(data.Config.Resolver.Type)
comment := strings.TrimSpace(strings.TrimLeft(rewriter.GetMethodComment(structName, f.GoFieldName), `\`))

implementation := strings.TrimSpace(rewriter.GetMethodBody(structName, f.GoFieldName))
if implementation == "" {
// Check for Implementer Plugin
var resolver_implementer plugin.ResolverImplementer
var exists bool
for _, p := range data.Plugins {
if p_cast, ok := p.(plugin.ResolverImplementer); ok {
resolver_implementer = p_cast
exists = true
break
}
// use default implementation, if no implementation was previously used
implementation = fmt.Sprintf("panic(fmt.Errorf(\"not implemented: %v - %v\"))", f.GoFieldName, f.Name)
}
resolver := Resolver{o, f, rewriter.GetPrevDecl(structName, f.GoFieldName), comment, implementation, nil}
var implExists bool
for _, p := range data.Plugins {
rImpl, ok := p.(plugin.ResolverImplementer)
if !ok {
continue
}

if exists {
implementation = resolver_implementer.Implement(f)
} else {
implementation = fmt.Sprintf("panic(fmt.Errorf(\"not implemented: %v - %v\"))", f.GoFieldName, f.Name)
if implExists {
return fmt.Errorf("multiple plugins implement ResolverImplementer")
}

implExists = true
resolver.ImplementationRender = rImpl.Implement
}

resolver := Resolver{o, f, rewriter.GetPrevDecl(structName, f.GoFieldName), comment, implementation}
fnCase := gqlToResolverName(data.Config.Resolver.Dir(), f.Position.Src.Name, data.Config.Resolver.FilenameTemplate)
fn := strings.ToLower(fnCase)
if files[fn] == nil {
Expand Down Expand Up @@ -257,11 +252,19 @@ func (f *File) Imports() string {
}

type Resolver struct {
Object *codegen.Object
Field *codegen.Field
PrevDecl *ast.FuncDecl
Comment string
Implementation string
Object *codegen.Object
Field *codegen.Field
PrevDecl *ast.FuncDecl
Comment string
ImplementationStr string
ImplementationRender func(r *codegen.Field) string
}

func (r *Resolver) Implementation() string {
if r.ImplementationRender != nil {
return r.ImplementationRender(r.Field)
}
return r.ImplementationStr
}

func gqlToResolverName(base string, gqlname, filenameTmpl string) string {
Expand Down
24 changes: 24 additions & 0 deletions plugin/resolvergen/resolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,24 @@ func TestOmitTemplateComment(t *testing.T) {
assertNoErrors(t, "github.com/99designs/gqlgen/plugin/resolvergen/testdata/omit_template_comment/out")
}

func TestResolver_Implementation(t *testing.T) {
_ = syscall.Unlink("testdata/resolver_implementor/resolver.go")

cfg, err := config.LoadConfig("testdata/resolver_implementor/gqlgen.yml")
require.NoError(t, err)
p := Plugin{}

require.NoError(t, cfg.Init())

data, err := codegen.BuildData(cfg, &implementorTest{})
if err != nil {
panic(err)
}

require.NoError(t, p.GenerateCode(data))
assertNoErrors(t, "github.com/99designs/gqlgen/plugin/resolvergen/testdata/resolver_implementor/out")
}

func TestCustomResolverTemplate(t *testing.T) {
_ = syscall.Unlink("testdata/resolvertemplate/out/resolver.go")
cfg, err := config.LoadConfig("testdata/resolvertemplate/gqlgen.yml")
Expand Down Expand Up @@ -142,3 +160,9 @@ func assertNoErrors(t *testing.T, pkg string) {
t.Fatal("see compilation errors above")
}
}

type implementorTest struct{}

func (i *implementorTest) Implement(field *codegen.Field) string {
return "panic(\"implementor implemented me\")"
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions plugin/resolvergen/testdata/resolver_implementor/gqlgen.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
schema:
- "testdata/schema.graphql"

exec:
filename: testdata/resolver_implementor/out/ignored.go
model:
filename: testdata/resolver_implementor/out/generated.go
resolver:
type: CustomResolverType
layout: follow-schema
dir: testdata/resolver_implementor/out

models:
Resolver:
model: github.com/99designs/gqlgen/plugin/resolvergen/testdata/resolver_implementor/out.Resolver
13 changes: 13 additions & 0 deletions plugin/resolvergen/testdata/resolver_implementor/out/model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package customresolver

import "context"

type Resolver struct{}

type QueryResolver interface {
Resolver(ctx context.Context) (*Resolver, error)
}

type ResolverResolver interface {
Name(ctx context.Context, obj *Resolver) (string, error)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package customresolver

// This file will not be regenerated automatically.
//
// It serves as dependency injection for your app, add any dependencies you require here.

type CustomResolverType struct{}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit bd9657f

Please sign in to comment.