Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: fix linter issues #84

Merged
merged 1 commit into from
Nov 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ linters:
issues:
new: false
fix: false
new-from-rev: 2b6063ac3c145007726044a5555b6d2a40d3b089
exclude-rules:
- path: _test\.go
linters:
Expand Down Expand Up @@ -113,5 +112,6 @@ linters-settings:
ignore-names:
- err
- id
- to
ignore-decls:
- i int
116 changes: 73 additions & 43 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ import (
const (
basePath = "graphql"
schemaBasePath = "graphql/schema"

filePermission755 = 0755
filePermission644 = 0644
)

var skipGoModTidy = true
Expand Down Expand Up @@ -56,28 +59,18 @@ func Generate(services []Service, basePath string, schemaBasePath string) error
schemaPath := path.Join(schemaBasePath, "schema.graphql")

cfg := config.DefaultConfig()

err := config.CompleteConfig(cfg)
if err != nil {
return err
return fmt.Errorf("failed to complete the config: %w", err)
}

cfg.SchemaFilename = []string{schemaPath}
cfg.Models = make(map[string]config.TypeMapEntry)

if err := os.MkdirAll(schemaBasePath, 0755); err != nil && !os.IsExist(err) {
return fmt.Errorf("mkdir %q failed: %w", schemaBasePath, err)
}

if err := os.WriteFile(schemaPath, schema, 0644); err != nil {
return fmt.Errorf("writefile %q failed: %w", schemaPath, err)
}

if err := os.WriteFile(path.Join(basePath, "module.go"), module, 0644); err != nil {
return fmt.Errorf("writefile %q/module.go failed: %w", basePath, err)
}

if err := os.WriteFile(path.Join(basePath, "emptymodule.go"), emptyModule, 0644); err != nil {
return fmt.Errorf("writefile %q/emptymodule.go failed: %w", basePath, err)
err = createFiles(schemaBasePath, schemaPath, basePath)
if err != nil {
return err
}

types := new(Types)
Expand All @@ -91,40 +84,17 @@ func Generate(services []Service, basePath string, schemaBasePath string) error
fpath := path.Join(schemaBasePath, fname)

log.Printf("Writing %s", fname)
if err := os.WriteFile(fpath, service.Schema(), 0644); err != nil {

if err := os.WriteFile(fpath, service.Schema(), filePermission644); err != nil {
return fmt.Errorf("writefile %q failed: %w", fpath, err)
}

cfg.SchemaFilename = append(cfg.SchemaFilename, fpath)

service.Types(types)
}

// merge models into config models
for graphqlObject, goType := range types.names {
cfg.Models[graphqlObject] = config.TypeMapEntry{Model: []string{goType}}
}

for graphqlObject, fields := range types.fields {
for graphqlField, goType := range fields {
model := cfg.Models[graphqlObject]
if cfg.Models[graphqlObject].Fields == nil {
model.Fields = make(map[string]config.TypeMapField)
}
model.Fields[graphqlField] = config.TypeMapField{FieldName: goType}
cfg.Models[graphqlObject] = model
}
}

for graphqlObject, resolver := range types.resolver {
for graphqlField := range resolver {
model := cfg.Models[graphqlObject]
if cfg.Models[graphqlObject].Fields == nil {
model.Fields = make(map[string]config.TypeMapField)
}
model.Fields[graphqlField] = config.TypeMapField{Resolver: true}
cfg.Models[graphqlObject] = model
}
}
mergeModels(types, cfg)

float := cfg.Models["Float"]
float.Model = append(float.Model, "flamingo.me/graphql.Float", "github.com/99designs/gqlgen/graphql.Float")
Expand All @@ -150,9 +120,61 @@ func Generate(services []Service, basePath string, schemaBasePath string) error
if err := api.Generate(cfg, api.AddPlugin(&plugin{types: types})); err != nil {
return fmt.Errorf("gqlgen/api.Generate failed: %w", err)
}

return nil
}

func createFiles(schemaBasePath string, schemaPath string, basePath string) error {
if err := os.MkdirAll(schemaBasePath, filePermission755); err != nil && !os.IsExist(err) {
return fmt.Errorf("mkdir %q failed: %w", schemaBasePath, err)
}

if err := os.WriteFile(schemaPath, schema, filePermission644); err != nil {
return fmt.Errorf("writefile %q failed: %w", schemaPath, err)
}

if err := os.WriteFile(path.Join(basePath, "module.go"), module, filePermission644); err != nil {
return fmt.Errorf("writefile %q/module.go failed: %w", basePath, err)
}

if err := os.WriteFile(path.Join(basePath, "emptymodule.go"), emptyModule, filePermission644); err != nil {
return fmt.Errorf("writefile %q/emptymodule.go failed: %w", basePath, err)
}

return nil
}

// merge models into config models
func mergeModels(types *Types, cfg *config.Config) {
for graphqlObject, goType := range types.names {
cfg.Models[graphqlObject] = config.TypeMapEntry{Model: []string{goType}}
}

for graphqlObject, fields := range types.fields {
for graphqlField, goType := range fields {
model := cfg.Models[graphqlObject]
if cfg.Models[graphqlObject].Fields == nil {
model.Fields = make(map[string]config.TypeMapField)
}

model.Fields[graphqlField] = config.TypeMapField{FieldName: goType}
cfg.Models[graphqlObject] = model
}
}

for graphqlObject, resolver := range types.resolver {
for graphqlField := range resolver {
model := cfg.Models[graphqlObject]
if cfg.Models[graphqlObject].Fields == nil {
model.Fields = make(map[string]config.TypeMapField)
}

model.Fields[graphqlField] = config.TypeMapField{Resolver: true}
cfg.Models[graphqlObject] = model
}
}
}

var _ plugin2.CodeGenerator = &plugin{}
var _ plugin2.ConfigMutator = &plugin{}
var _ plugin2.Plugin = &plugin{}
Expand Down Expand Up @@ -184,7 +206,8 @@ func (m *plugin) GenerateCode(data *codegen.Data) error {
panic("code generation failed")
}
}()
return gqltemplates.Render(gqltemplates.Options{

err := gqltemplates.Render(gqltemplates.Options{
PackageName: "graphql",
Filename: "graphql/resolver.go",
Data: &resolverBuild{
Expand All @@ -196,6 +219,7 @@ func (m *plugin) GenerateCode(data *codegen.Data) error {
Funcs: template.FuncMap{
"gpkg": func(from, to string, field codegen.Field) string {
if m.types.resolver[from][to][0] == "" {
//nolint: forbidigo // special case of error output
fmt.Printf(
"\nmissing resolver for %q.%q:\n\tfunc (r *%sResolver) %s%s\n\n\ttypes.Resolve(\"%s\", \"%s\", %sResolver{}, \"%s\")\n\n",
from, to,
Expand Down Expand Up @@ -346,6 +370,12 @@ func direct(root *{{$root.TypeName}}) map[string]interface{} {
}
`,
})

if err != nil {
return fmt.Errorf("failed to render generation template: %w", err)
}

return nil
}

type resolverBuild struct {
Expand Down
1 change: 1 addition & 0 deletions corshandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ func (h *corsHandler) validateOrigin(origin string) bool {
return true
}
}

return false
}

Expand Down
12 changes: 10 additions & 2 deletions example/todo/infrastructure/todo.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ var todos = []*domain.Todo{
{ID: "task-2", Task: "task c"},
}

var (
ErrNoTodoGiven = errors.New("no todo given")
ErrTodoNotFound = errors.New("todo not found")
)

// Todos returns a list of mocked todos
func (ts *TodoService) Todos(_ context.Context, _ string) ([]*domain.Todo, error) {
return todos, nil
Expand All @@ -25,13 +30,15 @@ func (ts *TodoService) Todos(_ context.Context, _ string) ([]*domain.Todo, error
// AddTodo mutation adds an entry to the list
func (ts *TodoService) AddTodo(_ context.Context, _ string, task string) (*domain.Todo, error) {
if task == "" {
return nil, errors.New("no todo given")
return nil, ErrNoTodoGiven
}

todo := &domain.Todo{
ID: "task-" + strconv.Itoa(len(todos)),
Task: task,
}
todos = append(todos, todo)

return todo, nil
}

Expand All @@ -43,5 +50,6 @@ func (ts *TodoService) TodoDone(_ context.Context, todoID string, done bool) (*d
return todos[i], nil
}
}
return nil, errors.New("todo not found")

return nil, ErrTodoNotFound
}
22 changes: 19 additions & 3 deletions example/todo/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package todo

import (
"context"
"fmt"

"flamingo.me/graphql/example/todo/domain"
"flamingo.me/graphql/example/todo/infrastructure"
Expand All @@ -21,7 +22,12 @@ func (r *UserResolver) Inject(todosBackend *infrastructure.TodoService) *UserRes

// Todos getter
func (r *UserResolver) Todos(ctx context.Context, obj *userDomain.User) ([]*domain.Todo, error) {
return r.todosBackend.Todos(ctx, obj.Name)
todos, err := r.todosBackend.Todos(ctx, obj.Name)
if err != nil {
return nil, fmt.Errorf("can not load todos: %w", err)
}

return todos, nil
}

// MutationResolver maps mutations
Expand All @@ -37,10 +43,20 @@ func (r *MutationResolver) Inject(resolver *UserResolver) *MutationResolver {

// TodoAdd mutation
func (r *MutationResolver) TodoAdd(ctx context.Context, user string, task string) (*domain.Todo, error) {
return r.resolver.todosBackend.AddTodo(ctx, user, task)
todo, err := r.resolver.todosBackend.AddTodo(ctx, user, task)
if err != nil {
return nil, fmt.Errorf("can not add todo: %w", err)
}

return todo, nil
}

// TodoDone mutation
func (r *MutationResolver) TodoDone(ctx context.Context, todo string, done bool) (*domain.Todo, error) {
return r.resolver.todosBackend.TodoDone(ctx, todo, done)
todoDone, err := r.resolver.todosBackend.TodoDone(ctx, todo, done)
if err != nil {
return nil, fmt.Errorf("can not update todo: %w", err)
}

return todoDone, nil
}
8 changes: 7 additions & 1 deletion example/user/domain/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,22 @@ type UserService interface {

// Get returns an attribute by its key
func (a Attributes) Get(key string) string {
return a[key].(string)
if s, ok := a[key].(string); ok {
return s
}

return ""
}

// Keys lists all attribute keys
func (a Attributes) Keys() []string {
keys := make([]string, len(a))
i := 0

for k := range a {
keys[i] = k
i++
}

return keys
}
8 changes: 7 additions & 1 deletion example/user/interfaces/graphql/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package graphql
import (
"context"
"errors"
"fmt"
"strings"

"flamingo.me/graphql/example/user/domain"
Expand All @@ -24,7 +25,12 @@ func (r *UserQueryResolver) Inject(userService domain.UserService) *UserQueryRes

// User getter
func (r *UserQueryResolver) User(ctx context.Context, id string) (*domain.User, error) {
return r.userService.UserByID(ctx, id)
user, err := r.userService.UserByID(ctx, id)
if err != nil {
return nil, fmt.Errorf("can not load user: %w", err)
}

return user, nil
}

// UserAttributeFilter directive
Expand Down
11 changes: 9 additions & 2 deletions graphqlhandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package graphql

import (
"context"
"fmt"
"io"
"net/http"
"net/http/httptest"
Expand All @@ -21,19 +22,25 @@ func wrapGqlHandler(handler http.Handler) web.Action {
return func(ctx context.Context, req *web.Request) web.Result {
rw := httptest.NewRecorder()
handler.ServeHTTP(rw, req.Request().WithContext(ctx))

return &gqlHandler{
request: req,
recorder: rw,
}
}
}

func (h *gqlHandler) Apply(ctx context.Context, rw http.ResponseWriter) error {
func (h *gqlHandler) Apply(_ context.Context, rw http.ResponseWriter) error {
for k, vs := range h.recorder.Header() {
for _, v := range vs {
rw.Header().Add(k, v)
}
}

_, err := io.Copy(rw, h.recorder.Body)
return err
if err != nil {
return fmt.Errorf("failed to write body: %w", err)
}

return nil
}
4 changes: 4 additions & 0 deletions helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ func (tc *Types) Resolve(graphqlType, graphqlField string, typ interface{}, meth
if tc.resolver == nil {
tc.resolver = make(map[string]map[string][3]string)
}

if tc.resolver[graphqlType] == nil {
tc.resolver[graphqlType] = make(map[string][3]string)
}
Expand All @@ -40,6 +41,7 @@ func (tc *Types) Resolve(graphqlType, graphqlField string, typ interface{}, meth
for t.Kind() == reflect.Ptr {
t = t.Elem()
}

tc.resolver[graphqlType][graphqlField] = [3]string{t.PkgPath(), t.Name(), method}
}

Expand All @@ -48,9 +50,11 @@ func (tc *Types) GoField(graphqlType, graphqlField, goField string) {
if tc.fields == nil {
tc.fields = make(map[string]map[string]string)
}

if tc.fields[graphqlType] == nil {
tc.fields[graphqlType] = make(map[string]string)
}

tc.fields[graphqlType][graphqlField] = goField
}

Expand Down
Loading
Loading