Skip to content

Commit

Permalink
Merge pull request #314 from tzneal/implement-enum-as-params
Browse files Browse the repository at this point in the history
enable parsing enums from query parameters
  • Loading branch information
tmc authored Feb 17, 2017
2 parents 6863684 + a0ee7de commit fdf0869
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 0 deletions.
53 changes: 53 additions & 0 deletions runtime/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"net/url"
"reflect"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -98,6 +99,12 @@ func fieldByProtoName(m reflect.Value, name string) reflect.Value {

func populateRepeatedField(f reflect.Value, values []string) error {
elemType := f.Type().Elem()

// is the destination field a slice of an enumeration type?
if enumValMap := proto.EnumValueMap(elemType.String()); enumValMap != nil {
return populateFieldEnumRepeated(f, values, enumValMap)
}

conv, ok := convFromType[elemType.Kind()]
if !ok {
return fmt.Errorf("unsupported field type %s", elemType)
Expand Down Expand Up @@ -137,6 +144,11 @@ func populateField(f reflect.Value, value string) error {
}
}

// is the destination field an enumeration type?
if enumValMap := proto.EnumValueMap(f.Type().String()); enumValMap != nil {
return populateFieldEnum(f, value, enumValMap)
}

conv, ok := convFromType[f.Kind()]
if !ok {
return fmt.Errorf("unsupported field type %T", f)
Expand All @@ -149,6 +161,47 @@ func populateField(f reflect.Value, value string) error {
return nil
}

func convertEnum(value string, t reflect.Type, enumValMap map[string]int32) (reflect.Value, error) {
// see if it's an enumeration string
if enumVal, ok := enumValMap[value]; ok {
return reflect.ValueOf(enumVal).Convert(t), nil
}

// check for an integer that matches an enumeration value
eVal, err := strconv.Atoi(value)
if err != nil {
return reflect.Value{}, fmt.Errorf("%s is not a valid %s", value, t)
}
for _, v := range enumValMap {
if v == int32(eVal) {
return reflect.ValueOf(eVal).Convert(t), nil
}
}
return reflect.Value{}, fmt.Errorf("%s is not a valid %s", value, t)
}

func populateFieldEnum(f reflect.Value, value string, enumValMap map[string]int32) error {
cval, err := convertEnum(value, f.Type(), enumValMap)
if err != nil {
return err
}
f.Set(cval)
return nil
}

func populateFieldEnumRepeated(f reflect.Value, values []string, enumValMap map[string]int32) error {
elemType := f.Type().Elem()
f.Set(reflect.MakeSlice(f.Type(), len(values), len(values)).Convert(f.Type()))
for i, v := range values {
result, err := convertEnum(v, elemType, enumValMap)
if err != nil {
return err
}
f.Index(i).Set(result)
}
return nil
}

var (
convFromType = map[reflect.Kind]reflect.Value{
reflect.String: reflect.ValueOf(String),
Expand Down
26 changes: 26 additions & 0 deletions runtime/query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,17 @@ func TestPopulateParameters(t *testing.T) {
TimestampValue: timePb,
},
},
{
values: url.Values{
"enum_value": {"EnumValue_Z"},
"repeated_enum": {"EnumValue_X", "2", "0"},
},
filter: utilities.NewDoubleArray(nil),
want: &proto3Message{
EnumValue: EnumValue_Z,
RepeatedEnum: []EnumValue{EnumValue_X, EnumValue_Z, EnumValue_X},
},
},
{
values: url.Values{
"float_value": {"1.5"},
Expand Down Expand Up @@ -343,3 +354,18 @@ const (
EnumValue_Y EnumValue = 1
EnumValue_Z EnumValue = 2
)

var EnumValue_name = map[int32]string{
0: "EnumValue_X",
1: "EnumValue_Y",
2: "EnumValue_Z",
}
var EnumValue_value = map[string]int32{
"EnumValue_X": 0,
"EnumValue_Y": 1,
"EnumValue_Z": 2,
}

func init() {
proto.RegisterEnum("runtime_test.EnumValue", EnumValue_name, EnumValue_value)
}

0 comments on commit fdf0869

Please sign in to comment.