From b2a832d51d5d67463d35fc1397b7d6133e1d6b43 Mon Sep 17 00:00:00 2001 From: Craig Silverstein Date: Wed, 12 Jan 2022 08:24:07 -0800 Subject: [PATCH] Avoid problems with `val` being undefined in the federation template. (#1760) * Avoid problems with `val` being undefined in the federation template. When running gqlgen over our schema, we were seeing errors like: ``` assignments/generated/graphql/service.go:300:4: val declared but not used ``` The generated code looks like this: ``` func entityResolverNameForMobileNavigation(ctx context.Context, rep map[string]interface{}) (string, error) { for { var ( m map[string]interface{} val interface{} ok bool ) m = rep if _, ok = m["kaid"]; !ok { break } m = rep if _, ok = m["language"]; !ok { break } return "findMobileNavigationByKaidAndLanguage", nil } return "", fmt.Errorf("%w for MobileNavigation", ErrTypeNotFound) } ``` Looking at the code, it's pretty clear that this happens when there are multiple key-fields, but each of them has only one keyField.Field entry. This is because the old code looked at `len(keyFields)` to decide whether to declare the `val` variable, but looks at `len(keyField.Field)` for each keyField to decide whether to use the `val` variable. The easiest solution, and the one I do in this PR, is to just declare `val` all the time, and use a null-assignment to quiet the compiler when it's not used. * run go generate to update generated files * run go generate to update moar generated files * Adding a test for verify that this fixes the issue. From `plugins/federation`, run the following command and verify that no errors are produced ``` go run github.com/99designs/gqlgen --config testdata/entityresolver/gqlgen.yml ``` Co-authored-by: MiguelCastillo --- .../accounts/graph/generated/federation.go | 12 +- .../products/graph/generated/federation.go | 13 +- .../reviews/graph/generated/federation.go | 7 +- plugin/federation/federation.gotpl | 5 +- .../allthethings/generated/federation.go | 26 +- .../entityresolver/entity.resolvers.go | 4 + .../testdata/entityresolver/generated/exec.go | 262 +++++++++++++++++- .../entityresolver/generated/federation.go | 95 +++++-- .../entityresolver/generated/models.go | 7 + .../testdata/entityresolver/schema.graphql | 5 + 10 files changed, 398 insertions(+), 38 deletions(-) diff --git a/example/federation/accounts/graph/generated/federation.go b/example/federation/accounts/graph/generated/federation.go index 462941b46d6..5c21a55acb2 100644 --- a/example/federation/accounts/graph/generated/federation.go +++ b/example/federation/accounts/graph/generated/federation.go @@ -192,9 +192,11 @@ func (ec *executionContext) __resolve_entities(ctx context.Context, representati func entityResolverNameForEmailHost(ctx context.Context, rep map[string]interface{}) (string, error) { for { var ( - m map[string]interface{} - ok bool + m map[string]interface{} + val interface{} + ok bool ) + _ = val m = rep if _, ok = m["id"]; !ok { break @@ -207,9 +209,11 @@ func entityResolverNameForEmailHost(ctx context.Context, rep map[string]interfac func entityResolverNameForUser(ctx context.Context, rep map[string]interface{}) (string, error) { for { var ( - m map[string]interface{} - ok bool + m map[string]interface{} + val interface{} + ok bool ) + _ = val m = rep if _, ok = m["id"]; !ok { break diff --git a/example/federation/products/graph/generated/federation.go b/example/federation/products/graph/generated/federation.go index 2e31d8ab6ae..aa76fede75a 100644 --- a/example/federation/products/graph/generated/federation.go +++ b/example/federation/products/graph/generated/federation.go @@ -208,9 +208,11 @@ func (ec *executionContext) __resolve_entities(ctx context.Context, representati func entityResolverNameForManufacturer(ctx context.Context, rep map[string]interface{}) (string, error) { for { var ( - m map[string]interface{} - ok bool + m map[string]interface{} + val interface{} + ok bool ) + _ = val m = rep if _, ok = m["id"]; !ok { break @@ -227,6 +229,7 @@ func entityResolverNameForProduct(ctx context.Context, rep map[string]interface{ val interface{} ok bool ) + _ = val m = rep if val, ok = m["manufacturer"]; !ok { break @@ -245,9 +248,11 @@ func entityResolverNameForProduct(ctx context.Context, rep map[string]interface{ } for { var ( - m map[string]interface{} - ok bool + m map[string]interface{} + val interface{} + ok bool ) + _ = val m = rep if _, ok = m["upc"]; !ok { break diff --git a/example/federation/reviews/graph/generated/federation.go b/example/federation/reviews/graph/generated/federation.go index ae0eb993343..ad8aedf59e4 100644 --- a/example/federation/reviews/graph/generated/federation.go +++ b/example/federation/reviews/graph/generated/federation.go @@ -208,6 +208,7 @@ func entityResolverNameForProduct(ctx context.Context, rep map[string]interface{ val interface{} ok bool ) + _ = val m = rep if val, ok = m["manufacturer"]; !ok { break @@ -230,9 +231,11 @@ func entityResolverNameForProduct(ctx context.Context, rep map[string]interface{ func entityResolverNameForUser(ctx context.Context, rep map[string]interface{}) (string, error) { for { var ( - m map[string]interface{} - ok bool + m map[string]interface{} + val interface{} + ok bool ) + _ = val m = rep if _, ok = m["id"]; !ok { break diff --git a/plugin/federation/federation.gotpl b/plugin/federation/federation.gotpl index fdbbf0753f8..b35fb3bb89a 100644 --- a/plugin/federation/federation.gotpl +++ b/plugin/federation/federation.gotpl @@ -233,11 +233,10 @@ func (ec *executionContext) __resolve_entities(ctx context.Context, representati for { var ( m map[string]interface{} - {{- if gt (len .KeyFields) 1 }} - val interface{} - {{- end }} + val interface{} ok bool ) + _ = val {{- range $_, $keyField := .KeyFields }} m = rep {{- range $i, $field := .Field }} diff --git a/plugin/federation/testdata/allthethings/generated/federation.go b/plugin/federation/testdata/allthethings/generated/federation.go index 5fdcd29e5b3..d15b163ca6a 100644 --- a/plugin/federation/testdata/allthethings/generated/federation.go +++ b/plugin/federation/testdata/allthethings/generated/federation.go @@ -292,9 +292,11 @@ func (ec *executionContext) __resolve_entities(ctx context.Context, representati func entityResolverNameForExternalExtension(ctx context.Context, rep map[string]interface{}) (string, error) { for { var ( - m map[string]interface{} - ok bool + m map[string]interface{} + val interface{} + ok bool ) + _ = val m = rep if _, ok = m["upc"]; !ok { break @@ -307,9 +309,11 @@ func entityResolverNameForExternalExtension(ctx context.Context, rep map[string] func entityResolverNameForHello(ctx context.Context, rep map[string]interface{}) (string, error) { for { var ( - m map[string]interface{} - ok bool + m map[string]interface{} + val interface{} + ok bool ) + _ = val m = rep if _, ok = m["name"]; !ok { break @@ -326,6 +330,7 @@ func entityResolverNameForNestedKey(ctx context.Context, rep map[string]interfac val interface{} ok bool ) + _ = val m = rep if _, ok = m["id"]; !ok { break @@ -352,6 +357,7 @@ func entityResolverNameForVeryNestedKey(ctx context.Context, rep map[string]inte val interface{} ok bool ) + _ = val m = rep if _, ok = m["id"]; !ok { break @@ -410,9 +416,11 @@ func entityResolverNameForVeryNestedKey(ctx context.Context, rep map[string]inte func entityResolverNameForWorld(ctx context.Context, rep map[string]interface{}) (string, error) { for { var ( - m map[string]interface{} - ok bool + m map[string]interface{} + val interface{} + ok bool ) + _ = val m = rep if _, ok = m["foo"]; !ok { break @@ -421,9 +429,11 @@ func entityResolverNameForWorld(ctx context.Context, rep map[string]interface{}) } for { var ( - m map[string]interface{} - ok bool + m map[string]interface{} + val interface{} + ok bool ) + _ = val m = rep if _, ok = m["bar"]; !ok { break diff --git a/plugin/federation/testdata/entityresolver/entity.resolvers.go b/plugin/federation/testdata/entityresolver/entity.resolvers.go index 0a2ff3fcff2..64c5356b636 100644 --- a/plugin/federation/testdata/entityresolver/entity.resolvers.go +++ b/plugin/federation/testdata/entityresolver/entity.resolvers.go @@ -16,6 +16,10 @@ func (r *entityResolver) FindHelloByName(ctx context.Context, name string) (*gen }, nil } +func (r *entityResolver) FindHelloMultiSingleKeysByKey1AndKey2(ctx context.Context, key1 string, key2 string) (*generated.HelloMultiSingleKeys, error) { + panic(fmt.Errorf("not implemented")) +} + func (r *entityResolver) FindHelloWithErrorsByName(ctx context.Context, name string) (*generated.HelloWithErrors, error) { if name == "inject error" { return nil, generated.ErrResolvingHelloWithErrorsByName diff --git a/plugin/federation/testdata/entityresolver/generated/exec.go b/plugin/federation/testdata/entityresolver/generated/exec.go index 23ba9f3fb7d..3a671764e66 100644 --- a/plugin/federation/testdata/entityresolver/generated/exec.go +++ b/plugin/federation/testdata/entityresolver/generated/exec.go @@ -46,6 +46,7 @@ type DirectiveRoot struct { type ComplexityRoot struct { Entity struct { FindHelloByName func(childComplexity int, name string) int + FindHelloMultiSingleKeysByKey1AndKey2 func(childComplexity int, key1 string, key2 string) int FindHelloWithErrorsByName func(childComplexity int, name string) int FindManyMultiHelloByNames func(childComplexity int, reps []*MultiHelloByNamesInput) int FindManyMultiHelloWithErrorByNames func(childComplexity int, reps []*MultiHelloWithErrorByNamesInput) int @@ -62,6 +63,11 @@ type ComplexityRoot struct { Secondary func(childComplexity int) int } + HelloMultiSingleKeys struct { + Key1 func(childComplexity int) int + Key2 func(childComplexity int) int + } + HelloWithErrors struct { Name func(childComplexity int) int } @@ -114,6 +120,7 @@ type ComplexityRoot struct { type EntityResolver interface { FindHelloByName(ctx context.Context, name string) (*Hello, error) + FindHelloMultiSingleKeysByKey1AndKey2(ctx context.Context, key1 string, key2 string) (*HelloMultiSingleKeys, error) FindHelloWithErrorsByName(ctx context.Context, name string) (*HelloWithErrors, error) FindManyMultiHelloByNames(ctx context.Context, reps []*MultiHelloByNamesInput) ([]*MultiHello, error) FindManyMultiHelloWithErrorByNames(ctx context.Context, reps []*MultiHelloWithErrorByNamesInput) ([]*MultiHelloWithError, error) @@ -152,6 +159,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Entity.FindHelloByName(childComplexity, args["name"].(string)), true + case "Entity.findHelloMultiSingleKeysByKey1AndKey2": + if e.complexity.Entity.FindHelloMultiSingleKeysByKey1AndKey2 == nil { + break + } + + args, err := ec.field_Entity_findHelloMultiSingleKeysByKey1AndKey2_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Entity.FindHelloMultiSingleKeysByKey1AndKey2(childComplexity, args["key1"].(string), args["key2"].(string)), true + case "Entity.findHelloWithErrorsByName": if e.complexity.Entity.FindHelloWithErrorsByName == nil { break @@ -274,6 +293,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Hello.Secondary(childComplexity), true + case "HelloMultiSingleKeys.key1": + if e.complexity.HelloMultiSingleKeys.Key1 == nil { + break + } + + return e.complexity.HelloMultiSingleKeys.Key1(childComplexity), true + + case "HelloMultiSingleKeys.key2": + if e.complexity.HelloMultiSingleKeys.Key2 == nil { + break + } + + return e.complexity.HelloMultiSingleKeys.Key2(childComplexity), true + case "HelloWithErrors.name": if e.complexity.HelloWithErrors.Name == nil { break @@ -508,6 +541,11 @@ type MultiHello @key(fields: "name") @entityResolver(multi: true) { type MultiHelloWithError @key(fields: "name") @entityResolver(multi: true) { name: String! } + +type HelloMultiSingleKeys @key(fields: "key1 key2") { + key1: String! + key2: String! +} `, BuiltIn: false}, {Name: "federation/directives.graphql", Input: ` scalar _Any @@ -521,7 +559,7 @@ directive @extends on OBJECT | INTERFACE `, BuiltIn: true}, {Name: "federation/entity.graphql", Input: ` # a union of all types that use the @key directive -union _Entity = Hello | HelloWithErrors | MultiHello | MultiHelloWithError | PlanetRequires | PlanetRequiresNested | World | WorldName | WorldWithMultipleKeys +union _Entity = Hello | HelloMultiSingleKeys | HelloWithErrors | MultiHello | MultiHelloWithError | PlanetRequires | PlanetRequiresNested | World | WorldName | WorldWithMultipleKeys input MultiHelloByNamesInput { Name: String! } @@ -532,6 +570,7 @@ input MultiHelloWithErrorByNamesInput { # fake type to build resolver interfaces for users to implement type Entity { findHelloByName(name: String!,): Hello! + findHelloMultiSingleKeysByKey1AndKey2(key1: String!,key2: String!,): HelloMultiSingleKeys! findHelloWithErrorsByName(name: String!,): HelloWithErrors! findManyMultiHelloByNames(reps: [MultiHelloByNamesInput!]!): [MultiHello] findManyMultiHelloWithErrorByNames(reps: [MultiHelloWithErrorByNamesInput!]!): [MultiHelloWithError] @@ -590,6 +629,30 @@ func (ec *executionContext) field_Entity_findHelloByName_args(ctx context.Contex return args, nil } +func (ec *executionContext) field_Entity_findHelloMultiSingleKeysByKey1AndKey2_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["key1"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("key1")) + arg0, err = ec.unmarshalNString2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["key1"] = arg0 + var arg1 string + if tmp, ok := rawArgs["key2"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("key2")) + arg1, err = ec.unmarshalNString2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["key2"] = arg1 + return args, nil +} + func (ec *executionContext) field_Entity_findHelloWithErrorsByName_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -853,6 +916,48 @@ func (ec *executionContext) _Entity_findHelloByName(ctx context.Context, field g return ec.marshalNHello2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚐHello(ctx, field.Selections, res) } +func (ec *executionContext) _Entity_findHelloMultiSingleKeysByKey1AndKey2(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Entity", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Entity_findHelloMultiSingleKeysByKey1AndKey2_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Entity().FindHelloMultiSingleKeysByKey1AndKey2(rctx, args["key1"].(string), args["key2"].(string)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*HelloMultiSingleKeys) + fc.Result = res + return ec.marshalNHelloMultiSingleKeys2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚐHelloMultiSingleKeys(ctx, field.Selections, res) +} + func (ec *executionContext) _Entity_findHelloWithErrorsByName(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -1343,6 +1448,76 @@ func (ec *executionContext) _Hello_secondary(ctx context.Context, field graphql. return ec.marshalNString2string(ctx, field.Selections, res) } +func (ec *executionContext) _HelloMultiSingleKeys_key1(ctx context.Context, field graphql.CollectedField, obj *HelloMultiSingleKeys) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HelloMultiSingleKeys", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Key1, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _HelloMultiSingleKeys_key2(ctx context.Context, field graphql.CollectedField, obj *HelloMultiSingleKeys) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "HelloMultiSingleKeys", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Key2, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + func (ec *executionContext) _HelloWithErrors_name(ctx context.Context, field graphql.CollectedField, obj *HelloWithErrors) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -3260,6 +3435,13 @@ func (ec *executionContext) __Entity(ctx context.Context, sel ast.SelectionSet, return graphql.Null } return ec._Hello(ctx, sel, obj) + case HelloMultiSingleKeys: + return ec._HelloMultiSingleKeys(ctx, sel, &obj) + case *HelloMultiSingleKeys: + if obj == nil { + return graphql.Null + } + return ec._HelloMultiSingleKeys(ctx, sel, obj) case HelloWithErrors: return ec._HelloWithErrors(ctx, sel, &obj) case *HelloWithErrors: @@ -3364,6 +3546,29 @@ func (ec *executionContext) _Entity(ctx context.Context, sel ast.SelectionSet) g return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) } + out.Concurrently(i, func() graphql.Marshaler { + return rrm(innerCtx) + }) + case "findHelloMultiSingleKeysByKey1AndKey2": + field := field + + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Entity_findHelloMultiSingleKeysByKey1AndKey2(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) + } + out.Concurrently(i, func() graphql.Marshaler { return rrm(innerCtx) }) @@ -3620,6 +3825,47 @@ func (ec *executionContext) _Hello(ctx context.Context, sel ast.SelectionSet, ob return out } +var helloMultiSingleKeysImplementors = []string{"HelloMultiSingleKeys", "_Entity"} + +func (ec *executionContext) _HelloMultiSingleKeys(ctx context.Context, sel ast.SelectionSet, obj *HelloMultiSingleKeys) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, helloMultiSingleKeysImplementors) + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("HelloMultiSingleKeys") + case "key1": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._HelloMultiSingleKeys_key1(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + case "key2": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._HelloMultiSingleKeys_key2(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + + if out.Values[i] == graphql.Null { + invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + var helloWithErrorsImplementors = []string{"HelloWithErrors", "_Entity"} func (ec *executionContext) _HelloWithErrors(ctx context.Context, sel ast.SelectionSet, obj *HelloWithErrors) graphql.Marshaler { @@ -4498,6 +4744,20 @@ func (ec *executionContext) marshalNHello2ᚖgithubᚗcomᚋ99designsᚋgqlgen return ec._Hello(ctx, sel, v) } +func (ec *executionContext) marshalNHelloMultiSingleKeys2githubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚐHelloMultiSingleKeys(ctx context.Context, sel ast.SelectionSet, v HelloMultiSingleKeys) graphql.Marshaler { + return ec._HelloMultiSingleKeys(ctx, sel, &v) +} + +func (ec *executionContext) marshalNHelloMultiSingleKeys2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚐHelloMultiSingleKeys(ctx context.Context, sel ast.SelectionSet, v *HelloMultiSingleKeys) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + return ec._HelloMultiSingleKeys(ctx, sel, v) +} + func (ec *executionContext) marshalNHelloWithErrors2githubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚐHelloWithErrors(ctx context.Context, sel ast.SelectionSet, v HelloWithErrors) graphql.Marshaler { return ec._HelloWithErrors(ctx, sel, &v) } diff --git a/plugin/federation/testdata/entityresolver/generated/federation.go b/plugin/federation/testdata/entityresolver/generated/federation.go index 05d237152ec..a65f34860da 100644 --- a/plugin/federation/testdata/entityresolver/generated/federation.go +++ b/plugin/federation/testdata/entityresolver/generated/federation.go @@ -101,6 +101,30 @@ func (ec *executionContext) __resolve_entities(ctx context.Context, representati return fmt.Errorf(`resolving Entity "Hello": %w`, err) } + list[idx[i]] = entity + return nil + } + case "HelloMultiSingleKeys": + resolverName, err := entityResolverNameForHelloMultiSingleKeys(ctx, rep) + if err != nil { + return fmt.Errorf(`finding resolver for Entity "HelloMultiSingleKeys": %w`, err) + } + switch resolverName { + + case "findHelloMultiSingleKeysByKey1AndKey2": + id0, err := ec.unmarshalNString2string(ctx, rep["key1"]) + if err != nil { + return fmt.Errorf(`unmarshalling param 0 for findHelloMultiSingleKeysByKey1AndKey2(): %w`, err) + } + id1, err := ec.unmarshalNString2string(ctx, rep["key2"]) + if err != nil { + return fmt.Errorf(`unmarshalling param 1 for findHelloMultiSingleKeysByKey1AndKey2(): %w`, err) + } + entity, err := ec.resolvers.Entity().FindHelloMultiSingleKeysByKey1AndKey2(ctx, id0, id1) + if err != nil { + return fmt.Errorf(`resolving Entity "HelloMultiSingleKeys": %w`, err) + } + list[idx[i]] = entity return nil } @@ -372,9 +396,11 @@ func (ec *executionContext) __resolve_entities(ctx context.Context, representati func entityResolverNameForHello(ctx context.Context, rep map[string]interface{}) (string, error) { for { var ( - m map[string]interface{} - ok bool + m map[string]interface{} + val interface{} + ok bool ) + _ = val m = rep if _, ok = m["name"]; !ok { break @@ -384,12 +410,35 @@ func entityResolverNameForHello(ctx context.Context, rep map[string]interface{}) return "", fmt.Errorf("%w for Hello", ErrTypeNotFound) } +func entityResolverNameForHelloMultiSingleKeys(ctx context.Context, rep map[string]interface{}) (string, error) { + for { + var ( + m map[string]interface{} + val interface{} + ok bool + ) + _ = val + m = rep + if _, ok = m["key1"]; !ok { + break + } + m = rep + if _, ok = m["key2"]; !ok { + break + } + return "findHelloMultiSingleKeysByKey1AndKey2", nil + } + return "", fmt.Errorf("%w for HelloMultiSingleKeys", ErrTypeNotFound) +} + func entityResolverNameForHelloWithErrors(ctx context.Context, rep map[string]interface{}) (string, error) { for { var ( - m map[string]interface{} - ok bool + m map[string]interface{} + val interface{} + ok bool ) + _ = val m = rep if _, ok = m["name"]; !ok { break @@ -402,9 +451,11 @@ func entityResolverNameForHelloWithErrors(ctx context.Context, rep map[string]in func entityResolverNameForMultiHello(ctx context.Context, rep map[string]interface{}) (string, error) { for { var ( - m map[string]interface{} - ok bool + m map[string]interface{} + val interface{} + ok bool ) + _ = val m = rep if _, ok = m["name"]; !ok { break @@ -417,9 +468,11 @@ func entityResolverNameForMultiHello(ctx context.Context, rep map[string]interfa func entityResolverNameForMultiHelloWithError(ctx context.Context, rep map[string]interface{}) (string, error) { for { var ( - m map[string]interface{} - ok bool + m map[string]interface{} + val interface{} + ok bool ) + _ = val m = rep if _, ok = m["name"]; !ok { break @@ -432,9 +485,11 @@ func entityResolverNameForMultiHelloWithError(ctx context.Context, rep map[strin func entityResolverNameForPlanetRequires(ctx context.Context, rep map[string]interface{}) (string, error) { for { var ( - m map[string]interface{} - ok bool + m map[string]interface{} + val interface{} + ok bool ) + _ = val m = rep if _, ok = m["name"]; !ok { break @@ -447,9 +502,11 @@ func entityResolverNameForPlanetRequires(ctx context.Context, rep map[string]int func entityResolverNameForPlanetRequiresNested(ctx context.Context, rep map[string]interface{}) (string, error) { for { var ( - m map[string]interface{} - ok bool + m map[string]interface{} + val interface{} + ok bool ) + _ = val m = rep if _, ok = m["name"]; !ok { break @@ -466,6 +523,7 @@ func entityResolverNameForWorld(ctx context.Context, rep map[string]interface{}) val interface{} ok bool ) + _ = val m = rep if val, ok = m["hello"]; !ok { break @@ -488,9 +546,11 @@ func entityResolverNameForWorld(ctx context.Context, rep map[string]interface{}) func entityResolverNameForWorldName(ctx context.Context, rep map[string]interface{}) (string, error) { for { var ( - m map[string]interface{} - ok bool + m map[string]interface{} + val interface{} + ok bool ) + _ = val m = rep if _, ok = m["name"]; !ok { break @@ -507,6 +567,7 @@ func entityResolverNameForWorldWithMultipleKeys(ctx context.Context, rep map[str val interface{} ok bool ) + _ = val m = rep if val, ok = m["hello"]; !ok { break @@ -525,9 +586,11 @@ func entityResolverNameForWorldWithMultipleKeys(ctx context.Context, rep map[str } for { var ( - m map[string]interface{} - ok bool + m map[string]interface{} + val interface{} + ok bool ) + _ = val m = rep if _, ok = m["bar"]; !ok { break diff --git a/plugin/federation/testdata/entityresolver/generated/models.go b/plugin/federation/testdata/entityresolver/generated/models.go index 3c26208ccdd..f2b1a626886 100644 --- a/plugin/federation/testdata/entityresolver/generated/models.go +++ b/plugin/federation/testdata/entityresolver/generated/models.go @@ -9,6 +9,13 @@ type Hello struct { func (Hello) IsEntity() {} +type HelloMultiSingleKeys struct { + Key1 string `json:"key1"` + Key2 string `json:"key2"` +} + +func (HelloMultiSingleKeys) IsEntity() {} + type HelloWithErrors struct { Name string `json:"name"` } diff --git a/plugin/federation/testdata/entityresolver/schema.graphql b/plugin/federation/testdata/entityresolver/schema.graphql index bea2ca5f899..8a21dcfccfd 100644 --- a/plugin/federation/testdata/entityresolver/schema.graphql +++ b/plugin/federation/testdata/entityresolver/schema.graphql @@ -44,3 +44,8 @@ type MultiHello @key(fields: "name") @entityResolver(multi: true) { type MultiHelloWithError @key(fields: "name") @entityResolver(multi: true) { name: String! } + +type HelloMultiSingleKeys @key(fields: "key1 key2") { + key1: String! + key2: String! +}