Skip to content

Commit

Permalink
feat(GraphQL): add support for IN filter (#6662)
Browse files Browse the repository at this point in the history
This PR adds support for the `IN` filter in GraphQL.
For the given type State having @id directive at the field code :
```
type State {
        code: String! @id
        name: String!
	capital: String
}
```
Suppose we want to query States having either code = `abc` or `def`, then the corresponding GraphQL query is:
```
query {
      queryState(filter: {code: {in : ["abc", "def"]}}){
        code 
        name
      }
    }
```
  • Loading branch information
minhaj-shakeel authored Oct 8, 2020
1 parent 4fc328d commit 6b43353
Show file tree
Hide file tree
Showing 50 changed files with 237 additions and 28 deletions.
20 changes: 13 additions & 7 deletions graphql/dgraph/graphquery.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,15 @@ func writeRoot(b *strings.Builder, q *gql.GraphQuery) {
x.Check2(b.WriteRune(')'))
}

func writeFilterArguments(b *strings.Builder, args []gql.Arg) {
for i, arg := range args {
if i != 0 {
x.Check2(b.WriteString(", "))
}
x.Check2(b.WriteString(arg.Value))
}
}

func writeFilterFunction(b *strings.Builder, f *gql.Function) {
if f == nil {
return
Expand All @@ -151,13 +160,10 @@ func writeFilterFunction(b *strings.Builder, f *gql.Function) {
switch {
case f.Name == "uid":
writeUIDFunc(b, f.UID, f.Args)
case len(f.Args) == 1:
x.Check2(b.WriteString(fmt.Sprintf("%s(%s)", f.Name, f.Args[0].Value)))
case len(f.Args) == 2:
x.Check2(b.WriteString(fmt.Sprintf("%s(%s, %s)", f.Name, f.Args[0].Value, f.Args[1].Value)))
case len(f.Args) == 3:
x.Check2(b.WriteString(fmt.Sprintf("%s(%s, %s, %s)", f.Name, f.Args[0].Value, f.Args[1].Value,
f.Args[2].Value)))
default:
x.Check2(b.WriteString(fmt.Sprintf("%s(", f.Name)))
writeFilterArguments(b, f.Args)
x.Check2(b.WriteRune(')'))
}
}

Expand Down
1 change: 1 addition & 0 deletions graphql/e2e/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ func RunAll(t *testing.T) {
t.Run("multiple search indexes", multipleSearchIndexes)
t.Run("multiple search indexes wrong field", multipleSearchIndexesWrongField)
t.Run("hash search", hashSearch)
t.Run("in filter", inFilter)
t.Run("deep filter", deepFilter)
t.Run("deep has filter", deepHasFilter)
t.Run("many queries", manyQueries)
Expand Down
81 changes: 81 additions & 0 deletions graphql/e2e/common/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,87 @@ func allPosts(t *testing.T) []*post {
return result.QueryPost
}

func inFilter(t *testing.T) {
addStateParams := &GraphQLParams{
Query: `mutation addState($name1: String!, $code1: String!, $name2: String!, $code2: String! ) {
addState(input: [{name: $name1, xcode: $code1},{name: $name2, xcode: $code2}]) {
state {
xcode
name
}
}
}`,

Variables: map[string]interface{}{
"name1": "A State",
"code1": "abc",
"name2": "B State",
"code2": "def",
},
}

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

updateStateParams := &GraphQLParams{
Query: `mutation{
updateState(input: {
filter: {
xcode: { in: ["abc", "def"]}},
set: {
capital: "Common Capital"} }){
state{
xcode
name
capital
}
}
}`,
}
gqlResponse = updateStateParams.ExecuteAsPost(t, GraphqlURL)
RequireNoGQLErrors(t, gqlResponse)

getStateParams := &GraphQLParams{
Query: `query{
queryState(filter: {xcode: {in: ["abc", "def"]}}){
xcode
name
capital
}
}`,
}

gqlResponse = getStateParams.ExecuteAsPost(t, GraphqlURL)
RequireNoGQLErrors(t, gqlResponse)

var result struct {
QueryState []*state
}
err := json.Unmarshal([]byte(gqlResponse.Data), &result)
require.NoError(t, err)
require.Equal(t, 2, len(result.QueryState))

state1 := &state{
Name: "A State",
Code: "abc",
Capital: "Common Capital",
}
state2 := &state{
Name: "B State",
Code: "def",
Capital: "Common Capital",
}

expected := []*state{state1, state2}

if diff := cmp.Diff(expected, result.QueryState); diff != "" {
t.Errorf("result mismatch (-want +got):\n%s", diff)
}

deleteFilter := map[string]interface{}{"xcode": map[string]interface{}{"in": []string{"abc", "def"}}}
deleteGqlType(t, "State", deleteFilter, 2, nil)
}

func deepFilter(t *testing.T) {
getAuthorParams := &GraphQLParams{
Query: `query {
Expand Down
2 changes: 2 additions & 0 deletions graphql/e2e/schema/generatedSchema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ input StringFullTextFilter {

input StringExactFilter {
eq: String
in: [String]
le: String
lt: String
ge: String
Expand All @@ -164,6 +165,7 @@ input StringExactFilter {

input StringHashFilter {
eq: String
in: [String]
}

#######################
Expand Down
47 changes: 26 additions & 21 deletions graphql/resolve/query_rewriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -1059,8 +1059,24 @@ func buildFilter(typ schema.Type, filter map[string]interface{}) *gql.FilterTree
// title: { anyofterms: "GraphQL" } -> anyofterms(Post.title, "GraphQL")
// OR
// numLikes: { le: 10 } -> le(Post.numLikes, 10)

fn, val := first(dgFunc)
args := []gql.Arg{
{Value: typ.DgraphPredicate(field)},
}
switch fn {
// in takes List of Scalars as argument, for eg:
// code : { in: {"abc", "def", "ghi"} } -> eq(State.code,"abc","def","ghi")
case "in":
// No need to check for List types as this would pass GraphQL validation
// if val was not list
vals := val.([]interface{})
fn = "eq"

for _, v := range vals {
args = append(args, gql.Arg{Value: maybeQuoteArg(fn, v)})
}

case "near":
// For Geo type we have `near` filter which is written as follows:
// { near: { distance: 33.33, coordinate: { latitude: 11.11, longitude: 22.22 } } }
Expand All @@ -1071,29 +1087,18 @@ func buildFilter(typ schema.Type, filter map[string]interface{}) *gql.FilterTree
lat := coordinate["latitude"]
long := coordinate["longitude"]

args := []gql.Arg{
{Value: typ.DgraphPredicate(field)},
{Value: fmt.Sprintf("[%v,%v]", long, lat)},
{Value: fmt.Sprintf("%v", distance)},
}
args = append(args, gql.Arg{Value: fmt.Sprintf("[%v,%v]", long, lat)})
args = append(args, gql.Arg{Value: fmt.Sprintf("%v", distance)})

ands = append(ands, &gql.FilterTree{
Func: &gql.Function{
Name: fn,
Args: args,
},
})
default:
ands = append(ands, &gql.FilterTree{
Func: &gql.Function{
Name: fn,
Args: []gql.Arg{
{Value: typ.DgraphPredicate(field)},
{Value: maybeQuoteArg(fn, val)},
},
},
})
default:
args = append(args, gql.Arg{Value: maybeQuoteArg(fn, val)})
}
ands = append(ands, &gql.FilterTree{
Func: &gql.Function{
Name: fn,
Args: args,
},
})
case []interface{}:
// ids: [ 0x123, 0x124 ] -> uid(0x123, 0x124)
ids := convertIDs(dgFunc)
Expand Down
18 changes: 18 additions & 0 deletions graphql/resolve/query_test.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
-
name: "in filter"
gqlquery: |
query {
queryState(filter: {code: {in: ["abc", "def", "ghi"]}}) {
code
name
}
}
dgquery: |-
query {
queryState(func: type(State)) @filter(eq(State.code, "abc", "def", "ghi")) {
code : State.code
name : State.name
dgraph.uid : uid
}
}
-
name: "Geo query"
gqlquery: |
Expand Down
2 changes: 2 additions & 0 deletions graphql/schema/gqlschema.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ input StringFullTextFilter {
input StringExactFilter {
eq: String
in: [String]
le: String
lt: String
ge: String
Expand All @@ -221,6 +222,7 @@ input StringExactFilter {
input StringHashFilter {
eq: String
in: [String]
}
`
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ input StringFullTextFilter {

input StringExactFilter {
eq: String
in: [String]
le: String
lt: String
ge: String
Expand All @@ -175,6 +176,7 @@ input StringExactFilter {

input StringHashFilter {
eq: String
in: [String]
}

#######################
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ input StringFullTextFilter {

input StringExactFilter {
eq: String
in: [String]
le: String
lt: String
ge: String
Expand All @@ -180,6 +181,7 @@ input StringExactFilter {

input StringHashFilter {
eq: String
in: [String]
}

#######################
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ input StringFullTextFilter {

input StringExactFilter {
eq: String
in: [String]
le: String
lt: String
ge: String
Expand All @@ -168,6 +169,7 @@ input StringExactFilter {

input StringHashFilter {
eq: String
in: [String]
}

#######################
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ input StringFullTextFilter {

input StringExactFilter {
eq: String
in: [String]
le: String
lt: String
ge: String
Expand All @@ -185,6 +186,7 @@ input StringExactFilter {

input StringHashFilter {
eq: String
in: [String]
}

#######################
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ input StringFullTextFilter {

input StringExactFilter {
eq: String
in: [String]
le: String
lt: String
ge: String
Expand All @@ -169,6 +170,7 @@ input StringExactFilter {

input StringHashFilter {
eq: String
in: [String]
}

#######################
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ input StringFullTextFilter {

input StringExactFilter {
eq: String
in: [String]
le: String
lt: String
ge: String
Expand All @@ -168,6 +169,7 @@ input StringExactFilter {

input StringHashFilter {
eq: String
in: [String]
}

#######################
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ input StringFullTextFilter {

input StringExactFilter {
eq: String
in: [String]
le: String
lt: String
ge: String
Expand All @@ -164,6 +165,7 @@ input StringExactFilter {

input StringHashFilter {
eq: String
in: [String]
}

#######################
Expand Down
2 changes: 2 additions & 0 deletions graphql/schema/testdata/schemagen/output/deprecated.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ input StringFullTextFilter {

input StringExactFilter {
eq: String
in: [String]
le: String
lt: String
ge: String
Expand All @@ -164,6 +165,7 @@ input StringExactFilter {

input StringHashFilter {
eq: String
in: [String]
}

#######################
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ input StringFullTextFilter {

input StringExactFilter {
eq: String
in: [String]
le: String
lt: String
ge: String
Expand All @@ -178,6 +179,7 @@ input StringExactFilter {

input StringHashFilter {
eq: String
in: [String]
}

#######################
Expand Down
Loading

0 comments on commit 6b43353

Please sign in to comment.