Closed hinego closed 1 year ago
这是我自动生成的代码,我只需要写好model,执行这个文件就能自动生成好
package main
import (
"context"
"errors"
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/encoding/gyaml"
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/v2/text/gstr"
"github.com/hinego/gen"
"github.com/hinego/types"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
"log"
"os"
"strings"
"time"
)
var (
g1 *gen.Generator
genConfig *gen.CmdParams
gdb *gorm.DB
newLogger = logger.New(log.New(os.Stdout, "\r\n", log.Ltime|log.Lshortfile), logger.Config{
SlowThreshold: time.Second, // 慢 SQL 阈值
LogLevel: logger.Silent, // 日志级别
IgnoreRecordNotFoundError: true, // 忽略ErrRecordNotFound(记录未找到)错误
Colorful: true, // 禁用彩色打印
})
cfg = &Config{
Reset: false,
Database: "host=192.168.32.130 user=postgres password=postgres dbname=status port=5432 sslmode=disable TimeZone=Asia/Shanghai",
Type: "postgres",
Path: "./app/dao",
}
)
type Config struct {
Reset bool `yaml:"reset"`
Database string `yaml:"database"`
Type string `yaml:"type"`
Path string `yaml:"path"`
}
func load() {
if !gfile.Exists("database.yml") {
if encode, err := gyaml.Encode(cfg); err != nil {
log.Fatalf("encode fail: %v", err)
} else {
if err = gfile.PutBytes("database.yml", encode); err != nil {
log.Fatalf("write fail: %v", err)
}
}
log.Fatalln("create database.yml success")
} else {
if decode := gfile.GetBytes("database.yml"); decode == nil {
log.Fatalf("read fail")
} else {
if err := gyaml.DecodeTo(decode, cfg); err != nil {
log.Fatalf("decode fail: %v", err)
}
}
}
}
func prepare(ctx context.Context, parser *gcmd.Parser) {
_ = os.Remove("/etc/gen.db")
log.SetFlags(log.Ltime | log.Lshortfile)
genConfig = gen.ArgParse()
if genConfig == nil {
log.Fatalf("parse genConfig fail")
}
schema.RegisterSerializer("auto", types.AutoSerializer{})
genConfig.DSN = cfg.Database
genConfig.DB = cfg.Type
genConfig.OutPath = cfg.Path
if db, err := gen.Connect(gen.DBType(genConfig.DB), genConfig.DSN); err != nil {
log.Fatalf("connect db server fail: %v", err)
} else {
g1 = gen.NewGenerator(gen.Config{
Mode: gen.WithDefaultQuery | gen.WithoutContext,
OutPath: genConfig.OutPath,
OutFile: genConfig.OutFile,
ModelPkgPath: genConfig.ModelPkgName,
WithUnitTest: genConfig.WithUnitTest,
FieldNullable: false,
FieldWithIndexTag: true,
FieldWithTypeTag: true,
FieldSignable: genConfig.FieldSignable,
})
db.Logger = newLogger
db.Logger.Info(ctx, "working directory: %s", gfile.Pwd())
if cfg.Reset {
if tables, err := db.Migrator().GetTables(); err != nil {
return
} else {
log.Println(gjson.MustEncodeString(tables))
for _, table := range tables {
if err := db.Migrator().DropTable(table); err != nil {
log.Println("删除失败", err)
}
}
}
if tables, err := db.Migrator().GetTables(); err != nil {
return
} else {
log.Println("清空后", len(tables))
}
}
g1.UseDB(db)
gdb = db
}
}
var gn = &gcmd.Command{
Name: "main",
Usage: "main",
Brief: "[开发专用]生成dao",
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
if !gfile.Exists("go.mod") {
return errors.New("此为开发使用命令")
}
load()
gfile.Remove("app/dao")
gfile.Remove("app/model")
prepare(ctx, parser)
g1.LinkModel(Md...)
if !genConfig.OnlyModel {
g1.ApplyBasic(g1.GenerateAllTable()...)
}
g1.Execute()
file, err := gfile.ScanDirFile("app/model", "*", true)
if err != nil {
log.Println(err)
return nil
}
for _, v := range file {
data := gfile.GetContents(v)
data = gstr.Replace(data, `"github.com/gogf/gf/v2`, `"github.com/gogf/gf`)
data = gstr.Replace(data, `"github.com/gogf/gf`, `"github.com/gogf/gf/v2`)
gfile.PutContents(v, data)
}
print(gproc.MustShellExec(ctx, "git add ./app/dao"))
print(gproc.MustShellExec(ctx, "git add ./app/model"))
db, err := gdb.DB()
if err == nil {
db.Close()
os.Remove("/etc/gen.db")
}
return nil
},
}
func print(result string) {
res := strings.Split(result, "\n")
for _, v := range res {
if !strings.Contains(v, "CRLF") && v != "" && !strings.Contains(v, "working directory") {
log.Println(v)
}
}
}
func main() {
gn.Run(gctx.New())
}
g1.LinkModel(Md...)
这个Md 其实就是类似于
var Md = []any{table.Token{}}
这样的,保存了当前全部需要生成结构体
这个Md也是自动生成的(我前置的一个脚本)
会自动读取table文件夹下全部除types.go结尾的go文件
提取出其中全部结构体名称,自动写到md里面去
这就实现了我只需要管table里面的结构体定义,不需要写任何其他代码
这个主要是针对已有结构体转查询结构体做的优化吧,这个我们确实没有花很多精力去做,因为很多人都是先写数据库再同步生成结构体的。你添加的功能确实很实用,欢迎把你的修改整理成PR提交
这个主要是针对已有结构体转查询结构体做的优化吧,这个我们确实没有花很多精力去做,因为很多人都是先写数据库再同步生成结构体的。你添加的功能确实很实用,欢迎把你的修改整理成PR提交
有空会尝试的,你们如果有空的话,也可以参考我写的,改一下加进去
你这么做为什么不直接用ent.io..
前景提要
gorm-gen这个项目我比较喜欢,但是使用起来的时候很麻烦,例如实现以下功能时:
诚然,这些功能都提供了function去实现,但是使用起来体验太差了,因为这些功能都是额外设定的规则,需要去学习熟悉!
我的解决方案?
我习惯于通过golang写gorm的model结构体,然后生成数据库结构!再通过gorm把生成的结构生成成model,但是如果按原方案就需要额外写挺多代码来实现上面写的这些功能,我并不想,所以我复用了我自己写的model结构体
例如:
现在的使用体验?
我现在根本不需要写任何额外的代码,只需要手写好原有的数据库结构体,就能自动生成最终的成品,不需要额外写任何代码
项目地址:https://github.com/hinego/gen.git
PS:传入结构体时不能传指针,然后关联关系时多对多目前有问题(等我用到时会去修复)
下面会提供目前我使用的自动生成的代码