Skip to content

Commit beb923f

Browse files
authored
Merge pull request #409 from sourcegraph/fix-union-interface-inline-fragments
fix #241
2 parents 9c36bba + 653514d commit beb923f

File tree

5 files changed

+164
-17
lines changed

5 files changed

+164
-17
lines changed

example/social/introspect.json

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,39 @@
214214
"name": "Pagination",
215215
"possibleTypes": null
216216
},
217+
{
218+
"description": null,
219+
"enumValues": null,
220+
"fields": [
221+
{
222+
"args": [],
223+
"deprecationReason": null,
224+
"description": null,
225+
"isDeprecated": false,
226+
"name": "name",
227+
"type": {
228+
"kind": "NON_NULL",
229+
"name": null,
230+
"ofType": {
231+
"kind": "SCALAR",
232+
"name": "String",
233+
"ofType": null
234+
}
235+
}
236+
}
237+
],
238+
"inputFields": null,
239+
"interfaces": null,
240+
"kind": "INTERFACE",
241+
"name": "Person",
242+
"possibleTypes": [
243+
{
244+
"kind": "OBJECT",
245+
"name": "User",
246+
"ofType": null
247+
}
248+
]
249+
},
217250
{
218251
"description": null,
219252
"enumValues": null,
@@ -545,6 +578,11 @@
545578
"kind": "INTERFACE",
546579
"name": "Admin",
547580
"ofType": null
581+
},
582+
{
583+
"kind": "INTERFACE",
584+
"name": "Person",
585+
"ofType": null
548586
}
549587
],
550588
"kind": "OBJECT",

example/social/social.go

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,13 @@ const Schema = `
2727
role: Role!
2828
}
2929
30+
interface Person {
31+
name: String!
32+
}
33+
3034
scalar Time
3135
32-
type User implements Admin {
36+
type User implements Admin & Person {
3337
id: ID!
3438
name: String!
3539
email: String!
@@ -64,6 +68,15 @@ type admin interface {
6468
Role() string
6569
}
6670

71+
type adminResolver struct {
72+
admin
73+
}
74+
75+
func (r *adminResolver) ToUser() (*user, bool) {
76+
n, ok := r.admin.(user)
77+
return &n, ok
78+
}
79+
6780
type searchResult struct {
6881
result interface{}
6982
}
@@ -189,14 +202,14 @@ type Resolver struct{}
189202
func (r *Resolver) Admin(ctx context.Context, args struct {
190203
ID string
191204
Role string
192-
}) (admin, error) {
205+
}) (*adminResolver, error) {
193206
if usr, ok := usersMap[args.ID]; ok {
194207
if usr.RoleField == args.Role {
195-
return *usr, nil
208+
return &adminResolver{*usr}, nil
196209
}
197210
}
198211
err := fmt.Errorf("user with id=%s and role=%s does not exist", args.ID, args.Role)
199-
return user{}, err
212+
return nil, err
200213
}
201214

202215
func (r *Resolver) User(ctx context.Context, args struct{ Id string }) (user, error) {

graphql_test.go

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1703,6 +1703,77 @@ func TestInlineFragments(t *testing.T) {
17031703
}
17041704
`,
17051705
},
1706+
1707+
{
1708+
Schema: starwarsSchema,
1709+
Query: `
1710+
query CharacterSearch {
1711+
search(text: "C-3PO") {
1712+
... on Character {
1713+
name
1714+
}
1715+
}
1716+
}
1717+
`,
1718+
ExpectedResult: `
1719+
{
1720+
"search": [
1721+
{
1722+
"name": "C-3PO"
1723+
}
1724+
]
1725+
}
1726+
`,
1727+
},
1728+
1729+
{
1730+
Schema: starwarsSchema,
1731+
Query: `
1732+
query CharacterSearch {
1733+
hero {
1734+
... on Character {
1735+
... on Human {
1736+
name
1737+
}
1738+
... on Droid {
1739+
name
1740+
}
1741+
}
1742+
}
1743+
}
1744+
`,
1745+
ExpectedResult: `
1746+
{
1747+
"hero": {
1748+
"name": "R2-D2"
1749+
}
1750+
}
1751+
`,
1752+
},
1753+
1754+
{
1755+
Schema: socialSchema,
1756+
Query: `
1757+
query {
1758+
admin(id: "0x01") {
1759+
... on User {
1760+
email
1761+
}
1762+
... on Person {
1763+
name
1764+
}
1765+
}
1766+
}
1767+
`,
1768+
ExpectedResult: `
1769+
{
1770+
"admin": {
1771+
"email": "[email protected]",
1772+
"name": "Albus Dumbledore"
1773+
}
1774+
}
1775+
`,
1776+
},
17061777
})
17071778
}
17081779

@@ -2946,27 +3017,27 @@ type helloInputMismatch struct {
29463017
World string
29473018
}
29483019

2949-
func (r *inputArgumentsHello) Hello(args struct { Input *helloInput }) string {
3020+
func (r *inputArgumentsHello) Hello(args struct{ Input *helloInput }) string {
29503021
return "Hello " + args.Input.Name + "!"
29513022
}
29523023

29533024
func (r *inputArgumentsScalarMismatch1) Hello(name string) string {
29543025
return "Hello " + name + "!"
29553026
}
29563027

2957-
func (r *inputArgumentsScalarMismatch2) Hello(args struct { World string }) string {
3028+
func (r *inputArgumentsScalarMismatch2) Hello(args struct{ World string }) string {
29583029
return "Hello " + args.World + "!"
29593030
}
29603031

29613032
func (r *inputArgumentsObjectMismatch1) Hello(in helloInput) string {
29623033
return "Hello " + in.Name + "!"
29633034
}
29643035

2965-
func (r *inputArgumentsObjectMismatch2) Hello(args struct { Input *helloInputMismatch }) string {
3036+
func (r *inputArgumentsObjectMismatch2) Hello(args struct{ Input *helloInputMismatch }) string {
29663037
return "Hello " + args.Input.World + "!"
29673038
}
29683039

2969-
func (r *inputArgumentsObjectMismatch3) Hello(args struct { Input *struct { Thing string } }) string {
3040+
func (r *inputArgumentsObjectMismatch3) Hello(args struct{ Input *struct{ Thing string } }) string {
29703041
return "Hello " + args.Input.Thing + "!"
29713042
}
29723043

internal/exec/selected/selected.go

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -173,16 +173,39 @@ func applySelectionSet(r *Request, s *resolvable.Schema, e *resolvable.Object, s
173173
}
174174

175175
func applyFragment(r *Request, s *resolvable.Schema, e *resolvable.Object, frag *query.Fragment) []Selection {
176-
if frag.On.Name != "" && frag.On.Name != e.Name {
177-
a, ok := e.TypeAssertions[frag.On.Name]
178-
if !ok {
179-
panic(fmt.Errorf("%q does not implement %q", frag.On, e.Name)) // TODO proper error handling
176+
if frag.On.Name != e.Name {
177+
t := r.Schema.Resolve(frag.On.Name)
178+
face, ok := t.(*schema.Interface)
179+
if !ok && frag.On.Name != "" {
180+
a, ok := e.TypeAssertions[frag.On.Name]
181+
if !ok {
182+
panic(fmt.Errorf("%q does not implement %q", frag.On, e.Name)) // TODO proper error handling
183+
}
184+
185+
return []Selection{&TypeAssertion{
186+
TypeAssertion: *a,
187+
Sels: applySelectionSet(r, s, a.TypeExec.(*resolvable.Object), frag.Selections),
188+
}}
180189
}
190+
if ok && len(face.PossibleTypes) > 0 {
191+
sels := []Selection{}
192+
for _, t := range face.PossibleTypes {
193+
if t.Name == e.Name {
194+
return applySelectionSet(r, s, e, frag.Selections)
195+
}
181196

182-
return []Selection{&TypeAssertion{
183-
TypeAssertion: *a,
184-
Sels: applySelectionSet(r, s, a.TypeExec.(*resolvable.Object), frag.Selections),
185-
}}
197+
if a, ok := e.TypeAssertions[t.Name]; ok {
198+
sels = append(sels, &TypeAssertion{
199+
TypeAssertion: *a,
200+
Sels: applySelectionSet(r, s, a.TypeExec.(*resolvable.Object), frag.Selections),
201+
})
202+
}
203+
}
204+
if len(sels) == 0 {
205+
panic(fmt.Errorf("%q does not implement %q", e.Name, frag.On)) // TODO proper error handling
206+
}
207+
return sels
208+
}
186209
}
187210
return applySelectionSet(r, s, e, frag.Selections)
188211
}

introspection_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import (
1111
"github.com/graph-gophers/graphql-go/example/starwars"
1212
)
1313

14+
var socialSchema = graphql.MustParseSchema(social.Schema, &social.Resolver{}, graphql.UseFieldResolvers())
15+
1416
func TestSchema_ToJSON(t *testing.T) {
1517
t.Parallel()
1618

@@ -27,7 +29,7 @@ func TestSchema_ToJSON(t *testing.T) {
2729
}{
2830
{
2931
Name: "Social Schema",
30-
Args: args{Schema: graphql.MustParseSchema(social.Schema, &social.Resolver{}, graphql.UseFieldResolvers())},
32+
Args: args{Schema: socialSchema},
3133
Want: want{JSON: mustReadFile("example/social/introspect.json")},
3234
},
3335
{

0 commit comments

Comments
 (0)