Skip to content

Commit

Permalink
Merge pull request #9 from dgraph-io/jatin/GRAPHQL-959
Browse files Browse the repository at this point in the history
The following query was giving panic because here we passed ID as an int which is expected to be a string.

query allStories {
      queryUser(filter: {
        id: 22
      }) {
        stories {
          id
          text
        }
      }
    }

We now added input coercion so that the ID type value will be coerced to string type. And if we give a slice of integer values or the required type is [ID] then that will be coerced to slice of integer values.
  • Loading branch information
JatinDev543 authored Jan 20, 2021
2 parents af5c357 + 1590604 commit b48c15b
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 4 deletions.
1 change: 1 addition & 0 deletions validator/testdata/vars.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ type Query {
defaultStructArg(i: InputType! = {name: "foo"}): Boolean!
arrayArg(i: [InputType!]): Boolean!
intArrayArg(i: [Int]): Boolean!
idArrayArg(i: [ID]): Boolean!
stringArrayArg(i: [String]): Boolean!
boolArrayArg(i: [Boolean]): Boolean!
typeArrayArg(i: [CustomType]): Boolean!
Expand Down
25 changes: 21 additions & 4 deletions validator/vars.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,20 @@ func (v *varValidator) validateVarType(typ *ast.Type, val reflect.Value) (reflec
v.path = currentPath
}
defer resetPath()
slc := make([]interface{}, 0)
if typ.Elem != nil {
if val.Kind() != reflect.Slice {
// GraphQL spec says that non-null values should be coerced to an array when possible.
// Hence if the value is not a slice, we create a slice and add val to it.
slc := make([]interface{}, 0)
slc = append(slc, val.Interface())
if typ.Name() == "ID" && val.Type().Name() != "string" {
val = val.Convert((reflect.ValueOf("string")).Type())
slc = append(slc, val.String())
} else if typ.Name() != "ID" {
slc = append(slc, val.Interface())
}
val = reflect.ValueOf(slc)
val.Convert(val.Type())
}
slc = []interface{}{}
for i := 0; i < val.Len(); i++ {
resetPath()
v.path = append(v.path, ast.PathIndex(i))
Expand All @@ -95,11 +100,20 @@ func (v *varValidator) validateVarType(typ *ast.Type, val reflect.Value) (reflec
}
field = field.Elem()
}
_, err := v.validateVarType(typ.Elem, field)
cval, err := v.validateVarType(typ.Elem, field)
if typ.Name() == "ID" && val.Type().Name() != "string" {
cval = cval.Convert((reflect.ValueOf("string")).Type())
slc = append(slc, cval.String())
} else if typ.Name() == "ID" {
slc = append(slc, cval.String())
}
if err != nil {
return val, err
}
}
if typ.Name() == "ID" {
val = reflect.ValueOf(slc)
}
return val, nil
}
def := v.schema.Types[typ.NamedType]
Expand Down Expand Up @@ -151,6 +165,9 @@ func (v *varValidator) validateVarType(typ *ast.Type, val reflect.Value) (reflec

case "ID":
if kind == reflect.Int || kind == reflect.Int32 || kind == reflect.Int64 || kind == reflect.String {
if val.Type().Name() != "string" {
val = val.Convert((reflect.ValueOf("string")).Type())
}
return val, nil
}
default:
Expand Down
30 changes: 30 additions & 0 deletions validator/vars_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,26 @@ func TestValidateVars(t *testing.T) {
require.EqualValues(t, expected, vars["var"])
})

t.Run("int value should be coerced to string array when required type is [ID]", func(t *testing.T) {
q := gqlparser.MustLoadQuery(schema, `query foo($var: [ID]) { idArrayArg(i: $var) }`)
vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
"var": 5,
})
require.Nil(t, gerr)
expected := []interface{}{"\x05"}
require.EqualValues(t, expected, vars["var"])
})

t.Run("int array should be coerced to string array when required type is [ID]", func(t *testing.T) {
q := gqlparser.MustLoadQuery(schema, `query foo($var: [ID]) { idArrayArg(i: $var) }`)
vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
"var": []interface{}{5, 6},
})
require.Nil(t, gerr)
expected := []interface{}{"\x05", "\x06"}
require.EqualValues(t, expected, vars["var"])
})

t.Run("non-null int deep value should be coerced to an array", func(t *testing.T) {
q := gqlparser.MustLoadQuery(schema, `query foo($var: [CustomType]) { typeArrayArg(i: $var) }`)
vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
Expand All @@ -180,6 +200,16 @@ func TestValidateVars(t *testing.T) {
require.EqualValues(t, expected, vars["var"])
})

t.Run("int value will be converted to string when required type is ID", func(t *testing.T) {
q := gqlparser.MustLoadQuery(schema, `query foo($var: ID!) { idArg(i: $var) }`)
vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
"var": 5,
})
require.Nil(t, gerr)
expected := "\x05"
require.EqualValues(t, expected, vars["var"])
})

t.Run("defaults", func(t *testing.T) {
q := gqlparser.MustLoadQuery(schema, `query foo($var: [InputType!] = [{name: "foo"}]) { arrayArg(i: $var) }`)
vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), nil)
Expand Down

0 comments on commit b48c15b

Please sign in to comment.