From 173799544b5ce4cdc26e290093019c6073b92381 Mon Sep 17 00:00:00 2001 From: "pzrr@qq.com" Date: Sun, 3 Nov 2019 16:03:21 +0800 Subject: [PATCH] #### Version 0.7.2 * New Feature: MapperSlice support ptr and struct * New Feature: MapperMapSlice support ptr and struct * Detail: - now support two slice's element type is ptr or struct in MapperSlice - now support slice's element type is ptr or struct in MapperMapSlice - About MapperMapSlice: ```golang //view test code in mapper_test.go:Test_MapperSlice\Test_MapperStructSlice //type ptr var toSlice []*testStruct //type struct var toSlice []testStruct ``` - About MapperSlice: ```golang //view test code in mapper_test.go:Test_MapperMapSlice\Test_MapperStructMapSlice //type ptr var fromSlice []*FromStruct var toSlice []*ToStruct //type struct var fromSlice []FromStruct var toSlice []ToStruct ``` * 2019-11-03 16:00 in ShangHai --- mapper.go | 95 ++++++++++++++++++++++++++++---------------------- mapper_test.go | 36 +++++++++++++++++++ version.md | 26 ++++++++++++++ 3 files changed, 116 insertions(+), 41 deletions(-) diff --git a/mapper.go b/mapper.go index 8f480b2..e197100 100644 --- a/mapper.go +++ b/mapper.go @@ -97,8 +97,7 @@ func Register(obj interface{}) error { if objValue == ZeroValue { return errors.New("no exists this value") } - - return registerValue(objValue.Elem()) + return registerValue(objValue) } // registerValue register Value to init Map @@ -168,7 +167,12 @@ func GetFieldName(objElem reflect.Value, index int) string { // 5.reflect.Float32\64 // 6.time.Time func MapperMap(fromMap map[string]interface{}, toObj interface{}) error { - toElem := reflect.ValueOf(toObj).Elem() + toElemType := reflect.ValueOf(toObj) + toElem := toElemType + if toElemType.Kind() == reflect.Ptr { + toElem = toElemType.Elem() + } + if toElem == ZeroValue { return errors.New("to obj is not legal value") } @@ -196,7 +200,7 @@ func MapperMap(fromMap map[string]interface{}, toObj interface{}) error { } // MapperMapSlice mapper from map[string]map[string]interface{} to a slice of any type's ptr -// toSlice must be a slice of any type's ptr. +// toSlice must be a slice of any type. func MapperMapSlice(fromMaps map[string]map[string]interface{}, toSlice interface{}) error { var err error toValue := reflect.ValueOf(toSlice) @@ -208,16 +212,57 @@ func MapperMapSlice(fromMaps map[string]map[string]interface{}, toSlice interfac } toElemType := reflect.TypeOf(toSlice).Elem().Elem() - if toElemType.Kind() != reflect.Ptr { - return errors.New("slice elem must ptr ") - } - + realType := toElemType.Kind() direct := reflect.Indirect(toValue) //3 elem parse: 1.[]*type 2.*type 3.type - toElemType = toElemType.Elem() + if realType == reflect.Ptr { + toElemType = toElemType.Elem() + } for _, v := range fromMaps { elem := reflect.New(toElemType) err = MapperMap(v, elem.Interface()) + if err == nil { + if realType == reflect.Ptr { + direct.Set(reflect.Append(direct, elem)) + } else { + direct.Set(reflect.Append(direct, elem.Elem())) + } + } + } + return err +} + +// MapperSlice mapper from slice of struct to a slice of any type +// fromSlice and toSlice must be a slice of any type. +func MapperSlice(fromSlice, toSlice interface{}) error { + var err error + toValue := reflect.ValueOf(toSlice) + if toValue.Kind() != reflect.Ptr { + return errors.New("toSlice must pointer of slice") + } + if toValue.IsNil() { + return errors.New("toSlice must not nil pointer") + } + + elemType := reflect.TypeOf(toSlice).Elem().Elem() + realType := elemType.Kind() + direct := reflect.Indirect(toValue) + //3 elem parse: 1.[]*type 2.*type 3.type + if realType == reflect.Ptr { + elemType = elemType.Elem() + } + + fromElems := convertToSlice(fromSlice) + for _, v := range fromElems { + elem := reflect.New(elemType).Elem() + if realType == reflect.Ptr { + elem = reflect.New(elemType) + } + if realType == reflect.Ptr { + err = elemMapper(reflect.ValueOf(v).Elem(), elem.Elem()) + } else { + err = elemMapper(reflect.ValueOf(v), elem) + } if err == nil { direct.Set(reflect.Append(direct, elem)) } @@ -254,38 +299,6 @@ func Mapper(fromObj, toObj interface{}) error { return elemMapper(fromElem, toElem) } -// MapperSlice mapper from slice of struct to a slice of any type -// fromSlice and toSlice must be a slice of any type. -func MapperSlice(fromSlice, toSlice interface{}) error { - var err error - toValue := reflect.ValueOf(toSlice) - if toValue.Kind() != reflect.Ptr { - return errors.New("toSlice must pointer of slice") - } - if toValue.IsNil() { - return errors.New("toSlice must not nil pointer") - } - - elemType := reflect.TypeOf(toSlice).Elem().Elem() - if elemType.Kind() != reflect.Ptr { - return errors.New("slice elem must ptr ") - } - - direct := reflect.Indirect(toValue) - //3 elem parse: 1.[]*type 2.*type 3.type - elemType = elemType.Elem() - - fromElems := convertToSlice(fromSlice) - for _, v := range fromElems { - elem := reflect.New(elemType) - err = elemMapper(reflect.ValueOf(v).Elem(), elem.Elem()) - if err == nil { - direct.Set(reflect.Append(direct, elem)) - } - } - return err -} - // Mapper mapper and set value from struct fromObj to toObj // support auto register struct func AutoMapper(fromObj, toObj interface{}) error { diff --git a/mapper_test.go b/mapper_test.go index 5c8756e..88f79e9 100644 --- a/mapper_test.go +++ b/mapper_test.go @@ -127,6 +127,24 @@ func Test_MapperSlice(t *testing.T) { } } +func Test_MapperStructSlice(t *testing.T) { + SetEnabledTypeChecking(true) + var fromSlice []FromStruct + var toSlice []ToStruct + for i := 0; i < 10; i++ { + fromSlice = append(fromSlice, FromStruct{Name: "From" + strconv.Itoa(i), Sex: true, AA: "AA" + strconv.Itoa(i)}) + } + err := MapperSlice(fromSlice, &toSlice) + if err != nil { + t.Error(err) + } else { + t.Log(toSlice, len(toSlice)) + for _, v := range toSlice { + fmt.Println(v) + } + } +} + func BenchmarkMapperSlice(b *testing.B) { var fromSlice []*FromStruct var toSlice []*ToStruct @@ -182,6 +200,24 @@ func Test_MapperMapSlice(t *testing.T) { } else { t.Log(toSlice, len(toSlice)) } +} + +func Test_MapperStructMapSlice(t *testing.T) { + var toSlice []testStruct + fromMaps := make(map[string]map[string]interface{}) + for i := 0; i < 10; i++ { + fromMap := make(map[string]interface{}) + fromMap["Name"] = "s" + strconv.Itoa(i) + fromMap["Sex"] = true + fromMap["Age"] = i + fromMaps[strconv.Itoa(i)] = fromMap + } + err := MapperMapSlice(fromMaps, &toSlice) + if err != nil { + t.Error(err) + } else { + t.Log(toSlice, len(toSlice)) + } } diff --git a/version.md b/version.md index 16d8e27..6d6683f 100644 --- a/version.md +++ b/version.md @@ -1,5 +1,31 @@ ## devfeel/mapper +#### Version 0.7.2 +* New Feature: MapperSlice support ptr and struct +* New Feature: MapperMapSlice support ptr and struct +* Detail: + - now support two slice's element type is ptr or struct in MapperSlice + - now support slice's element type is ptr or struct in MapperMapSlice + - About MapperMapSlice: + ```golang + //view test code in mapper_test.go:Test_MapperSlice\Test_MapperStructSlice + //type ptr + var toSlice []*testStruct + //type struct + var toSlice []testStruct + ``` + - About MapperSlice: + ```golang + //view test code in mapper_test.go:Test_MapperMapSlice\Test_MapperStructMapSlice + //type ptr + var fromSlice []*FromStruct + var toSlice []*ToStruct + //type struct + var fromSlice []FromStruct + var toSlice []ToStruct + ``` +* 2019-11-03 16:00 in ShangHai + #### Version 0.7.1 * New Feature: Add TypeWrapper used to register custom Type Checker * New Feature: Add UseWrapper used to add your TypeWrapper