feat(db): 添加数据库配置自动查找和缓存功能
- 实现配置文件自动查找功能,支持yaml、yml、toml、ini、json格式 - 添加查询缓存机制,提高重复查询性能 - 新增构建脚本build.sh和build.bat用于跨平台编译 - 添加完整的数据库连接配置和时间字段配置功能 - 实现DAO基类提供通用CRUD操作方法 - 添加配置文件示例和相关测试用例
This commit is contained in:
@@ -0,0 +1,307 @@
|
||||
# Magic-ORM 代码生成器使用指南
|
||||
|
||||
## 📚 什么是代码生成器?
|
||||
|
||||
代码生成器可以根据数据库表结构自动生成 Model 和 DAO 代码,大幅提高开发效率。
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
### 1. 创建代码生成器
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"git.magicany.cc/black1552/gin-base/db/generator"
|
||||
)
|
||||
|
||||
// 创建代码生成器实例
|
||||
cg := generator.NewCodeGenerator("./generated")
|
||||
```
|
||||
|
||||
### 2. 定义列信息
|
||||
|
||||
```go
|
||||
columns := []generator.ColumnInfo{
|
||||
{
|
||||
ColumnName: "id", // 数据库列名
|
||||
FieldName: "ID", // Go 字段名(驼峰)
|
||||
FieldType: "int64", // Go 字段类型
|
||||
JSONName: "id", // JSON 标签名
|
||||
IsPrimary: true, // 是否主键
|
||||
IsNullable: false, // 是否可为空
|
||||
},
|
||||
{
|
||||
ColumnName: "username",
|
||||
FieldName: "Username",
|
||||
FieldType: "string",
|
||||
JSONName: "username",
|
||||
IsPrimary: false,
|
||||
IsNullable: false,
|
||||
},
|
||||
{
|
||||
ColumnName: "email",
|
||||
FieldName: "Email",
|
||||
FieldType: "string",
|
||||
JSONName: "email",
|
||||
IsPrimary: false,
|
||||
IsNullable: true,
|
||||
},
|
||||
{
|
||||
ColumnName: "created_at",
|
||||
FieldName: "CreatedAt",
|
||||
FieldType: "time.Time",
|
||||
JSONName: "created_at",
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 生成代码
|
||||
|
||||
#### 方式一:一键生成(推荐)
|
||||
|
||||
```go
|
||||
// 同时生成 Model 和 DAO
|
||||
err := cg.GenerateAll("user", columns)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
```
|
||||
|
||||
#### 方式二:分别生成
|
||||
|
||||
```go
|
||||
// 只生成 Model
|
||||
err := cg.GenerateModel("user", columns)
|
||||
|
||||
// 只生成 DAO
|
||||
err := cg.GenerateDAO("user", "User")
|
||||
```
|
||||
|
||||
## 📁 生成的文件结构
|
||||
|
||||
```
|
||||
generated/
|
||||
├── user.go # User Model
|
||||
├── user_dao.go # User DAO
|
||||
├── product.go # Product Model
|
||||
└── product_dao.go # Product DAO
|
||||
```
|
||||
|
||||
## 💡 使用生成的代码
|
||||
|
||||
### 导入包
|
||||
|
||||
```go
|
||||
import (
|
||||
"context"
|
||||
"git.magicany.cc/black1552/gin-base/db/core"
|
||||
"git.magicany.cc/black1552/gin-base/db/model"
|
||||
"your-project/generated"
|
||||
)
|
||||
```
|
||||
|
||||
### 初始化数据库
|
||||
|
||||
```go
|
||||
db, err := core.AutoConnect(false)
|
||||
```
|
||||
|
||||
### 创建 DAO 实例
|
||||
|
||||
```go
|
||||
userDAO := generated.NewUserDAO(db)
|
||||
```
|
||||
|
||||
### CRUD 操作
|
||||
|
||||
```go
|
||||
// 创建用户
|
||||
user := &model.User{
|
||||
Username: "john",
|
||||
Email: "john@example.com",
|
||||
}
|
||||
err = userDAO.Create(context.Background(), user)
|
||||
|
||||
// 查询用户
|
||||
user, err := userDAO.GetByID(context.Background(), 1)
|
||||
|
||||
// 更新用户
|
||||
user.Email = "new@example.com"
|
||||
err = userDAO.Update(context.Background(), user)
|
||||
|
||||
// 删除用户
|
||||
err = userDAO.Delete(context.Background(), 1)
|
||||
|
||||
// 分页查询
|
||||
users, err := userDAO.FindByPage(context.Background(), 1, 10)
|
||||
```
|
||||
|
||||
## 🔧 API 参考
|
||||
|
||||
### NewCodeGenerator
|
||||
|
||||
```go
|
||||
func NewCodeGenerator(outputDir string) *CodeGenerator
|
||||
```
|
||||
|
||||
创建代码生成器实例。
|
||||
|
||||
**参数:**
|
||||
- `outputDir` - 输出目录路径
|
||||
|
||||
### GenerateModel
|
||||
|
||||
```go
|
||||
func (cg *CodeGenerator) GenerateModel(tableName string, columns []ColumnInfo) error
|
||||
```
|
||||
|
||||
生成 Model 代码。
|
||||
|
||||
**参数:**
|
||||
- `tableName` - 数据库表名
|
||||
- `columns` - 列信息数组
|
||||
|
||||
### GenerateDAO
|
||||
|
||||
```go
|
||||
func (cg *CodeGenerator) GenerateDAO(tableName string, modelName string) error
|
||||
```
|
||||
|
||||
生成 DAO 代码。
|
||||
|
||||
**参数:**
|
||||
- `tableName` - 数据库表名
|
||||
- `modelName` - Model 名称(驼峰)
|
||||
|
||||
### GenerateAll
|
||||
|
||||
```go
|
||||
func (cg *CodeGenerator) GenerateAll(tableName string, columns []ColumnInfo) error
|
||||
```
|
||||
|
||||
一键生成 Model + DAO(推荐)。
|
||||
|
||||
**参数:**
|
||||
- `tableName` - 数据库表名
|
||||
- `columns` - 列信息数组
|
||||
|
||||
## 📋 ColumnInfo 结构
|
||||
|
||||
```go
|
||||
type ColumnInfo struct {
|
||||
ColumnName string // 数据库列名(下划线风格)
|
||||
FieldName string // Go 字段名(驼峰风格)
|
||||
FieldType string // Go 数据类型
|
||||
JSONName string // JSON 标签名
|
||||
IsPrimary bool // 是否主键
|
||||
IsNullable bool // 是否可为空
|
||||
}
|
||||
```
|
||||
|
||||
## 🗺️ 类型映射表
|
||||
|
||||
| 数据库类型 | Go 类型 |
|
||||
|-----------|---------|
|
||||
| INT/BIGINT | int64 |
|
||||
| VARCHAR/TEXT | string |
|
||||
| DATETIME | time.Time |
|
||||
| TIMESTAMP | time.Time |
|
||||
| BOOLEAN | bool |
|
||||
| FLOAT/DOUBLE | float64 |
|
||||
| DECIMAL | string 或 float64 |
|
||||
|
||||
## 🎯 最佳实践
|
||||
|
||||
### 1. 从数据库读取真实表结构
|
||||
|
||||
```go
|
||||
// 示例:从 MySQL INFORMATION_SCHEMA 获取列信息
|
||||
query := `
|
||||
SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_KEY
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_SCHEMA = 'your_database'
|
||||
AND TABLE_NAME = 'your_table'
|
||||
`
|
||||
```
|
||||
|
||||
### 2. 批量生成所有表
|
||||
|
||||
```go
|
||||
tables := []string{"users", "products", "orders"}
|
||||
|
||||
for _, table := range tables {
|
||||
columns := getColumnsFromDB(table) // 从数据库获取列信息
|
||||
err := cg.GenerateAll(table, columns)
|
||||
if err != nil {
|
||||
log.Printf("生成 %s 失败:%v", table, err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 自定义模板
|
||||
|
||||
修改 `generator.go` 中的模板字符串,添加自定义方法:
|
||||
|
||||
```go
|
||||
tmpl := `package model
|
||||
|
||||
// {{.ModelName}} {{.TableName}} 模型
|
||||
type {{.ModelName}} struct {
|
||||
{{range .Columns}}
|
||||
{{.FieldName}} {{.FieldType}} ` + "`" + `json:"{{.JSONName}}" db:"{{.ColumnName}}"` + "`" + `
|
||||
{{end}}
|
||||
}
|
||||
|
||||
// 自定义方法
|
||||
func (m *{{.ModelName}}) Validate() error {
|
||||
// 验证逻辑
|
||||
return nil
|
||||
}
|
||||
`
|
||||
```
|
||||
|
||||
### 4. 代码审查
|
||||
|
||||
- ✅ 检查生成的字段类型是否正确
|
||||
- ✅ 验证主键和索引设置
|
||||
- ✅ 添加业务逻辑方法
|
||||
- ✅ 补充注释和文档
|
||||
|
||||
### 5. 版本控制
|
||||
|
||||
```bash
|
||||
# 将生成的代码纳入 Git 管理
|
||||
git add generated/
|
||||
git commit -m "feat: 生成用户和产品模块代码"
|
||||
```
|
||||
|
||||
## ⚠️ 注意事项
|
||||
|
||||
1. **不要频繁覆盖**: 手动修改的代码可能会被覆盖
|
||||
2. **代码审查**: 生成的代码需要人工审查
|
||||
3. **类型映射**: 特殊类型可能需要手动调整
|
||||
4. **关联关系**: 复杂的模型关联需要手动实现
|
||||
5. **验证逻辑**: 业务验证逻辑需要手动添加
|
||||
|
||||
## 🎉 总结
|
||||
|
||||
✅ **优势:**
|
||||
- 大幅提高开发效率
|
||||
- 代码规范统一
|
||||
- 减少重复劳动
|
||||
- 快速搭建项目骨架
|
||||
|
||||
✅ **适用场景:**
|
||||
- 新项目快速启动
|
||||
- 数据库表结构变更
|
||||
- 批量生成基础代码
|
||||
- 原型开发
|
||||
|
||||
✅ **推荐用法:**
|
||||
- 使用 `GenerateAll` 一键生成
|
||||
- 从真实数据库读取列信息
|
||||
- 定期重新生成保持同步
|
||||
- 配合版本控制管理代码
|
||||
|
||||
开始使用代码生成器,提升你的开发效率吧!🚀
|
||||
@@ -0,0 +1,201 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// CodeGenerator 代码生成器 - 自动生成 Model 和 DAO 代码
|
||||
type CodeGenerator struct {
|
||||
outputDir string // 输出目录
|
||||
}
|
||||
|
||||
// NewCodeGenerator 创建代码生成器实例
|
||||
func NewCodeGenerator(outputDir string) *CodeGenerator {
|
||||
return &CodeGenerator{
|
||||
outputDir: outputDir,
|
||||
}
|
||||
}
|
||||
|
||||
// GenerateModel 生成 Model 代码
|
||||
func (cg *CodeGenerator) GenerateModel(tableName string, columns []ColumnInfo) error {
|
||||
// 生成文件名
|
||||
fileName := strings.ToLower(tableName) + ".go"
|
||||
filePath := filepath.Join(cg.outputDir, fileName)
|
||||
|
||||
// 创建输出目录
|
||||
if err := os.MkdirAll(cg.outputDir, 0755); err != nil {
|
||||
return fmt.Errorf("创建目录失败:%w", err)
|
||||
}
|
||||
|
||||
// 生成代码
|
||||
code := cg.generateModelCode(tableName, columns)
|
||||
|
||||
// 写入文件
|
||||
if err := os.WriteFile(filePath, []byte(code), 0644); err != nil {
|
||||
return fmt.Errorf("写入文件失败:%w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("[Model] Generated: %s\n", filePath)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenerateDAO 生成 DAO 代码
|
||||
func (cg *CodeGenerator) GenerateDAO(tableName string, modelName string) error {
|
||||
fileName := strings.ToLower(tableName) + "_dao.go"
|
||||
// DAO 文件输出到 dao 子目录
|
||||
daoDir := filepath.Join(cg.outputDir, "dao")
|
||||
filePath := filepath.Join(daoDir, fileName)
|
||||
|
||||
// 创建输出目录(包括 dao 子目录)
|
||||
if err := os.MkdirAll(daoDir, 0755); err != nil {
|
||||
return fmt.Errorf("创建目录失败:%w", err)
|
||||
}
|
||||
|
||||
// 生成代码
|
||||
code := cg.generateDAOCode(tableName, modelName)
|
||||
|
||||
// 写入文件
|
||||
if err := os.WriteFile(filePath, []byte(code), 0644); err != nil {
|
||||
return fmt.Errorf("写入文件失败:%w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("[DAO] Generated: %s\n", filePath)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenerateAll 生成完整代码(Model + DAO)
|
||||
func (cg *CodeGenerator) GenerateAll(tableName string, columns []ColumnInfo) error {
|
||||
modelName := cg.toCamelCase(tableName)
|
||||
|
||||
// 生成 Model
|
||||
if err := cg.GenerateModel(tableName, columns); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 生成 DAO
|
||||
if err := cg.GenerateDAO(tableName, modelName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// generateModelCode 生成 Model 代码
|
||||
func (cg *CodeGenerator) generateModelCode(tableName string, columns []ColumnInfo) string {
|
||||
// 检查是否有时间字段
|
||||
hasTime := false
|
||||
for _, col := range columns {
|
||||
if col.FieldType == "time.Time" {
|
||||
hasTime = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
importStmt := ""
|
||||
if hasTime {
|
||||
importStmt = `import "time"`
|
||||
} else {
|
||||
importStmt = ``
|
||||
}
|
||||
|
||||
tmpl := `package model
|
||||
|
||||
` + importStmt + `
|
||||
// {{.ModelName}} {{.TableName}} 模型
|
||||
type {{.ModelName}} struct {
|
||||
{{range .Columns}} {{.FieldName}} {{.FieldType}} ` + "`" + `json:"{{.JSONName}}" db:"{{.ColumnName}}"` + "`" + `
|
||||
{{end}}
|
||||
}
|
||||
|
||||
// TableName 表名
|
||||
func ({{.ModelName}}) TableName() string {
|
||||
return "{{.TableName}}"
|
||||
}
|
||||
`
|
||||
|
||||
data := struct {
|
||||
ModelName string
|
||||
TableName string
|
||||
Columns []ColumnInfo
|
||||
}{
|
||||
ModelName: cg.toCamelCase(tableName),
|
||||
TableName: tableName,
|
||||
Columns: columns,
|
||||
}
|
||||
|
||||
return cg.executeTemplate(tmpl, data)
|
||||
}
|
||||
|
||||
// generateDAOCode 生成 DAO 代码 - 简化版本,只定义结构体并继承 Database
|
||||
func (cg *CodeGenerator) generateDAOCode(tableName string, modelName string) string {
|
||||
tmpl := `package dao
|
||||
|
||||
import (
|
||||
"git.magicany.cc/black1552/gin-base/db/core"
|
||||
"git.magicany.cc/black1552/gin-base/db/model"
|
||||
)
|
||||
|
||||
// {{.ModelName}}DAO {{.TableName}} 数据访问对象
|
||||
// 嵌入 core.DAO,自动获得所有 CRUD 方法
|
||||
type {{.ModelName}}DAO struct {
|
||||
*core.DAO
|
||||
}
|
||||
|
||||
// New{{.ModelName}}DAO 创建 {{.ModelName}}DAO 实例
|
||||
func New{{.ModelName}}DAO(db *core.Database) *{{.ModelName}}DAO {
|
||||
return &{{.ModelName}}DAO{
|
||||
DAO: core.NewDAOWithModel(db, &model.{{.ModelName}}{}),
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
data := struct {
|
||||
ModelName string
|
||||
TableName string
|
||||
}{
|
||||
ModelName: cg.toCamelCase(tableName),
|
||||
TableName: tableName,
|
||||
}
|
||||
|
||||
return cg.executeTemplate(tmpl, data)
|
||||
}
|
||||
|
||||
// executeTemplate 执行模板
|
||||
func (cg *CodeGenerator) executeTemplate(tmpl string, data interface{}) string {
|
||||
t := template.Must(template.New("code").Parse(tmpl))
|
||||
|
||||
var buf strings.Builder
|
||||
if err := t.Execute(&buf, data); err != nil {
|
||||
return fmt.Sprintf("// 模板执行错误:%v", err)
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// toCamelCase 转换为驼峰命名
|
||||
func (cg *CodeGenerator) toCamelCase(str string) string {
|
||||
parts := strings.Split(str, "_")
|
||||
result := ""
|
||||
|
||||
for _, part := range parts {
|
||||
if len(part) > 0 {
|
||||
result += strings.ToUpper(string(part[0])) + part[1:]
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// ColumnInfo 列信息
|
||||
type ColumnInfo struct {
|
||||
ColumnName string // 列名
|
||||
FieldName string // 字段名(驼峰)
|
||||
FieldType string // 字段类型
|
||||
JSONName string // JSON 标签名
|
||||
IsPrimary bool // 是否主键
|
||||
IsNullable bool // 是否可为空
|
||||
}
|
||||
Reference in New Issue
Block a user