From e686e7189c9361fe219b778ab347a0e88d658610 Mon Sep 17 00:00:00 2001 From: Bobo Date: Thu, 22 May 2025 10:53:04 +0800 Subject: [PATCH] feat: copier util --- copierutil/converters.go | 28 +++++- copierutil/converters_test.go | 167 +++++++++++++++++----------------- copierutil/go.mod | 12 ++- copierutil/go.sum | 10 ++ tag.bat | 2 +- 5 files changed, 130 insertions(+), 89 deletions(-) diff --git a/copierutil/converters.go b/copierutil/converters.go index 9723a6e..e36c296 100644 --- a/copierutil/converters.go +++ b/copierutil/converters.go @@ -42,7 +42,27 @@ var TimestamppbToTimeConverter = copier.TypeConverter{ }, } -func MakeTypeConverter(srcType, dstType interface{}, fn func(src interface{}) (interface{}, error)) copier.TypeConverter { +func NewTimeStringConverterPair() []copier.TypeConverter { + srcType := &time.Time{} + dstType := trans.Ptr("") + + fromFn := timeutil.TimeToTimeString + toFn := timeutil.StringTimeToTime + + return NewGenericTypeConverterPair(srcType, dstType, fromFn, toFn) +} + +func NewTimeTimestamppbConverterPair() []copier.TypeConverter { + srcType := &time.Time{} + dstType := ×tamppb.Timestamp{} + + fromFn := timeutil.TimeToTimestamppb + toFn := timeutil.TimestamppbToTime + + return NewGenericTypeConverterPair(srcType, dstType, fromFn, toFn) +} + +func NewTypeConverter(srcType, dstType interface{}, fn func(src interface{}) (interface{}, error)) copier.TypeConverter { return copier.TypeConverter{ SrcType: srcType, DstType: dstType, @@ -50,7 +70,7 @@ func MakeTypeConverter(srcType, dstType interface{}, fn func(src interface{}) (i } } -func MakeTypeConverterPair(srcType, dstType interface{}, fromFn, toFn func(src interface{}) (interface{}, error)) []copier.TypeConverter { +func NewTypeConverterPair(srcType, dstType interface{}, fromFn, toFn func(src interface{}) (interface{}, error)) []copier.TypeConverter { return []copier.TypeConverter{ { SrcType: srcType, @@ -65,7 +85,7 @@ func MakeTypeConverterPair(srcType, dstType interface{}, fromFn, toFn func(src i } } -func MakeGenericTypeConverterPair[A interface{}, B interface{}](srcType A, dstType B, fromFn func(src A) B, toFn func(src B) A) []copier.TypeConverter { +func NewGenericTypeConverterPair[A interface{}, B interface{}](srcType A, dstType B, fromFn func(src A) B, toFn func(src B) A) []copier.TypeConverter { return []copier.TypeConverter{ { SrcType: srcType, @@ -84,7 +104,7 @@ func MakeGenericTypeConverterPair[A interface{}, B interface{}](srcType A, dstTy } } -func MakeErrorHandlingTypeConverterPair[A interface{}, B interface{}](srcType A, dstType B, fromFn func(src A) (B, error), toFn func(src B) (A, error)) []copier.TypeConverter { +func NewErrorHandlingGenericTypeConverterPair[A interface{}, B interface{}](srcType A, dstType B, fromFn func(src A) (B, error), toFn func(src B) (A, error)) []copier.TypeConverter { return []copier.TypeConverter{ { SrcType: srcType, diff --git a/copierutil/converters_test.go b/copierutil/converters_test.go index defeece..5c4d89b 100644 --- a/copierutil/converters_test.go +++ b/copierutil/converters_test.go @@ -4,35 +4,33 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "google.golang.org/protobuf/types/known/timestamppb" + "github.com/tx7do/go-utils/timeutil" "github.com/tx7do/go-utils/trans" ) -func TestMakeTypeConverter(t *testing.T) { +func TestNewTypeConverter(t *testing.T) { srcType := &time.Time{} dstType := trans.Ptr("") fn := func(src interface{}) (interface{}, error) { return timeutil.TimeToTimeString(src.(*time.Time)), nil } - converter := MakeTypeConverter(srcType, dstType, fn) + converter := NewTypeConverter(srcType, dstType, fn) // 验证转换器的类型 - if converter.SrcType != srcType || converter.DstType != dstType { - t.Errorf("converter types mismatch") - } + assert.IsType(t, srcType, converter.SrcType) + assert.IsType(t, dstType, converter.DstType) // 验证转换器的功能 result, err := converter.Fn(&time.Time{}) - if err != nil { - t.Errorf("converter function failed: %v", err) - } - if _, ok := result.(*string); !ok { - t.Errorf("converter result type mismatch") - } + assert.NoError(t, err) + assert.IsType(t, dstType, result) } -func TestMakeTypeConverterPair(t *testing.T) { +func TestNewTypeConverterPair(t *testing.T) { srcType := &time.Time{} dstType := trans.Ptr("") fromFn := func(src interface{}) (interface{}, error) { @@ -42,75 +40,49 @@ func TestMakeTypeConverterPair(t *testing.T) { return timeutil.StringTimeToTime(src.(*string)), nil } - converters := MakeTypeConverterPair(srcType, dstType, fromFn, toFn) - - if len(converters) != 2 { - t.Fatalf("expected 2 converters, got %d", len(converters)) - } + converters := NewTypeConverterPair(srcType, dstType, fromFn, toFn) + assert.Len(t, converters, 2, "expected 2 converters") // 验证第一个转换器 - if converters[0].SrcType != srcType || converters[0].DstType != dstType { - t.Errorf("first converter types mismatch") - } + assert.IsType(t, srcType, converters[0].SrcType) + assert.IsType(t, dstType, converters[0].DstType) result, err := converters[0].Fn(&time.Time{}) - if err != nil { - t.Errorf("first converter function failed: %v", err) - } - if _, ok := result.(*string); !ok { - t.Errorf("first converter result type mismatch") - } + assert.NoError(t, err) + assert.IsType(t, dstType, result) // 验证第二个转换器 - if converters[1].SrcType != dstType || converters[1].DstType != srcType { - t.Errorf("second converter types mismatch") - } + assert.IsType(t, dstType, converters[1].SrcType) + assert.IsType(t, srcType, converters[1].DstType) result, err = converters[1].Fn(trans.Ptr("")) - if err != nil { - t.Errorf("second converter function failed: %v", err) - } - if _, ok := result.(*time.Time); !ok { - t.Errorf("second converter result type mismatch") - } + assert.NoError(t, err) + assert.IsType(t, srcType, result) } -func TestMakeGenericTypeConverterPair(t *testing.T) { +func TestNewGenericTypeConverterPair(t *testing.T) { srcType := &time.Time{} dstType := trans.Ptr("") fromFn := timeutil.TimeToTimeString toFn := timeutil.StringTimeToTime - converters := MakeGenericTypeConverterPair(srcType, dstType, fromFn, toFn) - - if len(converters) != 2 { - t.Fatalf("expected 2 converters, got %d", len(converters)) - } + converters := NewGenericTypeConverterPair(srcType, dstType, fromFn, toFn) + assert.Len(t, converters, 2, "expected 2 converters") // 验证第一个转换器 - if converters[0].SrcType != srcType || converters[0].DstType != dstType { - t.Errorf("first converter types mismatch") - } + assert.IsType(t, srcType, converters[0].SrcType) + assert.IsType(t, dstType, converters[0].DstType) result, err := converters[0].Fn(&time.Time{}) - if err != nil { - t.Errorf("first converter function failed: %v", err) - } - if _, ok := result.(*string); !ok { - t.Errorf("first converter result type mismatch") - } + assert.NoError(t, err) + assert.IsType(t, dstType, result) // 验证第二个转换器 - if converters[1].SrcType != dstType || converters[1].DstType != srcType { - t.Errorf("second converter types mismatch") - } + assert.IsType(t, dstType, converters[1].SrcType) + assert.IsType(t, srcType, converters[1].DstType) result, err = converters[1].Fn(trans.Ptr("")) - if err != nil { - t.Errorf("second converter function failed: %v", err) - } - if _, ok := result.(*time.Time); !ok { - t.Errorf("second converter result type mismatch") - } + assert.NoError(t, err) + assert.IsType(t, srcType, result) } -func TestMakeErrorHandlingTypeConverterPair(t *testing.T) { +func TestNewErrorHandlingGenericTypeConverterPair(t *testing.T) { srcType := &time.Time{} dstType := trans.Ptr("") fromFn := func(src *time.Time) (*string, error) { @@ -120,33 +92,62 @@ func TestMakeErrorHandlingTypeConverterPair(t *testing.T) { return timeutil.StringTimeToTime(src), nil } - converters := MakeErrorHandlingTypeConverterPair(srcType, dstType, fromFn, toFn) - - if len(converters) != 2 { - t.Fatalf("expected 2 converters, got %d", len(converters)) - } + converters := NewErrorHandlingGenericTypeConverterPair(srcType, dstType, fromFn, toFn) + assert.Len(t, converters, 2, "expected 2 converters") // 验证第一个转换器 - if converters[0].SrcType != srcType || converters[0].DstType != dstType { - t.Errorf("first converter types mismatch") - } + assert.IsType(t, srcType, converters[0].SrcType) + assert.IsType(t, dstType, converters[0].DstType) result, err := converters[0].Fn(&time.Time{}) - if err != nil { - t.Errorf("first converter function failed: %v", err) - } - if _, ok := result.(*string); !ok { - t.Errorf("first converter result type mismatch") - } + assert.NoError(t, err) + assert.IsType(t, dstType, result) // 验证第二个转换器 - if converters[1].SrcType != dstType || converters[1].DstType != srcType { - t.Errorf("second converter types mismatch") - } + assert.IsType(t, dstType, converters[1].SrcType) + assert.IsType(t, srcType, converters[1].DstType) result, err = converters[1].Fn(trans.Ptr("")) - if err != nil { - t.Errorf("second converter function failed: %v", err) - } - if _, ok := result.(*time.Time); !ok { - t.Errorf("second converter result type mismatch") - } + assert.NoError(t, err) + assert.IsType(t, srcType, result) +} + +func TestNewTimeStringConverterPair(t *testing.T) { + converters := NewTimeStringConverterPair() + assert.Len(t, converters, 2, "expected 2 converters") + + // 验证第一个转换器 + srcType := &time.Time{} + dstType := trans.Ptr("") + assert.IsType(t, srcType, converters[0].SrcType) + assert.IsType(t, dstType, converters[0].DstType) + result, err := converters[0].Fn(&time.Time{}) + assert.NoError(t, err) + assert.IsType(t, dstType, result) + + // 验证第二个转换器 + assert.IsType(t, dstType, converters[1].SrcType) + assert.IsType(t, srcType, converters[1].DstType) + result, err = converters[1].Fn(trans.Ptr("")) + assert.NoError(t, err) + assert.IsType(t, srcType, result) +} + +func TestNewTimeTimestamppbConverterPair(t *testing.T) { + converters := NewTimeTimestamppbConverterPair() + assert.Len(t, converters, 2, "expected 2 converters") + + // 验证第一个转换器 + srcType := &time.Time{} + dstType := ×tamppb.Timestamp{} + assert.IsType(t, srcType, converters[0].SrcType) + assert.IsType(t, dstType, converters[0].DstType) + result, err := converters[0].Fn(&time.Time{}) + assert.NoError(t, err) + assert.IsType(t, dstType, result) + + // 验证第二个转换器 + assert.IsType(t, dstType, converters[1].SrcType) + assert.IsType(t, srcType, converters[1].DstType) + result, err = converters[1].Fn(×tamppb.Timestamp{}) + assert.NoError(t, err) + assert.IsType(t, srcType, result) } diff --git a/copierutil/go.mod b/copierutil/go.mod index 613bb7d..39b8618 100644 --- a/copierutil/go.mod +++ b/copierutil/go.mod @@ -9,6 +9,16 @@ require ( github.com/tx7do/go-utils v1.1.22 ) -require google.golang.org/protobuf v1.36.6 +require ( + github.com/stretchr/testify v1.10.0 + google.golang.org/protobuf v1.36.6 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) replace github.com/tx7do/go-utils => ../ diff --git a/copierutil/go.sum b/copierutil/go.sum index 74f9dee..8d18b7e 100644 --- a/copierutil/go.sum +++ b/copierutil/go.sum @@ -1,16 +1,26 @@ +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tag.bat b/tag.bat index e165364..3029d1c 100644 --- a/tag.bat +++ b/tag.bat @@ -3,7 +3,7 @@ git tag v1.1.22 git tag bank_card/v1.1.5 git tag geoip/v1.1.5 git tag translator/v1.1.2 -git tag copierutil/v0.0.2 +git tag copierutil/v0.0.3 git tag entgo/v1.1.28 git tag gorm/v1.1.6