Skip to content

Commit

Permalink
Merge pull request #162 from XiXiangFiles/fix-issue-158
Browse files Browse the repository at this point in the history
Fix converter error do not apply
  • Loading branch information
jinzhu authored Jan 10, 2023
2 parents 6a4be2a + 81e15fe commit 71be026
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 22 deletions.
67 changes: 45 additions & 22 deletions copier.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,11 @@ func copier(toValue interface{}, fromValue interface{}, opt Option) (err error)

for _, k := range from.MapKeys() {
toKey := indirect(reflect.New(toType.Key()))
if !set(toKey, k, opt.DeepCopy, converters) {
isSet, err := set(toKey, k, opt.DeepCopy, converters)
if err != nil {
return err
}
if !isSet {
return fmt.Errorf("%w map, old key: %v, new key: %v", ErrNotSupported, k.Type(), toType.Key())
}

Expand All @@ -158,7 +162,11 @@ func copier(toValue interface{}, fromValue interface{}, opt Option) (err error)
elemType, _ = indirectType(elemType)
}
toValue := indirect(reflect.New(elemType))
if !set(toValue, from.MapIndex(k), opt.DeepCopy, converters) {
isSet, err = set(toValue, from.MapIndex(k), opt.DeepCopy, converters)
if err != nil {
return err
}
if !isSet {
if err = copier(toValue.Addr().Interface(), from.MapIndex(k).Interface(), opt); err != nil {
return err
}
Expand Down Expand Up @@ -186,8 +194,11 @@ func copier(toValue interface{}, fromValue interface{}, opt Option) (err error)
if to.Len() < i+1 {
to.Set(reflect.Append(to, reflect.New(to.Type().Elem()).Elem()))
}

if !set(to.Index(i), from.Index(i), opt.DeepCopy, converters) {
isSet, err := set(to.Index(i), from.Index(i), opt.DeepCopy, converters)
if err != nil {
return err
}
if !isSet {
// ignore error while copy slice element
err = copier(to.Index(i).Addr().Interface(), from.Index(i).Interface(), opt)
if err != nil {
Expand Down Expand Up @@ -292,7 +303,11 @@ func copier(toValue interface{}, fromValue interface{}, opt Option) (err error)
toField := dest.FieldByName(destFieldName)
if toField.IsValid() {
if toField.CanSet() {
if !set(toField, fromField, opt.DeepCopy, converters) {
isSet, err := set(toField, fromField, opt.DeepCopy, converters)
if err != nil {
return err
}
if !isSet {
if err := copier(toField.Addr().Interface(), fromField.Interface(), opt); err != nil {
return err
}
Expand Down Expand Up @@ -346,7 +361,11 @@ func copier(toValue interface{}, fromValue interface{}, opt Option) (err error)
if to.Len() < i+1 {
to.Set(reflect.Append(to, dest.Addr()))
} else {
if !set(to.Index(i), dest.Addr(), opt.DeepCopy, converters) {
isSet, err := set(to.Index(i), dest.Addr(), opt.DeepCopy, converters)
if err != nil {
return err
}
if !isSet {
// ignore error while copy slice element
err = copier(to.Index(i).Addr().Interface(), dest.Addr().Interface(), opt)
if err != nil {
Expand All @@ -358,7 +377,11 @@ func copier(toValue interface{}, fromValue interface{}, opt Option) (err error)
if to.Len() < i+1 {
to.Set(reflect.Append(to, dest))
} else {
if !set(to.Index(i), dest, opt.DeepCopy, converters) {
isSet, err := set(to.Index(i), dest, opt.DeepCopy, converters)
if err != nil {
return err
}
if !isSet {
// ignore error while copy slice element
err = copier(to.Index(i).Addr().Interface(), dest.Interface(), opt)
if err != nil {
Expand Down Expand Up @@ -450,32 +473,32 @@ func indirectType(reflectType reflect.Type) (_ reflect.Type, isPtr bool) {
return reflectType, isPtr
}

func set(to, from reflect.Value, deepCopy bool, converters map[converterPair]TypeConverter) bool {
func set(to, from reflect.Value, deepCopy bool, converters map[converterPair]TypeConverter) (bool, error) {
if !from.IsValid() {
return true
return true, nil
}
if ok, err := lookupAndCopyWithConverter(to, from, converters); err != nil {
return false
return false, err
} else if ok {
return true
return true, nil
}

if to.Kind() == reflect.Ptr {
// set `to` to nil if from is nil
if from.Kind() == reflect.Ptr && from.IsNil() {
to.Set(reflect.Zero(to.Type()))
return true
return true, nil
} else if to.IsNil() {
// `from` -> `to`
// sql.NullString -> *string
if fromValuer, ok := driverValuer(from); ok {
v, err := fromValuer.Value()
if err != nil {
return false
return true, nil
}
// if `from` is not valid do nothing with `to`
if v == nil {
return true
return true, nil
}
}
// allocate new `to` variable with default value (eg. *string -> new(string))
Expand All @@ -494,10 +517,10 @@ func set(to, from reflect.Value, deepCopy bool, converters map[converterPair]Typ
}
}
if from.Kind() == reflect.Ptr && from.IsNil() {
return true
return true, nil
}
if toKind == reflect.Struct || toKind == reflect.Map || toKind == reflect.Slice {
return false
return false, nil
}
}

Expand All @@ -509,7 +532,7 @@ func set(to, from reflect.Value, deepCopy bool, converters map[converterPair]Typ
if from.Kind() == reflect.Ptr {
// if `from` is nil do nothing with `to`
if from.IsNil() {
return true
return true, nil
}
// depointer `from`
from = indirect(from)
Expand All @@ -519,18 +542,18 @@ func set(to, from reflect.Value, deepCopy bool, converters map[converterPair]Typ
// set `to` by invoking method Scan(`from`)
err := toScanner.Scan(from.Interface())
if err != nil {
return false
return false, nil
}
} else if fromValuer, ok := driverValuer(from); ok {
// `from` -> `to`
// sql.NullString -> string
v, err := fromValuer.Value()
if err != nil {
return false
return false, nil
}
// if `from` is not valid do nothing with `to`
if v == nil {
return true
return true, nil
}
rv := reflect.ValueOf(v)
if rv.Type().AssignableTo(to.Type()) {
Expand All @@ -541,10 +564,10 @@ func set(to, from reflect.Value, deepCopy bool, converters map[converterPair]Typ
} else if from.Kind() == reflect.Ptr {
return set(to, from.Elem(), deepCopy, converters)
} else {
return false
return false, nil
}

return true
return true, nil
}

// lookupAndCopyWithConverter looks up the type pair, on success the TypeConverter Fn func is called to copy src to dst field.
Expand Down
36 changes: 36 additions & 0 deletions copier_converter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,3 +182,39 @@ func TestCopyWithConverterStrToStrPointer(t *testing.T) {
t.Fatalf("got %q, wanted nil", *dst.Field1)
}
}

func TestCopyWithConverterRaisingError(t *testing.T) {
type SrcStruct struct {
Field1 string
}

type DestStruct struct {
Field1 *string
}

src := SrcStruct{
Field1: "",
}

var dst DestStruct

ptrStrType := ""

err := copier.CopyWithOption(&dst, &src, copier.Option{
IgnoreEmpty: false,
DeepCopy: true,
Converters: []copier.TypeConverter{
{
SrcType: copier.String,
DstType: &ptrStrType,
Fn: func(src interface{}) (interface{}, error) {
return nil, errors.New("src type not matching")
},
},
},
})
if err == nil {
t.Fatalf(`Should be raising an error.`)
return
}
}

0 comments on commit 71be026

Please sign in to comment.