diff --git a/cmd/gf/internal/cmd/cmd_z_unit_gen_dao_test.go b/cmd/gf/internal/cmd/cmd_z_unit_gen_dao_test.go index 8e6690d28..9642ad36e 100644 --- a/cmd/gf/internal/cmd/cmd_z_unit_gen_dao_test.go +++ b/cmd/gf/internal/cmd/cmd_z_unit_gen_dao_test.go @@ -71,6 +71,7 @@ func Test_Gen_Dao_Default(t *testing.T) { NoModelComment: false, Clear: false, TypeMapping: nil, + FieldMapping: nil, } ) err = gutil.FillStructWithDefault(&in) @@ -171,6 +172,7 @@ func Test_Gen_Dao_TypeMapping(t *testing.T) { Import: "github.com/shopspring/decimal", }, }, + FieldMapping: nil, } ) err = gutil.FillStructWithDefault(&in) @@ -213,6 +215,108 @@ func Test_Gen_Dao_TypeMapping(t *testing.T) { }) } +func Test_Gen_Dao_FieldMapping(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + var ( + err error + db = testDB + table = "table_user" + sqlContent = fmt.Sprintf( + gtest.DataContent(`gendao`, `user.tpl.sql`), + table, + ) + ) + defer dropTableWithDb(db, table) + array := gstr.SplitAndTrim(sqlContent, ";") + for _, v := range array { + if _, err = db.Exec(ctx, v); err != nil { + t.AssertNil(err) + } + } + defer dropTableWithDb(db, table) + + var ( + path = gfile.Temp(guid.S()) + group = "test" + in = gendao.CGenDaoInput{ + Path: path, + Link: link, + Tables: "table_user", + TablesEx: "", + Group: group, + Prefix: "", + RemovePrefix: "", + JsonCase: "", + ImportPrefix: "", + DaoPath: "", + DoPath: "", + EntityPath: "", + TplDaoIndexPath: "", + TplDaoInternalPath: "", + TplDaoDoPath: "", + TplDaoEntityPath: "", + StdTime: false, + WithTime: false, + GJsonSupport: false, + OverwriteDao: false, + DescriptionTag: false, + NoJsonTag: false, + NoModelComment: false, + Clear: false, + TypeMapping: map[gendao.DBFieldTypeName]gendao.CustomAttributeType{ + "int": { + Type: "int64", + Import: "", + }, + }, + FieldMapping: map[gendao.DBTableFieldName]gendao.CustomAttributeType{ + "table_user.score": { + Type: "decimal.Decimal", + Import: "github.com/shopspring/decimal", + }, + }, + } + ) + err = gutil.FillStructWithDefault(&in) + t.AssertNil(err) + + err = gfile.Mkdir(path) + t.AssertNil(err) + + // for go mod import path auto retrieve. + err = gfile.Copy( + gtest.DataPath("gendao", "go.mod.txt"), + gfile.Join(path, "go.mod"), + ) + t.AssertNil(err) + + _, err = gendao.CGenDao{}.Dao(ctx, in) + t.AssertNil(err) + defer gfile.Remove(path) + + // files + files, err := gfile.ScanDir(path, "*.go", true) + t.AssertNil(err) + t.Assert(files, []string{ + filepath.FromSlash(path + "/dao/internal/table_user.go"), + filepath.FromSlash(path + "/dao/table_user.go"), + filepath.FromSlash(path + "/model/do/table_user.go"), + filepath.FromSlash(path + "/model/entity/table_user.go"), + }) + // content + testPath := gtest.DataPath("gendao", "generated_user_field_mapping") + expectFiles := []string{ + filepath.FromSlash(testPath + "/dao/internal/table_user.go"), + filepath.FromSlash(testPath + "/dao/table_user.go"), + filepath.FromSlash(testPath + "/model/do/table_user.go"), + filepath.FromSlash(testPath + "/model/entity/table_user.go"), + } + for i, _ := range files { + t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i])) + } + }) +} + func execSqlFile(db gdb.DB, filePath string, args ...any) error { sqlContent := fmt.Sprintf( gfile.GetContents(filePath), @@ -271,6 +375,7 @@ func Test_Gen_Dao_Issue2572(t *testing.T) { NoModelComment: false, Clear: false, TypeMapping: nil, + FieldMapping: nil, } ) err = gutil.FillStructWithDefault(&in) @@ -359,6 +464,7 @@ func Test_Gen_Dao_Issue2616(t *testing.T) { NoModelComment: false, Clear: false, TypeMapping: nil, + FieldMapping: nil, } ) err = gutil.FillStructWithDefault(&in) @@ -469,6 +575,7 @@ func Test_Gen_Dao_Issue2746(t *testing.T) { NoModelComment: false, Clear: false, TypeMapping: nil, + FieldMapping: nil, } ) err = gutil.FillStructWithDefault(&in) diff --git a/cmd/gf/internal/cmd/gendao/gendao.go b/cmd/gf/internal/cmd/gendao/gendao.go index 4482c6f95..2b7ae3d61 100644 --- a/cmd/gf/internal/cmd/gendao/gendao.go +++ b/cmd/gf/internal/cmd/gendao/gendao.go @@ -58,6 +58,10 @@ CONFIGURATION SUPPORT import: github.com/shopspring/decimal numeric: type: string + fieldMapping: + table_name.field_name: + type: decimal.Decimal + import: github.com/shopspring/decimal ` CGenDaoBriefPath = `directory path for generated files` CGenDaoBriefLink = `database configuration, the same as the ORM configuration of GoFrame` @@ -81,6 +85,7 @@ CONFIGURATION SUPPORT CGenDaoBriefNoModelComment = `no model comment will be added for each field` CGenDaoBriefClear = `delete all generated go files that do not exist in database` CGenDaoBriefTypeMapping = `custom local type mapping for generated struct attributes relevant to fields of table` + CGenDaoBriefFieldMapping = `custom local type mapping for generated struct attributes relevant to specific fields of table` CGenDaoBriefGroup = ` specifying the configuration group name of database for generated ORM instance, it's not necessary and the default value is "default" @@ -162,6 +167,7 @@ func init() { `CGenDaoBriefNoModelComment`: CGenDaoBriefNoModelComment, `CGenDaoBriefClear`: CGenDaoBriefClear, `CGenDaoBriefTypeMapping`: CGenDaoBriefTypeMapping, + `CGenDaoBriefFieldMapping`: CGenDaoBriefFieldMapping, `CGenDaoBriefGroup`: CGenDaoBriefGroup, `CGenDaoBriefJsonCase`: CGenDaoBriefJsonCase, `CGenDaoBriefTplDaoIndexPath`: CGenDaoBriefTplDaoIndexPath, @@ -201,8 +207,9 @@ type ( NoModelComment bool `name:"noModelComment" short:"m" brief:"{CGenDaoBriefNoModelComment}" orphan:"true"` Clear bool `name:"clear" short:"a" brief:"{CGenDaoBriefClear}" orphan:"true"` - TypeMapping map[DBFieldTypeName]CustomAttributeType `name:"typeMapping" short:"y" brief:"{CGenDaoBriefTypeMapping}" orphan:"true"` - genItems *CGenDaoInternalGenItems + TypeMapping map[DBFieldTypeName]CustomAttributeType `name:"typeMapping" short:"y" brief:"{CGenDaoBriefTypeMapping}" orphan:"true"` + FieldMapping map[DBTableFieldName]CustomAttributeType `name:"fieldMapping" short:"fm" brief:"{CGenDaoBriefFieldMapping}" orphan:"true"` + genItems *CGenDaoInternalGenItems } CGenDaoOutput struct{} @@ -212,7 +219,7 @@ type ( TableNames []string NewTableNames []string } - + DBTableFieldName = string DBFieldTypeName = string CustomAttributeType struct { Type string `brief:"custom attribute type name"` @@ -363,7 +370,7 @@ func getImportPartContent(ctx context.Context, source string, isDo bool, appendI } // Check and update imports in go.mod - if appendImports != nil && len(appendImports) > 0 { + if len(appendImports) > 0 { goModPath := utils.GetModPath() if goModPath == "" { mlog.Fatal("go.mod not found in current project") @@ -381,8 +388,9 @@ func getImportPartContent(ctx context.Context, source string, isDo bool, appendI } } if !found { - err = gproc.ShellRun(ctx, `go get `+appendImport) - mlog.Fatalf(`%+v`, err) + if err = gproc.ShellRun(ctx, `go get `+appendImport); err != nil { + mlog.Fatalf(`%+v`, err) + } } packageImportsArray.Append(fmt.Sprintf(`"%s"`, appendImport)) } diff --git a/cmd/gf/internal/cmd/gendao/gendao_structure.go b/cmd/gf/internal/cmd/gendao/gendao_structure.go index f6c585e4b..4e457aff3 100644 --- a/cmd/gf/internal/cmd/gendao/gendao_structure.go +++ b/cmd/gf/internal/cmd/gendao/gendao_structure.go @@ -131,6 +131,14 @@ func generateStructFieldDefinition( for _, v := range removeFieldPrefixArray { newFiledName = gstr.TrimLeftStr(newFiledName, v, 1) } + + if in.FieldMapping != nil && len(in.FieldMapping) > 0 { + if typeMapping, ok := in.FieldMapping[fmt.Sprintf("%s.%s", in.Tables, newFiledName)]; ok { + localTypeNameStr = typeMapping.Type + appendImport = typeMapping.Import + } + } + attrLines = []string{ " #" + gstr.CaseCamel(newFiledName), " #" + localTypeNameStr, diff --git a/cmd/gf/internal/cmd/testdata/gendao/generated_user_field_mapping/dao/internal/table_user.go b/cmd/gf/internal/cmd/testdata/gendao/generated_user_field_mapping/dao/internal/table_user.go new file mode 100644 index 000000000..f883408e4 --- /dev/null +++ b/cmd/gf/internal/cmd/testdata/gendao/generated_user_field_mapping/dao/internal/table_user.go @@ -0,0 +1,85 @@ +// ========================================================================== +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ========================================================================== + +package internal + +import ( + "context" + + "github.com/gogf/gf/v2/database/gdb" + "github.com/gogf/gf/v2/frame/g" +) + +// TableUserDao is the data access object for table table_user. +type TableUserDao struct { + table string // table is the underlying table name of the DAO. + group string // group is the database configuration group name of current DAO. + columns TableUserColumns // columns contains all the column names of Table for convenient usage. +} + +// TableUserColumns defines and stores column names for table table_user. +type TableUserColumns struct { + Id string // User ID + Passport string // User Passport + Password string // User Password + Nickname string // User Nickname + Score string // Total score amount. + CreateAt string // Created Time + UpdateAt string // Updated Time +} + +// tableUserColumns holds the columns for table table_user. +var tableUserColumns = TableUserColumns{ + Id: "id", + Passport: "passport", + Password: "password", + Nickname: "nickname", + Score: "score", + CreateAt: "create_at", + UpdateAt: "update_at", +} + +// NewTableUserDao creates and returns a new DAO object for table data access. +func NewTableUserDao() *TableUserDao { + return &TableUserDao{ + group: "test", + table: "table_user", + columns: tableUserColumns, + } +} + +// DB retrieves and returns the underlying raw database management object of current DAO. +func (dao *TableUserDao) DB() gdb.DB { + return g.DB(dao.group) +} + +// Table returns the table name of current dao. +func (dao *TableUserDao) Table() string { + return dao.table +} + +// Columns returns all column names of current dao. +func (dao *TableUserDao) Columns() TableUserColumns { + return dao.columns +} + +// Group returns the configuration group name of database of current dao. +func (dao *TableUserDao) Group() string { + return dao.group +} + +// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation. +func (dao *TableUserDao) Ctx(ctx context.Context) *gdb.Model { + return dao.DB().Model(dao.table).Safe().Ctx(ctx) +} + +// Transaction wraps the transaction logic using function f. +// It rollbacks the transaction and returns the error from function f if it returns non-nil error. +// It commits the transaction and returns nil if function f returns nil. +// +// Note that, you should not Commit or Rollback the transaction in function f +// as it is automatically handled by this function. +func (dao *TableUserDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) { + return dao.Ctx(ctx).Transaction(ctx, f) +} diff --git a/cmd/gf/internal/cmd/testdata/gendao/generated_user_field_mapping/dao/table_user.go b/cmd/gf/internal/cmd/testdata/gendao/generated_user_field_mapping/dao/table_user.go new file mode 100644 index 000000000..9bc9cff6f --- /dev/null +++ b/cmd/gf/internal/cmd/testdata/gendao/generated_user_field_mapping/dao/table_user.go @@ -0,0 +1,27 @@ +// ================================================================================= +// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish. +// ================================================================================= + +package dao + +import ( + "for-gendao-test/pkg/dao/internal" +) + +// internalTableUserDao is internal type for wrapping internal DAO implements. +type internalTableUserDao = *internal.TableUserDao + +// tableUserDao is the data access object for table table_user. +// You can define custom methods on it to extend its functionality as you wish. +type tableUserDao struct { + internalTableUserDao +} + +var ( + // TableUser is globally public accessible object for table table_user operations. + TableUser = tableUserDao{ + internal.NewTableUserDao(), + } +) + +// Fill with you ideas below. diff --git a/cmd/gf/internal/cmd/testdata/gendao/generated_user_field_mapping/model/do/table_user.go b/cmd/gf/internal/cmd/testdata/gendao/generated_user_field_mapping/model/do/table_user.go new file mode 100644 index 000000000..656fb9c3d --- /dev/null +++ b/cmd/gf/internal/cmd/testdata/gendao/generated_user_field_mapping/model/do/table_user.go @@ -0,0 +1,22 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package do + +import ( + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gtime" +) + +// TableUser is the golang structure of table table_user for DAO operations like Where/Data. +type TableUser struct { + g.Meta `orm:"table:table_user, do:true"` + Id interface{} // User ID + Passport interface{} // User Passport + Password interface{} // User Password + Nickname interface{} // User Nickname + Score interface{} // Total score amount. + CreateAt *gtime.Time // Created Time + UpdateAt *gtime.Time // Updated Time +} diff --git a/cmd/gf/internal/cmd/testdata/gendao/generated_user_field_mapping/model/entity/table_user.go b/cmd/gf/internal/cmd/testdata/gendao/generated_user_field_mapping/model/entity/table_user.go new file mode 100644 index 000000000..c447af20c --- /dev/null +++ b/cmd/gf/internal/cmd/testdata/gendao/generated_user_field_mapping/model/entity/table_user.go @@ -0,0 +1,21 @@ +// ================================================================================= +// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. +// ================================================================================= + +package entity + +import ( + "github.com/gogf/gf/v2/os/gtime" + "github.com/shopspring/decimal" +) + +// TableUser is the golang structure for table table_user. +type TableUser struct { + Id int64 `json:"id" orm:"id" ` // User ID + Passport string `json:"passport" orm:"passport" ` // User Passport + Password string `json:"password" orm:"password" ` // User Password + Nickname string `json:"nickname" orm:"nickname" ` // User Nickname + Score decimal.Decimal `json:"score" orm:"score" ` // Total score amount. + CreateAt *gtime.Time `json:"createAt" orm:"create_at" ` // Created Time + UpdateAt *gtime.Time `json:"updateAt" orm:"update_at" ` // Updated Time +}