Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Generate federation entity resolvers for interfaces with @key fields defined #2634

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 32 additions & 7 deletions plugin/federation/federation.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,18 @@ func (f *federation) InjectSourceLate(schema *ast.Schema) *ast.Source {
f.setEntities(schema)

var entities, resolvers, entityResolverInputDefinitions string
for i, e := range f.Entities {
if i != 0 {
entities += " | "
for _, e := range f.Entities {

if e.Def.Kind != ast.Interface {
if entities != "" {
entities += " | "
}
entities += e.Name
} else if len(schema.GetPossibleTypes(e.Def)) == 0 {
fmt.Println(
"skipping @key field on interface " + e.Def.Name + " as no types implement it",
)
}
entities += e.Name

for _, r := range e.Resolvers {
if e.Multi {
Expand Down Expand Up @@ -206,6 +213,16 @@ func (f *federation) GenerateCode(data *codegen.Data) error {
for _, e := range f.Entities {
obj := data.Objects.ByName(e.Def.Name)

if e.Def.Kind == ast.Interface {
if len(data.Interfaces[e.Def.Name].Implementors) == 0 {
fmt.Println(
"skipping @key field on interface " + e.Def.Name + " as no types implement it",
)
continue
}
obj = data.Objects.ByName(data.Interfaces[e.Def.Name].Implementors[0].Name)
}

for _, r := range e.Resolvers {
// fill in types for key fields
//
Expand Down Expand Up @@ -267,6 +284,12 @@ func (f *federation) setEntities(schema *ast.Schema) {
if !ok {
continue
}

if (schemaType.Kind == ast.Interface) && (len(schema.GetPossibleTypes(schemaType)) == 0) {
fmt.Printf("@key directive found on unused \"interface %s\". Will be ignored.\n", schemaType.Name)
continue
}

e := &Entity{
Name: schemaType.Name,
Def: schemaType,
Expand Down Expand Up @@ -385,10 +408,12 @@ func isFederatedEntity(schemaType *ast.Definition) ([]*ast.Directive, bool) {
return keys, true
}
case ast.Interface:
// TODO: support @key and @extends for interfaces
if dir := schemaType.Directives.ForName("key"); dir != nil {
fmt.Printf("@key directive found on \"interface %s\". Will be ignored.\n", schemaType.Name)
keys := schemaType.Directives.ForNames("key")
if len(keys) > 0 {
return keys, true
}

// TODO: support @extends for interfaces
if dir := schemaType.Directives.ForName("extends"); dir != nil {
panic(
fmt.Sprintf(
Expand Down
11 changes: 10 additions & 1 deletion plugin/federation/federation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,21 @@ func TestNoEntities(t *testing.T) {
require.Len(t, f.Entities, 0)
}

func TestUnusedInterfaceKeyDirective(t *testing.T) {
f, cfg := load(t, "testdata/interfaces/unused_key.yml")

err := f.MutateConfig(cfg)
require.NoError(t, err)
require.Len(t, f.Entities, 0)
}

func TestInterfaceKeyDirective(t *testing.T) {
f, cfg := load(t, "testdata/interfaces/key.yml")

err := f.MutateConfig(cfg)
require.NoError(t, err)
require.Len(t, f.Entities, 0)
require.Len(t, cfg.Schema.Types["_Entity"].Types, 1)
require.Len(t, f.Entities, 2)
}

func TestInterfaceExtendsDirective(t *testing.T) {
Expand Down
5 changes: 5 additions & 0 deletions plugin/federation/testdata/interfaces/key.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,8 @@ extend interface Hello @key(fields: "name") {
name: String!
secondary: String!
}

type World implements Hello @key(fields: "name") {
name: String!
secondary: String!
}
4 changes: 4 additions & 0 deletions plugin/federation/testdata/interfaces/unused_key.graphqls
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
extend interface Hello @key(fields: "name") {
name: String!
secondary: String!
}
6 changes: 6 additions & 0 deletions plugin/federation/testdata/interfaces/unused_key.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
schema:
- "testdata/interfaces/unused_key.graphqls"
exec:
filename: testdata/interfaces/generated/exec.go
federation:
filename: testdata/interfaces/generated/federation.go