Skip to content

Commit

Permalink
fix(GraphQL): Fix custom(dql: ...) with __typename (GRAPHQL-1098) (#7569
Browse files Browse the repository at this point in the history
)

This PR fixes the working of `@custom(dql: ...)` with `__typename` and fragments.

Bug Description:
1. Apply GraphQL schema:
```
interface Node {
 id: ID!
}
type User implements Node {
 name: String
}
type Token implements Node {
 key: String
}
type Query {
 queryNodeR: [Node] @Custom(dql: """
  query {
   queryNodeR(func: type(Node)) {
     dgraph.type
     id: uid
     name: User.name
     key: Token.key
   }
  } """)
}
```
2. Add data:
```
mutation {
 addUser(input: [{name: "User1"}]) {numUids}
 addToken(input: [{key: "Token1"}]) {numUids}
}
```
3. Query with both the auto-generated and the custom query and see the difference:
```
query {
 queryNode {
 id
 __typename
 ... UserFrag
 ... TokenFrag
 }
 queryNodeR {
 id
 __typename
 ... UserFrag
 ... TokenFrag
 }
}
fragment UserFrag on User {
 name
}
fragment TokenFrag on Token {
  key
}
```
4. The response being returned was:
```
{
  "data": {
    "queryNode": [
      {
        "id": "0x2",
        "__typename": "User",
        "name": "User1"
      },
      {
        "id": "0x3",
        "__typename": "Token",
        "key": "Token1"
      }
    ],
    "queryNodeR": [
      {
        "id": "0x2",
        "__typename": "Node",
        "name": "User1",
        "key": null
      },
      {
        "id": "0x3",
        "__typename": "Node",
        "name": null,
        "key": "Token1"
      }
    ]
  }
}
```

`queryNodeR` should have had the same result as `queryNode`.
  • Loading branch information
abhimanyusinghgaur authored and aman-bansal committed Mar 16, 2021
1 parent b0807da commit 2905756
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 6 deletions.
27 changes: 25 additions & 2 deletions graphql/e2e/custom_logic/custom_logic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2572,13 +2572,16 @@ func TestCustomDQL(t *testing.T) {
common.SafelyDropAll(t)

schema := `
type Tweets {
interface Node {
id: ID!
}
type Tweets implements Node {
id: ID!
text: String! @search(by: [fulltext, exact])
user: User
timestamp: DateTime! @search
}
type User {
type User implements Node {
screen_name: String! @id
followers: Int @search
tweets: [Tweets] @hasInverse(field: user)
Expand All @@ -2596,6 +2599,17 @@ func TestCustomDQL(t *testing.T) {
}
type Query {
queryNodeR: [Node] @custom(dql: """
query {
queryNodeR(func: type(Node), orderasc: User.screen_name) @filter(eq(Tweets.text, "Hello DQL!") OR eq(User.screen_name, "abhimanyu")) {
dgraph.type
id: uid
text: Tweets.text
screen_name: User.screen_name
}
}
""")
getFirstUserByFollowerCount(count: Int!): User @custom(dql: """
query getFirstUserByFollowerCount($count: int) {
getFirstUserByFollowerCount(func: eq(User.followers, $count),orderdesc: User.screen_name, first: 1) {
Expand Down Expand Up @@ -2708,6 +2722,11 @@ func TestCustomDQL(t *testing.T) {
params = &common.GraphQLParams{
Query: `
query ($count: Int!) {
queryNodeR {
__typename
... on User { screen_name }
... on Tweets { text }
}
queryWithVar: getFirstUserByFollowerCount(count: $count) {
screen_name
followers
Expand Down Expand Up @@ -2740,6 +2759,10 @@ func TestCustomDQL(t *testing.T) {
common.RequireNoGQLErrors(t, result)

require.JSONEq(t, `{
"queryNodeR": [
{"__typename": "User", "screen_name": "abhimanyu"},
{"__typename": "Tweets", "text": "Hello DQL!"}
],
"queryWithVar": {
"screen_name": "abhimanyu",
"followers": 5
Expand Down
15 changes: 11 additions & 4 deletions graphql/schema/completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ func Unmarshal(data []byte, v interface{}) error {
// At present, it is only used for building custom results by:
// * Admin Server
// * @custom(http: {...}) query/mutation
// * @custom(dql: ...) queries
//
// fields are all the fields from this bracketed level in the GraphQL query, e.g:
// {
Expand Down Expand Up @@ -117,12 +118,18 @@ func CompleteObject(
seenField := make(map[string]bool)

x.Check2(buf.WriteRune('{'))
// @custom(http: {...}) query/mutation results may return __typename in response for abstract
// fields, lets use that information if present.
typename, ok := res[Typename].(string)
var dgraphTypes []string
if ok && len(typename) > 0 {
if typename, ok := res[Typename].(string); ok && len(typename) > 0 {
// @custom(http: {...}) query/mutation results may return __typename in response for
// abstract fields, lets use that information if present.
dgraphTypes = []string{typename}
} else if dgTypeVals, ok := res["dgraph.type"].([]interface{}); ok {
// @custom(dql: ...) query results may return dgraph.type in response for abstract fields
for _, val := range dgTypeVals {
if typename, ok = val.(string); ok {
dgraphTypes = append(dgraphTypes, typename)
}
}
}

for _, f := range fields {
Expand Down

0 comments on commit 2905756

Please sign in to comment.