improve function Struct for package gconv

This commit is contained in:
John
2020-07-06 21:18:25 +08:00
parent 17b91dcad7
commit e6718f1113
2 changed files with 51 additions and 6 deletions

View File

@ -57,6 +57,13 @@ func Struct(params interface{}, pointer interface{}, mapping ...map[string]strin
return fmt.Errorf("invalid params: %v", params)
}
// UnmarshalValue.
// Assign value with interface UnmarshalValue.
// Note that only pointer can implement interface UnmarshalValue.
if v, ok := pointer.(apiUnmarshalValue); ok {
return v.UnmarshalValue(params)
}
// Using reflect to do the converting,
// it also supports type of reflect.Value for <pointer>(always in internal usage).
elem, ok := pointer.(reflect.Value)
@ -71,6 +78,7 @@ func Struct(params interface{}, pointer interface{}, mapping ...map[string]strin
}
elem = rv.Elem()
}
// It automatically creates struct object if necessary.
// For example, if <pointer> is **User, then <elem> is *User, which is a pointer to User.
if elem.Kind() == reflect.Ptr {
@ -79,14 +87,19 @@ func Struct(params interface{}, pointer interface{}, mapping ...map[string]strin
elem.Set(e.Addr())
elem = e
} else {
// Assign value with interface Set.
// Note that only pointer can implement interface Set.
if v, ok := elem.Interface().(apiUnmarshalValue); ok {
v.UnmarshalValue(params)
return nil
}
elem = elem.Elem()
}
}
// UnmarshalValue.
// Assign value with interface UnmarshalValue.
// Note that only pointer can implement interface UnmarshalValue.
if elem.Kind() == reflect.Struct {
if v, ok := elem.Addr().Interface().(apiUnmarshalValue); ok {
return v.UnmarshalValue(params)
}
}
// It only performs one converting to the same attribute.
// doneMap is used to check repeated converting, its key is the real attribute name
// of the struct.

View File

@ -805,3 +805,35 @@ func Test_Struct_CatchPanic(t *testing.T) {
t.AssertNE(err, nil)
})
}
type MyTime struct {
time.Time
}
type MyTimeSt struct {
ServiceDate MyTime
}
func (st *MyTimeSt) UnmarshalValue(v interface{}) error {
m := gconv.Map(v)
t, err := gtime.StrToTime(gconv.String(m["ServiceDate"]))
if err != nil {
return err
}
st.ServiceDate = MyTime{t.Time}
return nil
}
func Test_Struct_UnmarshalValue(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
st := &MyTimeSt{}
err := gconv.Struct(g.Map{"ServiceDate": "2020-10-10 12:00:01"}, st)
t.Assert(err, nil)
t.Assert(st.ServiceDate.Time.Format("2006-01-02 15:04:05"), "2020-10-10 12:00:01")
})
gtest.C(t, func(t *gtest.T) {
st := &MyTimeSt{}
err := gconv.Struct(g.Map{"ServiceDate": nil}, st)
t.AssertNE(err, nil)
})
}