Skip to content

Commit

Permalink
Improve federation resolver selection (#3029)
Browse files Browse the repository at this point in the history
* Improve federation resolver selection

Just checking for existence of keys in the representations isn't enough.  If the values are null, we should skip the resolver.

* Run go generate ./...

* Add test cases

* Fix linter
  • Loading branch information
clayne11 authored May 1, 2024
1 parent 9e8e7ed commit 835c2d1
Show file tree
Hide file tree
Showing 11 changed files with 648 additions and 72 deletions.
24 changes: 22 additions & 2 deletions _examples/federation/accounts/graph/federation.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

45 changes: 40 additions & 5 deletions _examples/federation/products/graph/federation.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 29 additions & 4 deletions _examples/federation/reviews/graph/federation.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 12 additions & 1 deletion plugin/federation/federation.gotpl
Original file line number Diff line number Diff line change
Expand Up @@ -253,19 +253,30 @@ func (ec *executionContext) __resolve_entities(ctx context.Context, representati
ok bool
)
_ = val
// if all of the KeyFields values for this resolver are null,
// we shouldn't use use it
allNull := true
{{- range $_, $keyField := .KeyFields }}
m = rep
{{- range $i, $field := .Field }}
if {{ if (ne $i $keyField.Field.LastIndex ) -}}val{{- else -}}_{{- end -}}, ok = m["{{.}}"]; !ok {
val, ok = m["{{.}}"]
if !ok {
break
}
{{- if (ne $i $keyField.Field.LastIndex ) }}
if m, ok = val.(map[string]interface{}); !ok {
break
}
{{- else}}
if allNull {
allNull = val == nil
}
{{- end}}
{{- end}}
{{- end }}
if allNull {
break
}
return "{{.ResolverName}}", nil
}
{{- end }}
Expand Down
37 changes: 37 additions & 0 deletions plugin/federation/federation_entityresolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,43 @@ func TestEntityResolver(t *testing.T) {
require.Equal(t, 11, resp.Entities[1].Bar)
})

t.Run("World entities with one single-key nil should hit resolver without nils", func(t *testing.T) {
representations := []map[string]interface{}{
{
"__typename": "WorldWithMultipleKeys",
"hello": map[string]interface{}{
"name": "world name - 1",
},
"foo": "foo 1",
"bar": nil,
},
}

var resp struct {
Entities []struct {
Foo string `json:"foo"`
Hello struct {
Name string `json:"name"`
} `json:"hello"`
Bar int `json:"bar"`
} `json:"_entities"`
}

err := c.Post(
entityQuery([]string{
"WorldWithMultipleKeys {foo hello {name} bar}",
}),
&resp,
client.Var("representations", representations),
)

require.NoError(t, err)
require.Len(t, resp.Entities, 1)
require.Equal(t, "foo 1", resp.Entities[0].Foo)
require.Equal(t, "world name - 1", resp.Entities[0].Hello.Name)
require.Equal(t, entityresolver.FindWorldWithMultipleKeysByHelloNameAndFooBarValue, resp.Entities[0].Bar)
})

t.Run("Hello WorldName entities (heterogeneous)", func(t *testing.T) {
// Entity resolution can handle heterogenenous representations. Meaning,
// the representations for resolving entities can be of different
Expand Down
Loading

0 comments on commit 835c2d1

Please sign in to comment.