Skip to content

Commit

Permalink
fix(GraphQL): Requesting only __typename now returns results (#5659)
Browse files Browse the repository at this point in the history
This PR fixes Type name issue for single level and nested GraphQL queries. #5020

(cherry picked from commit a4ae8b7)
  • Loading branch information
JatinDev543 committed Jul 6, 2020
1 parent 2beaf30 commit 2282905
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 4 deletions.
3 changes: 3 additions & 0 deletions graphql/e2e/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,9 @@ func RunAll(t *testing.T) {
t.Run("query typename", queryTypename)
t.Run("query nested typename", queryNestedTypename)
t.Run("typename for interface", typenameForInterface)
t.Run("query only typename", queryOnlyTypename)
t.Run("query nested only typename", querynestedOnlyTypename)
t.Run("test onlytypename for interface types", onlytypenameForInterface)

t.Run("get state by xid", getStateByXid)
t.Run("get state without args", getStateWithoutArgs)
Expand Down
126 changes: 126 additions & 0 deletions graphql/e2e/common/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -1218,6 +1218,132 @@ func typenameForInterface(t *testing.T) {
cleanupStarwars(t, newStarship.ID, humanID, droidID)
}

func queryOnlyTypename(t *testing.T) {

newCountry1 := addCountry(t, postExecutor)
newCountry2 := addCountry(t, postExecutor)
newCountry3 := addCountry(t, postExecutor)

getCountryParams := &GraphQLParams{
Query: `query {
queryCountry(filter: { name: {eq: "Testland"}}) {
__typename
}
}`,
}

gqlResponse := getCountryParams.ExecuteAsPost(t, graphqlURL)
RequireNoGQLErrors(t, gqlResponse)

expected := `{
"queryCountry": [
{
"__typename": "Country"
},
{
"__typename": "Country"
},
{
"__typename": "Country"
}
]
}`

require.JSONEq(t, expected, string(gqlResponse.Data))
cleanUp(t, []*country{newCountry1,newCountry2,newCountry3}, []*author{}, []*post{})
}

func querynestedOnlyTypename(t *testing.T) {

newCountry := addCountry(t, postExecutor)
newAuthor := addAuthor(t, newCountry.ID, postExecutor)
newPost1 := addPost(t, newAuthor.ID, newCountry.ID, postExecutor)
newPost2 := addPost(t, newAuthor.ID, newCountry.ID, postExecutor)
newPost3 := addPost(t, newAuthor.ID, newCountry.ID, postExecutor)

getCountryParams := &GraphQLParams{
Query: `query {
queryAuthor(filter: { name: { eq: "Test Author" } }) {
posts {
__typename
}
}
}`,
}

gqlResponse := getCountryParams.ExecuteAsPost(t, graphqlURL)
RequireNoGQLErrors(t, gqlResponse)

expected := `{
"queryAuthor": [
{
"posts": [
{
"__typename": "Post"
},
{
"__typename": "Post"
},
{
"__typename": "Post"
}
]
}
]
}`
require.JSONEq(t, expected, string(gqlResponse.Data))
cleanUp(t, []*country{newCountry}, []*author{newAuthor}, []*post{newPost1,newPost2,newPost3})
}


func onlytypenameForInterface(t *testing.T) {
newStarship := addStarship(t)
humanID := addHuman(t, newStarship.ID)
droidID := addDroid(t)
updateCharacter(t, humanID)

t.Run("test __typename for interface types", func(t *testing.T) {
queryCharacterParams := &GraphQLParams{
Query: `query {
queryCharacter (filter: {
appearsIn: {
eq: [EMPIRE]
}
}) {
... on Human {
__typename
}
... on Droid {
__typename
}
}
}`,
}

expected := `{
"queryCharacter": [
{
"__typename": "Human"
},
{
"__typename": "Droid"
}
]
}`

gqlResponse := queryCharacterParams.ExecuteAsPost(t, graphqlURL)
RequireNoGQLErrors(t, gqlResponse)
testutil.CompareJSON(t, expected, string(gqlResponse.Data))
})

cleanupStarwars(t, newStarship.ID, humanID, droidID)
}


func defaultEnumFilter(t *testing.T) {
newStarship := addStarship(t)
humanID := addHuman(t, newStarship.ID)
Expand Down
27 changes: 23 additions & 4 deletions graphql/resolve/query_rewriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,11 @@ func rewriteAsQuery(field schema.Field, authRw *authRewriter) *gql.GraphQuery {
return dgQuery
}

func (authRw *authRewriter) writingAuth() bool {
return authRw != nil && authRw.isWritingAuth

}

// addAuthQueries takes a field and the GraphQuery that has so far been constructed for
// the field and builds any auth queries that are need to restrict the result to only
// the nodes authorized to be queried, returning a new graphQuery that does the
Expand Down Expand Up @@ -596,10 +601,24 @@ func addSelectionSetFrom(
// Only add dgraph.type as a child if this field is an interface type and has some children.
// dgraph.type would later be used in completeObject as different objects in the resulting
// JSON would return different fields based on their concrete type.
if field.InterfaceType() && len(field.SelectionSet()) > 0 {
q.Children = append(q.Children, &gql.GraphQuery{
Attr: "dgraph.type",
})
selSet := field.SelectionSet()
if len(selSet) > 0 {
if field.InterfaceType() {
q.Children = append(q.Children, &gql.GraphQuery{
Attr: "dgraph.type",
})

} else if !auth.writingAuth() &&
len(selSet) == 1 &&
selSet[0].Name() == schema.Typename {
q.Children = append(q.Children, &gql.GraphQuery{
//we don't need this for auth queries because they are added by us used for internal purposes.
// Querying it for them would just add an overhead which we can avoid.
Attr: "uid",
Alias: "dgraph.uid",
})
}

}

// These fields might not have been requested by the user directly as part of the query but
Expand Down

0 comments on commit 2282905

Please sign in to comment.