From 71d7442196677f8e70255f12fa5a67eea3b6449b Mon Sep 17 00:00:00 2001 From: "jerry.wang" Date: Sun, 19 Nov 2023 00:34:56 +0800 Subject: [PATCH] feat: if err occur, dst will recover to init --- copier.go | 9 +++++++ copier_test.go | 68 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/copier.go b/copier.go index 43a14f1..836ce44 100644 --- a/copier.go +++ b/copier.go @@ -136,6 +136,15 @@ func copier(toValue interface{}, fromValue interface{}, opt Option) (err error) return ErrInvalidCopyFrom } + cacheToValue := indirect(reflect.New(to.Type())) + cacheToValue.Set(to) + defer func() { + // if err occur, toValue needs to recover to init state. + if err != nil { + to.Set(cacheToValue) + } + }() + fromType, isPtrFrom := indirectType(from.Type()) toType, _ := indirectType(to.Type()) diff --git a/copier_test.go b/copier_test.go index 4769eba..fd085da 100644 --- a/copier_test.go +++ b/copier_test.go @@ -1665,7 +1665,6 @@ func TestDeepCopyAnonymousFieldTime(t *testing.T) { } func TestSqlNullFiled(t *testing.T) { - type sqlStruct struct { MkId sql.NullInt64 MkExpiryDateType sql.NullInt32 @@ -1762,3 +1761,70 @@ func TestNestedNilPointerStruct(t *testing.T) { t.Errorf("to (%v) value should equal from (%v) value", to.Title, from.Title) } } + +func TestOccurErr(t *testing.T) { + t.Run("CopyWithOption err occur", func(t *testing.T) { + type srcTags struct { + Field string + Index int + } + type destTags struct { + Field string + Index string + } + + dst := &destTags{ + Field: "init", + Index: "0", + } + src := &srcTags{ + Field: "copied", + Index: 1, + } + err := copier.CopyWithOption(dst, src, copier.Option{ + Converters: []copier.TypeConverter{ + { + SrcType: 1, + DstType: "", + Fn: func(src interface{}) (dst interface{}, err error) { + return nil, fmt.Errorf("return err") + }, + }, + }, + }) + if err == nil { + t.Errorf("should return err") + } + if dst.Field != "init" || dst.Index != "0" { + t.Error("when err occur, the dst should be init") + } + + }) + t.Run("copy err occur", func(t *testing.T) { + type srcTags struct { + field string + Field2 string + } + + type destTags struct { + Field string `copier:"field"` + Field2 string `copier:"Field2"` + } + + dst := &destTags{ + Field: "init", + Field2: "init2", + } + src := &srcTags{ + field: "Field1->Field1", + Field2: "Field2->Field2", + } + err := copier.Copy(dst, src) + if err == nil { + t.Errorf("should return err") + } + if dst.Field != "init" || dst.Field2 != "init2" { + t.Error("when err occur, the dst should be init") + } + }) +}