feat(gendao): 添加代码生成工具用于自动生成DAO层代码

- 实现了完整的gendao命令行工具功能
- 添加了模板文件用于生成DAO、DO、Entity等代码结构
- 集成了数据库表字段映射和类型转换功能
- 支持分片表模式匹配和自定义配置选项
- 实现了代码清理和格式化功能
- 提供了灵活的表名过滤和前缀处理机制
This commit is contained in:
maguodong
2026-04-08 16:53:01 +08:00
parent 398e732301
commit 8475859a70
34 changed files with 99 additions and 1408 deletions
@@ -28,8 +28,8 @@ import (
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
"git.magicany.cc/black1552/gin-base/cmd/gf-source/internal/utility/mlog"
"git.magicany.cc/black1552/gin-base/cmd/gf-source/internal/utility/utils"
"git.magicany.cc/black1552/gin-base/cmd/gendao/internal/utility/mlog"
"git.magicany.cc/black1552/gin-base/cmd/gendao/internal/utility/utils"
)
type (
@@ -10,7 +10,7 @@ import (
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/text/gstr"
"git.magicany.cc/black1552/gin-base/cmd/gf-source/internal/utility/mlog"
"git.magicany.cc/black1552/gin-base/cmd/gendao/internal/utility/mlog"
)
func doClear(items *CGenDaoInternalGenItems) {
@@ -13,6 +13,7 @@ import (
"path/filepath"
"strings"
"git.magicany.cc/black1552/gin-base/cmd/consts"
"github.com/olekukonko/tablewriter"
"git.magicany.cc/black1552/gin-base/database"
@@ -21,9 +22,8 @@ import (
"github.com/gogf/gf/v2/os/gview"
"github.com/gogf/gf/v2/text/gstr"
"git.magicany.cc/black1552/gin-base/cmd/gf-source/internal/consts"
"git.magicany.cc/black1552/gin-base/cmd/gf-source/internal/utility/mlog"
"git.magicany.cc/black1552/gin-base/cmd/gf-source/internal/utility/utils"
"git.magicany.cc/black1552/gin-base/cmd/gendao/internal/utility/mlog"
"git.magicany.cc/black1552/gin-base/cmd/gendao/internal/utility/utils"
)
func generateDao(ctx context.Context, in CGenDaoInternalInput) {
@@ -12,14 +12,14 @@ import (
"path/filepath"
"strings"
"git.magicany.cc/black1552/gin-base/cmd/consts"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gview"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
"git.magicany.cc/black1552/gin-base/cmd/gf-source/internal/consts"
"git.magicany.cc/black1552/gin-base/cmd/gf-source/internal/utility/mlog"
"git.magicany.cc/black1552/gin-base/cmd/gf-source/internal/utility/utils"
"git.magicany.cc/black1552/gin-base/cmd/gendao/internal/utility/mlog"
"git.magicany.cc/black1552/gin-base/cmd/gendao/internal/utility/utils"
)
func generateDo(ctx context.Context, in CGenDaoInternalInput) {
@@ -11,13 +11,13 @@ import (
"path/filepath"
"strings"
"git.magicany.cc/black1552/gin-base/cmd/consts"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gview"
"github.com/gogf/gf/v2/text/gstr"
"git.magicany.cc/black1552/gin-base/cmd/gf-source/internal/consts"
"git.magicany.cc/black1552/gin-base/cmd/gf-source/internal/utility/mlog"
"git.magicany.cc/black1552/gin-base/cmd/gf-source/internal/utility/utils"
"git.magicany.cc/black1552/gin-base/cmd/gendao/internal/utility/mlog"
"git.magicany.cc/black1552/gin-base/cmd/gendao/internal/utility/utils"
)
func generateEntity(ctx context.Context, in CGenDaoInternalInput) {
@@ -14,15 +14,15 @@ import (
"strconv"
"strings"
"git.magicany.cc/black1552/gin-base/cmd/consts"
"git.magicany.cc/black1552/gin-base/database"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gview"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
"git.magicany.cc/black1552/gin-base/cmd/gf-source/internal/consts"
"git.magicany.cc/black1552/gin-base/cmd/gf-source/internal/utility/mlog"
"git.magicany.cc/black1552/gin-base/cmd/gf-source/internal/utility/utils"
"git.magicany.cc/black1552/gin-base/cmd/gendao/internal/utility/mlog"
"git.magicany.cc/black1552/gin-base/cmd/gendao/internal/utility/utils"
)
// generateTable generates dao files for given tables.
@@ -17,8 +17,8 @@ import (
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
"git.magicany.cc/black1552/gin-base/cmd/gf-source/internal/consts"
"git.magicany.cc/black1552/gin-base/cmd/gf-source/internal/utility/mlog"
"git.magicany.cc/black1552/gin-base/cmd/gendao/internal/consts"
"git.magicany.cc/black1552/gin-base/cmd/gendao/internal/utility/mlog"
)
// GoFmt formats the source file and adds or removes import statements as necessary.
@@ -16,7 +16,7 @@ import (
"github.com/gogf/gf/v2/errors/gerror"
"git.magicany.cc/black1552/gin-base/cmd/gf-source/internal/utility/mlog"
"git.magicany.cc/black1552/gin-base/cmd/gendao/internal/utility/mlog"
)
// HTTPDownloadFileWithPercent downloads target url file to local path with percent process printing.
@@ -12,7 +12,7 @@ import (
"github.com/gogf/gf/v2/test/gtest"
"git.magicany.cc/black1552/gin-base/cmd/gf-source/internal/utility/utils"
"git.magicany.cc/black1552/gin-base/cmd/gendao/internal/utility/utils"
)
func Test_GetModPath(t *testing.T) {
-12
View File
@@ -1,12 +0,0 @@
module git.magicany.cc/black1552/gin-base/cmd/gf-source
go 1.25.0
require (
git.magicany.cc/black1552/gin-base v0.0.0
github.com/gogf/gf/v2 v2.10.0
github.com/olekukonko/tablewriter v1.1.4
golang.org/x/mod v0.33.0
)
replace git.magicany.cc/black1552/gin-base => ../..
@@ -1,87 +0,0 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package consts
const TemplateGenCtrlControllerEmpty = `
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package {Module}
`
const TemplateGenCtrlControllerNewEmpty = `
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package {Module}
import (
{ImportPath}
)
`
const TemplateGenCtrlControllerNewFunc = `
type {CtrlName} struct{}
func {NewFuncName}() {InterfaceName} {
return &{CtrlName}{}
}
`
const TemplateGenCtrlControllerMethodFunc = `
package {Module}
import (
"context"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"{ImportPath}"
)
{MethodComment}
func (c *{CtrlName}) {MethodName}(ctx context.Context, req *{Version}.{MethodName}Req) (res *{Version}.{MethodName}Res, err error) {
return nil, gerror.NewCode(gcode.CodeNotImplemented)
}
`
const TemplateGenCtrlControllerHeader = `
package {Module}
import (
"context"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"{ImportPath}"
)
`
const TemplateGenCtrlControllerMethodFuncMerge = `
{MethodComment}
func (c *{CtrlName}) {MethodName}(ctx context.Context, req *{Version}.{MethodName}Req) (res *{Version}.{MethodName}Res, err error) {
return nil, gerror.NewCode(gcode.CodeNotImplemented)
}
`
const TemplateGenCtrlApiInterface = `
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package {Module}
import (
{ImportPaths}
)
{Interfaces}
`
@@ -1,89 +0,0 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package consts
const TemplateGenCtrlSdkPkgNew = `
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package {PkgName}
import (
"fmt"
"github.com/gogf/gf/contrib/sdk/httpclient/v2"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/text/gstr"
)
type implementer struct {
config httpclient.Config
}
func New(config httpclient.Config) IClient {
return &implementer{
config: config,
}
}
`
const TemplateGenCtrlSdkIClient = `
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package {PkgName}
import (
)
type IClient interface {
}
`
const TemplateGenCtrlSdkImplementer = `
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package {PkgName}
import (
"context"
"github.com/gogf/gf/contrib/sdk/httpclient/v2"
"github.com/gogf/gf/v2/text/gstr"
{ImportPaths}
)
type implementer{ImplementerName} struct {
*httpclient.Client
}
`
const TemplateGenCtrlSdkImplementerNew = `
func (i *implementer) {ImplementerName}() {Module}.I{ImplementerName} {
var (
client = httpclient.New(i.config)
prefix = gstr.TrimRight(i.config.URL, "/") + "{VersionPrefix}"
)
client.Client = client.Prefix(prefix)
return &implementer{ImplementerName}{client}
}
`
const TemplateGenCtrlSdkImplementerFunc = `{MethodComment}
func (i *implementer{ImplementerName}) {MethodName}(ctx context.Context, req *{Version}.{MethodName}Req) (res *{Version}.{MethodName}Res, err error) {
err = i.Request(ctx, req, &res)
return
}
`
@@ -1,23 +0,0 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package consts
const TemplateGenEnums = `
// ================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// ================================================================================
package {PackageName}
import (
"github.com/gogf/gf/v2/util/gtag"
)
func init() {
gtag.SetGlobalEnums({EnumsJson})
}
`
@@ -1,23 +0,0 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package consts
const TemplatePbEntityMessageContent = `
// ==========================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// ==========================================================================
syntax = "proto3";
package {PackageName};
option go_package = "{GoPackage}";
{OptionContent}
{Imports}
{EntityMessage}
`
@@ -1,41 +0,0 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package consts
const TemplateGenServiceContentHead = `
// ================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// You can delete these comments if you wish manually maintain this interface file.
// ================================================================================
package {PackageName}
{Imports}
`
const TemplateGenServiceContentInterface = `
{InterfaceName} interface {
{FuncDefinition}
}
`
const TemplateGenServiceContentVariable = `
local{StructName} {InterfaceName}
`
const TemplateGenServiceContentRegister = `
func {StructName}() {InterfaceName} {
if local{StructName} == nil {
panic("implement not found for interface {InterfaceName}, forgot register?")
}
return local{StructName}
}
func Register{StructName}(i {InterfaceName}) {
local{StructName} = i
}
`
@@ -1,19 +0,0 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package consts
const TemplateGenServiceLogicContent = `
// ==========================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// ==========================================================================
package {PackageName}
import(
{Imports}
)
`
@@ -1,138 +0,0 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package consts
const TemplateGenDaoIndexContent = `
// =================================================================================
// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.
// =================================================================================
package {{.TplPackageName}}
import (
"{{.TplImportPrefix}}/internal"
)
// {{.TplTableNameCamelLowerCase}}Dao is the data access object for the table {{.TplTableName}}.
// You can define custom methods on it to extend its functionality as needed.
type {{.TplTableNameCamelLowerCase}}Dao struct {
*internal.{{.TplTableNameCamelCase}}Dao
}
var (
// {{.TplTableNameCamelCase}} is a globally accessible object for table {{.TplTableName}} operations.
{{.TplTableNameCamelCase}} = {{.TplTableNameCamelLowerCase}}Dao{
{{- if .TplTableSharding -}}
internal.New{{.TplTableNameCamelCase}}Dao({{.TplTableNameCamelLowerCase}}ShardingHandler),
{{- else -}}
internal.New{{.TplTableNameCamelCase}}Dao(),
{{- end -}}
}
)
{{if .TplTableSharding -}}
// {{.TplTableNameCamelLowerCase}}ShardingHandler is the handler for sharding operations.
// You can fill this sharding handler with your custom implementation.
func {{.TplTableNameCamelLowerCase}}ShardingHandler(m *database.Model) *database.Model {
m = m.Sharding(database.ShardingConfig{
Table: database.ShardingTableConfig{
Enable: true,
Prefix: "{{.TplTableShardingPrefix}}",
// Replace Rule field with your custom sharding rule.
// Or you can use "&database.DefaultShardingRule{}" for default sharding rule.
Rule: nil,
},
Schema: database.ShardingSchemaConfig{},
})
return m
}
{{- end}}
// Add your custom methods and functionality below.
`
const TemplateGenDaoInternalContent = `
// ==========================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. {{.TplCreatedAtDatetimeStr}}
// ==========================================================================
package internal
import (
"context"
"git.magicany.cc/black1552/gin-base/database"
)
// {{.TplTableNameCamelCase}}Dao is the data access object for the table {{.TplTableName}}.
type {{.TplTableNameCamelCase}}Dao struct {
table string // table is the underlying table name of the DAO.
group string // group is the database configuration group name of the current DAO.
columns {{.TplTableNameCamelCase}}Columns // columns contains all the column names of Table for convenient usage.
handlers []database.ModelHandler // handlers for customized model modification.
}
// {{.TplTableNameCamelCase}}Columns defines and stores column names for the table {{.TplTableName}}.
type {{.TplTableNameCamelCase}}Columns struct {
{{.TplColumnDefine}}
}
// {{.TplTableNameCamelLowerCase}}Columns holds the columns for the table {{.TplTableName}}.
var {{.TplTableNameCamelLowerCase}}Columns = {{.TplTableNameCamelCase}}Columns{
{{.TplColumnNames}}
}
// New{{.TplTableNameCamelCase}}Dao creates and returns a new DAO object for table data access.
func New{{.TplTableNameCamelCase}}Dao(handlers ...database.ModelHandler) *{{.TplTableNameCamelCase}}Dao {
return &{{.TplTableNameCamelCase}}Dao{
group: "{{.TplGroupName}}",
table: "{{.TplTableName}}",
columns: {{.TplTableNameCamelLowerCase}}Columns,
handlers: handlers,
}
}
// DB retrieves and returns the underlying raw database management object of the current DAO.
func (dao *{{.TplTableNameCamelCase}}Dao) DB() database.DB {
return database.Database(dao.group)
}
// Table returns the table name of the current DAO.
func (dao *{{.TplTableNameCamelCase}}Dao) Table() string {
return dao.table
}
// Columns returns all column names of the current DAO.
func (dao *{{.TplTableNameCamelCase}}Dao) Columns() {{.TplTableNameCamelCase}}Columns {
return dao.columns
}
// Group returns the database configuration group name of the current DAO.
func (dao *{{.TplTableNameCamelCase}}Dao) Group() string {
return dao.group
}
// Ctx creates and returns a Model for the current DAO. It automatically sets the context for the current operation.
func (dao *{{.TplTableNameCamelCase}}Dao) Ctx(ctx context.Context) *database.Model {
model := dao.DB().Model(dao.table)
for _, handler := range dao.handlers {
model = handler(model)
}
return model.Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.
// It rolls back the transaction and returns the error if function f returns a non-nil error.
// It commits the transaction and returns nil if function f returns nil.
//
// Note: Do not commit or roll back the transaction in function f,
// as it is automatically handled by this function.
func (dao *{{.TplTableNameCamelCase}}Dao) Transaction(ctx context.Context, f func(ctx context.Context, tx database.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}
`
@@ -1,20 +0,0 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package consts
const TemplateGenDaoDoContent = `
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. {{.TplCreatedAtDatetimeStr}}
// =================================================================================
package {{.TplPackageName}}
{{.TplPackageImports}}
// {{.TplTableNameCamelCase}} is the golang structure of table {{.TplTableName}} for DAO operations like Where/Data.
{{.TplStructDefine}}
`
@@ -1,20 +0,0 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package consts
const TemplateGenDaoEntityContent = `
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT. {{.TplCreatedAtDatetimeStr}}
// =================================================================================
package {{.TplPackageName}}
{{.TplPackageImports}}
// {{.TplTableNameCamelCase}} is the golang structure for table {{.TplTableName}}.
{{.TplStructDefine}}
`
@@ -1,34 +0,0 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package consts
const TemplateGenTableContent = `
// =================================================================================
// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.
// =================================================================================
package {{.TplPackageName}}
import (
"context"
"git.magicany.cc/black1552/gin-base/database"
)
// {{.TplTableNameCamelCase}} defines the fields of table "{{.TplTableName}}" with their properties.
// This map is used internally by GoFrame ORM to understand table structure.
var {{.TplTableNameCamelCase}} = map[string]*database.TableField{
{{.TplTableFields}}
}
// Set{{.TplTableNameCamelCase}}TableFields registers the table fields definition to the database instance.
// db: database instance that implements database.DB interface.
// schema: optional schema/namespace name, especially for databases that support schemas.
func Set{{.TplTableNameCamelCase}}TableFields(ctx context.Context, db database.DB, schema ...string) error {
return db.GetCore().SetTableFields(ctx, "{{.TplTableName}}", {{.TplTableNameCamelCase}}, schema...)
}
`
-376
View File
@@ -1,376 +0,0 @@
package main
import (
"context"
"fmt"
"os"
"strings"
"git.magicany.cc/black1552/gin-base/config"
"git.magicany.cc/black1552/gin-base/database"
_ "git.magicany.cc/black1552/gin-base/database/drivers"
)
func main() {
ctx := context.Background()
// 加载配置
cfg := config.GetAllConfig()
if cfg == nil {
fmt.Println("❌ 错误: 配置为空")
os.Exit(1)
}
// 检查数据库配置
dbConfigMap, ok := cfg["database"].(map[string]any)
if !ok || len(dbConfigMap) == 0 {
fmt.Println("❌ 错误: 未找到数据库配置")
os.Exit(1)
}
// 获取默认数据库配置
defaultDbConfig, ok := dbConfigMap["default"].(map[string]any)
if !ok {
fmt.Println("❌ 错误: 未找到 default 数据库配置")
os.Exit(1)
}
// 提取配置值
host := getStringValue(defaultDbConfig, "host", "127.0.0.1")
port := getStringValue(defaultDbConfig, "port", "3306")
name := getStringValue(defaultDbConfig, "name", "test")
dbType := getStringValue(defaultDbConfig, "type", "mysql")
fmt.Println("=== Gin-Base DAO 代码生成工具 ===")
fmt.Printf("📊 数据库: %s\n", name)
fmt.Printf("🔧 类型: %s\n", dbType)
fmt.Printf("🌐 主机: %s:%s\n\n", host, port)
// 初始化数据库连接
err := initDatabaseFromMap(dbConfigMap)
if err != nil {
fmt.Printf("❌ 数据库初始化失败: %v\n", err)
os.Exit(1)
}
// 获取数据库实例
db := database.Database()
// 获取所有表
tables, err := db.Tables(ctx)
if err != nil {
fmt.Printf("❌ 获取表列表失败: %v\n", err)
os.Exit(1)
}
fmt.Printf("📋 找到 %d 个表:\n", len(tables))
for i, table := range tables {
fmt.Printf(" %d. %s\n", i+1, table)
}
fmt.Println()
// 询问用户要生成的表
var selectedTables []string
if len(os.Args) > 1 {
// 从命令行参数获取表名
selectedTables = os.Args[1:]
} else {
// 默认生成所有表
selectedTables = tables
fmt.Println("💡 提示: 可以通过命令行参数指定要生成的表")
fmt.Println(" 例如: gin-dao-gen users orders")
}
// 创建输出目录
dirs := []string{
"./internal/dao",
"./internal/model/do",
"./internal/model/entity",
"./internal/model/table",
}
for _, dir := range dirs {
if err := os.MkdirAll(dir, 0755); err != nil {
fmt.Printf("❌ 创建目录失败 %s: %v\n", dir, err)
os.Exit(1)
}
}
// 为每个表生成代码
for _, tableName := range selectedTables {
fmt.Printf("\n🔨 正在生成表 [%s] 的代码...\n", tableName)
// 获取表字段信息
fields, err := db.TableFields(ctx, tableName)
if err != nil {
fmt.Printf(" ⚠️ 获取表字段失败: %v\n", err)
continue
}
// 生成 Entity
entityName := tableNameToStructName(tableName)
generateEntity(tableName, entityName, fields)
// 生成 DO
generateDO(tableName, entityName, fields)
// 生成 DAO
generateDAO(tableName, entityName)
// 生成 Table
generateTable(tableName, entityName, fields)
fmt.Printf(" ✅ 完成\n")
}
fmt.Println("\n🎉 代码生成完成!")
fmt.Println("📁 生成的文件位于:")
fmt.Println(" - ./internal/dao/")
fmt.Println(" - ./internal/model/do/")
fmt.Println(" - ./internal/model/entity/")
fmt.Println(" - ./internal/model/table/")
}
// 从 Map 初始化数据库
func initDatabaseFromMap(dbConfigMap map[string]any) error {
for name, nodeConfig := range dbConfigMap {
nodeMap, ok := nodeConfig.(map[string]any)
if !ok {
continue
}
configNode := database.ConfigNode{
Host: getStringValue(nodeMap, "host", "127.0.0.1"),
Port: getStringValue(nodeMap, "port", "3306"),
User: getStringValue(nodeMap, "user", "root"),
Pass: getStringValue(nodeMap, "pass", ""),
Name: getStringValue(nodeMap, "name", ""),
Type: getStringValue(nodeMap, "type", "mysql"),
Role: database.Role(getStringValue(nodeMap, "role", "master")),
Debug: getBoolValue(nodeMap, "debug", false),
Prefix: getStringValue(nodeMap, "prefix", ""),
Charset: getStringValue(nodeMap, "charset", "utf8"),
}
if err := database.AddConfigNode(name, configNode); err != nil {
return fmt.Errorf("add config node %s failed: %w", name, err)
}
}
return nil
}
// 辅助函数:从 map 中获取字符串值
func getStringValue(m map[string]any, key string, defaultValue string) string {
if val, ok := m[key]; ok {
if str, ok := val.(string); ok {
return str
}
}
return defaultValue
}
// 辅助函数:从 map 中获取布尔值
func getBoolValue(m map[string]any, key string, defaultValue bool) bool {
if val, ok := m[key]; ok {
if b, ok := val.(bool); ok {
return b
}
}
return defaultValue
}
// 表名转结构体名
func tableNameToStructName(tableName string) string {
parts := strings.Split(tableName, "_")
var result strings.Builder
for _, part := range parts {
if len(part) > 0 {
result.WriteString(strings.ToUpper(part[:1]))
result.WriteString(part[1:])
}
}
return result.String()
}
// 生成 Entity 文件
func generateEntity(tableName, entityName string, fields map[string]*database.TableField) {
filename := fmt.Sprintf("./internal/model/entity/%s.go", tableName)
var content strings.Builder
content.WriteString("package entity\n\n")
content.WriteString("// Auto-generated by gin-base gen dao tool\n\n")
content.WriteString(fmt.Sprintf("// %s represents the entity for table %s\n", entityName, tableName))
content.WriteString(fmt.Sprintf("type %s struct {\n", entityName))
for _, field := range fields {
fieldName := fieldNameToStructName(field.Name)
goType := dbTypeToGoType(field.Type)
jsonTag := field.Name
content.WriteString(fmt.Sprintf("\t%s %s `json:\"%s\" description:\"%s\"`\n",
fieldName, goType, jsonTag, field.Comment))
}
content.WriteString("}\n")
if err := os.WriteFile(filename, []byte(content.String()), 0644); err != nil {
fmt.Printf(" ❌ 写入文件失败: %v\n", err)
} else {
fmt.Printf(" 📄 生成 Entity: %s\n", filename)
}
}
// 生成 DO 文件
func generateDO(tableName, entityName string, fields map[string]*database.TableField) {
filename := fmt.Sprintf("./internal/model/do/%s.go", tableName)
var content strings.Builder
content.WriteString("package do\n\n")
content.WriteString("import \"github.com/gogf/gf/v2/frame/g\"\n\n")
content.WriteString("// Auto-generated by gin-base gen dao tool\n\n")
content.WriteString(fmt.Sprintf("// %s represents the data object for table %s\n", entityName, tableName))
content.WriteString(fmt.Sprintf("type %s struct {\n\tg.Meta `orm:\"table:%s, do:true\"`\n\n", entityName, tableName))
for _, field := range fields {
fieldName := fieldNameToStructName(field.Name)
goType := dbTypeToGoType(field.Type)
content.WriteString(fmt.Sprintf("\t%s *%s `json:\"%s,omitempty\"`\n",
fieldName, goType, field.Name))
}
content.WriteString("}\n")
if err := os.WriteFile(filename, []byte(content.String()), 0644); err != nil {
fmt.Printf(" ❌ 写入文件失败: %v\n", err)
} else {
fmt.Printf(" 📄 生成 DO: %s\n", filename)
}
}
// 生成 DAO 文件
func generateDAO(tableName, entityName string) {
filename := fmt.Sprintf("./internal/dao/%s.go", tableName)
lowerName := strings.ToLower(entityName[:1]) + entityName[1:]
var content strings.Builder
content.WriteString("package dao\n\n")
content.WriteString("import (\n")
content.WriteString("\t\"git.magicany.cc/black1552/gin-base/database\"\n")
content.WriteString(fmt.Sprintf("\t\"git.magicany.cc/black1552/gin-base/internal/model/entity\"\n"))
content.WriteString(")\n\n")
content.WriteString("// Auto-generated by gin-base gen dao tool\n\n")
content.WriteString(fmt.Sprintf("// %s is the DAO for table %s\n", entityName, tableName))
content.WriteString(fmt.Sprintf("var %s = New%s()\n\n", lowerName, entityName))
content.WriteString(fmt.Sprintf("// %s creates and returns a new DAO instance\n", entityName))
content.WriteString(fmt.Sprintf("func New%s() *%sDao {\n", entityName, entityName))
content.WriteString(fmt.Sprintf("\treturn &%sDao{\n", entityName))
content.WriteString("\t\ttable: \"" + tableName + "\",\n")
content.WriteString("\t}\n")
content.WriteString("}\n\n")
content.WriteString(fmt.Sprintf("// %sDao is the data access object for %s\n", entityName, tableName))
content.WriteString(fmt.Sprintf("type %sDao struct {\n", entityName))
content.WriteString("\ttable string\n")
content.WriteString("}\n\n")
content.WriteString("// Table returns the table name\n")
content.WriteString(fmt.Sprintf("func (d *%sDao) Table() string {\n", entityName))
content.WriteString("\treturn d.table\n")
content.WriteString("}\n\n")
content.WriteString("// DB returns the database instance\n")
content.WriteString("func (d *DB) DB() database.DB {\n")
content.WriteString("\treturn database.Database()\n")
content.WriteString("}\n")
if err := os.WriteFile(filename, []byte(content.String()), 0644); err != nil {
fmt.Printf(" ❌ 写入文件失败: %v\n", err)
} else {
fmt.Printf(" 📄 生成 DAO: %s\n", filename)
}
}
// 生成 Table 文件
func generateTable(tableName, entityName string, fields map[string]*database.TableField) {
filename := fmt.Sprintf("./internal/model/table/%s.go", tableName)
var content strings.Builder
content.WriteString("package table\n\n")
content.WriteString("// Auto-generated by gin-base gen dao tool\n\n")
content.WriteString("const (\n")
content.WriteString(fmt.Sprintf("\t// %s is the table name\n", entityName))
content.WriteString(fmt.Sprintf("\t%s = \"%s\"\n", entityName, tableName))
content.WriteString(")\n\n")
content.WriteString("// Columns defines all columns of the table\n")
content.WriteString("var Columns = struct {\n")
for _, field := range fields {
fieldName := fieldNameToConstName(field.Name)
content.WriteString(fmt.Sprintf("\t%s string\n", fieldName))
}
content.WriteString("}{\n")
for _, field := range fields {
fieldName := fieldNameToConstName(field.Name)
content.WriteString(fmt.Sprintf("\t%s: \"%s\",\n", fieldName, field.Name))
}
content.WriteString("}\n")
if err := os.WriteFile(filename, []byte(content.String()), 0644); err != nil {
fmt.Printf(" ❌ 写入文件失败: %v\n", err)
} else {
fmt.Printf(" 📄 生成 Table: %s\n", filename)
}
}
// 字段名转结构体字段名
func fieldNameToStructName(fieldName string) string {
parts := strings.Split(fieldName, "_")
var result strings.Builder
for _, part := range parts {
if len(part) > 0 {
result.WriteString(strings.ToUpper(part[:1]))
result.WriteString(part[1:])
}
}
return result.String()
}
// 字段名转常量名
func fieldNameToConstName(fieldName string) string {
parts := strings.Split(fieldName, "_")
var result strings.Builder
for i, part := range parts {
if i > 0 {
result.WriteString("_")
}
result.WriteString(strings.ToUpper(part))
}
return result.String()
}
// 数据库类型转 Go 类型
func dbTypeToGoType(dbType string) string {
dbType = strings.ToLower(dbType)
switch {
case strings.Contains(dbType, "int"):
if strings.Contains(dbType, "bigint") {
return "int64"
}
return "int"
case strings.Contains(dbType, "float"), strings.Contains(dbType, "double"), strings.Contains(dbType, "decimal"):
return "float64"
case strings.Contains(dbType, "bool"):
return "bool"
case strings.Contains(dbType, "datetime"), strings.Contains(dbType, "timestamp"):
return "*gtime.Time"
case strings.Contains(dbType, "date"):
return "*gtime.Time"
case strings.Contains(dbType, "text"), strings.Contains(dbType, "char"), strings.Contains(dbType, "varchar"):
return "string"
case strings.Contains(dbType, "blob"), strings.Contains(dbType, "binary"):
return "[]byte"
default:
return "string"
}
}
+44 -330
View File
@@ -4,10 +4,9 @@ import (
"context"
"fmt"
"os"
"strings"
"git.magicany.cc/black1552/gin-base/cmd/gendao"
"git.magicany.cc/black1552/gin-base/config"
"git.magicany.cc/black1552/gin-base/database"
_ "git.magicany.cc/black1552/gin-base/database/drivers"
)
@@ -39,6 +38,8 @@ func main() {
host := getStringValue(defaultDbConfig, "host", "127.0.0.1")
port := getStringValue(defaultDbConfig, "port", "3306")
name := getStringValue(defaultDbConfig, "name", "test")
user := getStringValue(defaultDbConfig, "user", "root")
pass := getStringValue(defaultDbConfig, "pass", "")
dbType := getStringValue(defaultDbConfig, "type", "mysql")
fmt.Println("=== Gin-Base DAO 代码生成工具 ===")
@@ -46,144 +47,50 @@ func main() {
fmt.Printf("🔧 类型: %s\n", dbType)
fmt.Printf("🌐 主机: %s:%s\n\n", host, port)
// 初始化数据库连接
err := initDatabaseFromMap(dbConfigMap)
if err != nil {
fmt.Printf("❌ 数据库初始化失败: %v\n", err)
os.Exit(1)
}
// 构建数据库连接字符串
link := fmt.Sprintf("mysql:%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=true&loc=Local",
user, pass, host, port, name,
)
// 获取数据库实例(使用 default 组)
db := database.Database("default")
// 调试信息:打印当前使用的数据库名称
config := db.GetConfig()
if config != nil {
fmt.Printf("🔍 调试: 当前数据库名 = %s, 类型 = %s\n", config.Name, config.Type)
}
// 获取所有表
tables, err := db.Tables(ctx)
if err != nil {
fmt.Printf("❌ 获取表列表失败: %v\n", err)
os.Exit(1)
}
// 如果没找到表,尝试直接查询验证
if len(tables) == 0 {
fmt.Println("⚠️ 警告: 未找到任何表,尝试直接查询...")
result, err := db.Query(ctx, "SHOW TABLES")
if err != nil {
fmt.Printf("❌ 直接查询失败: %v\n", err)
} else {
fmt.Printf("🔍 直接查询结果: %d 行\n", len(result))
for _, row := range result {
fmt.Printf(" - %v\n", row)
}
}
}
fmt.Printf("📋 找到 %d 个表:\n", len(tables))
for i, table := range tables {
fmt.Printf(" %d. %s\n", i+1, table)
}
fmt.Println()
// 询问用户要生成的表
var selectedTables []string
// 准备表名参数
tablesArg := ""
if len(os.Args) > 1 {
// 从命令行参数获取表名
selectedTables = os.Args[1:]
tablesArg = joinStrings(os.Args[1:], ",")
fmt.Printf("📋 指定生成表: %s\n\n", tablesArg)
} else {
// 默认生成所有表
selectedTables = tables
fmt.Println("💡 提示: 可以通过命令行参数指定要生成的表")
fmt.Println(" 例如: gin-dao-gen users orders")
fmt.Println(" 例如: gin-dao-gen users orders\n")
}
// 创建输出目录
dirs := []string{
"./internal/dao",
"./internal/model/do",
"./internal/model/entity",
"./internal/model/table",
// 调用 gendao 的 Dao 函数生成代码
genDao := gendao.CGenDao{}
input := gendao.CGenDaoInput{
Link: link,
Tables: tablesArg,
Path: "./",
DaoPath: "dao",
DoPath: "model/do",
EntityPath: "model/entity",
TablePath: "model/table",
Group: "default",
JsonCase: "CamelLower",
DescriptionTag: true,
GenTable: true,
}
for _, dir := range dirs {
if err := os.MkdirAll(dir, 0755); err != nil {
fmt.Printf("❌ 创建目录失败 %s: %v\n", dir, err)
os.Exit(1)
}
}
// 为每个表生成代码
for _, tableName := range selectedTables {
fmt.Printf("\n🔨 正在生成表 [%s] 的代码...\n", tableName)
// 获取表字段信息
fields, err := db.TableFields(ctx, tableName)
if err != nil {
fmt.Printf(" ⚠️ 获取表字段失败: %v\n", err)
return // 使用 return 而不是 continue
}
// 调试:打印字段信息
fmt.Printf(" 🔍 调试: 找到 %d 个字段\n", len(fields))
for name, field := range fields {
fmt.Printf(" - %s: %s (%s)\n", name, field.Type, field.Comment)
}
// 生成 Entity
entityName := tableNameToStructName(tableName)
generateEntity(tableName, entityName, fields)
// 生成 DO
generateDO(tableName, entityName, fields)
// 生成 DAO
generateDAO(tableName, entityName)
// 生成 Table
generateTable(tableName, entityName, fields)
fmt.Printf(" ✅ 完成\n")
fmt.Println("🔨 开始生成代码...")
_, err := genDao.Dao(ctx, input)
if err != nil {
fmt.Printf("\n❌ 代码生成失败: %v\n", err)
os.Exit(1)
}
fmt.Println("\n🎉 代码生成完成!")
fmt.Println("📁 生成的文件位于:")
fmt.Println(" - ./internal/dao/")
fmt.Println(" - ./internal/model/do/")
fmt.Println(" - ./internal/model/entity/")
fmt.Println(" - ./internal/model/table/")
}
// 从 Map 初始化数据库
func initDatabaseFromMap(dbConfigMap map[string]any) error {
for name, nodeConfig := range dbConfigMap {
nodeMap, ok := nodeConfig.(map[string]any)
if !ok {
continue
}
configNode := database.ConfigNode{
Host: getStringValue(nodeMap, "host", "127.0.0.1"),
Port: getStringValue(nodeMap, "port", "3306"),
User: getStringValue(nodeMap, "user", "root"),
Pass: getStringValue(nodeMap, "pass", ""),
Name: getStringValue(nodeMap, "name", ""),
Type: getStringValue(nodeMap, "type", "mysql"),
Role: database.Role(getStringValue(nodeMap, "role", "master")),
Debug: getBoolValue(nodeMap, "debug", false),
Prefix: getStringValue(nodeMap, "prefix", ""),
Charset: getStringValue(nodeMap, "charset", "utf8"),
}
if err := database.AddConfigNode(name, configNode); err != nil {
return fmt.Errorf("add config node %s failed: %w", name, err)
}
}
return nil
fmt.Println(" - ./dao/")
fmt.Println(" - ./model/do/")
fmt.Println(" - ./model/entity/")
fmt.Println(" - ./model/table/")
}
// 辅助函数:从 map 中获取字符串值
@@ -196,207 +103,14 @@ func getStringValue(m map[string]any, key string, defaultValue string) string {
return defaultValue
}
// 辅助函数:从 map 中获取布尔值
func getBoolValue(m map[string]any, key string, defaultValue bool) bool {
if val, ok := m[key]; ok {
if b, ok := val.(bool); ok {
return b
}
}
return defaultValue
}
// 表名转结构体名
func tableNameToStructName(tableName string) string {
parts := strings.Split(tableName, "_")
var result strings.Builder
for _, part := range parts {
if len(part) > 0 {
result.WriteString(strings.ToUpper(part[:1]))
result.WriteString(part[1:])
}
}
return result.String()
}
// 生成 Entity 文件
func generateEntity(tableName, entityName string, fields map[string]*database.TableField) {
filename := fmt.Sprintf("./internal/model/entity/%s.go", tableName)
var content strings.Builder
content.WriteString("package entity\n\n")
content.WriteString("// Auto-generated by gin-base gen dao tool\n\n")
content.WriteString(fmt.Sprintf("// %s represents the entity for table %s\n", entityName, tableName))
content.WriteString(fmt.Sprintf("type %s struct {\n", entityName))
for _, field := range fields {
fieldName := fieldNameToStructName(field.Name)
goType := dbTypeToGoType(field.Type)
jsonTag := field.Name
content.WriteString(fmt.Sprintf("\t%s %s `json:\"%s\" description:\"%s\"`\n",
fieldName, goType, jsonTag, field.Comment))
}
content.WriteString("}\n")
if err := os.WriteFile(filename, []byte(content.String()), 0644); err != nil {
fmt.Printf(" ❌ 写入文件失败: %v\n", err)
} else {
fmt.Printf(" 📄 生成 Entity: %s\n", filename)
}
}
// 生成 DO 文件
func generateDO(tableName, entityName string, fields map[string]*database.TableField) {
filename := fmt.Sprintf("./internal/model/do/%s.go", tableName)
var content strings.Builder
content.WriteString("package do\n\n")
content.WriteString("import \"github.com/gogf/gf/v2/frame/g\"\n\n")
content.WriteString("// Auto-generated by gin-base gen dao tool\n\n")
content.WriteString(fmt.Sprintf("// %s represents the data object for table %s\n", entityName, tableName))
content.WriteString(fmt.Sprintf("type %s struct {\n\tg.Meta `orm:\"table:%s, do:true\"`\n\n", entityName, tableName))
for _, field := range fields {
fieldName := fieldNameToStructName(field.Name)
goType := dbTypeToGoType(field.Type)
content.WriteString(fmt.Sprintf("\t%s *%s `json:\"%s,omitempty\"`\n",
fieldName, goType, field.Name))
}
content.WriteString("}\n")
if err := os.WriteFile(filename, []byte(content.String()), 0644); err != nil {
fmt.Printf(" ❌ 写入文件失败: %v\n", err)
} else {
fmt.Printf(" 📄 生成 DO: %s\n", filename)
}
}
// 生成 DAO 文件
func generateDAO(tableName, entityName string) {
filename := fmt.Sprintf("./internal/dao/%s.go", tableName)
lowerName := strings.ToLower(entityName[:1]) + entityName[1:]
var content strings.Builder
content.WriteString("package dao\n\n")
content.WriteString("import (\n")
content.WriteString("\t\"git.magicany.cc/black1552/gin-base/database\"\n")
content.WriteString(fmt.Sprintf("\t\"git.magicany.cc/black1552/gin-base/internal/model/entity\"\n"))
content.WriteString(")\n\n")
content.WriteString("// Auto-generated by gin-base gen dao tool\n\n")
content.WriteString(fmt.Sprintf("// %s is the DAO for table %s\n", entityName, tableName))
content.WriteString(fmt.Sprintf("var %s = New%s()\n\n", lowerName, entityName))
content.WriteString(fmt.Sprintf("// %s creates and returns a new DAO instance\n", entityName))
content.WriteString(fmt.Sprintf("func New%s() *%sDao {\n", entityName, entityName))
content.WriteString(fmt.Sprintf("\treturn &%sDao{\n", entityName))
content.WriteString("\t\ttable: \"" + tableName + "\",\n")
content.WriteString("\t}\n")
content.WriteString("}\n\n")
content.WriteString(fmt.Sprintf("// %sDao is the data access object for %s\n", entityName, tableName))
content.WriteString(fmt.Sprintf("type %sDao struct {\n", entityName))
content.WriteString("\ttable string\n")
content.WriteString("}\n\n")
content.WriteString("// Table returns the table name\n")
content.WriteString(fmt.Sprintf("func (d *%sDao) Table() string {\n", entityName))
content.WriteString("\treturn d.table\n")
content.WriteString("}\n\n")
content.WriteString("// DB returns the database instance\n")
content.WriteString("func (d *DB) DB() database.DB {\n")
content.WriteString("\treturn database.Database()\n")
content.WriteString("}\n")
if err := os.WriteFile(filename, []byte(content.String()), 0644); err != nil {
fmt.Printf(" ❌ 写入文件失败: %v\n", err)
} else {
fmt.Printf(" 📄 生成 DAO: %s\n", filename)
}
}
// 生成 Table 文件
func generateTable(tableName, entityName string, fields map[string]*database.TableField) {
filename := fmt.Sprintf("./internal/model/table/%s.go", tableName)
var content strings.Builder
content.WriteString("package table\n\n")
content.WriteString("// Auto-generated by gin-base gen dao tool\n\n")
content.WriteString("const (\n")
content.WriteString(fmt.Sprintf("\t// %s is the table name\n", entityName))
content.WriteString(fmt.Sprintf("\t%s = \"%s\"\n", entityName, tableName))
content.WriteString(")\n\n")
content.WriteString("// Columns defines all columns of the table\n")
content.WriteString("var Columns = struct {\n")
for _, field := range fields {
fieldName := fieldNameToConstName(field.Name)
content.WriteString(fmt.Sprintf("\t%s string\n", fieldName))
}
content.WriteString("}{\n")
for _, field := range fields {
fieldName := fieldNameToConstName(field.Name)
content.WriteString(fmt.Sprintf("\t%s: \"%s\",\n", fieldName, field.Name))
}
content.WriteString("}\n")
if err := os.WriteFile(filename, []byte(content.String()), 0644); err != nil {
fmt.Printf(" ❌ 写入文件失败: %v\n", err)
} else {
fmt.Printf(" 📄 生成 Table: %s\n", filename)
}
}
// 字段名转结构体字段名
func fieldNameToStructName(fieldName string) string {
parts := strings.Split(fieldName, "_")
var result strings.Builder
for _, part := range parts {
if len(part) > 0 {
result.WriteString(strings.ToUpper(part[:1]))
result.WriteString(part[1:])
}
}
return result.String()
}
// 字段名转常量名
func fieldNameToConstName(fieldName string) string {
parts := strings.Split(fieldName, "_")
var result strings.Builder
for i, part := range parts {
if i > 0 {
result.WriteString("_")
}
result.WriteString(strings.ToUpper(part))
}
return result.String()
}
// 数据库类型转 Go 类型
func dbTypeToGoType(dbType string) string {
dbType = strings.ToLower(dbType)
switch {
case strings.Contains(dbType, "int"):
if strings.Contains(dbType, "bigint") {
return "int64"
}
return "int"
case strings.Contains(dbType, "float"), strings.Contains(dbType, "double"), strings.Contains(dbType, "decimal"):
return "float64"
case strings.Contains(dbType, "bool"):
return "bool"
case strings.Contains(dbType, "datetime"), strings.Contains(dbType, "timestamp"):
return "*gtime.Time"
case strings.Contains(dbType, "date"):
return "*gtime.Time"
case strings.Contains(dbType, "text"), strings.Contains(dbType, "char"), strings.Contains(dbType, "varchar"):
return "string"
case strings.Contains(dbType, "blob"), strings.Contains(dbType, "binary"):
return "[]byte"
default:
return "string"
// 辅助函数:连接字符串数组
func joinStrings(strs []string, sep string) string {
if len(strs) == 0 {
return ""
}
result := strs[0]
for i := 1; i < len(strs); i++ {
result += sep + strs[i]
}
return result
}