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

[Breaking]fix(GraphQL):Added support for parameterized cascade with variables. #7477

Merged
merged 12 commits into from
Feb 26, 2021
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ require (
github.com/dgraph-io/badger/v3 v3.0.0-20210209201111-6c35ad6c28e0
github.com/dgraph-io/dgo/v200 v200.0.0-20210212152539-e0a5bde40ba2
github.com/dgraph-io/gqlgen v0.13.2
github.com/dgraph-io/gqlparser/v2 v2.1.5
github.com/dgraph-io/gqlparser/v2 v2.1.6
github.com/dgraph-io/graphql-transport-ws v0.0.0-20210223074046-e5b8b80bb4ed
github.com/dgraph-io/ristretto v0.0.4-0.20210223002318-8ec1dc18f880
github.com/dgraph-io/simdjson-go v0.3.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ github.com/dgraph-io/dgo/v200 v200.0.0-20210212152539-e0a5bde40ba2/go.mod h1:zCf
github.com/dgraph-io/gqlgen v0.13.2 h1:TNhndk+eHKj5qE7BenKKSYdSIdOGhLqxR1rCiMso9KM=
github.com/dgraph-io/gqlgen v0.13.2/go.mod h1:iCOrOv9lngN7KAo+jMgvUPVDlYHdf7qDwsTkQby2Sis=
github.com/dgraph-io/gqlparser/v2 v2.1.1/go.mod h1:MYS4jppjyx8b9tuUtjV7jU1UFZK6P9fvO8TsIsQtRKU=
github.com/dgraph-io/gqlparser/v2 v2.1.5 h1:FNFSzyOEZ8gs97SLBtn2Pez9f12emvsQ6Vv6oNtg5rc=
github.com/dgraph-io/gqlparser/v2 v2.1.5/go.mod h1:MYS4jppjyx8b9tuUtjV7jU1UFZK6P9fvO8TsIsQtRKU=
github.com/dgraph-io/gqlparser/v2 v2.1.6 h1:i+hYTDB+V9cpPYkXY8KYrpPnZIr3uk4S6CPEqV4KrPM=
github.com/dgraph-io/gqlparser/v2 v2.1.6/go.mod h1:MYS4jppjyx8b9tuUtjV7jU1UFZK6P9fvO8TsIsQtRKU=
github.com/dgraph-io/graphql-transport-ws v0.0.0-20210223074046-e5b8b80bb4ed h1:pgGMBoTtFhR+xkyzINaToLYRurHn+6pxMYffIGmmEPc=
github.com/dgraph-io/graphql-transport-ws v0.0.0-20210223074046-e5b8b80bb4ed/go.mod h1:7z3c/5w0sMYYZF5bHsrh8IH4fKwG5O5Y70cPH1ZLLRQ=
github.com/dgraph-io/ristretto v0.0.4-0.20210205182321-f8e4908e34d1/go.mod h1:tv2ec8nA7vRpSYX7/MbP52ihrUMXIHit54CQMq8npXQ=
Expand Down
96 changes: 86 additions & 10 deletions graphql/e2e/common/error_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@
[ { "message": "Cannot query field \"getAuthorszzz\" on type \"Query\". Did you mean
\"getAuthor\" or \"getauthor1\"?",
"locations": [ { "line": 2, "column": 3 } ] } ]

-
name: "Unknown field"
gqlrequest: |
query {
getAuthor(id: "0x1") { namezzz }
}
gqlvariables: |
gqlvariables: |
{ }
errors:
[ { "message": "Cannot query field \"namezzz\" on type \"Author\". Did you mean \"name\"?",
Expand All @@ -29,7 +29,7 @@
query {
getAuthor(id: $theID) { name }
}
gqlvariables: |
gqlvariables: |
{ }
errors:
[ { "message": "Variable \"$theID\" is not defined.",
Expand All @@ -41,7 +41,7 @@
query {
queryAuthor(filter: { reputation: { le: "hi there" } }) { name }
}
gqlvariables: |
gqlvariables: |
{ }
errors:
[ { "message": "Expected type Float, found \"hi there\".",
Expand All @@ -53,7 +53,7 @@
query queryAuthor($filter: AuthorFiltarzzz!) {
queryAuthor(filter: $filter) { name }
}
gqlvariables: |
gqlvariables: |
{ "filter": "type was wrong" }
errors:
[ { "message": "Variable type provided AuthorFiltarzzz! is incompatible with expected
Expand All @@ -71,7 +71,7 @@
query queryAuthor($filter: AuthorFilter!) {
queryAuthor(filter: $filter) { name }
}
gqlvariables: |
gqlvariables: |
{ "filter": 57 }
errors:
[ { "message": "must be a AuthorFilter",
Expand Down Expand Up @@ -101,7 +101,7 @@
"locations": [ { "line": 2, "column": 3 } ] } ]

-
name: "@cascade only accepts those fields as a argument, which are present in given type "
name: "@cascade only accepts those fields as a argument, which are present in given type"
gqlrequest: |
query {
queryAuthor @cascade(fields:["title"]){
Expand All @@ -112,7 +112,8 @@
gqlvariables: |
{ }
errors:
[ { "message": "Field `title` is not present in type `Author`. You can only use fields which are in type `Author`",
[ { "message": "Field `title` is not present in type `Author`. You can only use fields in cascade which are in type `Author`",
"locations": [{ "line": 2, "column": 16}]
} ]

-
Expand Down Expand Up @@ -168,7 +169,8 @@
gqlvariables: |
{ }
errors:
[ { "message": "Field `name` is not present in type `AddAuthorPayload`. You can only use fields which are in type `AddAuthorPayload`",
[ { "message": "Field `name` is not present in type `AddAuthorPayload`. You can only use fields in cascade which are in type `AddAuthorPayload`",
"locations": [{ "line": 2, "column": 38}]
} ]

-
Expand Down Expand Up @@ -362,4 +364,78 @@
{ }
errors:
[ { "message": "Int64Filter filter expects only one filter function, got: 2",
"locations": [ { "line": 2, "column": 29 } ] } ]
"locations": [ { "line": 2, "column": 29 } ] } ]

-
name: "@cascade only accepts those fields as a argument, which are present in given type at both root and deep levels"
gqlrequest: |
query {
queryAuthor @cascade(fields: ["dob","reputation"]) {
dob
reputation
posts @cascade(fields: ["text1"]) {
text
title
}
}
}
errors:
[ { "message": "Field `text1` is not present in type `Post`. You can only use fields in cascade which are in type `Post`",
"locations": [{ "line": 5, "column": 10}]
} ]

-
name: "@cascade only accepts those fields as a argument, which are present in given type at deep level using variables"
gqlrequest: |
query($fieldsRoot: [String], $fieldsDeep: [String]) {
queryAuthor @cascade(fields: $fieldsRoot) {
dob
reputation
posts @cascade(fields: $fieldsDeep) {
text
title
}
}
}
gqlvariables: |
{
"fieldsRoot": [
"dob",
"reputation"
],
"fieldsDeep": [
"text1"
]
}
errors:
[ { "message": "input: variables.fieldsDeep.text1 Field `text1` is not present in type `Post`. You can only use fields in cascade which are in type `Post`",
"locations": [{ "line": 5, "column": 10}]
} ]

-
name: "@cascade only accepts those fields as a argument, which are present in given type at root level using variables"
gqlrequest: |
query($fieldsRoot: [String], $fieldsDeep: [String]) {
queryAuthor @cascade(fields: $fieldsRoot) {
dob
reputation
posts @cascade(fields: $fieldsDeep) {
text
title
}
}
}
gqlvariables: |
{
"fieldsRoot": [
"dob",
"reputation1"
],
"fieldsDeep": [
"text"
]
}
errors:
[ { "message": "input: variables.fieldsRoot.reputation1 Field `reputation1` is not present in type `Author`. You can only use fields in cascade which are in type `Author`",
"locations": [{ "line": 2, "column": 15}]
} ]
36 changes: 36 additions & 0 deletions graphql/e2e/common/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -2460,6 +2460,42 @@ func queryWithCascade(t *testing.T) {
]
}`,
},
{
name: "parameterized cascade at all levels using variables",
query: `query ($ids: [ID!],$fieldsRoot: [String], $fieldsDeep: [String]) {
queryAuthor(filter: {id: $ids}) @cascade(fields: $fieldsRoot) {
reputation
name
dob
posts @cascade(fields: $fieldsDeep) {
title
text
}
}
}`,
variables: map[string]interface{}{"ids": authorIds, "fieldsRoot": []string{"reputation", "name"}, "fieldsDeep": []string{"text"}},
respData: `{
"queryAuthor": [
{
"reputation": 4.5,
"name": "George",
"dob": null,
"posts": [
{
"title": "A show about nothing",
"text": "Got ya!"
}
]
},
{
"dob": null,
"name": "Jerry",
"posts": [],
"reputation": 4.6
}
]
}`,
},
{
name: "parameterized cascade on ID type ",
query: `query ($ids: [ID!]) {
Expand Down
8 changes: 5 additions & 3 deletions graphql/resolve/mutation_query_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,6 @@ ADD_UPDATE_MUTATION:

-
name: "can work with skip and filter"
variables:
skip: true
include: false
gqlquery: |
mutation ($skip: Boolean!, $include: Boolean!) {
ADD_UPDATE_MUTATION {
Expand All @@ -142,6 +139,11 @@ ADD_UPDATE_MUTATION:
}
}
}
gqlvariables: |
{
"skip": true,
"include": false
}
dgquery: |-
query {
PAYLOAD_TYPE.post(func: uid(0x4)) {
Expand Down
7 changes: 6 additions & 1 deletion graphql/resolve/mutation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,10 +368,15 @@ func TestMutationQueryRewriting(t *testing.T) {
gqlMutationStr := strings.Replace(tcase.GQLQuery, testType, tt.mut, 1)
tcase.DGQuery = strings.Replace(tcase.DGQuery, "PAYLOAD_TYPE",
tt.payloadType, 1)
var vars map[string]interface{}
if tcase.GQLVariables != "" {
err := json.Unmarshal([]byte(tcase.GQLVariables), &vars)
require.NoError(t, err)
}
op, err := gqlSchema.Operation(
&schema.Request{
Query: gqlMutationStr,
Variables: tcase.Variables,
Variables: vars,
})
require.NoError(t, err)
gqlMutation := test.GetMutation(t, op)
Expand Down
15 changes: 10 additions & 5 deletions graphql/resolve/query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ import (
// Tests showing that the query rewriter produces the expected Dgraph queries

type QueryRewritingCase struct {
Name string
GQLQuery string
Variables map[string]interface{}
DGQuery string
Name string
GQLQuery string
GQLVariables string
DGQuery string
}

func TestQueryRewriting(t *testing.T) {
Expand All @@ -56,10 +56,15 @@ func TestQueryRewriting(t *testing.T) {

for _, tcase := range tests {
t.Run(tcase.Name, func(t *testing.T) {
var vars map[string]interface{}
if tcase.GQLVariables != "" {
err := json.Unmarshal([]byte(tcase.GQLVariables), &vars)
require.NoError(t, err)
}
op, err := gqlSchema.Operation(
&schema.Request{
Query: tcase.GQLQuery,
Variables: tcase.Variables,
Variables: vars,
})
require.NoError(t, err)
gqlQuery := test.GetQuery(t, op)
Expand Down
61 changes: 55 additions & 6 deletions graphql/resolve/query_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1574,9 +1574,6 @@

-
name: "Skip directive"
variables:
skipTrue: true
skipFalse: false
gqlquery: |
query ($skipTrue: Boolean!, $skipFalse: Boolean!) {
getAuthor(id: "0x1") {
Expand All @@ -1587,6 +1584,11 @@
}
}
}
gqlvariables: |
{
"skipTrue": true,
"skipFalse": false
}
dgquery: |-
query {
getAuthor(func: uid(0x1)) @filter(type(Author)) {
Expand All @@ -1597,9 +1599,6 @@

-
name: "Include directive"
variables:
includeTrue: true
includeFalse: false
gqlquery: |
query ($includeTrue: Boolean!, $includeFalse: Boolean!) {
queryAuthor {
Expand All @@ -1609,6 +1608,12 @@
}
}
}

gqlvariables: |
{
"includeTrue": true,
"includeFalse": false
}
dgquery: |-
query {
queryAuthor(func: type(Author)) {
Expand Down Expand Up @@ -1638,6 +1643,13 @@
}
}
}
gqlvariables: |
{
"includeTrue": true,
"includeFalse": false,
"skipTrue": true,
"skipFalse": false
}
dgquery: |-
query {
queryAuthor(func: type(Author)) {
Expand Down Expand Up @@ -1935,6 +1947,43 @@
}
}

-
name: "Parameterized Cascade directive on root and nested field using variables"
gqlquery: |
query($fieldsRoot:[String],$fieldsDeep:[String]) {
queryAuthor @cascade(fields: $fieldsRoot) {
dob
reputation
posts @cascade(fields: $fieldsDeep) {
text
title
}
}
}
gqlvariables: |
{
"fieldsRoot": [
"dob",
"reputation"
],
"fieldsDeep": [
"text"
]
}
dgquery: |-
query {
queryAuthor(func: type(Author)) @cascade(Author.dob, Author.reputation) {
Author.dob : Author.dob
Author.reputation : Author.reputation
Author.posts : Author.posts @cascade(Post.text) {
Post.text : Post.text
Post.title : Post.title
dgraph.uid : uid
}
dgraph.uid : uid
}
}

-
name: "getHuman which implements an interface"
gqlquery: |
Expand Down
Loading