Skip to content

Commit cd1dbeb

Browse files
authored
Feat(GraphQL): This PR adds parameterised cascade in graphql. (#6251)
This PR adds parameterised cascade in graphql. We can now specify individual fields in @cascade. query { queryperson @cascade(fields: ["name"]){ id name Friends @cascade(fields: ["name1"]) { id name1 } } }
1 parent e9dda24 commit cd1dbeb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+647
-44
lines changed

graphql/dgraph/graphquery.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ func writeQuery(b *strings.Builder, query *gql.GraphQuery, prefix string) {
7272
if len(query.Cascade) != 0 {
7373
if query.Cascade[0] == "__all__" {
7474
x.Check2(b.WriteString(" @cascade"))
75+
} else {
76+
x.Check2(b.WriteString(" @cascade("))
77+
x.Check2(b.WriteString(strings.Join(query.Cascade, ", ")))
78+
x.Check2(b.WriteRune(')'))
7579
}
7680
}
7781

graphql/e2e/common/common.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,7 @@ func RunAll(t *testing.T) {
318318
t.Run("alias works for mutations", mutationsWithAlias)
319319
t.Run("three level deep", threeLevelDeepMutation)
320320
t.Run("update mutation without set & remove", updateMutationWithoutSetRemove)
321+
t.Run("Check cascade with mutation without ID field", checkCascadeWithMutationWithoutIDField)
321322

322323
// error tests
323324
t.Run("graphql completion on", graphQLCompletionOn)

graphql/e2e/common/error_test.yaml

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@
8989
[ { "message": "must be defined",
9090
"path": [ "variable", "filter"] } ]
9191
-
92-
name: "subscription on type without @withSubscription directive should retur error"
92+
name: "subscription on type without @withSubscription directive should return error"
9393
gqlrequest: |
9494
subscription {
9595
getAuthor(id: "0x1") { name }
@@ -100,3 +100,33 @@
100100
[ { "message": "Cannot query field \"getAuthor\" on type \"Subscription\".",
101101
"locations": [ { "line": 2, "column": 3 } ] } ]
102102

103+
-
104+
name: "@cascade only accepts those fields as a argument, which are present in given type "
105+
gqlrequest: |
106+
query {
107+
queryAuthor @cascade(fields:["title"]){
108+
dob
109+
reputation
110+
}
111+
}
112+
gqlvariables:
113+
{ }
114+
errors:
115+
[ { "message": "Field `title` is not present in type `Author`. You can only use fields which are in type `Author`",
116+
} ]
117+
118+
-
119+
name: "@cascade only accepts numUids or given type name as arguments for add or update payload "
120+
gqlrequest: |
121+
mutation {
122+
addAuthor(input:[{name:"jatin"}]) @cascade(fields:["name"]) {
123+
author {
124+
name
125+
}
126+
}
127+
}
128+
gqlvariables:
129+
{ }
130+
errors:
131+
[ { "message": "Field `name` is not present in type `AddAuthorPayload`. You can only use fields which are in type `AddAuthorPayload`",
132+
} ]

graphql/e2e/common/mutation.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3366,3 +3366,32 @@ func updateMutationWithoutSetRemove(t *testing.T) {
33663366
// cleanup
33673367
deleteCountry(t, map[string]interface{}{"id": []string{country.ID}}, 1, nil)
33683368
}
3369+
3370+
func checkCascadeWithMutationWithoutIDField(t *testing.T) {
3371+
addStateParams := &GraphQLParams{
3372+
Query: `mutation {
3373+
addState(input: [{xcode: "S2", name: "State2"}]) @cascade(fields:["numUids"]) {
3374+
state @cascade(fields:["xcode"]) {
3375+
xcode
3376+
name
3377+
}
3378+
}
3379+
}`,
3380+
}
3381+
3382+
gqlResponse := addStateParams.ExecuteAsPost(t, graphqlURL)
3383+
RequireNoGQLErrors(t, gqlResponse)
3384+
3385+
addStateExpected := `{
3386+
"addState": {
3387+
"state": [{
3388+
"xcode": "S2",
3389+
"name": "State2"
3390+
}]
3391+
}
3392+
}`
3393+
testutil.CompareJSON(t, addStateExpected, string(gqlResponse.Data))
3394+
3395+
filter := map[string]interface{}{"xcode": map[string]interface{}{"eq": "S2"}}
3396+
deleteState(t, filter, 1, nil)
3397+
}

graphql/e2e/common/query.go

Lines changed: 186 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1743,7 +1743,7 @@ func DgraphDirectiveWithSpecialCharacters(t *testing.T) {
17431743
}
17441744

17451745
func queryWithCascade(t *testing.T) {
1746-
// for testing @cascade with get by ID and filter queries, also for testing @cascade on field
1746+
// for testing normal and parameterized @cascade with get by ID and filter queries on multiple levels
17471747
authors := addMultipleAuthorFromRef(t, []*author{
17481748
{
17491749
Name: "George",
@@ -1752,15 +1752,20 @@ func queryWithCascade(t *testing.T) {
17521752
}, {
17531753
Name: "Jerry",
17541754
Reputation: 4.6,
1755+
Country: &country{Name: "outer Galaxy2"},
17551756
Posts: []*post{{Title: "Outside", Tags: []string{}}},
17561757
}, {
1757-
Name: "Kramer",
1758-
Posts: []*post{{Title: "Ha! Cosmo Kramer", Text: "Giddy up!", Tags: []string{}}},
1758+
Name: "Kramer",
1759+
Country: &country{Name: "outer space2"},
1760+
Posts: []*post{{Title: "Ha! Cosmo Kramer", Text: "Giddy up!", Tags: []string{}}},
17591761
},
17601762
}, postExecutor)
1763+
newStarship := addStarship(t)
1764+
humanID := addHuman(t, newStarship.ID)
17611765
authorIds := []string{authors[0].ID, authors[1].ID, authors[2].ID}
17621766
postIds := []string{authors[0].Posts[0].PostID, authors[1].Posts[0].PostID,
17631767
authors[2].Posts[0].PostID}
1768+
countryIds := []string{authors[1].Country.ID, authors[2].Country.ID}
17641769
getAuthorByIdQuery := `query ($id: ID!) {
17651770
getAuthor(id: $id) @cascade {
17661771
reputation
@@ -1881,6 +1886,182 @@ func queryWithCascade(t *testing.T) {
18811886
}]
18821887
}`,
18831888
},
1889+
{
1890+
name: "parameterized cascade with argument at outer level only",
1891+
query: `query ($ids: [ID!]) {
1892+
queryAuthor(filter: {id: $ids}) @cascade(fields:["name"]) {
1893+
reputation
1894+
name
1895+
country {
1896+
name
1897+
}
1898+
}
1899+
}`,
1900+
variables: map[string]interface{}{"ids": authorIds},
1901+
respData:`{
1902+
"queryAuthor": [
1903+
{
1904+
"reputation": 4.6,
1905+
"name": "Jerry",
1906+
"country": {
1907+
"name": "outer Galaxy2"
1908+
}
1909+
},
1910+
{
1911+
"name": "Kramer",
1912+
"reputation": null,
1913+
"country": {
1914+
"name": "outer space2"
1915+
}
1916+
},
1917+
{
1918+
"reputation": 4.5,
1919+
"name": "George",
1920+
"country": null
1921+
}
1922+
]
1923+
}`,
1924+
},
1925+
{
1926+
name: "parameterized cascade only at inner level ",
1927+
query: `query ($ids: [ID!]) {
1928+
queryAuthor(filter: {id: $ids}) {
1929+
reputation
1930+
name
1931+
posts @cascade(fields:["text"]) {
1932+
title
1933+
text
1934+
}
1935+
}
1936+
}`,
1937+
variables: map[string]interface{}{"ids": authorIds},
1938+
respData: `{
1939+
"queryAuthor": [
1940+
{
1941+
"reputation": 4.5,
1942+
"name": "George",
1943+
"posts": [
1944+
{
1945+
"title": "A show about nothing",
1946+
"text": "Got ya!"
1947+
}
1948+
]
1949+
},
1950+
{
1951+
"name": "Kramer",
1952+
"reputation": null,
1953+
"posts": [
1954+
{
1955+
"title": "Ha! Cosmo Kramer",
1956+
"text": "Giddy up!"
1957+
}
1958+
]
1959+
},
1960+
{
1961+
"name": "Jerry",
1962+
"reputation": 4.6,
1963+
"posts": []
1964+
}
1965+
]
1966+
}`,
1967+
},
1968+
{
1969+
name: "parameterized cascade at all levels ",
1970+
query: `query ($ids: [ID!]) {
1971+
queryAuthor(filter: {id: $ids}) @cascade(fields:["reputation","name"]) {
1972+
reputation
1973+
name
1974+
dob
1975+
posts @cascade(fields:["text"]) {
1976+
title
1977+
text
1978+
}
1979+
}
1980+
}`,
1981+
variables: map[string]interface{}{"ids": authorIds},
1982+
respData: `{
1983+
"queryAuthor": [
1984+
{
1985+
"reputation": 4.5,
1986+
"name": "George",
1987+
"dob": null,
1988+
"posts": [
1989+
{
1990+
"title": "A show about nothing",
1991+
"text": "Got ya!"
1992+
}
1993+
]
1994+
},
1995+
{
1996+
"dob": null,
1997+
"name": "Jerry",
1998+
"posts": [],
1999+
"reputation": 4.6
2000+
}
2001+
]
2002+
}`,
2003+
},
2004+
{
2005+
name: "parameterized cascade on ID type ",
2006+
query: `query ($ids: [ID!]) {
2007+
queryAuthor(filter: {id: $ids}) @cascade(fields:["reputation","id"]) {
2008+
reputation
2009+
name
2010+
dob
2011+
}
2012+
}`,
2013+
variables: map[string]interface{}{"ids": authorIds},
2014+
respData: `{
2015+
"queryAuthor": [
2016+
{
2017+
"reputation": 4.5,
2018+
"name": "George",
2019+
"dob": null
2020+
},
2021+
{
2022+
"dob": null,
2023+
"name": "Jerry",
2024+
"reputation": 4.6
2025+
}
2026+
]
2027+
}`,
2028+
},
2029+
{
2030+
name: "parameterized cascade on field of interface ",
2031+
query: `query {
2032+
queryHuman() @cascade(fields:["name"]) {
2033+
name
2034+
totalCredits
2035+
}
2036+
}`,
2037+
respData: `{
2038+
"queryHuman": [
2039+
{
2040+
"name": "Han",
2041+
"totalCredits": 10
2042+
}
2043+
]
2044+
}`,
2045+
},
2046+
{
2047+
name: "parameterized cascade on interface ",
2048+
query: `query {
2049+
queryCharacter (filter: { appearsIn: { eq: [EMPIRE] } }) @cascade(fields:["appearsIn"]){
2050+
name
2051+
appearsIn
2052+
}
2053+
}`,
2054+
respData: `{
2055+
"queryCharacter": [
2056+
{
2057+
"name": "Han",
2058+
"appearsIn": [
2059+
"EMPIRE"
2060+
]
2061+
}
2062+
]
2063+
}`,
2064+
},
18842065
}
18852066

18862067
for _, tcase := range tcases {
@@ -1897,7 +2078,9 @@ func queryWithCascade(t *testing.T) {
18972078

18982079
// cleanup
18992080
deleteAuthors(t, authorIds, nil)
2081+
deleteCountry(t, map[string]interface{}{"id": countryIds}, len(countryIds), nil)
19002082
deleteGqlType(t, "Post", map[string]interface{}{"postID": postIds}, len(postIds), nil)
19012083
deleteState(t, getXidFilter("xcode", []string{states[0].Code, states[1].Code}), len(states),
19022084
nil)
2085+
cleanupStarwars(t, newStarship.ID, humanID, "")
19032086
}

0 commit comments

Comments
 (0)