forked from Fuyu/forms
Return parse errors
This commit is contained in:
parent
0efb52d29e
commit
34a9eba03a
62
forms.go
62
forms.go
@ -8,18 +8,28 @@ import (
|
|||||||
"unicode"
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type DecodeError struct {
|
||||||
|
Field string
|
||||||
|
Type string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (de DecodeError) Error() string {
|
||||||
|
return `Failed to decode "` + de.Value + `" into field ` + de.Field + ` of type ` + de.Type + `.`
|
||||||
|
}
|
||||||
|
|
||||||
type Values = map[string][]string
|
type Values = map[string][]string
|
||||||
|
|
||||||
func Decode(form Values, v interface{}) {
|
func Decode(form Values, v interface{}) error {
|
||||||
rv := reflect.ValueOf(v)
|
rv := reflect.ValueOf(v)
|
||||||
if rv.Kind() != reflect.Ptr {
|
if rv.Kind() != reflect.Ptr {
|
||||||
panic(`Input is not a pointer`)
|
panic(`Input is not a pointer`)
|
||||||
}
|
}
|
||||||
|
|
||||||
decode(form, rv.Elem(), ``)
|
return decode(form, rv.Elem(), ``)
|
||||||
}
|
}
|
||||||
|
|
||||||
func decode(form Values, rv reflect.Value, prefix string) {
|
func decode(form Values, rv reflect.Value, prefix string) error {
|
||||||
for i := 0; i < rv.NumField(); i++ {
|
for i := 0; i < rv.NumField(); i++ {
|
||||||
ft, fv := rv.Type().Field(i), rv.Field(i)
|
ft, fv := rv.Type().Field(i), rv.Field(i)
|
||||||
|
|
||||||
@ -60,11 +70,15 @@ func decode(form Values, rv reflect.Value, prefix string) {
|
|||||||
fv = fv.Elem()
|
fv = fv.Elem()
|
||||||
}
|
}
|
||||||
|
|
||||||
decode(form, fv, getPrefix(ft, prefix))
|
err := decode(form, fv, getPrefix(ft, prefix))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
v, ok := form[getName(ft, prefix)]
|
fieldName := getName(ft, prefix)
|
||||||
|
v, ok := form[fieldName]
|
||||||
if !ok || len(v) == 0 {
|
if !ok || len(v) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -75,37 +89,55 @@ func decode(form Values, rv reflect.Value, prefix string) {
|
|||||||
fv.Set(reflect.New(ft.Type.Elem()))
|
fv.Set(reflect.New(ft.Type.Elem()))
|
||||||
}
|
}
|
||||||
|
|
||||||
setValue(v, fv)
|
err := setValue(fieldName, v, fv)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setValue(values []string, fv reflect.Value) {
|
func setValue(fieldName string, values []string, fv reflect.Value) error {
|
||||||
if fv.Elem().Type().Kind() != reflect.Slice {
|
if fv.Elem().Type().Kind() != reflect.Slice {
|
||||||
parse(values[0], fv)
|
return parse(fieldName, values[0], fv)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
slice := reflect.MakeSlice(fv.Elem().Type(), len(values), len(values))
|
slice := reflect.MakeSlice(fv.Elem().Type(), len(values), len(values))
|
||||||
val := reflect.New(slice.Type().Elem())
|
val := reflect.New(slice.Type().Elem())
|
||||||
for i, v := range values {
|
for i, v := range values {
|
||||||
parse(v, val)
|
err := parse(fieldName, v, val)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
slice.Index(i).Set(val.Elem())
|
slice.Index(i).Set(val.Elem())
|
||||||
}
|
}
|
||||||
fv.Elem().Set(slice)
|
fv.Elem().Set(slice)
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parse(v string, fv reflect.Value) {
|
func parse(fieldName, v string, fv reflect.Value) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
switch f := fv.Interface().(type) {
|
switch f := fv.Interface().(type) {
|
||||||
case *string:
|
case *string:
|
||||||
*f = v
|
*f = v
|
||||||
case *int:
|
case *int:
|
||||||
*f, _ = strconv.Atoi(v)
|
*f, err = strconv.Atoi(v)
|
||||||
case *float32:
|
case *float32:
|
||||||
v, _ := strconv.ParseFloat(v, 32)
|
var f64 float64
|
||||||
*f = float32(v)
|
f64, err = strconv.ParseFloat(v, 32)
|
||||||
|
*f = float32(f64)
|
||||||
case *float64:
|
case *float64:
|
||||||
*f, _ = strconv.ParseFloat(v, 64)
|
*f, err = strconv.ParseFloat(v, 64)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return DecodeError{fieldName, fv.Elem().Type().Kind().String(), v}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPrefix(ft reflect.StructField, prefix string) string {
|
func getPrefix(ft reflect.StructField, prefix string) string {
|
||||||
|
@ -73,7 +73,7 @@ var expectedPD = nested{`test5`, 30, 3.75}
|
|||||||
func TestDecode(t *testing.T) {
|
func TestDecode(t *testing.T) {
|
||||||
data := testStruct{}
|
data := testStruct{}
|
||||||
|
|
||||||
Decode(input, &data)
|
_ = Decode(input, &data)
|
||||||
|
|
||||||
if *data.PA != expectedPA {
|
if *data.PA != expectedPA {
|
||||||
t.Errorf(`PA was incorrect. Expected %v but got %v`, expectedPA, *data.PA)
|
t.Errorf(`PA was incorrect. Expected %v but got %v`, expectedPA, *data.PA)
|
||||||
@ -87,3 +87,19 @@ func TestDecode(t *testing.T) {
|
|||||||
t.Errorf("Data dit not match expected output. Expected \n%v\nbut got\n%v", expected, data)
|
t.Errorf("Data dit not match expected output. Expected \n%v\nbut got\n%v", expected, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDecodeError(t *testing.T) {
|
||||||
|
var data struct {
|
||||||
|
A struct {
|
||||||
|
B float64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := Decode(Values{`A.B`: {`a`}}, &data)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
t.Error(`Expected error but got nil`)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log(err)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user