From f8c83a9291566141045b45c84c4084009250d4a3 Mon Sep 17 00:00:00 2001 From: Brian Kamotho Date: Tue, 6 Dec 2022 16:14:07 +0300 Subject: [PATCH 1/2] Add ability to customize resolvergen behavior using additional plugins --- api/generate.go | 6 +++++- codegen/data.go | 4 +++- codegen/field.go | 8 ++++++++ codegen/object.go | 10 ++++++++++ internal/rewrite/rewriter.go | 1 + plugin/plugin.go | 5 +++++ plugin/resolvergen/resolver.go | 20 +++++++++++++++++++- 7 files changed, 51 insertions(+), 3 deletions(-) diff --git a/api/generate.go b/api/generate.go index 6619dd5cd2b..8aecc4ca5a4 100644 --- a/api/generate.go +++ b/api/generate.go @@ -83,7 +83,11 @@ func Generate(cfg *config.Config, option ...Option) error { } } // Merge again now that the generated models have been injected into the typemap - data, err := codegen.BuildData(cfg) + data_plugins := make([]interface{}, len(plugins)) + for index := range plugins { + data_plugins[index] = plugins[index] + } + data, err := codegen.BuildData(cfg, data_plugins...) if err != nil { return fmt.Errorf("merging type systems failed: %w", err) } diff --git a/codegen/data.go b/codegen/data.go index 592140ae6c6..6cd72213f04 100644 --- a/codegen/data.go +++ b/codegen/data.go @@ -34,6 +34,7 @@ type Data struct { MutationRoot *Object SubscriptionRoot *Object AugmentedSources []AugmentedSource + Plugins []interface{} } func (d *Data) HasEmbeddableSources() bool { @@ -76,7 +77,7 @@ func (d *Data) Directives() DirectiveList { return res } -func BuildData(cfg *config.Config) (*Data, error) { +func BuildData(cfg *config.Config, plugins ...interface{}) (*Data, error) { // We reload all packages to allow packages to be compared correctly. cfg.ReloadAllPackages() @@ -105,6 +106,7 @@ func BuildData(cfg *config.Config) (*Data, error) { AllDirectives: dataDirectives, Schema: b.Schema, Interfaces: map[string]*Interface{}, + Plugins: plugins, } for _, schemaType := range b.Schema.Types { diff --git a/codegen/field.go b/codegen/field.go index a33cc18e5a5..e6a77782518 100644 --- a/codegen/field.go +++ b/codegen/field.go @@ -502,6 +502,14 @@ func (f *Field) ResolverType() string { return fmt.Sprintf("%s().%s(%s)", f.Object.Definition.Name, f.GoFieldName, f.CallArgs()) } +func (f *Field) IsInputObject() bool { + return f.Object.Kind == ast.InputObject +} + +func (f *Field) IsRoot() bool { + return f.Object.Root +} + func (f *Field) ShortResolverDeclaration() string { if f.Object.Kind == ast.InputObject { return fmt.Sprintf("(ctx context.Context, obj %s, data %s) error", diff --git a/codegen/object.go b/codegen/object.go index ed0042a61f2..8609232719b 100644 --- a/codegen/object.go +++ b/codegen/object.go @@ -153,6 +153,16 @@ func (o *Object) Description() string { return o.Definition.Description } +func (o *Object) HasField(name string) bool { + for _, f := range o.Fields { + if f.Name == name { + return true + } + } + + return false +} + func (os Objects) ByName(name string) *Object { for i, o := range os { if strings.EqualFold(o.Definition.Name, name) { diff --git a/internal/rewrite/rewriter.go b/internal/rewrite/rewriter.go index a8a6485cff7..156d0f76f72 100644 --- a/internal/rewrite/rewriter.go +++ b/internal/rewrite/rewriter.go @@ -99,6 +99,7 @@ func (r *Rewriter) GetMethodComment(structname string, methodname string) string return "" } + func (r *Rewriter) GetMethodBody(structname string, methodname string) string { for _, f := range r.pkg.Syntax { for _, d := range f.Decls { diff --git a/plugin/plugin.go b/plugin/plugin.go index 7de36bd8cd5..69801c8816a 100644 --- a/plugin/plugin.go +++ b/plugin/plugin.go @@ -29,3 +29,8 @@ type EarlySourceInjector interface { type LateSourceInjector interface { InjectSourceLate(schema *ast.Schema) *ast.Source } + +// Implementer is used to generate code inside resolvers +type ResolverImplementer interface { + Implement(field *codegen.Field) string +} diff --git a/plugin/resolvergen/resolver.go b/plugin/resolvergen/resolver.go index aa3be72739e..8fef27e4153 100644 --- a/plugin/resolvergen/resolver.go +++ b/plugin/resolvergen/resolver.go @@ -119,9 +119,27 @@ func (m *Plugin) generatePerSchema(data *codegen.Data) error { structName := templates.LcFirst(o.Name) + templates.UcFirst(data.Config.Resolver.Type) implementation := strings.TrimSpace(rewriter.GetMethodBody(structName, f.GoFieldName)) comment := strings.TrimSpace(strings.TrimLeft(rewriter.GetMethodComment(structName, f.GoFieldName), `\`)) + if implementation == "" { - implementation = fmt.Sprintf("panic(fmt.Errorf(\"not implemented: %v - %v\"))", f.GoFieldName, f.Name) + // 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 + } + } + + if exists { + implementation = resolver_implementer.Implement(f) + } else { + implementation = fmt.Sprintf("panic(fmt.Errorf(\"not implemented: %v - %v\"))", f.GoFieldName, f.Name) + } + } + if comment == "" { comment = fmt.Sprintf("%v is the resolver for the %v field.", f.GoFieldName, f.Name) } From 5f854bc25ff232f47c4939d3d12a3e2e7fd443d4 Mon Sep 17 00:00:00 2001 From: Brian Kamotho Date: Mon, 23 Jan 2023 16:10:59 +0300 Subject: [PATCH 2/2] Add field.GoResultName() --- codegen/field.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/codegen/field.go b/codegen/field.go index e6a77782518..81d795bf550 100644 --- a/codegen/field.go +++ b/codegen/field.go @@ -536,6 +536,13 @@ func (f *Field) ShortResolverDeclaration() string { return res } +func (f *Field) GoResultName() (string, bool) { + name := fmt.Sprintf("%v", f.TypeReference.GO) + splits := strings.Split(name, "/") + + return splits[len(splits)-1], strings.HasPrefix(name, "[]") +} + func (f *Field) ComplexitySignature() string { res := "func(childComplexity int" for _, arg := range f.Args {