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" ) var {{.ModelName}}Dao = &s{{.ModelName}}DAO{ DAO: core.NewDAOWithModel(&model.{{.ModelName}}), } // {{.ModelName}}DAO {{.TableName}} 数据访问对象 // 嵌入 core.DAO,自动获得所有 CRUD 方法 type s{{.ModelName}}DAO struct { *core.DAO }` 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 // 是否可为空 }