From da3e2f3afa4e87513be1d83c5b649ef920c9ebd3 Mon Sep 17 00:00:00 2001 From: zhuyasen Date: Wed, 28 May 2025 20:15:12 +0800 Subject: [PATCH] feat: custom copier library --- .../initial/initApp.go | 3 +- cmd/sponge/commands/root.go | 8 +- internal/handler/userExample.go | 2 +- internal/handler/userExample.go.exp | 2 +- internal/handler/userExample.go.exp.tpl | 2 +- internal/handler/userExample.go.mgo | 2 +- internal/handler/userExample.go.mgo.exp | 2 +- internal/handler/userExample.go.tpl | 2 +- internal/handler/userExample_logic.go | 12 +- internal/handler/userExample_logic.go.exp | 12 +- internal/handler/userExample_logic.go.exp.tpl | 12 +- internal/handler/userExample_logic.go.mgo | 11 +- internal/handler/userExample_logic.go.mgo.exp | 11 +- internal/handler/userExample_logic.go.tpl | 12 +- internal/handler/userExample_logic_test.go | 2 +- .../handler/userExample_logic_test.go.exp | 2 +- internal/handler/userExample_test.go | 2 +- internal/handler/userExample_test.go.exp | 2 +- internal/service/userExample.go | 11 +- internal/service/userExample.go.exp | 11 +- internal/service/userExample.go.exp.tpl | 11 +- internal/service/userExample.go.mgo | 10 +- internal/service/userExample.go.mgo.exp | 10 +- internal/service/userExample.go.tpl | 11 +- internal/service/userExample_test.go | 2 +- pkg/copier/README.md | 56 ++ pkg/copier/copy.go | 92 ++++ pkg/copier/copy_test.go | 478 ++++++++++++++++++ 28 files changed, 680 insertions(+), 113 deletions(-) create mode 100644 pkg/copier/README.md create mode 100644 pkg/copier/copy.go create mode 100644 pkg/copier/copy_test.go diff --git a/cmd/serverNameExample_mixExample/initial/initApp.go b/cmd/serverNameExample_mixExample/initial/initApp.go index df0d64b..9548a23 100644 --- a/cmd/serverNameExample_mixExample/initial/initApp.go +++ b/cmd/serverNameExample_mixExample/initial/initApp.go @@ -8,9 +8,8 @@ import ( "fmt" "strconv" - "github.com/jinzhu/copier" - "github.com/go-dev-frame/sponge/pkg/conf" + "github.com/go-dev-frame/sponge/pkg/copier" "github.com/go-dev-frame/sponge/pkg/logger" "github.com/go-dev-frame/sponge/pkg/nacoscli" "github.com/go-dev-frame/sponge/pkg/stat" diff --git a/cmd/sponge/commands/root.go b/cmd/sponge/commands/root.go index c84dca8..624c770 100644 --- a/cmd/sponge/commands/root.go +++ b/cmd/sponge/commands/root.go @@ -20,9 +20,13 @@ var ( func NewRootCMD() *cobra.Command { cmd := &cobra.Command{ Use: "sponge", - Long: fmt.Sprintf(`Sponge is a powerful Go development framework, it's easy to develop web and microservice projects. + Long: fmt.Sprintf(` +A powerful and easy-to-use Go development framework that enables you to effortlessly +build stable, reliable, and high-performance backend services with a "low-code" approach. Repo: %s -Docs: %s`, color.HiCyanString("https://github.com/go-dev-frame/sponge"), color.HiCyanString("https://go-sponge.com")), +Docs: %s`, + color.HiCyanString("https://github.com/go-dev-frame/sponge"), + color.HiCyanString("https://go-sponge.com")), SilenceErrors: true, SilenceUsage: true, Version: getVersion(), diff --git a/internal/handler/userExample.go b/internal/handler/userExample.go index f48d56a..7456258 100644 --- a/internal/handler/userExample.go +++ b/internal/handler/userExample.go @@ -4,8 +4,8 @@ import ( "errors" "github.com/gin-gonic/gin" - "github.com/jinzhu/copier" + "github.com/go-dev-frame/sponge/pkg/copier" "github.com/go-dev-frame/sponge/pkg/gin/middleware" "github.com/go-dev-frame/sponge/pkg/gin/response" "github.com/go-dev-frame/sponge/pkg/logger" diff --git a/internal/handler/userExample.go.exp b/internal/handler/userExample.go.exp index 5832eef..2b427c4 100644 --- a/internal/handler/userExample.go.exp +++ b/internal/handler/userExample.go.exp @@ -5,8 +5,8 @@ import ( "math" "github.com/gin-gonic/gin" - "github.com/jinzhu/copier" + "github.com/go-dev-frame/sponge/pkg/copier" "github.com/go-dev-frame/sponge/pkg/gin/middleware" "github.com/go-dev-frame/sponge/pkg/gin/response" "github.com/go-dev-frame/sponge/pkg/logger" diff --git a/internal/handler/userExample.go.exp.tpl b/internal/handler/userExample.go.exp.tpl index a479173..70501e4 100644 --- a/internal/handler/userExample.go.exp.tpl +++ b/internal/handler/userExample.go.exp.tpl @@ -5,8 +5,8 @@ import ( "math" "github.com/gin-gonic/gin" - "github.com/jinzhu/copier" + "github.com/go-dev-frame/sponge/pkg/copier" "github.com/go-dev-frame/sponge/pkg/gin/middleware" "github.com/go-dev-frame/sponge/pkg/gin/response" "github.com/go-dev-frame/sponge/pkg/logger" diff --git a/internal/handler/userExample.go.mgo b/internal/handler/userExample.go.mgo index 7338a5e..6d9d910 100644 --- a/internal/handler/userExample.go.mgo +++ b/internal/handler/userExample.go.mgo @@ -4,8 +4,8 @@ import ( "errors" "github.com/gin-gonic/gin" - "github.com/jinzhu/copier" + "github.com/go-dev-frame/sponge/pkg/copier" "github.com/go-dev-frame/sponge/pkg/gin/middleware" "github.com/go-dev-frame/sponge/pkg/gin/response" "github.com/go-dev-frame/sponge/pkg/logger" diff --git a/internal/handler/userExample.go.mgo.exp b/internal/handler/userExample.go.mgo.exp index 5adf085..06c86ec 100644 --- a/internal/handler/userExample.go.mgo.exp +++ b/internal/handler/userExample.go.mgo.exp @@ -4,8 +4,8 @@ import ( "errors" "github.com/gin-gonic/gin" - "github.com/jinzhu/copier" + "github.com/go-dev-frame/sponge/pkg/copier" "github.com/go-dev-frame/sponge/pkg/gin/middleware" "github.com/go-dev-frame/sponge/pkg/gin/response" "github.com/go-dev-frame/sponge/pkg/logger" diff --git a/internal/handler/userExample.go.tpl b/internal/handler/userExample.go.tpl index 631a1f0..79f062f 100644 --- a/internal/handler/userExample.go.tpl +++ b/internal/handler/userExample.go.tpl @@ -4,8 +4,8 @@ import ( "errors" "github.com/gin-gonic/gin" - "github.com/jinzhu/copier" + "github.com/go-dev-frame/sponge/pkg/copier" "github.com/go-dev-frame/sponge/pkg/gin/middleware" "github.com/go-dev-frame/sponge/pkg/gin/response" "github.com/go-dev-frame/sponge/pkg/logger" diff --git a/internal/handler/userExample_logic.go b/internal/handler/userExample_logic.go index 1a50457..e5cbdcd 100644 --- a/internal/handler/userExample_logic.go +++ b/internal/handler/userExample_logic.go @@ -6,8 +6,7 @@ import ( "strings" "time" - "github.com/jinzhu/copier" - + "github.com/go-dev-frame/sponge/pkg/copier" "github.com/go-dev-frame/sponge/pkg/gin/middleware" "github.com/go-dev-frame/sponge/pkg/logger" "github.com/go-dev-frame/sponge/pkg/sgorm/query" @@ -179,12 +178,7 @@ func convertUserExamplePb(record *model.UserExample) (*serverNameExampleV1.UserE if err != nil { return nil, err } - // Note: if copier.Copy cannot assign a value to a field, add it here, e.g. CreatedAt, UpdatedAt - value.Id = record.ID - // todo generate the conversion createdAt and updatedAt code here - // delete the templates code start - value.CreatedAt = record.CreatedAt.Format(time.RFC3339) - value.UpdatedAt = record.UpdatedAt.Format(time.RFC3339) - // delete the templates code end + // Note: if copier.Copy cannot assign a value to a field, add it here + return value, nil } diff --git a/internal/handler/userExample_logic.go.exp b/internal/handler/userExample_logic.go.exp index 8c50124..61d0279 100644 --- a/internal/handler/userExample_logic.go.exp +++ b/internal/handler/userExample_logic.go.exp @@ -7,8 +7,7 @@ import ( "strings" "time" - "github.com/jinzhu/copier" - + "github.com/go-dev-frame/sponge/pkg/copier" "github.com/go-dev-frame/sponge/pkg/sgorm/query" "github.com/go-dev-frame/sponge/pkg/gin/middleware" "github.com/go-dev-frame/sponge/pkg/logger" @@ -301,12 +300,7 @@ func convertUserExamplePb(record *model.UserExample) (*serverNameExampleV1.UserE if err != nil { return nil, err } - // Note: if copier.Copy cannot assign a value to a field, add it here, e.g. CreatedAt, UpdatedAt - value.Id = record.ID - // todo generate the conversion createdAt and updatedAt code here - // delete the templates code start - value.CreatedAt = record.CreatedAt.Format(time.RFC3339) - value.UpdatedAt = record.UpdatedAt.Format(time.RFC3339) - // delete the templates code end + // Note: if copier.Copy cannot assign a value to a field, add it here + return value, nil } diff --git a/internal/handler/userExample_logic.go.exp.tpl b/internal/handler/userExample_logic.go.exp.tpl index 430f74f..7c597e7 100644 --- a/internal/handler/userExample_logic.go.exp.tpl +++ b/internal/handler/userExample_logic.go.exp.tpl @@ -7,8 +7,7 @@ import ( "strings" "time" - "github.com/jinzhu/copier" - + "github.com/go-dev-frame/sponge/pkg/copier" "github.com/go-dev-frame/sponge/pkg/sgorm/query" "github.com/go-dev-frame/sponge/pkg/gin/middleware" "github.com/go-dev-frame/sponge/pkg/logger" @@ -304,12 +303,7 @@ func convert{{.TableNameCamel}}Pb(record *model.{{.TableNameCamel}}) (*serverNam if err != nil { return nil, err } - // Note: if copier.Copy cannot assign a value to a field, add it here, e.g. CreatedAt, UpdatedAt - value.{{if .IsStandardPrimaryKey}}Id{{else}}{{.ColumnNameCamel}}{{end}} = record.{{.ColumnNameCamel}} - // todo generate the conversion createdAt and updatedAt code here - // delete the templates code start - value.CreatedAt = record.CreatedAt.Format(time.RFC3339) - value.UpdatedAt = record.UpdatedAt.Format(time.RFC3339) - // delete the templates code end + // Note: if copier.Copy cannot assign a value to a field, add it here + return value, nil } diff --git a/internal/handler/userExample_logic.go.mgo b/internal/handler/userExample_logic.go.mgo index 422a352..3c12882 100644 --- a/internal/handler/userExample_logic.go.mgo +++ b/internal/handler/userExample_logic.go.mgo @@ -6,8 +6,7 @@ import ( "strings" "time" - "github.com/jinzhu/copier" - + "github.com/go-dev-frame/sponge/pkg/copier" "github.com/go-dev-frame/sponge/pkg/gin/middleware" "github.com/go-dev-frame/sponge/pkg/logger" "github.com/go-dev-frame/sponge/pkg/mgo/query" @@ -180,12 +179,8 @@ func convertUserExamplePb(record *model.UserExample) (*serverNameExampleV1.UserE if err != nil { return nil, err } - // Note: if copier.Copy cannot assign a value to a field, add it here, e.g. CreatedAt, UpdatedAt + // Note: if copier.Copy cannot assign a value to a field, add it here value.Id = record.ID.Hex() - // todo generate the conversion createdAt and updatedAt code here - // delete the templates code start - value.CreatedAt = record.CreatedAt.Format(time.RFC3339) - value.UpdatedAt = record.UpdatedAt.Format(time.RFC3339) - // delete the templates code end + return value, nil } diff --git a/internal/handler/userExample_logic.go.mgo.exp b/internal/handler/userExample_logic.go.mgo.exp index a36a348..1a943df 100644 --- a/internal/handler/userExample_logic.go.mgo.exp +++ b/internal/handler/userExample_logic.go.mgo.exp @@ -6,8 +6,7 @@ import ( "strings" "time" - "github.com/jinzhu/copier" - + "github.com/go-dev-frame/sponge/pkg/copier" "github.com/go-dev-frame/sponge/pkg/gin/middleware" "github.com/go-dev-frame/sponge/pkg/logger" "github.com/go-dev-frame/sponge/pkg/mgo/query" @@ -301,12 +300,8 @@ func convertUserExamplePb(record *model.UserExample) (*serverNameExampleV1.UserE if err != nil { return nil, err } - // Note: if copier.Copy cannot assign a value to a field, add it here, e.g. CreatedAt, UpdatedAt + // Note: if copier.Copy cannot assign a value to a field, add it here value.Id = record.ID.Hex() - // todo generate the conversion createdAt and updatedAt code here - // delete the templates code start - value.CreatedAt = record.CreatedAt.Format(time.RFC3339) - value.UpdatedAt = record.UpdatedAt.Format(time.RFC3339) - // delete the templates code end + return value, nil } diff --git a/internal/handler/userExample_logic.go.tpl b/internal/handler/userExample_logic.go.tpl index 903bb69..466c05d 100644 --- a/internal/handler/userExample_logic.go.tpl +++ b/internal/handler/userExample_logic.go.tpl @@ -6,8 +6,7 @@ import ( "strings" "time" - "github.com/jinzhu/copier" - + "github.com/go-dev-frame/sponge/pkg/copier" "github.com/go-dev-frame/sponge/pkg/sgorm/query" "github.com/go-dev-frame/sponge/pkg/gin/middleware" "github.com/go-dev-frame/sponge/pkg/logger" @@ -179,12 +178,7 @@ func convert{{.TableNameCamel}}Pb(record *model.{{.TableNameCamel}}) (*serverNam if err != nil { return nil, err } - // Note: if copier.Copy cannot assign a value to a field, add it here, e.g. CreatedAt, UpdatedAt - value.{{if .IsStandardPrimaryKey}}Id{{else}}{{.ColumnNameCamel}}{{end}} = record.{{.ColumnNameCamel}} - // todo generate the conversion createdAt and updatedAt code here - // delete the templates code start - value.CreatedAt = record.CreatedAt.Format(time.RFC3339) - value.UpdatedAt = record.UpdatedAt.Format(time.RFC3339) - // delete the templates code end + // Note: if copier.Copy cannot assign a value to a field, add it here + return value, nil } diff --git a/internal/handler/userExample_logic_test.go b/internal/handler/userExample_logic_test.go index 9387b18..bddc8ac 100644 --- a/internal/handler/userExample_logic_test.go +++ b/internal/handler/userExample_logic_test.go @@ -8,9 +8,9 @@ import ( "github.com/DATA-DOG/go-sqlmock" "github.com/gin-gonic/gin" "github.com/go-dev-frame/sponge/api/types" - "github.com/jinzhu/copier" "github.com/stretchr/testify/assert" + "github.com/go-dev-frame/sponge/pkg/copier" "github.com/go-dev-frame/sponge/pkg/gin/response" "github.com/go-dev-frame/sponge/pkg/gotest" "github.com/go-dev-frame/sponge/pkg/httpcli" diff --git a/internal/handler/userExample_logic_test.go.exp b/internal/handler/userExample_logic_test.go.exp index b5a84b0..1c93400 100644 --- a/internal/handler/userExample_logic_test.go.exp +++ b/internal/handler/userExample_logic_test.go.exp @@ -7,10 +7,10 @@ import ( "github.com/DATA-DOG/go-sqlmock" "github.com/gin-gonic/gin" - "github.com/jinzhu/copier" "github.com/stretchr/testify/assert" "github.com/go-dev-frame/sponge/api/types" + "github.com/go-dev-frame/sponge/pkg/copier" "github.com/go-dev-frame/sponge/pkg/gin/response" "github.com/go-dev-frame/sponge/pkg/httpcli" "github.com/go-dev-frame/sponge/pkg/gotest" diff --git a/internal/handler/userExample_test.go b/internal/handler/userExample_test.go index 432bb8e..f90c133 100644 --- a/internal/handler/userExample_test.go +++ b/internal/handler/userExample_test.go @@ -6,9 +6,9 @@ import ( "time" "github.com/DATA-DOG/go-sqlmock" - "github.com/jinzhu/copier" "github.com/stretchr/testify/assert" + "github.com/go-dev-frame/sponge/pkg/copier" "github.com/go-dev-frame/sponge/pkg/gotest" "github.com/go-dev-frame/sponge/pkg/httpcli" "github.com/go-dev-frame/sponge/pkg/sgorm/query" diff --git a/internal/handler/userExample_test.go.exp b/internal/handler/userExample_test.go.exp index 9f3e645..34aba8b 100644 --- a/internal/handler/userExample_test.go.exp +++ b/internal/handler/userExample_test.go.exp @@ -6,9 +6,9 @@ import ( "time" "github.com/DATA-DOG/go-sqlmock" - "github.com/jinzhu/copier" "github.com/stretchr/testify/assert" + "github.com/go-dev-frame/sponge/pkg/copier" "github.com/go-dev-frame/sponge/pkg/sgorm/query" "github.com/go-dev-frame/sponge/pkg/httpcli" "github.com/go-dev-frame/sponge/pkg/gotest" diff --git a/internal/service/userExample.go b/internal/service/userExample.go index 54d737b..a753340 100644 --- a/internal/service/userExample.go +++ b/internal/service/userExample.go @@ -6,9 +6,9 @@ import ( "strings" "time" - "github.com/jinzhu/copier" "google.golang.org/grpc" + "github.com/go-dev-frame/sponge/pkg/copier" "github.com/go-dev-frame/sponge/pkg/grpc/interceptor" "github.com/go-dev-frame/sponge/pkg/logger" "github.com/go-dev-frame/sponge/pkg/sgorm/query" @@ -191,12 +191,7 @@ func convertUserExample(record *model.UserExample) (*serverNameExampleV1.UserExa if err != nil { return nil, err } - // Note: if copier.Copy cannot assign a value to a field, add it here, e.g. CreatedAt, UpdatedAt - value.Id = record.ID - // todo generate the conversion createdAt and updatedAt code here - // delete the templates code start - value.CreatedAt = record.CreatedAt.Format(time.RFC3339) - value.UpdatedAt = record.UpdatedAt.Format(time.RFC3339) - // delete the templates code end + // Note: if copier.Copy cannot assign a value to a field, add it here + return value, nil } diff --git a/internal/service/userExample.go.exp b/internal/service/userExample.go.exp index 6b62df0..351a3db 100644 --- a/internal/service/userExample.go.exp +++ b/internal/service/userExample.go.exp @@ -7,9 +7,9 @@ import ( "strings" "time" - "github.com/jinzhu/copier" "google.golang.org/grpc" + "github.com/go-dev-frame/sponge/pkg/copier" "github.com/go-dev-frame/sponge/pkg/sgorm/query" "github.com/go-dev-frame/sponge/pkg/grpc/interceptor" "github.com/go-dev-frame/sponge/pkg/logger" @@ -317,12 +317,7 @@ func convertUserExample(record *model.UserExample) (*serverNameExampleV1.UserExa if err != nil { return nil, err } - // Note: if copier.Copy cannot assign a value to a field, add it here, e.g. CreatedAt, UpdatedAt - value.Id = record.ID - // todo generate the conversion createdAt and updatedAt code here - // delete the templates code start - value.CreatedAt = record.CreatedAt.Format(time.RFC3339) - value.UpdatedAt = record.UpdatedAt.Format(time.RFC3339) - // delete the templates code end + // Note: if copier.Copy cannot assign a value to a field, add it here + return value, nil } diff --git a/internal/service/userExample.go.exp.tpl b/internal/service/userExample.go.exp.tpl index 85c778d..82b7ac8 100644 --- a/internal/service/userExample.go.exp.tpl +++ b/internal/service/userExample.go.exp.tpl @@ -7,9 +7,9 @@ import ( "strings" "time" - "github.com/jinzhu/copier" "google.golang.org/grpc" + "github.com/go-dev-frame/sponge/pkg/copier" "github.com/go-dev-frame/sponge/pkg/sgorm/query" "github.com/go-dev-frame/sponge/pkg/grpc/interceptor" "github.com/go-dev-frame/sponge/pkg/logger" @@ -320,12 +320,7 @@ func convert{{.TableNameCamel}}(record *model.{{.TableNameCamel}}) (*serverNameE if err != nil { return nil, err } - // Note: if copier.Copy cannot assign a value to a field, add it here, e.g. CreatedAt, UpdatedAt - value.{{if .IsStandardPrimaryKey}}Id{{else}}{{.ColumnNameCamel}}{{end}} = record.{{.ColumnNameCamel}} - // todo generate the conversion createdAt and updatedAt code here - // delete the templates code start - value.CreatedAt = record.CreatedAt.Format(time.RFC3339) - value.UpdatedAt = record.UpdatedAt.Format(time.RFC3339) - // delete the templates code end + // Note: if copier.Copy cannot assign a value to a field, add it here + return value, nil } diff --git a/internal/service/userExample.go.mgo b/internal/service/userExample.go.mgo index e6342fa..ab2400b 100644 --- a/internal/service/userExample.go.mgo +++ b/internal/service/userExample.go.mgo @@ -6,9 +6,9 @@ import ( "strings" "time" - "github.com/jinzhu/copier" "google.golang.org/grpc" + "github.com/go-dev-frame/sponge/pkg/copier" "github.com/go-dev-frame/sponge/pkg/grpc/interceptor" "github.com/go-dev-frame/sponge/pkg/logger" "github.com/go-dev-frame/sponge/pkg/mgo/query" @@ -192,12 +192,8 @@ func convertUserExample(record *model.UserExample) (*serverNameExampleV1.UserExa if err != nil { return nil, err } - // Note: if copier.Copy cannot assign a value to a field, add it here, e.g. CreatedAt, UpdatedAt + // Note: if copier.Copy cannot assign a value to a field, add it here value.Id = record.ID.Hex() - // todo generate the conversion createdAt and updatedAt code here - // delete the templates code start - value.CreatedAt = record.CreatedAt.Format(time.RFC3339) - value.UpdatedAt = record.UpdatedAt.Format(time.RFC3339) - // delete the templates code end + return value, nil } diff --git a/internal/service/userExample.go.mgo.exp b/internal/service/userExample.go.mgo.exp index 1080d9e..db3f59e 100644 --- a/internal/service/userExample.go.mgo.exp +++ b/internal/service/userExample.go.mgo.exp @@ -6,9 +6,9 @@ import ( "strings" "time" - "github.com/jinzhu/copier" "google.golang.org/grpc" + "github.com/go-dev-frame/sponge/pkg/copier" "github.com/go-dev-frame/sponge/pkg/grpc/interceptor" "github.com/go-dev-frame/sponge/pkg/logger" "github.com/go-dev-frame/sponge/pkg/mgo/query" @@ -317,12 +317,8 @@ func convertUserExample(record *model.UserExample) (*serverNameExampleV1.UserExa if err != nil { return nil, err } - // Note: if copier.Copy cannot assign a value to a field, add it here, e.g. CreatedAt, UpdatedAt + // Note: if copier.Copy cannot assign a value to a field, add it here value.Id = record.ID.Hex() - // todo generate the conversion createdAt and updatedAt code here - // delete the templates code start - value.CreatedAt = record.CreatedAt.Format(time.RFC3339) - value.UpdatedAt = record.UpdatedAt.Format(time.RFC3339) - // delete the templates code end + return value, nil } diff --git a/internal/service/userExample.go.tpl b/internal/service/userExample.go.tpl index dc24375..b1614f2 100644 --- a/internal/service/userExample.go.tpl +++ b/internal/service/userExample.go.tpl @@ -6,9 +6,9 @@ import ( "strings" "time" - "github.com/jinzhu/copier" "google.golang.org/grpc" + "github.com/go-dev-frame/sponge/pkg/copier" "github.com/go-dev-frame/sponge/pkg/sgorm/query" "github.com/go-dev-frame/sponge/pkg/grpc/interceptor" "github.com/go-dev-frame/sponge/pkg/logger" @@ -191,12 +191,7 @@ func convert{{.TableNameCamel}}(record *model.{{.TableNameCamel}}) (*serverNameE if err != nil { return nil, err } - // Note: if copier.Copy cannot assign a value to a field, add it here, e.g. CreatedAt, UpdatedAt - value.{{if .IsStandardPrimaryKey}}Id{{else}}{{.ColumnNameCamel}}{{end}} = record.{{.ColumnNameCamel}} - // todo generate the conversion createdAt and updatedAt code here - // delete the templates code start - value.CreatedAt = record.CreatedAt.Format(time.RFC3339) - value.UpdatedAt = record.UpdatedAt.Format(time.RFC3339) - // delete the templates code end + // Note: if copier.Copy cannot assign a value to a field, add it here + return value, nil } diff --git a/internal/service/userExample_test.go b/internal/service/userExample_test.go index b095da7..5834765 100644 --- a/internal/service/userExample_test.go +++ b/internal/service/userExample_test.go @@ -5,9 +5,9 @@ import ( "time" "github.com/DATA-DOG/go-sqlmock" - "github.com/jinzhu/copier" "github.com/stretchr/testify/assert" + "github.com/go-dev-frame/sponge/pkg/copier" "github.com/go-dev-frame/sponge/pkg/gotest" "github.com/go-dev-frame/sponge/pkg/utils" diff --git a/pkg/copier/README.md b/pkg/copier/README.md new file mode 100644 index 0000000..c7d9ab3 --- /dev/null +++ b/pkg/copier/README.md @@ -0,0 +1,56 @@ +## copyopt + +`copier` is `github.com/jinzhu/copier`, default option is add converters for time.Time <--> String. + +### Example of use + +```go. +package main + +import ( + "fmt" + "time" + + "github.com/go-dev-frame/sponge/pkg/copier" +) + +type Model struct { + ID int64 + MyIP string + OrderID uint32 + CreatedAt *time.Time + UpdatedAt *time.Time + DeletedAt *time.Time +} + +type Reply struct { + Id int + MyIp string + OrderId int + CreatedAt string + UpdatedAt string + DeletedAt string +} + +func main() { + now := time.Now() + updated := now.Add(time.Hour) + deleted := updated.Add(time.Hour) + + src := &Model{ + ID: 123, + MyIP: "127.0.0.1", + OrderID: 888, + CreatedAt: &now, + UpdatedAt: &updated, + DeletedAt: &deleted, + } + dst := &Reply{} + err := copier.Copy(dst, src) + if err != nil { + panic(err) + } + + fmt.Printf("%+v\n", dst) +} +``` \ No newline at end of file diff --git a/pkg/copier/copy.go b/pkg/copier/copy.go new file mode 100644 index 0000000..322a97e --- /dev/null +++ b/pkg/copier/copy.go @@ -0,0 +1,92 @@ +// Package copier is github.com/jinzhu/copier, default option is add converters for time.Time <--> String +package copier + +import ( + "fmt" + "time" + + "github.com/jinzhu/copier" +) + +// Copy src to dst with option Converters for time.Time <--> String +func Copy(dst interface{}, src interface{}) error { + return copier.CopyWithOption(dst, src, Converter) +} + +// Converter Converters for time.Time <--> String +var Converter = copier.Option{ + DeepCopy: true, + Converters: []copier.TypeConverter{ + // time.Time to string + { + SrcType: time.Time{}, + DstType: copier.String, + Fn: func(src interface{}) (interface{}, error) { + s, ok := src.(time.Time) + if !ok { + return nil, fmt.Errorf("expected time.Time got %T", src) + } + return s.Format(time.RFC3339), nil + }, + }, + + // *time.Time to string + { + SrcType: &time.Time{}, + DstType: copier.String, + Fn: func(src interface{}) (interface{}, error) { + s, ok := src.(*time.Time) + if !ok { + return nil, fmt.Errorf("expected *time.Time got %T", src) + } + if s == nil { + return "", nil + } + return s.Format(time.RFC3339), nil + }, + }, + + // string to time.Time + { + SrcType: copier.String, + DstType: time.Time{}, + Fn: func(src interface{}) (interface{}, error) { + s, ok := src.(string) + if !ok { + return nil, fmt.Errorf("expected string got %T", src) + } + if s == "" { + return time.Time{}, nil + } + return time.Parse(time.RFC3339, s) + }, + }, + + // string to *time.Time + { + SrcType: copier.String, + DstType: &time.Time{}, + Fn: func(src interface{}) (interface{}, error) { + s, ok := src.(string) + if !ok { + return nil, fmt.Errorf("expected string got %T", src) + } + if s == "" { + return nil, nil + } + t, err := time.Parse(time.RFC3339, s) + return &t, err + }, + }, + }, +} + +// CopyDefault copy src to dst with default option +func CopyDefault(dst interface{}, src interface{}) error { + return copier.Copy(dst, src) +} + +// CopyWithOption copy src to dst with option +func CopyWithOption(dst interface{}, src interface{}, options copier.Option) error { + return copier.CopyWithOption(dst, src, options) +} diff --git a/pkg/copier/copy_test.go b/pkg/copier/copy_test.go new file mode 100644 index 0000000..7627783 --- /dev/null +++ b/pkg/copier/copy_test.go @@ -0,0 +1,478 @@ +package copier + +import ( + "gorm.io/gorm" + "testing" + "time" + + "github.com/jinzhu/copier" + "github.com/stretchr/testify/assert" +) + +type MyUser1 struct { + Id uint64 + MyIp string + OrderId int32 + CreatedAt time.Time + UpdatedAt time.Time + DeletedAt time.Time +} + +type MyUser2 struct { + ID int64 + MyIP string + OrderID uint32 + CreatedAt *time.Time + UpdatedAt *time.Time + DeletedAt *time.Time +} + +type UserReply struct { + Id int + MyIp string + OrderId int + CreatedAt string + UpdatedAt string + DeletedAt string +} + +func copyCustom1() (*UserReply, *UserReply) { + user1 := &MyUser1{ + Id: 123, + MyIp: "127.0.0.1", + OrderId: 888, + CreatedAt: time.Now(), + UpdatedAt: time.Now().Add(time.Hour), + DeletedAt: time.Now().Add(-2 * time.Hour), + } + user2 := &MyUser2{ + ID: 456, + MyIP: "localhost", + OrderID: 999, + CreatedAt: &user1.CreatedAt, + UpdatedAt: &user1.UpdatedAt, + DeletedAt: &user1.DeletedAt, + } + reply1 := &UserReply{} + reply2 := &UserReply{} + + Copy(reply1, user1) + Copy(reply2, user2) + + return reply1, reply2 +} + +func copyStandard1() (*UserReply, *UserReply) { + user1 := &MyUser1{ + Id: 789, + MyIp: "127.0.0.1", + OrderId: 888, + CreatedAt: time.Now(), + UpdatedAt: time.Now().Add(time.Hour), + DeletedAt: time.Now().Add(-2 * time.Hour), + } + user2 := &MyUser2{ + ID: 1010, + MyIP: "localhost", + OrderID: 999, + CreatedAt: &user1.CreatedAt, + UpdatedAt: &user1.UpdatedAt, + DeletedAt: &user1.DeletedAt, + } + reply1 := &UserReply{} + reply2 := &UserReply{} + + copier.Copy(reply1, user1) + copier.Copy(reply2, user2) + + return reply1, reply2 +} + +func copyCustom2() (*MyUser1, *MyUser2) { + req := &UserReply{ + Id: 123, + MyIp: "127.0.0.1", + OrderId: 888, + CreatedAt: "2025-05-25T15:38:20+08:00", + UpdatedAt: "2025-05-25T16:38:20+08:00", + DeletedAt: "2025-05-25T17:38:20+08:00", + } + user1 := &MyUser1{} + user2 := &MyUser2{} + + Copy(user1, req) + Copy(user2, req) + + return user1, user2 +} + +func copyStandard2() (*MyUser1, *MyUser2) { + req := &UserReply{ + Id: 456, + MyIp: "localhost", + OrderId: 888, + CreatedAt: "2025-05-25T15:38:20+08:00", + UpdatedAt: "2025-05-25T16:38:20+08:00", + DeletedAt: "2025-05-25T17:38:20+08:00", + } + user1 := &MyUser1{} + user2 := &MyUser2{} + + copier.Copy(user1, req) + copier.Copy(user2, req) + + return user1, user2 +} + +func TestCopyCustom1(t *testing.T) { + reply1, reply2 := copyCustom1() + assert.Equal(t, reply1.Id, 123) + assert.Equal(t, reply2.Id, 456) + t.Log(reply1) + t.Log(reply2) +} + +func TestCopyStandard1(t *testing.T) { + reply1, reply2 := copyStandard1() + assert.Equal(t, reply1.Id, 789) + assert.Equal(t, reply2.Id, 1010) + t.Log(reply1) + t.Log(reply2) +} + +func TestCopyCustom2(t *testing.T) { + user1, user2 := copyCustom2() + assert.Equal(t, int(user1.Id), 123) + assert.Equal(t, int(user2.ID), 123) + t.Log(user1) + t.Log(user2) +} + +func TestCopyStandard2(t *testing.T) { + user1, user2 := copyStandard2() + assert.Equal(t, int(user1.Id), 456) + assert.Equal(t, int(user2.ID), 456) + t.Log(user1) + t.Log(user2) +} + +func BenchmarkCopyStandard1(b *testing.B) { + for i := 0; i < b.N; i++ { + copyStandard1() + } +} + +func BenchmarkCopyCustom1(b *testing.B) { + for i := 0; i < b.N; i++ { + copyCustom1() + } +} + +func BenchmarkCopyStandard2(b *testing.B) { + for i := 0; i < b.N; i++ { + copyStandard2() + } +} + +func BenchmarkCopyCustom2(b *testing.B) { + for i := 0; i < b.N; i++ { + copyCustom2() + } +} + +// ------------------------------------------------- + +func SliceData1() []*MyUser1 { + users := []*MyUser1{ + { + Id: 123, + MyIp: "127.0.0.1", + OrderId: 888, + CreatedAt: time.Now(), + UpdatedAt: time.Now().Add(time.Hour), + DeletedAt: time.Now().Add(-2 * time.Hour), + }, + { + Id: 456, + MyIp: "localhost", + OrderId: 999, + CreatedAt: time.Now().Add(2 * time.Hour), + UpdatedAt: time.Now().Add(3 * time.Hour), + DeletedAt: time.Now().Add(-3 * time.Hour), + }, + { + Id: 789, + MyIp: "192.168.1.1", + OrderId: 1010, + CreatedAt: time.Now().Add(-2 * time.Hour), + UpdatedAt: time.Now().Add(-3 * time.Hour), + DeletedAt: time.Now().Add(3 * time.Hour), + }, + } + + return users +} + +func SliceData2() []*MyUser2 { + now := time.Now() + updated := now.Add(time.Hour) + deleted := now.Add(-2 * time.Hour) + users := []*MyUser2{ + { + ID: 123, + MyIP: "127.0.0.1", + OrderID: 888, + CreatedAt: &now, + UpdatedAt: &updated, + DeletedAt: &deleted, + }, + { + ID: 456, + MyIP: "localhost", + OrderID: 999, + CreatedAt: &now, + UpdatedAt: &updated, + DeletedAt: &deleted, + }, + { + ID: 789, + MyIP: "192.168.1.1", + OrderID: 1010, + CreatedAt: &now, + UpdatedAt: &updated, + DeletedAt: &deleted, + }, + } + + return users +} + +func SliceData3() []*UserReply { + userReplies := []*UserReply{ + { + Id: 123, + MyIp: "127.0.0.1", + OrderId: 888, + CreatedAt: "2025-05-25T15:38:20+08:00", + UpdatedAt: "2025-05-25T16:38:20+08:00", + DeletedAt: "2025-05-25T17:38:20+08:00", + }, + { + Id: 456, + MyIp: "localhost", + OrderId: 999, + CreatedAt: "2025-05-25T15:38:20+08:00", + UpdatedAt: "2025-05-25T16:38:20+08:00", + DeletedAt: "2025-05-25T17:38:20+08:00", + }, + { + Id: 789, + MyIp: "192.168.1.1", + OrderId: 1010, + CreatedAt: "2025-05-25T15:38:20+08:00", + UpdatedAt: "2025-05-25T16:38:20+08:00", + DeletedAt: "2025-05-25T17:38:20+08:00", + }, + } + return userReplies +} + +func TestSliceCopyCustom1(t *testing.T) { + users := SliceData1() + replies := make([]*UserReply, len(users)) + Copy(&replies, &users) + for _, reply := range replies { + t.Log(reply) + } +} + +func TestSliceCopyStandard1(t *testing.T) { + users := SliceData1() + replies := make([]*UserReply, len(users)) + copier.Copy(&replies, &users) + for _, reply := range replies { + t.Log(reply) + } +} + +func TestSliceCopyCustom2(t *testing.T) { + users := SliceData2() + replies := make([]*UserReply, len(users)) + Copy(&replies, &users) + for _, reply := range replies { + t.Log(reply) + } +} + +func TestSliceCopyStandard2(t *testing.T) { + users := SliceData2() + replies := make([]*UserReply, len(users)) + copier.Copy(&replies, &users) + for _, reply := range replies { + t.Log(reply) + } +} + +func TestSliceCopyCustom3(t *testing.T) { + users := SliceData3() + replies := make([]*MyUser1, len(users)) + Copy(&replies, &users) + for _, reply := range replies { + t.Log(reply) + } +} + +func TestSliceCopyStandard3(t *testing.T) { + users := SliceData3() + replies := make([]*MyUser1, len(users)) + copier.Copy(&replies, &users) + for _, reply := range replies { + t.Log(reply) + } +} + +func TestSliceCopyCustom4(t *testing.T) { + users := SliceData3() + replies := make([]*MyUser2, len(users)) + Copy(&replies, &users) + for _, reply := range replies { + t.Log(reply) + } +} + +func TestSliceCopyStandard4(t *testing.T) { + users := SliceData3() + replies := make([]*MyUser2, len(users)) + copier.Copy(&replies, &users) + for _, reply := range replies { + t.Log(reply) + } +} + +func BenchmarkSliceCopyStandard1(b *testing.B) { + users := SliceData1() + for i := 0; i < b.N; i++ { + replies := make([]*UserReply, len(users)) + copier.Copy(&replies, &users) + } +} + +func BenchmarkSliceCopyStandardSingle1(b *testing.B) { + users := SliceData1() + for i := 0; i < b.N; i++ { + reply := &UserReply{} + for _, user := range users { + copier.Copy(reply, user) + } + } +} + +func BenchmarkSliceCopyCustom1(b *testing.B) { + users := SliceData1() + for i := 0; i < b.N; i++ { + replies := make([]*UserReply, len(users)) + Copy(&replies, &users) + } +} + +func BenchmarkSliceCopyCustomSingle1(b *testing.B) { + users := SliceData1() + for i := 0; i < b.N; i++ { + reply := &UserReply{} + for _, user := range users { + Copy(reply, user) + } + } +} + +// --------------------------------------------------------------------- + +func TestCopyDefault(t *testing.T) { + user1 := &MyUser1{ + Id: 123, + MyIp: "127.0.0.1", + OrderId: 888, + CreatedAt: time.Now(), + UpdatedAt: time.Now().Add(time.Hour), + DeletedAt: time.Now().Add(2 * time.Hour), + } + + user2 := &MyUser2{} + + err := CopyDefault(user2, user1) + if err != nil { + t.Error(err) + return + } + assert.Equal(t, user2.ID, int64(123)) + + t.Log(user2) +} + +func TestCopyWithOption(t *testing.T) { + user1 := &MyUser1{ + Id: 123, + MyIp: "127.0.0.1", + OrderId: 888, + CreatedAt: time.Now(), + UpdatedAt: time.Now().Add(time.Hour), + DeletedAt: time.Now().Add(2 * time.Hour), + } + + user2 := &MyUser2{} + option := copier.Option{ + DeepCopy: true, + } + err := CopyWithOption(user2, user1, option) + if err != nil { + t.Error(err) + return + } + assert.Equal(t, user2.ID, int64(123)) + + t.Log(user2) +} + +func TestCopyEmbedStruct(t *testing.T) { + type Model struct { + ID uint64 `gorm:"column:id;AUTO_INCREMENT;primary_key" json:"id"` + CreatedAt time.Time `gorm:"column:created_at" json:"createdAt"` + UpdatedAt time.Time `gorm:"column:updated_at" json:"updatedAt"` + DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;index" json:"-"` + } + + type User struct { + Model `gorm:"embedded"` + Name string `gorm:"column:name" json:"name"` + Age int `gorm:"column:age" json:"age"` + } + + user := &User{ + Model: Model{ + ID: 123, + CreatedAt: time.Now(), + UpdatedAt: time.Now().Add(time.Hour), + DeletedAt: gorm.DeletedAt{Time: time.Now().Add(2 * time.Hour)}, + }, + Name: "test", + Age: 18, + } + + type UserReply struct { + Id uint64 `json:"id"` + Age int `json:"age"` + CreatedAt string `json:"createdAt"` + UpdatedAt string `json:"updatedAt"` + DeletedAt string `json:"deletedAt"` + } + + reply := &UserReply{} + err := Copy(reply, user) + if err != nil { + t.Error(err) + return + } + reply.DeletedAt = user.DeletedAt.Time.Format(time.RFC3339) + + t.Log(*reply) +}