Skip to content

Commit

Permalink
Config option to preserve single file resolvers instead of always rew…
Browse files Browse the repository at this point in the history
…riting (#3359)

Signed-off-by: Steve Coffman <steve@khanacademy.org>
  • Loading branch information
StevenACoffman authored Nov 9, 2024
1 parent b207ed5 commit b332879
Show file tree
Hide file tree
Showing 11 changed files with 193 additions and 7 deletions.
2 changes: 1 addition & 1 deletion TESTING.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
How to write tests for gqlgen
===

Testing generated code is a little tricky, heres how its currently set up.
Testing generated code is a little tricky, here's how its currently set up.

### Testing responses from a server

Expand Down
4 changes: 4 additions & 0 deletions codegen/config/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type ResolverConfig struct {
DirName string `yaml:"dir"`
OmitTemplateComment bool `yaml:"omit_template_comment,omitempty"`
ResolverTemplate string `yaml:"resolver_template,omitempty"`
PreserveResolver bool `yaml:"preserve_resolver,omitempty"`
}

type ResolverLayout string
Expand Down Expand Up @@ -55,6 +56,9 @@ func (r *ResolverConfig) Check() error {
} else {
r.Filename = abs(r.Filename)
}
if r.PreserveResolver {
return fmt.Errorf("preserve_resolver=true cannot be used with layout=%s", r.Layout)
}
default:
return fmt.Errorf("invalid layout %s. must be %s or %s", r.Layout, LayoutSingleFile, LayoutFollowSchema)
}
Expand Down
15 changes: 14 additions & 1 deletion plugin/resolvergen/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ func (m *Plugin) GenerateCode(data *codegen.Data) error {

func (m *Plugin) generateSingleFile(data *codegen.Data) error {
file := File{}

if _, err := os.Stat(data.Config.Resolver.Filename); err == nil &&
data.Config.Resolver.PreserveResolver {
// file already exists and config says not to update resolver
// with layout = single so just return
return nil
}

rewriter, err := rewrite.New(data.Config.Resolver.Dir())
if err != nil {
return err
Expand Down Expand Up @@ -104,9 +112,14 @@ func (m *Plugin) generateSingleFile(data *codegen.Data) error {
newResolverTemplate = readResolverTemplate(data.Config.Resolver.ResolverTemplate)
}

fileNotice := `// THIS CODE WILL BE UPDATED WITH SCHEMA CHANGES. PREVIOUS IMPLEMENTATION FOR SCHEMA CHANGES WILL BE KEPT IN THE COMMENT SECTION. IMPLEMENTATION FOR UNCHANGED SCHEMA WILL BE KEPT.`
if data.Config.Resolver.PreserveResolver {
fileNotice = `// THIS CODE IS A STARTING POINT ONLY. IT WILL NOT BE UPDATED WITH SCHEMA CHANGES.`
}

return templates.Render(templates.Options{
PackageName: data.Config.Resolver.Package,
FileNotice: `// THIS CODE WILL BE UPDATED WITH SCHEMA CHANGES. PREVIOUS IMPLEMENTATION FOR SCHEMA CHANGES WILL BE KEPT IN THE COMMENT SECTION. IMPLEMENTATION FOR UNCHANGED SCHEMA WILL BE KEPT.`,
FileNotice: fileNotice,
Filename: data.Config.Resolver.Filename,
Data: resolverBuild,
Packages: data.Config.Packages,
Expand Down
39 changes: 37 additions & 2 deletions plugin/resolvergen/resolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,35 @@ func TestLayoutSingleFile(t *testing.T) {
assertNoErrors(t, "github.com/99designs/gqlgen/plugin/resolvergen/testdata/singlefile/out")
}

func TestLayoutSingleFileWithEnableRewrite(t *testing.T) {
// Ensure the resolver file exists before running the test
resolverFilePath := "testdata/singlefile_preserve/out/resolver.go"
_, err := os.Stat(resolverFilePath)
if os.IsNotExist(err) {
t.Fatalf("Expected resolver file does not exist: %s", resolverFilePath)
}
require.NoError(t, err)

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

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

data, err := codegen.BuildData(cfg)
require.NoError(t, err)

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

func TestLayoutFollowSchema(t *testing.T) {
testFollowSchemaPersistence(t, "testdata/followschema")

b, err := os.ReadFile("testdata/followschema/out/schema.resolvers.go")
resolverFilePath := "testdata/followschema/out/schema.resolvers.go"
overWriteFile(t, resolverFilePath+".txt", resolverFilePath)

b, err := os.ReadFile(resolverFilePath)
require.NoError(t, err)
source := string(b)

Expand All @@ -45,7 +70,9 @@ func TestLayoutFollowSchema(t *testing.T) {
func TestLayoutFollowSchemaWithCustomFilename(t *testing.T) {
testFollowSchemaPersistence(t, "testdata/filetemplate")

b, err := os.ReadFile("testdata/filetemplate/out/schema.custom.go")
resolverFilePath := "testdata/filetemplate/out/schema.custom.go"
overWriteFile(t, resolverFilePath+".txt", resolverFilePath)
b, err := os.ReadFile(resolverFilePath)
require.NoError(t, err)
source := string(b)

Expand Down Expand Up @@ -126,6 +153,14 @@ func testFollowSchemaPersistence(t *testing.T, dir string) {
assertNoErrors(t, "github.com/99designs/gqlgen/plugin/resolvergen/"+dir+"/out")
}

func overWriteFile(t *testing.T, sourceFile, destinationFile string) {
input, err := os.ReadFile(sourceFile)
require.NoError(t, err)

err = os.WriteFile(destinationFile, input, 0644)
require.NoError(t, err)
}

func assertNoErrors(t *testing.T, pkg string) {
pkgs, err := packages.Load(&packages.Config{
Mode: packages.NeedName |
Expand Down
38 changes: 38 additions & 0 deletions plugin/resolvergen/testdata/filetemplate/out/schema.custom.go.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package customresolver

// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.
// Code generated by github.com/99designs/gqlgen

import (
"context"

customresolver "github.com/99designs/gqlgen/plugin/resolvergen/testdata/singlefile/out"
)

// Resolver is the resolver for the resolver field.
func (r *queryCustomResolverType) Resolver(ctx context.Context) (*customresolver.Resolver, error) {
// CustomerResolverType.Resolver implementation
return nil, nil
}

// Name is the resolver for the name field.
func (r *resolverCustomResolverType) Name(ctx context.Context, obj *customresolver.Resolver) (string, error) {
// CustomerResolverType.Name implementation
return "", nil
}

// Query returns customresolver.QueryResolver implementation.
func (r *CustomResolverType) Query() customresolver.QueryResolver { return &queryCustomResolverType{r} }

// Resolver returns customresolver.ResolverResolver implementation.
func (r *CustomResolverType) Resolver() customresolver.ResolverResolver {
return &resolverCustomResolverType{r}
}

type queryCustomResolverType struct{ *CustomResolverType }
type resolverCustomResolverType struct{ *CustomResolverType }

func AUserHelperFunction() {
// AUserHelperFunction implementation
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package customresolver

// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.
// Code generated by github.com/99designs/gqlgen

import (
"context"

customresolver "github.com/99designs/gqlgen/plugin/resolvergen/testdata/singlefile/out"
)

// Resolver is the resolver for the resolver field.
func (r *queryCustomResolverType) Resolver(ctx context.Context) (_ *customresolver.Resolver, err error) {
// Named return values are supported.
return
}

// Name is the resolver for the name field.
func (r *resolverCustomResolverType) Name(ctx context.Context, obj *customresolver.Resolver) (string, error) {
// CustomerResolverType.Name implementation
return "", nil
}

// Query returns customresolver.QueryResolver implementation.
func (r *CustomResolverType) Query() customresolver.QueryResolver { return &queryCustomResolverType{r} }

// Resolver returns customresolver.ResolverResolver implementation.
func (r *CustomResolverType) Resolver() customresolver.ResolverResolver {
return &resolverCustomResolverType{r}
}

type queryCustomResolverType struct{ *CustomResolverType }
type resolverCustomResolverType struct{ *CustomResolverType }

func AUserHelperFunction() {
// AUserHelperFunction implementation
}
1 change: 1 addition & 0 deletions plugin/resolvergen/testdata/singlefile/gqlgen.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ model:
resolver:
filename: testdata/singlefile/out/resolver.go
type: CustomResolverType
preserve_resolver: false

models:
Resolver:
Expand Down
5 changes: 2 additions & 3 deletions plugin/resolvergen/testdata/singlefile/out/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,18 @@ package customresolver

import (
"context"
"fmt"
)

type CustomResolverType struct{}

// Resolver is the resolver for the resolver field.
func (r *queryCustomResolverType) Resolver(ctx context.Context) (*Resolver, error) {
panic(fmt.Errorf("not implemented: Resolver - resolver"))
panic("not implemented")
}

// Name is the resolver for the name field.
func (r *resolverCustomResolverType) Name(ctx context.Context, obj *Resolver) (string, error) {
panic(fmt.Errorf("not implemented: Name - name"))
panic("not implemented")
}

// Query returns QueryResolver implementation.
Expand Down
17 changes: 17 additions & 0 deletions plugin/resolvergen/testdata/singlefile_preserve/gqlgen.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
schema:
- "testdata/schema.graphql"

exec:
filename: testdata/singlefile_preserve/out/ignored.go
model:
filename: testdata/singlefile_preserve/out/generated.go
resolver:
filename: testdata/singlefile_preserve/out/resolver.go
type: CustomResolverType
preserve_resolver: true

models:
Resolver:
model: github.com/99designs/gqlgen/plugin/resolvergen/testdata/singlefile_preserve/out.Resolver

omit_gqlgen_version_in_file_notice: true
13 changes: 13 additions & 0 deletions plugin/resolvergen/testdata/singlefile_preserve/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)
}
28 changes: 28 additions & 0 deletions plugin/resolvergen/testdata/singlefile_preserve/out/resolver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package customresolver

// THIS CODE IS A STARTING POINT ONLY. IT WILL NOT BE UPDATED WITH SCHEMA CHANGES.

import (
"context"
)

type CustomResolverType struct{}

// Resolver is the resolver for the resolver field.
func (r *queryCustomResolverType) Resolver(ctx context.Context) (*Resolver, error) {
panic("not implemented")
}

// Name is the resolver for the name field.
func (r *resolverCustomResolverType) Name(ctx context.Context, obj *Resolver) (string, error) {
panic("not implemented")
}

// Query returns QueryResolver implementation.
func (r *CustomResolverType) Query() QueryResolver { return &queryCustomResolverType{r} }

// Resolver returns ResolverResolver implementation.
func (r *CustomResolverType) Resolver() ResolverResolver { return &resolverCustomResolverType{r} }

type queryCustomResolverType struct{ *CustomResolverType }
type resolverCustomResolverType struct{ *CustomResolverType }

0 comments on commit b332879

Please sign in to comment.