diff --git a/plugin/federation/federation.go b/plugin/federation/federation.go index f7a4d6be27d..2af9205ff92 100644 --- a/plugin/federation/federation.go +++ b/plugin/federation/federation.go @@ -279,10 +279,13 @@ func (f *Federation) GenerateCode(data *codegen.Data) error { typeString := strings.Split(obj.Type.String(), ".") requiresImports[strings.Join(typeString[:len(typeString)-1], ".")] = true + if containsUnionField(reqField) { + continue + } + cgField := reqField.Field.TypeReference(obj, data.Objects) reqField.Type = cgField.TypeReference } - // add type info to entity e.Type = obj.Type } @@ -329,6 +332,15 @@ func (f *Federation) GenerateCode(data *codegen.Data) error { }) } +func containsUnionField(reqField *Requires) bool { + for _, requireFields := range reqField.Field { + if strings.HasPrefix(requireFields, "... on") { + return true + } + } + return false +} + // Fill in types for key fields func populateKeyFieldTypes( resolver *EntityResolver, diff --git a/plugin/federation/fieldset/fieldset.go b/plugin/federation/fieldset/fieldset.go index 8ff53cd2ab3..65b32eae285 100644 --- a/plugin/federation/fieldset/fieldset.go +++ b/plugin/federation/fieldset/fieldset.go @@ -133,8 +133,22 @@ func (f Field) LastIndex() int { // parseUnnestedKeyFieldSet // handles simple case where none of the fields are nested. func parseUnnestedKeyFieldSet(raw string, prefix []string) Set { ret := Set{} + unionField := false for _, s := range strings.Fields(raw) { + if s == "..." { + continue + } + if s == "on" { + unionField = true + continue + } + + if unionField { + s = "... on " + s + unionField = false + } + next := append(prefix[0:len(prefix):len(prefix)], s) //nolint:gocritic // set cap=len in order to force slice reallocation ret = append(ret, next) } diff --git a/plugin/federation/testdata/computedrequires/entity.resolvers.go b/plugin/federation/testdata/computedrequires/entity.resolvers.go index 1786a07f6a4..cdc7806de01 100644 --- a/plugin/federation/testdata/computedrequires/entity.resolvers.go +++ b/plugin/federation/testdata/computedrequires/entity.resolvers.go @@ -110,6 +110,11 @@ func (r *entityResolver) FindManyMultiPlanetRequiresNestedByNames(ctx context.Co return results, nil } +// FindPersonByName is the resolver for the findPersonByName field. +func (r *entityResolver) FindPersonByName(ctx context.Context, name string) (*model.Person, error) { + panic(fmt.Errorf("not implemented: FindPersonByName - findPersonByName")) +} + // FindPlanetMultipleRequiresByName is the resolver for the findPlanetMultipleRequiresByName field. func (r *entityResolver) FindPlanetMultipleRequiresByName(ctx context.Context, name string) (*model.PlanetMultipleRequires, error) { return &model.PlanetMultipleRequires{Name: name}, nil diff --git a/plugin/federation/testdata/computedrequires/generated/exec.go b/plugin/federation/testdata/computedrequires/generated/exec.go index d2f97a14c23..1ca93f41773 100644 --- a/plugin/federation/testdata/computedrequires/generated/exec.go +++ b/plugin/federation/testdata/computedrequires/generated/exec.go @@ -43,6 +43,7 @@ type ResolverRoot interface { MultiHelloMultipleRequires() MultiHelloMultipleRequiresResolver MultiHelloRequires() MultiHelloRequiresResolver MultiPlanetRequiresNested() MultiPlanetRequiresNestedResolver + Person() PersonResolver PlanetMultipleRequires() PlanetMultipleRequiresResolver PlanetRequires() PlanetRequiresResolver PlanetRequiresNested() PlanetRequiresNestedResolver @@ -64,6 +65,7 @@ type EntityResolver interface { FindManyMultiHelloRequiresByNames(ctx context.Context, reps []*model.MultiHelloRequiresByNamesInput) ([]*model.MultiHelloRequires, error) FindManyMultiHelloWithErrorByNames(ctx context.Context, reps []*model.MultiHelloWithErrorByNamesInput) ([]*model.MultiHelloWithError, error) FindManyMultiPlanetRequiresNestedByNames(ctx context.Context, reps []*model.MultiPlanetRequiresNestedByNamesInput) ([]*model.MultiPlanetRequiresNested, error) + FindPersonByName(ctx context.Context, name string) (*model.Person, error) FindPlanetMultipleRequiresByName(ctx context.Context, name string) (*model.PlanetMultipleRequires, error) FindPlanetRequiresByName(ctx context.Context, name string) (*model.PlanetRequires, error) FindPlanetRequiresNestedByName(ctx context.Context, name string) (*model.PlanetRequiresNested, error) @@ -81,6 +83,9 @@ type MultiHelloRequiresResolver interface { type MultiPlanetRequiresNestedResolver interface { Size(ctx context.Context, obj *model.MultiPlanetRequiresNested, federationRequires map[string]interface{}) (int, error) } +type PersonResolver interface { + WelcomeMessage(ctx context.Context, obj *model.Person, federationRequires map[string]interface{}) (*string, error) +} type PlanetMultipleRequiresResolver interface { Weight(ctx context.Context, obj *model.PlanetMultipleRequires, foo *string, federationRequires map[string]interface{}) (int, error) } @@ -250,6 +255,22 @@ type World @key(fields: "hello { name } foo ") { hello: Hello } +type Person @key(fields: "name"){ + name: String! + gender: Gender! + welcomeMessage: String @requires(fields:"gender { ... on Male {description} ... on Female {description}}") +} + +union Gender = Male | Female + +type Male { + description: String! +} + +type Female { + description: String! +} + type WorldWithMultipleKeys @key(fields: "hello { name } foo ") @key(fields: "bar") { foo: String! bar: Int! @@ -371,7 +392,7 @@ type MultiHelloMultipleRequires @key(fields: "name") @entityResolver(multi: true `, BuiltIn: true}, {Name: "../../../federation/entity.graphql", Input: ` # a union of all types that use the @key directive -union _Entity = Hello | HelloMultiSingleKeys | HelloWithErrors | MultiHello | MultiHelloMultipleRequires | MultiHelloRequires | MultiHelloWithError | MultiPlanetRequiresNested | PlanetMultipleRequires | PlanetRequires | PlanetRequiresNested | World | WorldName | WorldWithMultipleKeys +union _Entity = Hello | HelloMultiSingleKeys | HelloWithErrors | MultiHello | MultiHelloMultipleRequires | MultiHelloRequires | MultiHelloWithError | MultiPlanetRequiresNested | Person | PlanetMultipleRequires | PlanetRequires | PlanetRequiresNested | World | WorldName | WorldWithMultipleKeys input MultiHelloByNamesInput { Name: String! @@ -403,6 +424,7 @@ type Entity { findManyMultiHelloRequiresByNames(reps: [MultiHelloRequiresByNamesInput]!): [MultiHelloRequires] findManyMultiHelloWithErrorByNames(reps: [MultiHelloWithErrorByNamesInput]!): [MultiHelloWithError] findManyMultiPlanetRequiresNestedByNames(reps: [MultiPlanetRequiresNestedByNamesInput]!): [MultiPlanetRequiresNested] + findPersonByName(name: String!,): Person! findPlanetMultipleRequiresByName(name: String!,): PlanetMultipleRequires! findPlanetRequiresByName(name: String!,): PlanetRequires! findPlanetRequiresNestedByName(name: String!,): PlanetRequiresNested! @@ -630,6 +652,29 @@ func (ec *executionContext) field_Entity_findManyMultiPlanetRequiresNestedByName return zeroVal, nil } +func (ec *executionContext) field_Entity_findPersonByName_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + arg0, err := ec.field_Entity_findPersonByName_argsName(ctx, rawArgs) + if err != nil { + return nil, err + } + args["name"] = arg0 + return args, nil +} +func (ec *executionContext) field_Entity_findPersonByName_argsName( + ctx context.Context, + rawArgs map[string]interface{}, +) (string, error) { + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) + if tmp, ok := rawArgs["name"]; ok { + return ec.unmarshalNString2string(ctx, tmp) + } + + var zeroVal string + return zeroVal, nil +} + func (ec *executionContext) field_Entity_findPlanetMultipleRequiresByName_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -959,6 +1004,50 @@ func (ec *executionContext) field_MultiPlanetRequiresNested_size_argsFederationR } } +func (ec *executionContext) field_Person_welcomeMessage_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + arg0, err := ec.field_Person_welcomeMessage_argsFederationRequires(ctx, rawArgs) + if err != nil { + return nil, err + } + args["_federationRequires"] = arg0 + return args, nil +} +func (ec *executionContext) field_Person_welcomeMessage_argsFederationRequires( + ctx context.Context, + rawArgs map[string]interface{}, +) (map[string]interface{}, error) { + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("_federationRequires")) + directive0 := func(ctx context.Context) (interface{}, error) { + tmp, ok := rawArgs["_federationRequires"] + if !ok { + var zeroVal map[string]interface{} + return zeroVal, nil + } + return ec.unmarshalO_RequiresMap2map(ctx, tmp) + } + + directive1 := func(ctx context.Context) (interface{}, error) { + return builtInDirectivePopulateFromRepresentations(ctx, rawArgs, directive0) + } + + tmp, err := directive1(ctx) + if err != nil { + var zeroVal map[string]interface{} + return zeroVal, graphql.ErrorOnPath(ctx, err) + } + if data, ok := tmp.(map[string]interface{}); ok { + return data, nil + } else if tmp == nil { + var zeroVal map[string]interface{} + return zeroVal, nil + } else { + var zeroVal map[string]interface{} + return zeroVal, graphql.ErrorOnPath(ctx, fmt.Errorf(`unexpected type %T from directive, should be map[string]interface{}`, tmp)) + } +} + func (ec *executionContext) field_PlanetMultipleRequires_anotherField_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -1751,6 +1840,69 @@ func (ec *executionContext) fieldContext_Entity_findManyMultiPlanetRequiresNeste return fc, nil } +func (ec *executionContext) _Entity_findPersonByName(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Entity_findPersonByName(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Entity().FindPersonByName(rctx, fc.Args["name"].(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.(*model.Person) + fc.Result = res + return ec.marshalNPerson2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋcomputedrequiresᚋgeneratedᚋmodelsᚐPerson(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Entity_findPersonByName(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Entity", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "name": + return ec.fieldContext_Person_name(ctx, field) + case "gender": + return ec.fieldContext_Person_gender(ctx, field) + case "welcomeMessage": + return ec.fieldContext_Person_welcomeMessage(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Person", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Entity_findPersonByName_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + func (ec *executionContext) _Entity_findPlanetMultipleRequiresByName(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Entity_findPlanetMultipleRequiresByName(ctx, field) if err != nil { @@ -2196,6 +2348,50 @@ func (ec *executionContext) fieldContext_Entity_findWorldWithMultipleKeysByBar(c return fc, nil } +func (ec *executionContext) _Female_description(ctx context.Context, field graphql.CollectedField, obj *model.Female) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Female_description(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Description, 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) fieldContext_Female_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Female", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _Hello_name(ctx context.Context, field graphql.CollectedField, obj *model.Hello) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Hello_name(ctx, field) if err != nil { @@ -2416,6 +2612,50 @@ func (ec *executionContext) fieldContext_HelloWithErrors_name(_ context.Context, return fc, nil } +func (ec *executionContext) _Male_description(ctx context.Context, field graphql.CollectedField, obj *model.Male) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Male_description(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Description, 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) fieldContext_Male_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Male", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _MultiHello_name(ctx context.Context, field graphql.CollectedField, obj *model.MultiHello) (ret graphql.Marshaler) { fc, err := ec.fieldContext_MultiHello_name(ctx, field) if err != nil { @@ -2985,6 +3225,146 @@ func (ec *executionContext) fieldContext_MultiPlanetRequiresNested_size(ctx cont return fc, nil } +func (ec *executionContext) _Person_name(ctx context.Context, field graphql.CollectedField, obj *model.Person) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Person_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, 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) fieldContext_Person_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Person", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Person_gender(ctx context.Context, field graphql.CollectedField, obj *model.Person) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Person_gender(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Gender, 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.(model.Gender) + fc.Result = res + return ec.marshalNGender2githubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋcomputedrequiresᚋgeneratedᚋmodelsᚐGender(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Person_gender(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Person", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Gender does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Person_welcomeMessage(ctx context.Context, field graphql.CollectedField, obj *model.Person) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Person_welcomeMessage(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Person().WelcomeMessage(rctx, obj, fc.Args["_federationRequires"].(map[string]interface{})) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Person_welcomeMessage(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Person", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Person_welcomeMessage_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + func (ec *executionContext) _PlanetMultipleRequires_name(ctx context.Context, field graphql.CollectedField, obj *model.PlanetMultipleRequires) (ret graphql.Marshaler) { fc, err := ec.fieldContext_PlanetMultipleRequires_name(ctx, field) if err != nil { @@ -6159,6 +6539,29 @@ func (ec *executionContext) unmarshalInputMultiPlanetRequiresNestedByNamesInput( // region ************************** interface.gotpl *************************** +func (ec *executionContext) _Gender(ctx context.Context, sel ast.SelectionSet, obj model.Gender) graphql.Marshaler { + switch obj := (obj).(type) { + case nil: + return graphql.Null + case model.Male: + return ec._Male(ctx, sel, &obj) + case *model.Male: + if obj == nil { + return graphql.Null + } + return ec._Male(ctx, sel, obj) + case model.Female: + return ec._Female(ctx, sel, &obj) + case *model.Female: + if obj == nil { + return graphql.Null + } + return ec._Female(ctx, sel, obj) + default: + panic(fmt.Errorf("unexpected type %T", obj)) + } +} + func (ec *executionContext) __Entity(ctx context.Context, sel ast.SelectionSet, obj fedruntime.Entity) graphql.Marshaler { switch obj := (obj).(type) { case nil: @@ -6219,6 +6622,13 @@ func (ec *executionContext) __Entity(ctx context.Context, sel ast.SelectionSet, return graphql.Null } return ec._MultiPlanetRequiresNested(ctx, sel, obj) + case model.Person: + return ec._Person(ctx, sel, &obj) + case *model.Person: + if obj == nil { + return graphql.Null + } + return ec._Person(ctx, sel, obj) case model.PlanetMultipleRequires: return ec._PlanetMultipleRequires(ctx, sel, &obj) case *model.PlanetMultipleRequires: @@ -6449,6 +6859,28 @@ func (ec *executionContext) _Entity(ctx context.Context, sel ast.SelectionSet) g func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "findPersonByName": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Entity_findPersonByName(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "findPlanetMultipleRequiresByName": field := field @@ -6627,6 +7059,45 @@ func (ec *executionContext) _Entity(ctx context.Context, sel ast.SelectionSet) g return out } +var femaleImplementors = []string{"Female", "Gender"} + +func (ec *executionContext) _Female(ctx context.Context, sel ast.SelectionSet, obj *model.Female) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, femaleImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Female") + case "description": + out.Values[i] = ec._Female_description(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + var helloImplementors = []string{"Hello", "_Entity"} func (ec *executionContext) _Hello(ctx context.Context, sel ast.SelectionSet, obj *model.Hello) graphql.Marshaler { @@ -6754,6 +7225,45 @@ func (ec *executionContext) _HelloWithErrors(ctx context.Context, sel ast.Select return out } +var maleImplementors = []string{"Male", "Gender"} + +func (ec *executionContext) _Male(ctx context.Context, sel ast.SelectionSet, obj *model.Male) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, maleImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Male") + case "description": + out.Values[i] = ec._Male_description(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + var multiHelloImplementors = []string{"MultiHello", "_Entity"} func (ec *executionContext) _MultiHello(ctx context.Context, sel ast.SelectionSet, obj *model.MultiHello) graphql.Marshaler { @@ -7077,6 +7587,83 @@ func (ec *executionContext) _MultiPlanetRequiresNested(ctx context.Context, sel return out } +var personImplementors = []string{"Person", "_Entity"} + +func (ec *executionContext) _Person(ctx context.Context, sel ast.SelectionSet, obj *model.Person) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, personImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Person") + case "name": + out.Values[i] = ec._Person_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } + case "gender": + out.Values[i] = ec._Person_gender(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } + case "welcomeMessage": + field := field + + innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Person_welcomeMessage(ctx, field, obj) + return res + } + + if field.Deferrable != nil { + dfs, ok := deferred[field.Deferrable.Label] + di := 0 + if ok { + dfs.AddField(field) + di = len(dfs.Values) - 1 + } else { + dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) + deferred[field.Deferrable.Label] = dfs + } + dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { + return innerFunc(ctx, dfs) + }) + + // don't run the out.Concurrently() call below + out.Values[i] = graphql.Null + continue + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + var planetMultipleRequiresImplementors = []string{"PlanetMultipleRequires", "_Entity"} func (ec *executionContext) _PlanetMultipleRequires(ctx context.Context, sel ast.SelectionSet, obj *model.PlanetMultipleRequires) graphql.Marshaler { @@ -7995,6 +8582,16 @@ func (ec *executionContext) marshalNFieldSet2string(ctx context.Context, sel ast return res } +func (ec *executionContext) marshalNGender2githubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋcomputedrequiresᚋgeneratedᚋmodelsᚐGender(ctx context.Context, sel ast.SelectionSet, v model.Gender) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._Gender(ctx, sel, v) +} + func (ec *executionContext) marshalNHello2githubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋcomputedrequiresᚋgeneratedᚋmodelsᚐHello(ctx context.Context, sel ast.SelectionSet, v model.Hello) graphql.Marshaler { return ec._Hello(ctx, sel, &v) } @@ -8137,6 +8734,20 @@ func (ec *executionContext) unmarshalNMultiPlanetRequiresNestedByNamesInput2ᚕ return res, nil } +func (ec *executionContext) marshalNPerson2githubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋcomputedrequiresᚋgeneratedᚋmodelsᚐPerson(ctx context.Context, sel ast.SelectionSet, v model.Person) graphql.Marshaler { + return ec._Person(ctx, sel, &v) +} + +func (ec *executionContext) marshalNPerson2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋcomputedrequiresᚋgeneratedᚋmodelsᚐPerson(ctx context.Context, sel ast.SelectionSet, v *model.Person) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._Person(ctx, sel, v) +} + func (ec *executionContext) marshalNPlanetMultipleRequires2githubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋcomputedrequiresᚋgeneratedᚋmodelsᚐPlanetMultipleRequires(ctx context.Context, sel ast.SelectionSet, v model.PlanetMultipleRequires) graphql.Marshaler { return ec._PlanetMultipleRequires(ctx, sel, &v) } diff --git a/plugin/federation/testdata/computedrequires/generated/federation.go b/plugin/federation/testdata/computedrequires/generated/federation.go index 56b2edb15d0..619ac8d1a15 100644 --- a/plugin/federation/testdata/computedrequires/generated/federation.go +++ b/plugin/federation/testdata/computedrequires/generated/federation.go @@ -223,6 +223,25 @@ func (ec *executionContext) resolveEntity( return nil, fmt.Errorf(`resolving Entity "HelloWithErrors": %w`, err) } + return entity, nil + } + case "Person": + resolverName, err := entityResolverNameForPerson(ctx, rep) + if err != nil { + return nil, fmt.Errorf(`finding resolver for Entity "Person": %w`, err) + } + switch resolverName { + + case "findPersonByName": + id0, err := ec.unmarshalNString2string(ctx, rep["name"]) + if err != nil { + return nil, fmt.Errorf(`unmarshalling param 0 for findPersonByName(): %w`, err) + } + entity, err := ec.resolvers.Entity().FindPersonByName(ctx, id0) + if err != nil { + return nil, fmt.Errorf(`resolving Entity "Person": %w`, err) + } + return entity, nil } case "PlanetMultipleRequires": @@ -799,6 +818,33 @@ func entityResolverNameForMultiPlanetRequiresNested(ctx context.Context, rep Ent return "", fmt.Errorf("%w for MultiPlanetRequiresNested", ErrTypeNotFound) } +func entityResolverNameForPerson(ctx context.Context, rep EntityRepresentation) (string, error) { + for { + var ( + m EntityRepresentation + val interface{} + ok bool + ) + _ = val + // if all of the KeyFields values for this resolver are null, + // we shouldn't use use it + allNull := true + m = rep + val, ok = m["name"] + if !ok { + break + } + if allNull { + allNull = val == nil + } + if allNull { + break + } + return "findPersonByName", nil + } + return "", fmt.Errorf("%w for Person", ErrTypeNotFound) +} + func entityResolverNameForPlanetMultipleRequires(ctx context.Context, rep EntityRepresentation) (string, error) { for { var ( diff --git a/plugin/federation/testdata/computedrequires/generated/models/models.go b/plugin/federation/testdata/computedrequires/generated/models/models.go index a3f39e1a6da..da79839292c 100644 --- a/plugin/federation/testdata/computedrequires/generated/models/models.go +++ b/plugin/federation/testdata/computedrequires/generated/models/models.go @@ -2,6 +2,16 @@ package model +type Gender interface { + IsGender() +} + +type Female struct { + Description string `json:"description"` +} + +func (Female) IsGender() {} + type Hello struct { Name string `json:"name"` Secondary string `json:"secondary"` @@ -22,6 +32,12 @@ type HelloWithErrors struct { func (HelloWithErrors) IsEntity() {} +type Male struct { + Description string `json:"description"` +} + +func (Male) IsGender() {} + type MultiHello struct { Name string `json:"name"` } @@ -79,6 +95,14 @@ type MultiPlanetRequiresNestedByNamesInput struct { Name string `json:"Name"` } +type Person struct { + Name string `json:"name"` + Gender Gender `json:"gender"` + WelcomeMessage *string `json:"welcomeMessage,omitempty"` +} + +func (Person) IsEntity() {} + type PlanetMultipleRequires struct { Name string `json:"name"` Diameter int `json:"diameter"` diff --git a/plugin/federation/testdata/computedrequires/schema.graphql b/plugin/federation/testdata/computedrequires/schema.graphql index 127e6e10f9f..43567d04cfc 100644 --- a/plugin/federation/testdata/computedrequires/schema.graphql +++ b/plugin/federation/testdata/computedrequires/schema.graphql @@ -16,6 +16,22 @@ type World @key(fields: "hello { name } foo ") { hello: Hello } +type Person @key(fields: "name"){ + name: String! + gender: Gender! + welcomeMessage: String @requires(fields:"gender { ... on Male {description} ... on Female {description}}") +} + +union Gender = Male | Female + +type Male { + description: String! +} + +type Female { + description: String! +} + type WorldWithMultipleKeys @key(fields: "hello { name } foo ") @key(fields: "bar") { foo: String! bar: Int! diff --git a/plugin/federation/testdata/computedrequires/schema.resolvers.go b/plugin/federation/testdata/computedrequires/schema.resolvers.go index 969494cc300..64e59450d42 100644 --- a/plugin/federation/testdata/computedrequires/schema.resolvers.go +++ b/plugin/federation/testdata/computedrequires/schema.resolvers.go @@ -32,6 +32,11 @@ func (r *multiPlanetRequiresNestedResolver) Size(ctx context.Context, obj *model return len(foo), nil } +// WelcomeMessage is the resolver for the welcomeMessage field. +func (r *personResolver) WelcomeMessage(ctx context.Context, obj *model.Person, federationRequires map[string]interface{}) (*string, error) { + panic(fmt.Errorf("not implemented: WelcomeMessage - welcomeMessage")) +} + // Weight is the resolver for the weight field. func (r *planetMultipleRequiresResolver) Weight(ctx context.Context, obj *model.PlanetMultipleRequires, foo *string, federationRequires map[string]interface{}) (int, error) { diameter, err := federationRequires["diameter"].(json.Number).Int64() @@ -89,6 +94,9 @@ func (r *Resolver) MultiPlanetRequiresNested() explicitrequires.MultiPlanetRequi return &multiPlanetRequiresNestedResolver{r} } +// Person returns explicitrequires.PersonResolver implementation. +func (r *Resolver) Person() explicitrequires.PersonResolver { return &personResolver{r} } + // PlanetMultipleRequires returns explicitrequires.PlanetMultipleRequiresResolver implementation. func (r *Resolver) PlanetMultipleRequires() explicitrequires.PlanetMultipleRequiresResolver { return &planetMultipleRequiresResolver{r} @@ -110,6 +118,7 @@ func (r *Resolver) Query() explicitrequires.QueryResolver { return &queryResolve type multiHelloMultipleRequiresResolver struct{ *Resolver } type multiHelloRequiresResolver struct{ *Resolver } type multiPlanetRequiresNestedResolver struct{ *Resolver } +type personResolver struct{ *Resolver } type planetMultipleRequiresResolver struct{ *Resolver } type planetRequiresResolver struct{ *Resolver } type planetRequiresNestedResolver struct{ *Resolver } diff --git a/plugin/federation/testdata/explicitrequires/entity.resolvers.go b/plugin/federation/testdata/explicitrequires/entity.resolvers.go index 1b754d510f6..67c29383d45 100644 --- a/plugin/federation/testdata/explicitrequires/entity.resolvers.go +++ b/plugin/federation/testdata/explicitrequires/entity.resolvers.go @@ -109,6 +109,11 @@ func (r *entityResolver) FindManyMultiPlanetRequiresNestedByNames(ctx context.Co return results, nil } +// FindPersonByName is the resolver for the findPersonByName field. +func (r *entityResolver) FindPersonByName(ctx context.Context, name string) (*generated.Person, error) { + panic(fmt.Errorf("not implemented: FindPersonByName - findPersonByName")) +} + // FindPlanetMultipleRequiresByName is the resolver for the findPlanetMultipleRequiresByName field. func (r *entityResolver) FindPlanetMultipleRequiresByName(ctx context.Context, name string) (*generated.PlanetMultipleRequires, error) { return &generated.PlanetMultipleRequires{Name: name}, nil diff --git a/plugin/federation/testdata/explicitrequires/generated/exec.go b/plugin/federation/testdata/explicitrequires/generated/exec.go index 0a0ee574a9c..9e3f9a48d94 100644 --- a/plugin/federation/testdata/explicitrequires/generated/exec.go +++ b/plugin/federation/testdata/explicitrequires/generated/exec.go @@ -56,6 +56,7 @@ type EntityResolver interface { FindManyMultiHelloRequiresByNames(ctx context.Context, reps []*MultiHelloRequiresByNamesInput) ([]*MultiHelloRequires, error) FindManyMultiHelloWithErrorByNames(ctx context.Context, reps []*MultiHelloWithErrorByNamesInput) ([]*MultiHelloWithError, error) FindManyMultiPlanetRequiresNestedByNames(ctx context.Context, reps []*MultiPlanetRequiresNestedByNamesInput) ([]*MultiPlanetRequiresNested, error) + FindPersonByName(ctx context.Context, name string) (*Person, error) FindPlanetMultipleRequiresByName(ctx context.Context, name string) (*PlanetMultipleRequires, error) FindPlanetRequiresByName(ctx context.Context, name string) (*PlanetRequires, error) FindPlanetRequiresNestedByName(ctx context.Context, name string) (*PlanetRequiresNested, error) @@ -190,6 +191,22 @@ type World @key(fields: "hello { name } foo ") { hello: Hello } +type Person @key(fields: "name"){ + name: String! + gender: Gender! + welcomeMessage: String @requires(fields:"gender { ... on Male {description} ... on Female {description}}") +} + +union Gender = Male | Female + +type Male { + description: String! +} + +type Female { + description: String! +} + type WorldWithMultipleKeys @key(fields: "hello { name } foo ") @key(fields: "bar") { foo: String! bar: Int! @@ -268,7 +285,7 @@ type MultiHelloMultipleRequires @key(fields: "name") @entityResolver(multi: true `, BuiltIn: true}, {Name: "../../../federation/entity.graphql", Input: ` # a union of all types that use the @key directive -union _Entity = Hello | HelloMultiSingleKeys | HelloWithErrors | MultiHello | MultiHelloMultipleRequires | MultiHelloRequires | MultiHelloWithError | MultiPlanetRequiresNested | PlanetMultipleRequires | PlanetRequires | PlanetRequiresNested | World | WorldName | WorldWithMultipleKeys +union _Entity = Hello | HelloMultiSingleKeys | HelloWithErrors | MultiHello | MultiHelloMultipleRequires | MultiHelloRequires | MultiHelloWithError | MultiPlanetRequiresNested | Person | PlanetMultipleRequires | PlanetRequires | PlanetRequiresNested | World | WorldName | WorldWithMultipleKeys input MultiHelloByNamesInput { Name: String! @@ -300,6 +317,7 @@ type Entity { findManyMultiHelloRequiresByNames(reps: [MultiHelloRequiresByNamesInput]!): [MultiHelloRequires] findManyMultiHelloWithErrorByNames(reps: [MultiHelloWithErrorByNamesInput]!): [MultiHelloWithError] findManyMultiPlanetRequiresNestedByNames(reps: [MultiPlanetRequiresNestedByNamesInput]!): [MultiPlanetRequiresNested] + findPersonByName(name: String!,): Person! findPlanetMultipleRequiresByName(name: String!,): PlanetMultipleRequires! findPlanetRequiresByName(name: String!,): PlanetRequires! findPlanetRequiresNestedByName(name: String!,): PlanetRequiresNested! @@ -608,6 +626,38 @@ func (ec *executionContext) field_Entity_findManyMultiPlanetRequiresNestedByName return zeroVal, nil } +func (ec *executionContext) field_Entity_findPersonByName_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + arg0, err := ec.field_Entity_findPersonByName_argsName(ctx, rawArgs) + if err != nil { + return nil, err + } + args["name"] = arg0 + return args, nil +} +func (ec *executionContext) field_Entity_findPersonByName_argsName( + ctx context.Context, + rawArgs map[string]interface{}, +) (string, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["name"] + if !ok { + var zeroVal string + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) + if tmp, ok := rawArgs["name"]; ok { + return ec.unmarshalNString2string(ctx, tmp) + } + + var zeroVal string + return zeroVal, nil +} + func (ec *executionContext) field_Entity_findPlanetMultipleRequiresByName_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -1497,6 +1547,69 @@ func (ec *executionContext) fieldContext_Entity_findManyMultiPlanetRequiresNeste return fc, nil } +func (ec *executionContext) _Entity_findPersonByName(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Entity_findPersonByName(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Entity().FindPersonByName(rctx, fc.Args["name"].(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.(*Person) + fc.Result = res + return ec.marshalNPerson2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋexplicitrequiresᚋgeneratedᚐPerson(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Entity_findPersonByName(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Entity", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "name": + return ec.fieldContext_Person_name(ctx, field) + case "gender": + return ec.fieldContext_Person_gender(ctx, field) + case "welcomeMessage": + return ec.fieldContext_Person_welcomeMessage(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Person", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Entity_findPersonByName_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + func (ec *executionContext) _Entity_findPlanetMultipleRequiresByName(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Entity_findPlanetMultipleRequiresByName(ctx, field) if err != nil { @@ -1940,6 +2053,50 @@ func (ec *executionContext) fieldContext_Entity_findWorldWithMultipleKeysByBar(c return fc, nil } +func (ec *executionContext) _Female_description(ctx context.Context, field graphql.CollectedField, obj *Female) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Female_description(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Description, 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) fieldContext_Female_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Female", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _Hello_name(ctx context.Context, field graphql.CollectedField, obj *Hello) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Hello_name(ctx, field) if err != nil { @@ -2160,6 +2317,50 @@ func (ec *executionContext) fieldContext_HelloWithErrors_name(_ context.Context, return fc, nil } +func (ec *executionContext) _Male_description(ctx context.Context, field graphql.CollectedField, obj *Male) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Male_description(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Description, 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) fieldContext_Male_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Male", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _MultiHello_name(ctx context.Context, field graphql.CollectedField, obj *MultiHello) (ret graphql.Marshaler) { fc, err := ec.fieldContext_MultiHello_name(ctx, field) if err != nil { @@ -2696,6 +2897,135 @@ func (ec *executionContext) fieldContext_MultiPlanetRequiresNested_size(_ contex return fc, nil } +func (ec *executionContext) _Person_name(ctx context.Context, field graphql.CollectedField, obj *Person) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Person_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, 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) fieldContext_Person_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Person", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Person_gender(ctx context.Context, field graphql.CollectedField, obj *Person) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Person_gender(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Gender, 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.(Gender) + fc.Result = res + return ec.marshalNGender2githubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋexplicitrequiresᚋgeneratedᚐGender(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Person_gender(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Person", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Gender does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Person_welcomeMessage(ctx context.Context, field graphql.CollectedField, obj *Person) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Person_welcomeMessage(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.WelcomeMessage, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Person_welcomeMessage(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Person", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _PlanetMultipleRequires_name(ctx context.Context, field graphql.CollectedField, obj *PlanetMultipleRequires) (ret graphql.Marshaler) { fc, err := ec.fieldContext_PlanetMultipleRequires_name(ctx, field) if err != nil { @@ -5733,6 +6063,29 @@ func (ec *executionContext) unmarshalInputMultiPlanetRequiresNestedByNamesInput( // region ************************** interface.gotpl *************************** +func (ec *executionContext) _Gender(ctx context.Context, sel ast.SelectionSet, obj Gender) graphql.Marshaler { + switch obj := (obj).(type) { + case nil: + return graphql.Null + case Male: + return ec._Male(ctx, sel, &obj) + case *Male: + if obj == nil { + return graphql.Null + } + return ec._Male(ctx, sel, obj) + case Female: + return ec._Female(ctx, sel, &obj) + case *Female: + if obj == nil { + return graphql.Null + } + return ec._Female(ctx, sel, obj) + default: + panic(fmt.Errorf("unexpected type %T", obj)) + } +} + func (ec *executionContext) __Entity(ctx context.Context, sel ast.SelectionSet, obj fedruntime.Entity) graphql.Marshaler { switch obj := (obj).(type) { case nil: @@ -5793,6 +6146,13 @@ func (ec *executionContext) __Entity(ctx context.Context, sel ast.SelectionSet, return graphql.Null } return ec._MultiPlanetRequiresNested(ctx, sel, obj) + case Person: + return ec._Person(ctx, sel, &obj) + case *Person: + if obj == nil { + return graphql.Null + } + return ec._Person(ctx, sel, obj) case PlanetMultipleRequires: return ec._PlanetMultipleRequires(ctx, sel, &obj) case *PlanetMultipleRequires: @@ -6023,6 +6383,28 @@ func (ec *executionContext) _Entity(ctx context.Context, sel ast.SelectionSet) g func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "findPersonByName": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Entity_findPersonByName(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "findPlanetMultipleRequiresByName": field := field @@ -6201,6 +6583,45 @@ func (ec *executionContext) _Entity(ctx context.Context, sel ast.SelectionSet) g return out } +var femaleImplementors = []string{"Female", "Gender"} + +func (ec *executionContext) _Female(ctx context.Context, sel ast.SelectionSet, obj *Female) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, femaleImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Female") + case "description": + out.Values[i] = ec._Female_description(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + var helloImplementors = []string{"Hello", "_Entity"} func (ec *executionContext) _Hello(ctx context.Context, sel ast.SelectionSet, obj *Hello) graphql.Marshaler { @@ -6328,6 +6749,45 @@ func (ec *executionContext) _HelloWithErrors(ctx context.Context, sel ast.Select return out } +var maleImplementors = []string{"Male", "Gender"} + +func (ec *executionContext) _Male(ctx context.Context, sel ast.SelectionSet, obj *Male) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, maleImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Male") + case "description": + out.Values[i] = ec._Male_description(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + var multiHelloImplementors = []string{"MultiHello", "_Entity"} func (ec *executionContext) _MultiHello(ctx context.Context, sel ast.SelectionSet, obj *MultiHello) graphql.Marshaler { @@ -6558,6 +7018,52 @@ func (ec *executionContext) _MultiPlanetRequiresNested(ctx context.Context, sel return out } +var personImplementors = []string{"Person", "_Entity"} + +func (ec *executionContext) _Person(ctx context.Context, sel ast.SelectionSet, obj *Person) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, personImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Person") + case "name": + out.Values[i] = ec._Person_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "gender": + out.Values[i] = ec._Person_gender(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "welcomeMessage": + out.Values[i] = ec._Person_welcomeMessage(ctx, field, obj) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + var planetMultipleRequiresImplementors = []string{"PlanetMultipleRequires", "_Entity"} func (ec *executionContext) _PlanetMultipleRequires(ctx context.Context, sel ast.SelectionSet, obj *PlanetMultipleRequires) graphql.Marshaler { @@ -7316,6 +7822,16 @@ func (ec *executionContext) marshalNBoolean2bool(ctx context.Context, sel ast.Se return res } +func (ec *executionContext) marshalNGender2githubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋexplicitrequiresᚋgeneratedᚐGender(ctx context.Context, sel ast.SelectionSet, v Gender) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._Gender(ctx, sel, v) +} + func (ec *executionContext) marshalNHello2githubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋexplicitrequiresᚋgeneratedᚐHello(ctx context.Context, sel ast.SelectionSet, v Hello) graphql.Marshaler { return ec._Hello(ctx, sel, &v) } @@ -7458,6 +7974,20 @@ func (ec *executionContext) unmarshalNMultiPlanetRequiresNestedByNamesInput2ᚕ return res, nil } +func (ec *executionContext) marshalNPerson2githubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋexplicitrequiresᚋgeneratedᚐPerson(ctx context.Context, sel ast.SelectionSet, v Person) graphql.Marshaler { + return ec._Person(ctx, sel, &v) +} + +func (ec *executionContext) marshalNPerson2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋexplicitrequiresᚋgeneratedᚐPerson(ctx context.Context, sel ast.SelectionSet, v *Person) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._Person(ctx, sel, v) +} + func (ec *executionContext) marshalNPlanetMultipleRequires2githubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋexplicitrequiresᚋgeneratedᚐPlanetMultipleRequires(ctx context.Context, sel ast.SelectionSet, v PlanetMultipleRequires) graphql.Marshaler { return ec._PlanetMultipleRequires(ctx, sel, &v) } diff --git a/plugin/federation/testdata/explicitrequires/generated/federation.go b/plugin/federation/testdata/explicitrequires/generated/federation.go index 48d3ddfef1b..69593ebdb4c 100644 --- a/plugin/federation/testdata/explicitrequires/generated/federation.go +++ b/plugin/federation/testdata/explicitrequires/generated/federation.go @@ -222,6 +222,28 @@ func (ec *executionContext) resolveEntity( return nil, fmt.Errorf(`resolving Entity "HelloWithErrors": %w`, err) } + return entity, nil + } + case "Person": + resolverName, err := entityResolverNameForPerson(ctx, rep) + if err != nil { + return nil, fmt.Errorf(`finding resolver for Entity "Person": %w`, err) + } + switch resolverName { + + case "findPersonByName": + id0, err := ec.unmarshalNString2string(ctx, rep["name"]) + if err != nil { + return nil, fmt.Errorf(`unmarshalling param 0 for findPersonByName(): %w`, err) + } + entity, err := ec.resolvers.Entity().FindPersonByName(ctx, id0) + if err != nil { + return nil, fmt.Errorf(`resolving Entity "Person": %w`, err) + } + err = ec.PopulatePersonRequires(ctx, entity, rep) + if err != nil { + return nil, fmt.Errorf(`populating requires for Entity "Person": %w`, err) + } return entity, nil } case "PlanetMultipleRequires": @@ -807,6 +829,33 @@ func entityResolverNameForMultiPlanetRequiresNested(ctx context.Context, rep Ent return "", fmt.Errorf("%w for MultiPlanetRequiresNested", ErrTypeNotFound) } +func entityResolverNameForPerson(ctx context.Context, rep EntityRepresentation) (string, error) { + for { + var ( + m EntityRepresentation + val interface{} + ok bool + ) + _ = val + // if all of the KeyFields values for this resolver are null, + // we shouldn't use use it + allNull := true + m = rep + val, ok = m["name"] + if !ok { + break + } + if allNull { + allNull = val == nil + } + if allNull { + break + } + return "findPersonByName", nil + } + return "", fmt.Errorf("%w for Person", ErrTypeNotFound) +} + func entityResolverNameForPlanetMultipleRequires(ctx context.Context, rep EntityRepresentation) (string, error) { for { var ( diff --git a/plugin/federation/testdata/explicitrequires/generated/federation.requires.go b/plugin/federation/testdata/explicitrequires/generated/federation.requires.go index ba3f6224ac6..1a3a9335114 100644 --- a/plugin/federation/testdata/explicitrequires/generated/federation.requires.go +++ b/plugin/federation/testdata/explicitrequires/generated/federation.requires.go @@ -21,6 +21,11 @@ func (ec *executionContext) PopulateMultiPlanetRequiresNestedRequires(ctx contex panic(fmt.Errorf("not implemented: PopulateMultiPlanetRequiresNestedRequires")) } +// PopulatePersonRequires is the requires populator for the Person entity. +func (ec *executionContext) PopulatePersonRequires(ctx context.Context, entity *Person, reps map[string]interface{}) error { + panic(fmt.Errorf("not implemented: PopulatePersonRequires")) +} + // PopulatePlanetMultipleRequiresRequires is the requires populator for the PlanetMultipleRequires entity. func (ec *executionContext) PopulatePlanetMultipleRequiresRequires(ctx context.Context, entity *PlanetMultipleRequires, reps map[string]interface{}) error { diameter, _ := reps["diameter"].(json.Number).Int64() diff --git a/plugin/federation/testdata/explicitrequires/generated/models.go b/plugin/federation/testdata/explicitrequires/generated/models.go index 810b4673dd1..f7c335c999c 100644 --- a/plugin/federation/testdata/explicitrequires/generated/models.go +++ b/plugin/federation/testdata/explicitrequires/generated/models.go @@ -2,6 +2,16 @@ package generated +type Gender interface { + IsGender() +} + +type Female struct { + Description string `json:"description"` +} + +func (Female) IsGender() {} + type Hello struct { Name string `json:"name"` Secondary string `json:"secondary"` @@ -22,6 +32,12 @@ type HelloWithErrors struct { func (HelloWithErrors) IsEntity() {} +type Male struct { + Description string `json:"description"` +} + +func (Male) IsGender() {} + type MultiHello struct { Name string `json:"name"` } @@ -79,6 +95,14 @@ type MultiPlanetRequiresNestedByNamesInput struct { Name string `json:"Name"` } +type Person struct { + Name string `json:"name"` + Gender Gender `json:"gender"` + WelcomeMessage *string `json:"welcomeMessage,omitempty"` +} + +func (Person) IsEntity() {} + type PlanetMultipleRequires struct { Name string `json:"name"` Diameter int `json:"diameter"` diff --git a/plugin/federation/testdata/explicitrequires/schema.graphql b/plugin/federation/testdata/explicitrequires/schema.graphql index 4d5e5707ebf..ab082bde136 100644 --- a/plugin/federation/testdata/explicitrequires/schema.graphql +++ b/plugin/federation/testdata/explicitrequires/schema.graphql @@ -11,6 +11,22 @@ type World @key(fields: "hello { name } foo ") { hello: Hello } +type Person @key(fields: "name"){ + name: String! + gender: Gender! + welcomeMessage: String @requires(fields:"gender { ... on Male {description} ... on Female {description}}") +} + +union Gender = Male | Female + +type Male { + description: String! +} + +type Female { + description: String! +} + type WorldWithMultipleKeys @key(fields: "hello { name } foo ") @key(fields: "bar") { foo: String! bar: Int!