Files
huangguo_server/generate/common/generate.go
T
rootandClaude Opus 5 8679200f41 Initial commit
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 13:57:10 +08:00

365 lines
8.6 KiB
Go

package common
import (
"errors"
"fmt"
"os"
"path"
"path/filepath"
"reflect"
"strings"
"91porn-server/generate/tpl"
)
func NewGen(moduleName, tblComment string) *G {
rootPath := RootPath()
return &G{
AppGenerate: true,
WebGenerate: true,
RootPath: rootPath,
ModuleName: moduleName,
TableComment: tblComment,
}
}
type Field struct {
Name string
TypeName string
Tag string
BsonField string
FormTag string
UpdateTag string
Comment string
SubField []Field
SubStructName string
}
type G struct {
AppGenerate bool
WebGenerate bool
RootPath string
ModuleName string
StructName string
FileName string
TableName string
TableComment string
Fields []Field
}
// Generate 生成...
func (o *G) Generate(s interface{}) {
var err error
// 获取model结构
t := reflect.TypeOf(s)
o.Fields, err = o.explodeStruct(t)
if err != nil {
log(err.Error(), "error")
return
}
o.StructName = FirstUpper(t.Name())
if o.TableName == "" {
o.TableName = o.StructName
}
o.FileName = strings.ToLower(o.TableName)
// 生成变量表
v := make(map[string]string)
v["FileName"] = strings.ToLower(o.TableName)
v["ModuleName"] = o.ModuleName
v["TableComment"] = o.TableComment
v["TableName"] = o.TableName
v["StructName"] = o.StructName
v["PackageTableName"] = strings.ToLower(o.TableName)
v["RouterName"] = FirstLower(o.TableName)
v["StructDefine"] = o.genStructDefine(o.StructName, o.Fields)
v["AppRespStructFields"] = o.genAppRespStructFields(o.Fields)
v["AppRespTransferStatement"] = o.genAppRespTransferStatement(o.Fields)
v["CreateReqFields"] = o.genCreateStructFields(o.Fields)
v["CreateStatement"] = o.genCreateStatement(o.Fields)
v["UpdateReqFields"] = o.genUpdateStructFields(o.Fields)
v["UpdateStatement"] = o.genUpdateStatement(o.Fields)
// 循环配置进行生成
for tpDir, c := range tpl.Config {
// 判断是否生成 app web
if !o.AppGenerate && strings.HasPrefix(tpDir, "/app") {
continue
}
if !o.WebGenerate && strings.HasPrefix(tpDir, "/web") {
continue
}
// 遍历目录
tplPath := path.Join(o.RootPath, "/generate/tpl", tpDir)
var tpls []string
err := filepath.Walk(tplPath, func(path string, info os.FileInfo, err error) error {
if !info.IsDir() && strings.HasSuffix(info.Name(), ".tpl") {
tpls = append(tpls, path)
}
return nil
})
if err != nil {
log(err.Error(), "error")
return
}
// 创建文件
for _, tf := range tpls {
err = o.CreateFile(tpDir, tf, c, v)
if err != nil {
log(err.Error(), "error")
}
}
}
// 执行完成
log("生成完毕!", "info")
}
// CreateFile 根据模板创建文件
func (o *G) CreateFile(dir, tf string, conf tpl.Tpl, val map[string]string) (err error) {
val["VariablePrefix"] = FirstUpper(conf.VariablePrefix)
_, f := path.Split(tf)
f = strings.Replace(TplReplace(f, val), ".tpl", ".go", -1)
fPath := path.Join(o.RootPath, dir)
if conf.SplitDir {
fPath = path.Join(fPath, o.FileName+conf.DirSuffix)
}
// 创建目录
err = EnsurePath(fPath)
if err != nil {
return err
}
fPath = path.Join(fPath, f)
// 检查文件是否存在,存在则跳过
//_, err = os.Stat(fPath)
//if err == nil {
// log("目标文件已存在,不可覆盖!File:"+fPath, "warn")
// return nil
//}
log("准备写入目标文件:"+fPath, "info")
// 读取文件并替换内容
b, err := os.ReadFile(tf)
if err != nil {
return err
}
tplContent := string(b)
tplContent = TplReplace(tplContent, val)
// 写入目标文件
if err := os.WriteFile(fPath, []byte(tplContent), 0755); err != nil {
log("写入目标文件:"+fPath+"失败!", "error")
return err
}
log("写入目标文件:"+fPath+"成功!", "error")
return nil
}
// genStructDefine 生成结构体定义语句
func (o *G) genStructDefine(structName string, fields []Field) string {
var s []string
sub := make(map[string][]Field)
for _, f := range fields {
tmp := fmt.Sprintf(" %s\t%s\t`%s`\t// %s", f.Name, f.TypeName, f.Tag, f.Comment)
s = append(s, tmp)
if len(f.SubField) > 0 {
sub[f.SubStructName] = f.SubField
}
}
ms := fmt.Sprintf("type %s struct {\n%s\n} \n\n", structName, strings.Join(s, "\n"))
if len(sub) == 0 {
return ms
}
var subs []string
for n, v := range sub {
subs = append(subs, o.genStructDefine(n, v))
}
ss := strings.Join(subs, "\n\n")
return ms + ss
}
// genAppRespStructFields 生成app返回结构
func (o *G) genAppRespStructFields(fields []Field) string {
var s []string
for _, f := range fields {
tmp := fmt.Sprintf(" %s\t%s\t`%s`\t// %s", f.Name, f.TypeName, f.UpdateTag, f.Comment)
s = append(s, tmp)
}
return strings.Join(s, "\n")
}
// genAppRespTransferStatement 生成app返回转换过程代码
func (o *G) genAppRespTransferStatement(fields []Field) string {
var s []string
for _, f := range fields {
tmp := fmt.Sprintf(" %s: item.%s,", f.Name, f.Name)
s = append(s, tmp)
}
str := strings.Join(s, "\n")
return str
}
// genCreateStructFields 生成创建数据字段定义
func (o *G) genCreateStructFields(fields []Field) string {
var s []string
for _, f := range fields {
fn := strings.ToLower(f.Name)
if fn == "id" || fn == "createdat" || fn == "updatedat" {
continue
}
tmp := fmt.Sprintf(" %s\t%s\t`%s`\t// %s", f.Name, f.TypeName, f.FormTag, f.Comment)
s = append(s, tmp)
}
return strings.Join(s, "\n")
}
// genCreateStatement 生成创建过程代码
func (o *G) genCreateStatement(fields []Field) string {
var s []string
hasCreateTime := false
hasUpdateTime := false
for _, f := range fields {
fn := strings.ToLower(f.Name)
if fn == "id" {
continue
}
if fn == "createdat" {
hasCreateTime = true
continue
}
if fn == "updatedat" {
hasUpdateTime = true
continue
}
tmp := fmt.Sprintf(" %s: p.%s,", f.Name, f.Name)
s = append(s, tmp)
}
str := strings.Join(s, "\n")
if hasCreateTime {
str += "\n CreatedAt: time.Now(),"
}
if hasUpdateTime {
str += "\n UpdatedAt: time.Now(),"
}
return str
}
// genUpdateStructFields 生成更新数据字段定义
func (o *G) genUpdateStructFields(fields []Field) string {
var s []string
for _, f := range fields {
fn := strings.ToLower(f.Name)
if fn == "id" || fn == "createdat" || fn == "updatedat" {
continue
}
tmp := fmt.Sprintf(" %s\t*%s\t`%s`\t// %s", f.Name, f.TypeName, f.UpdateTag, f.Comment)
s = append(s, tmp)
}
return strings.Join(s, "\n")
}
// genUpdateStatement 生成更新过程代码
func (o *G) genUpdateStatement(fields []Field) string {
var s []string
hasUpdateTime := false
for _, f := range fields {
fn := strings.ToLower(f.Name)
if fn == "id" || fn == "createdat" {
continue
}
if fn == "updatedat" {
hasUpdateTime = true
continue
}
tmp := fmt.Sprintf(" if p.%s != nil {\n\t\tdata[\"%s\"] = *p.%s\n\t}", f.Name, f.BsonField, f.Name)
s = append(s, tmp)
}
str := strings.Join(s, "\n")
if hasUpdateTime {
str += "\n\tdata[\"updatedAt\"] = time.Now()\n"
}
return str
}
// SetTableName 自定义表名
func (o *G) SetTableName(n string) {
o.TableName = FirstUpper(n)
}
// NoApp 不生成app
func (o *G) NoApp() {
o.AppGenerate = false
}
// NoWeb 不生成web
func (o *G) NoWeb() {
o.WebGenerate = false
}
// explodeStruct 解剖struct
func (o *G) explodeStruct(t reflect.Type) (f []Field, err error) {
if t.Kind() != reflect.Struct {
return nil, errors.New("不支持结构体以外的类型!")
}
// 遍历结构体的字段
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
jsonTag := field.Tag.Get("json")
if jsonTag == "" {
jsonTag = "-"
}
bsonTag := field.Tag.Get("bson")
if bsonTag == "" {
bsonTag = "-"
}
tag := fmt.Sprintf("json:\"%s\" bson:\"%s\"", jsonTag, bsonTag)
fTag := fmt.Sprintf("json:\"%s\" form:\"%s\" binding:\"required\"", jsonTag, jsonTag)
uTag := fmt.Sprintf("json:\"%s\"", jsonTag)
isDefinedType := strings.Count(field.Type.String(), "main.") > 0
typeName := strings.Replace(field.Type.String(), "main.", "", 1)
tmp := Field{
Name: field.Name,
TypeName: typeName,
Tag: tag,
BsonField: bsonTag,
FormTag: fTag,
UpdateTag: uTag,
Comment: field.Tag.Get("comment"),
}
if isDefinedType {
if field.Type.Kind() == reflect.Slice || field.Type.Kind() == reflect.Pointer {
tmp.SubField, _ = o.explodeStruct(field.Type.Elem())
if field.Type.Kind() == reflect.Slice {
tmp.SubStructName = strings.TrimLeft(typeName, "[]")
} else {
tmp.SubStructName = strings.TrimLeft(typeName, "*")
}
} else if field.Type.Kind() == reflect.Struct {
tmp.SubField, _ = o.explodeStruct(field.Type)
tmp.SubStructName = typeName
}
}
f = append(f, tmp)
}
return
}