mirror of
https://gitee.com/johng/gf
synced 2026-06-26 09:27:31 +08:00
up
This commit is contained in:
@ -3,6 +3,14 @@
|
||||
## 功能概述
|
||||
基于数据库表结构,通过自定义模板生成Go代码的工具。
|
||||
|
||||
## 功能设计
|
||||
|
||||
生成流程:
|
||||
1. 读取数据库表结构
|
||||
2. 解析出表结构信息,包括表名、表注释、字段列表
|
||||
3. 根据规则裁切表数据,生成模板数据
|
||||
4. 根据模板生成代码
|
||||
|
||||
## 命令参数设计
|
||||
|
||||
```shell
|
||||
|
||||
18
cmd/gf/internal/cmd/gen/tpl/testdata/dao/dao.tpl
vendored
18
cmd/gf/internal/cmd/gen/tpl/testdata/dao/dao.tpl
vendored
@ -5,22 +5,22 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"{{.table.PackageName}}/internal/cmd/gen/tpl/output/dao/internal"
|
||||
"{{.table.PackageName}}/internal"
|
||||
)
|
||||
|
||||
// internal{{.table.CaseCamel}}Dao is internal type for wrapping internal DAO implements.
|
||||
type internal{{.table.CaseCamel}}Dao = *internal.{{.table.CaseCamel}}Dao
|
||||
// internal{{.table.NameCaseCamel}}Dao is internal type for wrapping internal DAO implements.
|
||||
type internal{{.table.NameCaseCamel}}Dao = *internal.{{.table.NameCaseCamel}}Dao
|
||||
|
||||
// {{.table.CaseCamelLower}}Dao is the data access object for table {{.table.Name}}.
|
||||
// {{.table.NameCaseCamelLower}}Dao is the data access object for table {{.table.Name}}.
|
||||
// You can define custom methods on it to extend its functionality as you wish.
|
||||
type {{.table.CaseCamelLower}}Dao struct {
|
||||
internal{{.table.CaseCamel}}Dao
|
||||
type {{.table.NameCaseCamelLower}}Dao struct {
|
||||
internal{{.table.NameCaseCamel}}Dao
|
||||
}
|
||||
|
||||
var (
|
||||
// {{.table.CaseCamel}} is globally public accessible object for table {{.table.Name}} operations.
|
||||
{{.table.CaseCamel}} = {{.table.CaseCamelLower}}Dao{
|
||||
internal.New{{.table.CaseCamel}}Dao(),
|
||||
// {{.table.NameCaseCamel}} is globally public accessible object for table {{.table.Name}} operations.
|
||||
{{.table.NameCaseCamel}} = {{.table.NameCaseCamelLower}}Dao{
|
||||
internal.New{{.table.NameCaseCamel}}Dao(),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@ -7,54 +7,54 @@ import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// {{.table.CaseCamel}}Dao is the data access object for table {{.table.Name}}.
|
||||
type {{.table.CaseCamel}}Dao struct {
|
||||
// {{.table.NameCaseCamel}}Dao is the data access object for table {{.table.Name}}.
|
||||
type {{.table.NameCaseCamel}}Dao 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 {{.table.CaseCamel}}Columns // columns contains all the column names of Table for convenient usage.
|
||||
columns {{.table.NameCaseCamel}}Columns // columns contains all the column names of Table for convenient usage.
|
||||
}
|
||||
|
||||
// {{.table.CaseCamel}}Columns defines and stores column names for table {{.table.Name}}.
|
||||
type {{.table.CaseCamel}}Columns struct { {{range $i,$v := .table.Fields}}
|
||||
{{$v.NameCase "Camel"}} string // {{$v.Comment}}{{end}}
|
||||
// {{.table.NameCaseCamel}}Columns defines and stores column names for table {{.table.Name}}.
|
||||
type {{.table.NameCaseCamel}}Columns struct { {{range $i,$v := .table.Fields}}
|
||||
{{$v.NameCaseCamel}} string // {{$v.Comment}}{{end}}
|
||||
}
|
||||
|
||||
// {{.table.CaseCamelLower}}Columns holds the columns for table {{.table.Name}}.
|
||||
var {{.table.CaseCamelLower}}Columns = {{.table.CaseCamel}}Columns{ {{range $i,$v := .table.Fields}}
|
||||
{{$v.CaseCamel}}: "{{$v.CaseCamelLower}}",{{end}}
|
||||
// {{.table.NameCaseCamelLower}}Columns holds the columns for table {{.table.Name}}.
|
||||
var {{.table.NameCaseCamelLower}}Columns = {{.table.NameCaseCamel}}Columns{ {{range $i,$v := .table.Fields}}
|
||||
{{$v.NameCaseCamel}}: "{{$v.NameCaseCamelLower}}",{{end}}
|
||||
}
|
||||
|
||||
// New{{.table.CaseCamel}}Dao creates and returns a new DAO object for table data access.
|
||||
func New{{.table.CaseCamel}}Dao() *{{.table.CaseCamel}}Dao {
|
||||
return &{{.table.CaseCamel}}Dao{
|
||||
// New{{.table.NameCaseCamel}}Dao creates and returns a new DAO object for table data access.
|
||||
func New{{.table.NameCaseCamel}}Dao() *{{.table.NameCaseCamel}}Dao {
|
||||
return &{{.table.NameCaseCamel}}Dao{
|
||||
group: "test",
|
||||
table: "{{.table.Name}}",
|
||||
columns: {{.table.CaseCamelLower}}Columns,
|
||||
columns: {{.table.NameCaseCamelLower}}Columns,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
||||
func (dao *{{.table.CaseCamel}}Dao) DB() gdb.DB {
|
||||
func (dao *{{.table.NameCaseCamel}}Dao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of current dao.
|
||||
func (dao *{{.table.CaseCamel}}Dao) Table() string {
|
||||
func (dao *{{.table.NameCaseCamel}}Dao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns all column names of current dao.
|
||||
func (dao *{{.table.CaseCamel}}Dao) Columns() {{.table.CaseCamel}}Columns {
|
||||
func (dao *{{.table.NameCaseCamel}}Dao) Columns() {{.table.NameCaseCamel}}Columns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the configuration group name of database of current dao.
|
||||
func (dao *{{.table.CaseCamel}}Dao) Group() string {
|
||||
func (dao *{{.table.NameCaseCamel}}Dao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
||||
func (dao *{{.table.CaseCamel}}Dao) Ctx(ctx context.Context) *gdb.Model {
|
||||
func (dao *{{.table.NameCaseCamel}}Dao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
@ -64,6 +64,6 @@ func (dao *{{.table.CaseCamel}}Dao) Ctx(ctx context.Context) *gdb.Model {
|
||||
//
|
||||
// Note that, you should not Commit or Rollback the transaction in function f
|
||||
// as it is automatically handled by this function.
|
||||
func (dao *{{.table.CaseCamel}}Dao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
|
||||
func (dao *{{.table.NameCaseCamel}}Dao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
||||
@ -31,35 +31,118 @@ const (
|
||||
CGenTplBrief = `automatically generate template files`
|
||||
CGenTplEg = `
|
||||
gf gen tpl
|
||||
gf gen tpl -t default -p ./template
|
||||
gf gen tpl -l "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
gf gen tpl -p ./model -g user-center -t user,user_detail,user_login
|
||||
gf gen tpl -r user_
|
||||
`
|
||||
|
||||
CGenTplAd = `
|
||||
CONFIGURATION SUPPORT
|
||||
Options are also supported by configuration file.
|
||||
It's suggested using configuration file instead of command line arguments.
|
||||
The configuration node name is "gfcli.gen.tpl" which also supports multiple databases, for example(config.yaml):
|
||||
It's suggested using configuration file instead of command line arguments making producing.
|
||||
The configuration node name is "gfcli.gen.dao", which also supports multiple databases, for example(config.yaml):
|
||||
gfcli:
|
||||
gen:
|
||||
tpl:
|
||||
dao:
|
||||
- link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
tables: "order,products"
|
||||
jsonCase: "CamelLower"
|
||||
- link: "mysql:root:12345678@tcp(127.0.0.1:3306)/primary"
|
||||
path: "./my-app"
|
||||
prefix: "primary_"
|
||||
tables: "user, userDetail"
|
||||
- link: "mysql:root:12345678@tcp(127.0.0.1:3306)/primary"
|
||||
path: "./my-app"
|
||||
prefix: "primary_"
|
||||
tables: "user, userDetail"
|
||||
typeMapping:
|
||||
decimal:
|
||||
type: decimal.Decimal
|
||||
import: github.com/shopspring/decimal
|
||||
numeric:
|
||||
type: string
|
||||
fieldMapping:
|
||||
table_name.field_name:
|
||||
type: decimal.Decimal
|
||||
import: github.com/shopspring/decimal
|
||||
`
|
||||
|
||||
CGenTplBriefPath = `output directory path (default: "./template")`
|
||||
CGenTplBriefPath = `directory path for generated files`
|
||||
CGenTplBriefLink = `database configuration, the same as the ORM configuration of GoFrame`
|
||||
CGenTplBriefTables = `generate models only for given tables, multiple table names separated with ','`
|
||||
CGenTplBriefTablesEx = `generate models excluding given tables, multiple table names separated with ','`
|
||||
CGenTplBriefPrefix = `add prefix for all table of specified link/database tables`
|
||||
CGenTplBriefRemovePrefix = `remove specified prefix of the table, multiple prefix separated with ','`
|
||||
CGenTplBriefRemoveFieldPrefix = `remove specified prefix of the field, multiple prefix separated with ','`
|
||||
CGenTplBriefStdTime = `use time.Time from stdlib instead of gtime.Time for generated time/date fields of tables`
|
||||
CGenTplBriefWithTime = `add created time for auto produced go files`
|
||||
CGenTplBriefGJsonSupport = `use gJsonSupport to use *gjson.Json instead of string for generated json fields of tables`
|
||||
CGenTplBriefImportPrefix = `custom import prefix for generated go files`
|
||||
CGenTplBriefDaoPath = `directory path for storing generated dao files under path`
|
||||
CGenTplBriefDoPath = `directory path for storing generated do files under path`
|
||||
CGenTplBriefEntityPath = `directory path for storing generated entity files under path`
|
||||
CGenTplBriefOverwriteDao = `overwrite all dao files both inside/outside internal folder`
|
||||
CGenTplBriefModelFile = `custom file name for storing generated model content`
|
||||
CGenTplBriefModelFileForDao = `custom file name generating model for DAO operations like Where/Data. It's empty in default`
|
||||
CGenTplBriefDescriptionTag = `add comment to description tag for each field`
|
||||
CGenTplBriefNoJsonTag = `no json tag will be added for each field`
|
||||
CGenTplBriefNoModelComment = `no model comment will be added for each field`
|
||||
CGenTplBriefClear = `delete all generated go files that do not exist in database`
|
||||
CGenTplBriefTypeMapping = `custom local type mapping for generated struct attributes relevant to fields of table`
|
||||
CGenTplBriefFieldMapping = `custom local type mapping for generated struct attributes relevant to specific fields of table`
|
||||
CGenTplBriefGroup = `
|
||||
specifying the configuration group name of database for generated ORM instance,
|
||||
it's not necessary and the default value is "default"
|
||||
`
|
||||
CGenTplBriefJsonCase = `
|
||||
generated json tag case for model struct, cases are as follows:
|
||||
| Case | Example |
|
||||
|---------------- |--------------------|
|
||||
| Camel | AnyKindOfString |
|
||||
| CamelLower | anyKindOfString | default
|
||||
| Snake | any_kind_of_string |
|
||||
| SnakeScreaming | ANY_KIND_OF_STRING |
|
||||
| SnakeFirstUpper | rgb_code_md5 |
|
||||
| Kebab | any-kind-of-string |
|
||||
| KebabScreaming | ANY-KIND-OF-STRING |
|
||||
`
|
||||
CGenTplBriefTplDaoIndexPath = `template file path for dao index file`
|
||||
CGenTplBriefTplDaoInternalPath = `template file path for dao internal file`
|
||||
CGenTplBriefTplDaoDoPathPath = `template file path for dao do file`
|
||||
CGenTplBriefTplDaoEntityPath = `template file path for dao entity file`
|
||||
)
|
||||
|
||||
func init() {
|
||||
gtag.Sets(g.MapStrStr{
|
||||
`CGenTplConfig`: CGenTplConfig,
|
||||
`CGenTplUsage`: CGenTplUsage,
|
||||
`CGenTplBrief`: CGenTplBrief,
|
||||
`CGenTplEg`: CGenTplEg,
|
||||
`CGenTplAd`: CGenTplAd,
|
||||
`CGenTplConfig`: CGenTplConfig,
|
||||
`CGenTplUsage`: CGenTplUsage,
|
||||
`CGenTplBrief`: CGenTplBrief,
|
||||
`CGenTplEg`: CGenTplEg,
|
||||
`CGenTplAd`: CGenTplAd,
|
||||
`CGenTplBriefPath`: CGenTplBriefPath,
|
||||
`CGenTplBriefLink`: CGenTplBriefLink,
|
||||
`CGenTplBriefTables`: CGenTplBriefTables,
|
||||
`CGenTplBriefTablesEx`: CGenTplBriefTablesEx,
|
||||
`CGenTplBriefPrefix`: CGenTplBriefPrefix,
|
||||
`CGenTplBriefRemovePrefix`: CGenTplBriefRemovePrefix,
|
||||
`CGenTplBriefRemoveFieldPrefix`: CGenTplBriefRemoveFieldPrefix,
|
||||
`CGenTplBriefStdTime`: CGenTplBriefStdTime,
|
||||
`CGenTplBriefWithTime`: CGenTplBriefWithTime,
|
||||
`CGenTplBriefDaoPath`: CGenTplBriefDaoPath,
|
||||
`CGenTplBriefDoPath`: CGenTplBriefDoPath,
|
||||
`CGenTplBriefEntityPath`: CGenTplBriefEntityPath,
|
||||
`CGenTplBriefGJsonSupport`: CGenTplBriefGJsonSupport,
|
||||
`CGenTplBriefImportPrefix`: CGenTplBriefImportPrefix,
|
||||
`CGenTplBriefOverwriteDao`: CGenTplBriefOverwriteDao,
|
||||
`CGenTplBriefModelFile`: CGenTplBriefModelFile,
|
||||
`CGenTplBriefModelFileForDao`: CGenTplBriefModelFileForDao,
|
||||
`CGenTplBriefDescriptionTag`: CGenTplBriefDescriptionTag,
|
||||
`CGenTplBriefNoJsonTag`: CGenTplBriefNoJsonTag,
|
||||
`CGenTplBriefNoModelComment`: CGenTplBriefNoModelComment,
|
||||
`CGenTplBriefClear`: CGenTplBriefClear,
|
||||
`CGenTplBriefTypeMapping`: CGenTplBriefTypeMapping,
|
||||
`CGenTplBriefFieldMapping`: CGenTplBriefFieldMapping,
|
||||
`CGenTplBriefGroup`: CGenTplBriefGroup,
|
||||
`CGenTplBriefJsonCase`: CGenTplBriefJsonCase,
|
||||
`CGenTplBriefTplDaoIndexPath`: CGenTplBriefTplDaoIndexPath,
|
||||
`CGenTplBriefTplDaoInternalPath`: CGenTplBriefTplDaoInternalPath,
|
||||
`CGenTplBriefTplDaoDoPathPath`: CGenTplBriefTplDaoDoPathPath,
|
||||
`CGenTplBriefTplDaoEntityPath`: CGenTplBriefTplDaoEntityPath,
|
||||
})
|
||||
}
|
||||
|
||||
@ -69,32 +152,34 @@ type (
|
||||
g.Meta `name:"tpl" config:"{CGenTplConfig}" usage:"{CGenTplUsage}" brief:"{CGenTplBrief}" eg:"{CGenTplEg}" ad:"{CGenTplAd}"`
|
||||
Path string `name:"path" short:"p" brief:"{CGenTplBriefPath}" d:"./output"`
|
||||
TplPath string `name:"tplPath" short:"tp" brief:"模板目录路径"`
|
||||
Link string `name:"link" short:"l" brief:"{CGenDaoBriefLink}"`
|
||||
Tables string `name:"tables" short:"t" brief:"{CGenDaoBriefTables}"`
|
||||
TablesEx string `name:"tablesEx" short:"x" brief:"{CGenDaoBriefTablesEx}"`
|
||||
Group string `name:"group" short:"g" brief:"{CGenDaoBriefGroup}" d:"default"`
|
||||
Prefix string `name:"prefix" short:"f" brief:"{CGenDaoBriefPrefix}"`
|
||||
RemovePrefix string `name:"removePrefix" short:"r" brief:"{CGenDaoBriefRemovePrefix}"`
|
||||
RemoveFieldPrefix string `name:"removeFieldPrefix" short:"rf" brief:"{CGenDaoBriefRemoveFieldPrefix}"`
|
||||
JsonCase string `name:"jsonCase" short:"j" brief:"{CGenDaoBriefJsonCase}" d:"CamelLower"`
|
||||
ImportPrefix string `name:"importPrefix" short:"i" brief:"{CGenDaoBriefImportPrefix}"`
|
||||
// DaoPath string `name:"daoPath" short:"d" brief:"{CGenDaoBriefDaoPath}" d:"dao"`
|
||||
// DoPath string `name:"doPath" short:"o" brief:"{CGenDaoBriefDoPath}" d:"model/do"`
|
||||
// EntityPath string `name:"entityPath" short:"e" brief:"{CGenDaoBriefEntityPath}" d:"model/entity"`
|
||||
// TplDaoIndexPath string `name:"tplDaoIndexPath" short:"t1" brief:"{CGenDaoBriefTplDaoIndexPath}"`
|
||||
// TplDaoInternalPath string `name:"tplDaoInternalPath" short:"t2" brief:"{CGenDaoBriefTplDaoInternalPath}"`
|
||||
// TplDaoDoPath string `name:"tplDaoDoPath" short:"t3" brief:"{CGenDaoBriefTplDaoDoPathPath}"`
|
||||
// TplDaoEntityPath string `name:"tplDaoEntityPath" short:"t4" brief:"{CGenDaoBriefTplDaoEntityPath}"`
|
||||
StdTime bool `name:"stdTime" short:"s" brief:"{CGenDaoBriefStdTime}" orphan:"true"`
|
||||
WithTime bool `name:"withTime" short:"w" brief:"{CGenDaoBriefWithTime}" orphan:"true"`
|
||||
GJsonSupport bool `name:"gJsonSupport" short:"n" brief:"{CGenDaoBriefGJsonSupport}" orphan:"true"`
|
||||
OverwriteDao bool `name:"overwriteDao" short:"v" brief:"{CGenDaoBriefOverwriteDao}" orphan:"true"`
|
||||
DescriptionTag bool `name:"descriptionTag" short:"c" brief:"{CGenDaoBriefDescriptionTag}" orphan:"true"`
|
||||
NoJsonTag bool `name:"noJsonTag" short:"k" brief:"{CGenDaoBriefNoJsonTag}" orphan:"true"`
|
||||
NoModelComment bool `name:"noModelComment" short:"m" brief:"{CGenDaoBriefNoModelComment}" orphan:"true"`
|
||||
Clear bool `name:"clear" short:"a" brief:"{CGenDaoBriefClear}" orphan:"true"`
|
||||
TypeMapping map[string]CustomAttributeType `name:"typeMapping" short:"y" brief:"{CGenDaoBriefTypeMapping}" orphan:"true"`
|
||||
FieldMapping map[string]CustomAttributeType `name:"fieldMapping" short:"fm" brief:"{CGenDaoBriefFieldMapping}" orphan:"true"`
|
||||
Link string `name:"link" short:"l" brief:"{CGenTplBriefLink}"`
|
||||
Tables string `name:"tables" short:"t" brief:"{CGenTplBriefTables}"`
|
||||
TablesEx string `name:"tablesEx" short:"x" brief:"{CGenTplBriefTablesEx}"`
|
||||
Group string `name:"group" short:"g" brief:"{CGenTplBriefGroup}" d:"default"`
|
||||
Prefix string `name:"prefix" short:"f" brief:"{CGenTplBriefPrefix}"`
|
||||
RemovePrefix string `name:"removePrefix" short:"r" brief:"{CGenTplBriefRemovePrefix}"`
|
||||
RemoveFieldPrefix string `name:"removeFieldPrefix" short:"rf" brief:"{CGenTplBriefRemoveFieldPrefix}"`
|
||||
JsonCase string `name:"jsonCase" short:"j" brief:"{CGenTplBriefJsonCase}" d:"CamelLower"`
|
||||
ImportPrefix string `name:"importPrefix" short:"i" brief:"{CGenTplBriefImportPrefix}"`
|
||||
// 新增过滤参数
|
||||
TableNamePattern string `name:"tableNamePattern" short:"tn" brief:"表名匹配模式,支持通配符"`
|
||||
// DaoPath string `name:"daoPath" short:"d" brief:"{CGenTplBriefDaoPath}" d:"dao"`
|
||||
// DoPath string `name:"doPath" short:"o" brief:"{CGenTplBriefDoPath}" d:"model/do"`
|
||||
// EntityPath string `name:"entityPath" short:"e" brief:"{CGenTplBriefEntityPath}" d:"model/entity"`
|
||||
// TplDaoIndexPath string `name:"tplDaoIndexPath" short:"t1" brief:"{CGenTplBriefTplDaoIndexPath}"`
|
||||
// TplDaoInternalPath string `name:"tplDaoInternalPath" short:"t2" brief:"{CGenTplBriefTplDaoInternalPath}"`
|
||||
// TplDaoDoPath string `name:"tplDaoDoPath" short:"t3" brief:"{CGenTplBriefTplDaoDoPathPath}"`
|
||||
// TplDaoEntityPath string `name:"tplDaoEntityPath" short:"t4" brief:"{CGenTplBriefTplDaoEntityPath}"`
|
||||
StdTime bool `name:"stdTime" short:"s" brief:"{CGenTplBriefStdTime}" orphan:"true"`
|
||||
WithTime bool `name:"withTime" short:"w" brief:"{CGenTplBriefWithTime}" orphan:"true"`
|
||||
GJsonSupport bool `name:"gJsonSupport" short:"n" brief:"{CGenTplBriefGJsonSupport}" orphan:"true"`
|
||||
OverwriteDao bool `name:"overwriteDao" short:"v" brief:"{CGenTplBriefOverwriteDao}" orphan:"true"`
|
||||
DescriptionTag bool `name:"descriptionTag" short:"c" brief:"{CGenTplBriefDescriptionTag}" orphan:"true"`
|
||||
NoJsonTag bool `name:"noJsonTag" short:"k" brief:"{CGenTplBriefNoJsonTag}" orphan:"true"`
|
||||
NoModelComment bool `name:"noModelComment" short:"m" brief:"{CGenTplBriefNoModelComment}" orphan:"true"`
|
||||
Clear bool `name:"clear" short:"a" brief:"{CGenTplBriefClear}" orphan:"true"`
|
||||
TypeMapping map[string]CustomAttributeType `name:"typeMapping" short:"y" brief:"{CGenTplBriefTypeMapping}" orphan:"true"`
|
||||
FieldMapping map[string]CustomAttributeType `name:"fieldMapping" short:"fm" brief:"{CGenTplBriefFieldMapping}" orphan:"true"`
|
||||
}
|
||||
CGenTplOutput struct{}
|
||||
|
||||
@ -125,23 +210,47 @@ type (
|
||||
DBFieldTypeName = string
|
||||
)
|
||||
|
||||
// GetTables 获取数据库表结构信息
|
||||
func GetTables(ctx context.Context, db gdb.DB) Tables {
|
||||
tablesName, err := db.Tables(ctx)
|
||||
// TplObj description
|
||||
type TplObj struct {
|
||||
ctx context.Context
|
||||
in CGenTplInput
|
||||
db gdb.DB
|
||||
TplPathAbs string
|
||||
}
|
||||
|
||||
// NewTpl description
|
||||
//
|
||||
// createTime: 2025-01-25 16:36:43
|
||||
func NewTpl(ctx context.Context, in CGenTplInput) (*TplObj, error) {
|
||||
db, err := in.GetDB()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
fmt.Println(tablesName)
|
||||
tables := make(Tables, 0)
|
||||
for _, v := range tablesName {
|
||||
t, err := NewTable(ctx, db, v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
t.SortFields(true)
|
||||
tables = append(tables, t)
|
||||
return &TplObj{
|
||||
ctx: ctx,
|
||||
in: in,
|
||||
db: db,
|
||||
TplPathAbs: gfile.Abs(in.TplPath),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t *TplObj) ShowParams() {
|
||||
mlog.Debug("tplPath:", t.in.TplPath)
|
||||
mlog.Debug("output:", t.in.Path)
|
||||
}
|
||||
func (t *TplObj) Format() {
|
||||
utils.GoFmt(t.in.Path)
|
||||
}
|
||||
|
||||
// GetTplFileList description
|
||||
//
|
||||
// createTime: 2025-01-25 16:43:06
|
||||
func (t *TplObj) GetTplFileList() ([]string, error) {
|
||||
tplList, err := gfile.ScanDirFile(t.TplPathAbs, "*.tpl", true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tables
|
||||
return tplList, nil
|
||||
}
|
||||
|
||||
func (c CGenTpl) Tpl(ctx context.Context, in CGenTplInput) (out *CGenTplOutput, err error) {
|
||||
@ -163,17 +272,12 @@ func (c CGenTpl) Tpl(ctx context.Context, in CGenTplInput) (out *CGenTplOutput,
|
||||
}
|
||||
}
|
||||
|
||||
db, err := in.GetDB()
|
||||
tplObj, err := NewTpl(ctx, in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outputDir := in.Path
|
||||
tplRootDir := in.TplPath
|
||||
mlog.Print("output directory:", outputDir)
|
||||
mlog.Print("template directory:", tplRootDir)
|
||||
tplRootDir = gfile.Abs(tplRootDir)
|
||||
fmt.Println(tplRootDir)
|
||||
tplList, err := gfile.ScanDirFile(tplRootDir, "*.tpl", true)
|
||||
|
||||
tplList, err := tplObj.GetTplFileList()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -182,38 +286,64 @@ func (c CGenTpl) Tpl(ctx context.Context, in CGenTplInput) (out *CGenTplOutput,
|
||||
fmt.Printf("%#v\n", Table{})
|
||||
fmt.Printf("%#v\n", TableField{})
|
||||
|
||||
tables := GetTables(ctx, db)
|
||||
tables, err := tplObj.GetTables()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
view := gview.New()
|
||||
|
||||
for _, table := range tables {
|
||||
table.PackageName = "github.com/gogf/gf/cmd/gf/v2"
|
||||
|
||||
tplData := g.Map{
|
||||
"table": table,
|
||||
"tables": tables,
|
||||
}
|
||||
fmt.Println(table.FieldsJsonStr("Snake"))
|
||||
fmt.Println(table.FieldsJsonStr(in.JsonCase))
|
||||
for _, tpl := range tplList {
|
||||
tplDir := gfile.Dir(tpl)
|
||||
mlog.Print("generating template file:", tpl)
|
||||
// 相对路径
|
||||
relativePath := strings.TrimPrefix(gfile.Dir(tpl), tplObj.TplPathAbs)
|
||||
mlog.Print("relativePath:", relativePath)
|
||||
table.PackageName = filepath.ToSlash(filepath.Join(in.ImportPrefix, relativePath))
|
||||
filePath := filepath.Join(relativePath, table.FileName())
|
||||
mlog.Print("generating table filePath:", filePath)
|
||||
|
||||
res, err := view.Parse(ctx, tpl, tplData)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
// fmt.Println(res, err)
|
||||
filePath := filepath.FromSlash(fmt.Sprintf(outputDir+"%s/%s.go", strings.TrimPrefix(tplDir, tplRootDir), table.Name))
|
||||
err = gfile.PutContents(filePath, res)
|
||||
fmt.Println(len(res), err)
|
||||
|
||||
err = tplObj.SaveFile(ctx, filePath, res)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
utils.GoFmt(filePath)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Format generated files
|
||||
tplObj.Format()
|
||||
|
||||
mlog.Print("template files generated successfully!")
|
||||
return &CGenTplOutput{}, nil
|
||||
}
|
||||
|
||||
// SaveFile description
|
||||
//
|
||||
// createTime: 2025-01-25 17:05:25
|
||||
func (t *TplObj) SaveFile(ctx context.Context, path, content string) error {
|
||||
mlog.Print("saving file:", path)
|
||||
path = filepath.Join(t.in.Path, path)
|
||||
mlog.Print("saving file:", path)
|
||||
path = filepath.FromSlash(path)
|
||||
mlog.Print("saving file:", path)
|
||||
if err := gfile.PutContents(path, content); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetDB description
|
||||
//
|
||||
// createTime: 2025-01-24 16:58:46
|
||||
|
||||
@ -13,12 +13,18 @@ import (
|
||||
type TableField struct {
|
||||
gdb.TableField
|
||||
LocalType string
|
||||
JsonCase string
|
||||
}
|
||||
|
||||
type TableFields []*TableField
|
||||
|
||||
func (s TableFields) Len() int { return len(s) }
|
||||
// Len returns the length of TableFields slice
|
||||
func (s TableFields) Len() int { return len(s) }
|
||||
|
||||
// Swap swaps the elements with indexes i and j
|
||||
func (s TableFields) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// Less reports whether the element with index i should sort before the element with index j
|
||||
func (s TableFields) Less(i, j int) bool {
|
||||
return strings.Compare(s[i].Name, s[j].Name) < 0
|
||||
}
|
||||
@ -94,27 +100,34 @@ func (field *TableField) GetLocalTypeName(ctx context.Context, db gdb.DB, in Inp
|
||||
return
|
||||
}
|
||||
|
||||
// NameCase description
|
||||
func (f *TableField) NameCase(caseName string) string {
|
||||
// NameJsonCase description
|
||||
//
|
||||
// createTime: 2025-01-25 15:27:01
|
||||
func (f *TableField) NameJsonCase() string {
|
||||
return gstr.CaseConvert(f.Name, gstr.CaseTypeMatch(f.JsonCase))
|
||||
}
|
||||
|
||||
// NameCaseConvert 字段名转换
|
||||
func (f *TableField) NameCaseConvert(caseName string) string {
|
||||
return gstr.CaseConvert(f.Name, gstr.CaseTypeMatch(caseName))
|
||||
}
|
||||
|
||||
// CaseCamel description
|
||||
func (f *TableField) CaseCamel() string {
|
||||
// NameCaseCamel returns the field name in camel case format
|
||||
func (f *TableField) NameCaseCamel() string {
|
||||
return gstr.CaseCamel(f.Name)
|
||||
}
|
||||
|
||||
// CaseCamelLower description
|
||||
func (f *TableField) CaseCamelLower() string {
|
||||
// NameCaseCamelLower returns the field name in lower camel case format
|
||||
func (f *TableField) NameCaseCamelLower() string {
|
||||
return gstr.CaseCamelLower(f.Name)
|
||||
}
|
||||
|
||||
// CaseSnake description
|
||||
func (f *TableField) CaseSnake() string {
|
||||
// NameCaseSnake returns the field name in snake case format
|
||||
func (f *TableField) NameCaseSnake() string {
|
||||
return gstr.CaseSnake(f.Name)
|
||||
}
|
||||
|
||||
// CaseKebabScreaming description
|
||||
func (f *TableField) CaseKebabScreaming() string {
|
||||
// NameCaseKebabScreaming returns the field name in screaming kebab case format
|
||||
func (f *TableField) NameCaseKebabScreaming() string {
|
||||
return gstr.CaseKebabScreaming(f.Name)
|
||||
}
|
||||
|
||||
@ -4,7 +4,9 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
@ -12,12 +14,14 @@ import (
|
||||
|
||||
// Table description
|
||||
type Table struct {
|
||||
Name string
|
||||
PackageName string
|
||||
db gdb.DB
|
||||
Fields TableFields
|
||||
FieldsSource map[string]*gdb.TableField
|
||||
Imports map[string]struct{}
|
||||
Name string // 表名
|
||||
OutputName string // 输出表名,用于生成文件名
|
||||
OutputNameCase string // 输出表名的命名规则
|
||||
PackageName string
|
||||
db gdb.DB
|
||||
Fields TableFields
|
||||
FieldsSource map[string]*gdb.TableField
|
||||
Imports map[string]struct{}
|
||||
}
|
||||
|
||||
type Tables []*Table
|
||||
@ -27,13 +31,14 @@ type Tables []*Table
|
||||
// createTime: 2023-12-11 16:17:33
|
||||
//
|
||||
// author: hailaz
|
||||
func NewTable(ctx context.Context, db gdb.DB, tableName string) (*Table, error) {
|
||||
func NewTable(ctx context.Context, db gdb.DB, tableName string, tableOutputName string) (*Table, error) {
|
||||
fields, err := db.TableFields(ctx, tableName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
table := Table{
|
||||
Name: tableName,
|
||||
OutputName: tableOutputName,
|
||||
FieldsSource: fields,
|
||||
db: db,
|
||||
Imports: make(map[string]struct{}),
|
||||
@ -51,26 +56,36 @@ func (t *Table) Show() string {
|
||||
return fmt.Sprintf("table name is %s", t.Name)
|
||||
}
|
||||
|
||||
// CaseCamel description
|
||||
func (t *Table) CaseCamel() string {
|
||||
// NameCase description
|
||||
func (t *Table) NameCase() string {
|
||||
return gstr.CaseConvert(t.Name, gstr.CaseTypeMatch(t.OutputNameCase))
|
||||
}
|
||||
|
||||
// NameCaseCamel description
|
||||
func (t *Table) NameCaseCamel() string {
|
||||
return gstr.CaseCamel(t.Name)
|
||||
}
|
||||
|
||||
// CaseCamelLower description
|
||||
func (t *Table) CaseCamelLower() string {
|
||||
// NameCaseCamelLower description
|
||||
func (t *Table) NameCaseCamelLower() string {
|
||||
return gstr.CaseCamelLower(t.Name)
|
||||
}
|
||||
|
||||
// CaseSnake description
|
||||
func (t *Table) CaseSnake() string {
|
||||
// NameCaseSnake description
|
||||
func (t *Table) NameCaseSnake() string {
|
||||
return gstr.CaseSnake(t.Name)
|
||||
}
|
||||
|
||||
// CaseKebabScreaming description
|
||||
func (t *Table) CaseKebabScreaming() string {
|
||||
// NameCaseKebabScreaming description
|
||||
func (t *Table) NameCaseKebabScreaming() string {
|
||||
return gstr.CaseKebabScreaming(t.Name)
|
||||
}
|
||||
|
||||
// FileName description
|
||||
func (t *Table) FileName() string {
|
||||
return gstr.CaseConvert(t.OutputName, gstr.CaseTypeMatch(t.OutputNameCase)) + ".go"
|
||||
}
|
||||
|
||||
// toTableFields description
|
||||
//
|
||||
// createTime: 2023-10-23 17:22:40
|
||||
@ -96,7 +111,7 @@ func (t *Table) toTableFields() {
|
||||
}
|
||||
}
|
||||
|
||||
// SortFields description
|
||||
// SortFields 字段排序
|
||||
//
|
||||
// createTime: 2023-10-23 17:18:22
|
||||
//
|
||||
@ -109,7 +124,7 @@ func (t *Table) SortFields(isReverse bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// JsonStr description
|
||||
// FieldsJsonStr 表字段json字符串
|
||||
//
|
||||
// createTime: 2023-10-23 17:29:39
|
||||
//
|
||||
@ -117,7 +132,7 @@ func (t *Table) SortFields(isReverse bool) {
|
||||
func (t *Table) FieldsJsonStr(caseName string) string {
|
||||
mapStr := make(map[string]interface{}, len(t.Fields))
|
||||
for _, v := range t.Fields {
|
||||
mapStr[v.NameCase(caseName)] = v.Default
|
||||
mapStr[v.NameCaseConvert(caseName)] = v.Default
|
||||
}
|
||||
b, err := json.MarshalIndent(mapStr, "", " ")
|
||||
if err != nil {
|
||||
@ -125,3 +140,106 @@ func (t *Table) FieldsJsonStr(caseName string) string {
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// GetTables 获取数据库表结构信息
|
||||
func (t *TplObj) GetTables() (Tables, error) {
|
||||
nameList, err := t.db.Tables(t.ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 过滤表名
|
||||
nameList = filterTablesByName(nameList, t.in.TableNamePattern)
|
||||
|
||||
// 根据Tables参数过滤
|
||||
nameList = filterTablesByInclude(nameList, t.in.Tables)
|
||||
|
||||
// 根据TablesEx参数过滤
|
||||
nameList = filterTablesByExclude(nameList, t.in.TablesEx)
|
||||
|
||||
tables := make(Tables, 0, len(nameList))
|
||||
for _, v := range nameList {
|
||||
t, err := NewTable(t.ctx, t.db, v, t.TableOutputName(v))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
t.SortFields(true)
|
||||
tables = append(tables, t)
|
||||
}
|
||||
|
||||
return tables, nil
|
||||
}
|
||||
|
||||
// TableOutputName description
|
||||
//
|
||||
// createTime: 2025-01-25 17:20:46
|
||||
func (t *TplObj) TableOutputName(name string) string {
|
||||
if t.in.Prefix != "" {
|
||||
name = t.in.Prefix + name
|
||||
}
|
||||
|
||||
if t.in.RemovePrefix != "" {
|
||||
name = strings.TrimPrefix(name, t.in.RemovePrefix)
|
||||
}
|
||||
|
||||
return name
|
||||
}
|
||||
|
||||
// 新增过滤函数
|
||||
func filterTablesByName(tables []string, pattern string) []string {
|
||||
if pattern == "" {
|
||||
return tables
|
||||
}
|
||||
var result []string
|
||||
re, err := regexp.Compile(pattern)
|
||||
if err != nil {
|
||||
return tables
|
||||
}
|
||||
for _, table := range tables {
|
||||
if re.MatchString(table) {
|
||||
result = append(result, table)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// 根据包含表名过滤
|
||||
func filterTablesByInclude(tables []string, include string) []string {
|
||||
if include == "" {
|
||||
return tables
|
||||
}
|
||||
includeTables := strings.Split(include, ",")
|
||||
result := make([]string, 0, len(includeTables))
|
||||
for _, table := range tables {
|
||||
for _, includeTable := range includeTables {
|
||||
if table == includeTable {
|
||||
result = append(result, table)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// 根据排除表名过滤
|
||||
func filterTablesByExclude(tables []string, exclude string) []string {
|
||||
if exclude == "" {
|
||||
return tables
|
||||
}
|
||||
excludeTables := strings.Split(exclude, ",")
|
||||
result := make([]string, 0, len(tables))
|
||||
for _, table := range tables {
|
||||
exclude := false
|
||||
for _, excludeTable := range excludeTables {
|
||||
if table == excludeTable {
|
||||
exclude = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !exclude {
|
||||
result = append(result, table)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@ -12,9 +12,11 @@ func TestTpl(t *testing.T) {
|
||||
c := tpl.CGenTpl{}
|
||||
t.Log(c)
|
||||
out, err := c.Tpl(context.Background(), tpl.CGenTplInput{
|
||||
Path: "./output",
|
||||
TplPath: "./testdata",
|
||||
Link: fmt.Sprintf("mysql:root:%s@tcp(127.0.0.1:3306)/focus?loc=Local&parseTime=true", "root123"),
|
||||
Path: "./output",
|
||||
TplPath: "./testdata",
|
||||
Link: fmt.Sprintf("mysql:root:%s@tcp(127.0.0.1:3306)/focus?loc=Local&parseTime=true", "root123"),
|
||||
Tables: "gf_user",
|
||||
ImportPrefix: "github.com/gogf/gf/cmd/gf/v2/internal/cmd/gen/tpl/output",
|
||||
})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
|
||||
Reference in New Issue
Block a user