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

feat(GraphQL): Unions #6722

Merged
merged 15 commits into from
Oct 19, 2020
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
1 change: 1 addition & 0 deletions graphql/e2e/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,7 @@ func RunAll(t *testing.T) {
t.Run("fragment in mutation", fragmentInMutation)
t.Run("fragment in query", fragmentInQuery)
t.Run("fragment in query on Interface", fragmentInQueryOnInterface)
t.Run("fragment in query on union", fragmentInQueryOnUnion)
t.Run("fragment in query on Object", fragmentInQueryOnObject)

// lambda tests
Expand Down
117 changes: 117 additions & 0 deletions graphql/e2e/common/fragment.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import (
"fmt"
"testing"

"github.com/dgraph-io/dgraph/testutil"

"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -383,6 +385,121 @@ func fragmentInQueryOnInterface(t *testing.T) {
deleteThingTwo(t, thingTwoId)
}

func fragmentInQueryOnUnion(t *testing.T) {
newStarship := addStarship(t)
humanID := addHuman(t, newStarship.ID)
homeId, dogId, parrotId, plantId := addHome(t, humanID)

queryHomeParams := &GraphQLParams{
Query: `query {
queryHome {
members {
__typename
... on Animal {
category
}
... on Dog {
id
breed
}
... on Parrot {
repeatsWords
}
... on Employee {
ename
}
... on Character {
id
}
... on Human {
name
}
... on Plant {
id
}
}
}
qh: queryHome {
members {
... on Animal {
__typename
}
... on Dog {
breed
}
... on Human {
name
}
... on Plant {
breed
}
}
}
}
`,
}

gqlResponse := queryHomeParams.ExecuteAsPost(t, GraphqlURL)
RequireNoGQLErrors(t, gqlResponse)

queryHomeExpected := fmt.Sprintf(`
{
"queryHome": [
{
"members": [
{
"__typename": "Human",
"ename": "Han_employee",
"id": "%s",
"name": "Han"
},
{
"__typename": "Dog",
"category": "Mammal",
"id": "%s",
"breed": "German Shephard"
},
{
"__typename": "Parrot",
"category": "Bird",
"repeatsWords": [
"Good Morning!",
"squawk"
]
},
{
"__typename": "Plant",
"id": "%s"
}
]
}
],
"qh": [
{
"members": [
{
"name": "Han"
},
{
"__typename": "Dog",
"breed": "German Shephard"
},
{
"__typename": "Parrot"
},
{
"breed": "Flower"
}
]
}
]
}`, humanID, dogId, plantId)
testutil.CompareJSON(t, queryHomeExpected, string(gqlResponse.Data))

cleanupStarwars(t, newStarship.ID, humanID, "")
deleteHome(t, homeId, dogId, parrotId, plantId)
}

func fragmentInQueryOnObject(t *testing.T) {
newStarship := addStarship(t)
humanID := addHuman(t, newStarship.ID)
Expand Down
113 changes: 109 additions & 4 deletions graphql/e2e/common/mutation.go
Original file line number Diff line number Diff line change
Expand Up @@ -2376,7 +2376,7 @@ func addDroid(t *testing.T) string {
}

func addThingOne(t *testing.T) string {
addDroidParams := &GraphQLParams{
addThingOneParams := &GraphQLParams{
Query: `mutation addThingOne($input: AddThingOneInput!) {
addThingOne(input: [$input]) {
thingOne {
Expand All @@ -2391,7 +2391,7 @@ func addThingOne(t *testing.T) string {
}},
}

gqlResponse := addDroidParams.ExecuteAsPost(t, GraphqlURL)
gqlResponse := addThingOneParams.ExecuteAsPost(t, GraphqlURL)
RequireNoGQLErrors(t, gqlResponse)

var result struct {
Expand All @@ -2409,7 +2409,7 @@ func addThingOne(t *testing.T) string {
}

func addThingTwo(t *testing.T) string {
addDroidParams := &GraphQLParams{
addThingTwoParams := &GraphQLParams{
Query: `mutation addThingTwo($input: AddThingTwoInput!) {
addThingTwo(input: [$input]) {
thingTwo {
Expand All @@ -2424,7 +2424,7 @@ func addThingTwo(t *testing.T) string {
}},
}

gqlResponse := addDroidParams.ExecuteAsPost(t, GraphqlURL)
gqlResponse := addThingTwoParams.ExecuteAsPost(t, GraphqlURL)
RequireNoGQLErrors(t, gqlResponse)

var result struct {
Expand All @@ -2441,6 +2441,111 @@ func addThingTwo(t *testing.T) string {
return result.AddThingTwo.ThingTwo[0].ID
}

func addHome(t *testing.T, humanId string) (string, string, string, string) {
addHomeParams := &GraphQLParams{
Query: `mutation addHome($input: AddHomeInput!) {
addHome(input: [$input]) {
home {
id
members {
__typename
... on Animal {
id
}
... on Human {
id
}
... on Plant {
id
}
}
}
}
}`,
Variables: map[string]interface{}{
"input": map[string]interface{}{
"address": "Avenger Street",
"members": []interface{}{
map[string]interface{}{
"dogRef": map[string]interface{}{
"category": "Mammal",
"breed": "German Shephard",
},
},
map[string]interface{}{
"parrotRef": map[string]interface{}{
"category": "Bird",
"repeatsWords": []interface{}{
"squawk",
"Good Morning!",
},
},
},
map[string]interface{}{
"humanRef": map[string]interface{}{
"id": humanId,
},
},
map[string]interface{}{
"plantRef": map[string]interface{}{
"breed": "Flower",
},
},
},
"favouriteMember": map[string]interface{}{
"humanRef": map[string]interface{}{
"id": humanId,
},
},
},
},
}

gqlResponse := addHomeParams.ExecuteAsPost(t, GraphqlURL)
RequireNoGQLErrors(t, gqlResponse)

var result struct {
AddHome struct {
Home []struct {
ID string
Members []struct {
Typename string `json:"__typename"`
ID string
}
}
}
}
err := json.Unmarshal([]byte(gqlResponse.Data), &result)
require.NoError(t, err)

homeId := result.AddHome.Home[0].ID
requireUID(t, homeId)

var dogId, parrotId, plantId string
for _, member := range result.AddHome.Home[0].Members {
switch member.Typename {
case "Dog":
dogId = member.ID
case "Parrot":
parrotId = member.ID
case "Plant":
plantId = member.ID
}
}
return homeId, dogId, parrotId, plantId
}

func deleteHome(t *testing.T, homeId, dogId, parrotId, plantId string) {
homeFilter := map[string]interface{}{"id": []string{homeId}}
deleteGqlType(t, "Home", homeFilter, 1, nil)
dogFilter := map[string]interface{}{"id": []string{dogId}}
deleteGqlType(t, "Dog", dogFilter, 1, nil)
parrotFilter := map[string]interface{}{"id": []string{parrotId}}
deleteGqlType(t, "Parrot", parrotFilter, 1, nil)
plantFilter := map[string]interface{}{"id": []string{plantId}}
deleteGqlType(t, "Plant", plantFilter, 1, nil)
}

func deleteThingOne(t *testing.T, thingOneId string) {
thingOneFilter := map[string]interface{}{"id": []string{thingOneId}}
deleteGqlType(t, "ThingOne", thingOneFilter, 1, nil)
Expand Down
52 changes: 52 additions & 0 deletions graphql/e2e/directives/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,58 @@ type Person1 {
friends: [Person1] @hasInverse(field: friends)
}

# union testing - start
enum AnimalCategory {
Fish
Amphibian
Reptile
Bird
Mammal
InVertebrate
}

interface Animal {
id: ID!
category: AnimalCategory @search
}

type Dog implements Animal {
breed: String @search
}

type Parrot implements Animal {
repeatsWords: [String]
}

type Cheetah implements Animal {
speed: Float
}

"""
This type specifically doesn't implement any interface.
We need this to test out all cases with union.
"""
type Plant {
id: ID!
breed: String # field with same name as a field in type Dog
}

union HomeMember = Dog | Parrot | Human | Plant

type Zoo {
id: ID!
animals: [Animal]
city: String
}

type Home {
id: ID!
address: String
members: [HomeMember]
favouriteMember: HomeMember
}
# union testing - end

type Query {
authorsByName(name: String!): [Author] @lambda
}
Expand Down
Loading