mirror of
https://github.com/labstack/echo.git
synced 2024-12-24 20:14:31 +02:00
Add support for encoding.TextUnmarshaler in bind. (#1314)
This commit is contained in:
parent
842fc8772f
commit
c824b8ddc3
21
bind.go
21
bind.go
@ -1,6 +1,7 @@
|
||||
package echo
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
@ -21,6 +22,8 @@ type (
|
||||
DefaultBinder struct{}
|
||||
|
||||
// BindUnmarshaler is the interface used to wrap the UnmarshalParam method.
|
||||
// Types that don't implement this, but do implement encoding.TextUnmarshaler
|
||||
// will use that interface instead.
|
||||
BindUnmarshaler interface {
|
||||
// UnmarshalParam decodes and assigns a value from an form or query param.
|
||||
UnmarshalParam(param string) error
|
||||
@ -211,12 +214,30 @@ func bindUnmarshaler(field reflect.Value) (BindUnmarshaler, bool) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// textUnmarshaler attempts to unmarshal a reflect.Value into a TextUnmarshaler
|
||||
func textUnmarshaler(field reflect.Value) (encoding.TextUnmarshaler, bool) {
|
||||
ptr := reflect.New(field.Type())
|
||||
if ptr.CanInterface() {
|
||||
iface := ptr.Interface()
|
||||
if unmarshaler, ok := iface.(encoding.TextUnmarshaler); ok {
|
||||
return unmarshaler, ok
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func unmarshalFieldNonPtr(value string, field reflect.Value) (bool, error) {
|
||||
if unmarshaler, ok := bindUnmarshaler(field); ok {
|
||||
err := unmarshaler.UnmarshalParam(value)
|
||||
field.Set(reflect.ValueOf(unmarshaler).Elem())
|
||||
return true, err
|
||||
}
|
||||
if unmarshaler, ok := textUnmarshaler(field); ok {
|
||||
err := unmarshaler.UnmarshalText([]byte(value))
|
||||
field.Set(reflect.ValueOf(unmarshaler).Elem())
|
||||
return true, err
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
|
40
bind_test.go
40
bind_test.go
@ -50,6 +50,8 @@ type (
|
||||
PtrS *string
|
||||
cantSet string
|
||||
DoesntExist string
|
||||
GoT time.Time
|
||||
GoTptr *time.Time
|
||||
T Timestamp
|
||||
Tptr *Timestamp
|
||||
SA StringArray
|
||||
@ -116,6 +118,8 @@ var values = map[string][]string{
|
||||
"cantSet": {"test"},
|
||||
"T": {"2016-12-06T19:09:05+01:00"},
|
||||
"Tptr": {"2016-12-06T19:09:05+01:00"},
|
||||
"GoT": {"2016-12-06T19:09:05+01:00"},
|
||||
"GoTptr": {"2016-12-06T19:09:05+01:00"},
|
||||
"ST": {"bar"},
|
||||
}
|
||||
|
||||
@ -216,6 +220,28 @@ func TestBindUnmarshalParam(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBindUnmarshalText(t *testing.T) {
|
||||
e := New()
|
||||
req := httptest.NewRequest(GET, "/?ts=2016-12-06T19:09:05Z&sa=one,two,three&ta=2016-12-06T19:09:05Z&ta=2016-12-06T19:09:05Z&ST=baz", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
c := e.NewContext(req, rec)
|
||||
result := struct {
|
||||
T time.Time `query:"ts"`
|
||||
TA []time.Time `query:"ta"`
|
||||
SA StringArray `query:"sa"`
|
||||
ST Struct
|
||||
}{}
|
||||
err := c.Bind(&result)
|
||||
ts := time.Date(2016, 12, 6, 19, 9, 5, 0, time.UTC)
|
||||
if assert.NoError(t, err) {
|
||||
// assert.Equal(t, Timestamp(reflect.TypeOf(&Timestamp{}), time.Date(2016, 12, 6, 19, 9, 5, 0, time.UTC)), result.T)
|
||||
assert.Equal(t, ts, result.T)
|
||||
assert.Equal(t, StringArray([]string{"one", "two", "three"}), result.SA)
|
||||
assert.Equal(t, []time.Time{ts, ts}, result.TA)
|
||||
assert.Equal(t, Struct{"baz"}, result.ST)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBindUnmarshalParamPtr(t *testing.T) {
|
||||
e := New()
|
||||
req := httptest.NewRequest(http.MethodGet, "/?ts=2016-12-06T19:09:05Z", nil)
|
||||
@ -230,6 +256,20 @@ func TestBindUnmarshalParamPtr(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBindUnmarshalTextPtr(t *testing.T) {
|
||||
e := New()
|
||||
req := httptest.NewRequest(GET, "/?ts=2016-12-06T19:09:05Z", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
c := e.NewContext(req, rec)
|
||||
result := struct {
|
||||
Tptr *time.Time `query:"ts"`
|
||||
}{}
|
||||
err := c.Bind(&result)
|
||||
if assert.NoError(t, err) {
|
||||
assert.Equal(t, time.Date(2016, 12, 6, 19, 9, 5, 0, time.UTC), *result.Tptr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBindMultipartForm(t *testing.T) {
|
||||
body := new(bytes.Buffer)
|
||||
mw := multipart.NewWriter(body)
|
||||
|
Loading…
Reference in New Issue
Block a user