mirror of
https://github.com/labstack/echo.git
synced 2025-01-26 03:20:08 +02:00
binder: make binding to Map work better with string destinations (#2554)
This commit is contained in:
parent
226e4f076a
commit
60fc2fb1b7
20
bind.go
20
bind.go
@ -131,10 +131,26 @@ func (b *DefaultBinder) bindData(destination interface{}, data map[string][]stri
|
|||||||
typ := reflect.TypeOf(destination).Elem()
|
typ := reflect.TypeOf(destination).Elem()
|
||||||
val := reflect.ValueOf(destination).Elem()
|
val := reflect.ValueOf(destination).Elem()
|
||||||
|
|
||||||
// Map
|
// Support binding to limited Map destinations:
|
||||||
if typ.Kind() == reflect.Map {
|
// - map[string][]string,
|
||||||
|
// - map[string]string <-- (binds first value from data slice)
|
||||||
|
// - map[string]interface{}
|
||||||
|
// You are better off binding to struct but there are user who want this map feature. Source of data for these cases are:
|
||||||
|
// params,query,header,form as these sources produce string values, most of the time slice of strings, actually.
|
||||||
|
if typ.Kind() == reflect.Map && typ.Key().Kind() == reflect.String {
|
||||||
|
k := typ.Elem().Kind()
|
||||||
|
isElemInterface := k == reflect.Interface
|
||||||
|
isElemString := k == reflect.String
|
||||||
|
isElemSliceOfStrings := k == reflect.Slice && typ.Elem().Elem().Kind() == reflect.String
|
||||||
|
if !(isElemSliceOfStrings || isElemString || isElemInterface) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
for k, v := range data {
|
for k, v := range data {
|
||||||
|
if isElemString {
|
||||||
val.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(v[0]))
|
val.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(v[0]))
|
||||||
|
} else {
|
||||||
|
val.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(v))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
56
bind_test.go
56
bind_test.go
@ -429,6 +429,62 @@ func TestBindUnsupportedMediaType(t *testing.T) {
|
|||||||
testBindError(t, strings.NewReader(invalidContent), MIMEApplicationJSON, &json.SyntaxError{})
|
testBindError(t, strings.NewReader(invalidContent), MIMEApplicationJSON, &json.SyntaxError{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDefaultBinder_bindDataToMap(t *testing.T) {
|
||||||
|
exampleData := map[string][]string{
|
||||||
|
"multiple": {"1", "2"},
|
||||||
|
"single": {"3"},
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("ok, bind to map[string]string", func(t *testing.T) {
|
||||||
|
dest := map[string]string{}
|
||||||
|
assert.NoError(t, new(DefaultBinder).bindData(&dest, exampleData, "param"))
|
||||||
|
assert.Equal(t,
|
||||||
|
map[string]string{
|
||||||
|
"multiple": "1",
|
||||||
|
"single": "3",
|
||||||
|
},
|
||||||
|
dest,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ok, bind to map[string][]string", func(t *testing.T) {
|
||||||
|
dest := map[string][]string{}
|
||||||
|
assert.NoError(t, new(DefaultBinder).bindData(&dest, exampleData, "param"))
|
||||||
|
assert.Equal(t,
|
||||||
|
map[string][]string{
|
||||||
|
"multiple": {"1", "2"},
|
||||||
|
"single": {"3"},
|
||||||
|
},
|
||||||
|
dest,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ok, bind to map[string]interface", func(t *testing.T) {
|
||||||
|
dest := map[string]interface{}{}
|
||||||
|
assert.NoError(t, new(DefaultBinder).bindData(&dest, exampleData, "param"))
|
||||||
|
assert.Equal(t,
|
||||||
|
map[string]interface{}{
|
||||||
|
"multiple": []string{"1", "2"},
|
||||||
|
"single": []string{"3"},
|
||||||
|
},
|
||||||
|
dest,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ok, bind to map[string]int skips", func(t *testing.T) {
|
||||||
|
dest := map[string]int{}
|
||||||
|
assert.NoError(t, new(DefaultBinder).bindData(&dest, exampleData, "param"))
|
||||||
|
assert.Equal(t, map[string]int{}, dest)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ok, bind to map[string][]int skips", func(t *testing.T) {
|
||||||
|
dest := map[string][]int{}
|
||||||
|
assert.NoError(t, new(DefaultBinder).bindData(&dest, exampleData, "param"))
|
||||||
|
assert.Equal(t, map[string][]int{}, dest)
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func TestBindbindData(t *testing.T) {
|
func TestBindbindData(t *testing.T) {
|
||||||
ts := new(bindTestStruct)
|
ts := new(bindTestStruct)
|
||||||
b := new(DefaultBinder)
|
b := new(DefaultBinder)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user