Skip to content

Commit a0ee7de

Browse files
tznealTodd Neal
authored andcommitted
enable parsing enums from query parameters
- parses enumeration strings and integer values - range checks both the string and integer form Fixes #166
1 parent 6863684 commit a0ee7de

File tree

2 files changed

+79
-0
lines changed

2 files changed

+79
-0
lines changed

runtime/query.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"net/url"
66
"reflect"
7+
"strconv"
78
"strings"
89
"time"
910

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

99100
func populateRepeatedField(f reflect.Value, values []string) error {
100101
elemType := f.Type().Elem()
102+
103+
// is the destination field a slice of an enumeration type?
104+
if enumValMap := proto.EnumValueMap(elemType.String()); enumValMap != nil {
105+
return populateFieldEnumRepeated(f, values, enumValMap)
106+
}
107+
101108
conv, ok := convFromType[elemType.Kind()]
102109
if !ok {
103110
return fmt.Errorf("unsupported field type %s", elemType)
@@ -137,6 +144,11 @@ func populateField(f reflect.Value, value string) error {
137144
}
138145
}
139146

147+
// is the destination field an enumeration type?
148+
if enumValMap := proto.EnumValueMap(f.Type().String()); enumValMap != nil {
149+
return populateFieldEnum(f, value, enumValMap)
150+
}
151+
140152
conv, ok := convFromType[f.Kind()]
141153
if !ok {
142154
return fmt.Errorf("unsupported field type %T", f)
@@ -149,6 +161,47 @@ func populateField(f reflect.Value, value string) error {
149161
return nil
150162
}
151163

164+
func convertEnum(value string, t reflect.Type, enumValMap map[string]int32) (reflect.Value, error) {
165+
// see if it's an enumeration string
166+
if enumVal, ok := enumValMap[value]; ok {
167+
return reflect.ValueOf(enumVal).Convert(t), nil
168+
}
169+
170+
// check for an integer that matches an enumeration value
171+
eVal, err := strconv.Atoi(value)
172+
if err != nil {
173+
return reflect.Value{}, fmt.Errorf("%s is not a valid %s", value, t)
174+
}
175+
for _, v := range enumValMap {
176+
if v == int32(eVal) {
177+
return reflect.ValueOf(eVal).Convert(t), nil
178+
}
179+
}
180+
return reflect.Value{}, fmt.Errorf("%s is not a valid %s", value, t)
181+
}
182+
183+
func populateFieldEnum(f reflect.Value, value string, enumValMap map[string]int32) error {
184+
cval, err := convertEnum(value, f.Type(), enumValMap)
185+
if err != nil {
186+
return err
187+
}
188+
f.Set(cval)
189+
return nil
190+
}
191+
192+
func populateFieldEnumRepeated(f reflect.Value, values []string, enumValMap map[string]int32) error {
193+
elemType := f.Type().Elem()
194+
f.Set(reflect.MakeSlice(f.Type(), len(values), len(values)).Convert(f.Type()))
195+
for i, v := range values {
196+
result, err := convertEnum(v, elemType, enumValMap)
197+
if err != nil {
198+
return err
199+
}
200+
f.Index(i).Set(result)
201+
}
202+
return nil
203+
}
204+
152205
var (
153206
convFromType = map[reflect.Kind]reflect.Value{
154207
reflect.String: reflect.ValueOf(String),

runtime/query_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,17 @@ func TestPopulateParameters(t *testing.T) {
5757
TimestampValue: timePb,
5858
},
5959
},
60+
{
61+
values: url.Values{
62+
"enum_value": {"EnumValue_Z"},
63+
"repeated_enum": {"EnumValue_X", "2", "0"},
64+
},
65+
filter: utilities.NewDoubleArray(nil),
66+
want: &proto3Message{
67+
EnumValue: EnumValue_Z,
68+
RepeatedEnum: []EnumValue{EnumValue_X, EnumValue_Z, EnumValue_X},
69+
},
70+
},
6071
{
6172
values: url.Values{
6273
"float_value": {"1.5"},
@@ -343,3 +354,18 @@ const (
343354
EnumValue_Y EnumValue = 1
344355
EnumValue_Z EnumValue = 2
345356
)
357+
358+
var EnumValue_name = map[int32]string{
359+
0: "EnumValue_X",
360+
1: "EnumValue_Y",
361+
2: "EnumValue_Z",
362+
}
363+
var EnumValue_value = map[string]int32{
364+
"EnumValue_X": 0,
365+
"EnumValue_Y": 1,
366+
"EnumValue_Z": 2,
367+
}
368+
369+
func init() {
370+
proto.RegisterEnum("runtime_test.EnumValue", EnumValue_name, EnumValue_value)
371+
}

0 commit comments

Comments
 (0)