diff --git a/executor.go b/executor.go index 7440ae21..7f530c79 100644 --- a/executor.go +++ b/executor.go @@ -995,7 +995,22 @@ func DefaultResolveFn(p ResolveParams) (interface{}, error) { // Try accessing as map via reflection if r := reflect.ValueOf(p.Source); r.Kind() == reflect.Map && r.Type().Key().Kind() == reflect.String { - val := r.MapIndex(reflect.ValueOf(p.Info.FieldName)) + fieldNameValue := reflect.ValueOf(p.Info.FieldName) + // The map key type might be a string type alias and its underlying type is string, + // but it will be panic if we try to use it as a string value in `MapIndex`. + // So we need to convert the value of the field name to the map key type before + // using it as a map key. + // + // Related issue: https://github.com/graphql-go/graphql/issues/700 + // + // We cannot use `CanConvert` here since we need to be compatible with Go before 1.17. + if fieldNameValue.Kind() != reflect.String { + return nil, nil + } + mapKeyType := r.Type().Key() + fieldNameValue = fieldNameValue.Convert(mapKeyType) + + val := r.MapIndex(fieldNameValue) if val.IsValid() { property := val.Interface() if val.Type().Kind() == reflect.Func { diff --git a/executor_test.go b/executor_test.go index 856aadf3..f2cee54f 100644 --- a/executor_test.go +++ b/executor_test.go @@ -15,6 +15,17 @@ import ( "github.com/graphql-go/graphql/testutil" ) +func TestDefaultResolveFn(t *testing.T) { + type Key string + type Source map[Key]interface{} + source := Source{ + "foo": "bar", + } + graphql.DefaultResolveFn(graphql.ResolveParams{ + Source: source, + }) +} + func TestExecutesArbitraryCode(t *testing.T) { deepData := map[string]interface{}{}