framework1/framework/command/database.go

145 lines
3.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package command
import (
"errors"
"fmt"
"github.com/Superdanda/hade/framework"
"github.com/Superdanda/hade/framework/cobra"
"github.com/Superdanda/hade/framework/contract"
"github.com/Superdanda/hade/framework/provider/orm"
"go/ast"
"go/parser"
"go/token"
"gorm.io/gorm"
"os"
"path/filepath"
"reflect"
)
func initDatabaseCommand() *cobra.Command {
databaseCommand.AddCommand(databaseModelSyncCommand)
return databaseCommand
}
var databaseCommand = &cobra.Command{
Use: "database",
Short: "数据库相关命令",
Long: "操控数据库相关命令,同步数据模型到数据库",
RunE: func(c *cobra.Command, args []string) error {
if len(args) == 0 {
c.Help()
}
return nil
},
}
var databaseModelSyncCommand = &cobra.Command{
Use: "modelSync",
Short: "同步数据模型到数据库",
RunE: func(c *cobra.Command, args []string) error {
if len(args) != 1 {
fmt.Println("请输入数据库连接名称")
}
container := c.GetContainer()
appService := container.MustMake(contract.AppKey).(contract.App)
configService := container.MustMake(contract.ConfigKey).(contract.Config)
syncPathFolder := filepath.Join(appService.BaseFolder(), configService.GetString("database.sync.filePath"))
ormService := container.MustMake(contract.ORMKey).(contract.ORMService)
db, err := ormService.GetDB(orm.WithConfigPath("database." + args[0]))
if err != nil {
return err
}
err = AutoMigrateStructs(db, syncPathFolder, container)
if err != nil {
return err
}
return nil
},
}
// ScanStructsInPackage 扫描给定包路径下的所有结构体
func ScanStructsInPackage(pkgPath string, container framework.Container) ([]interface{}, error) {
var structs []interface{}
// 遍历包路径下的所有 Go 文件
err := filepath.Walk(pkgPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// 只处理 .go 文件
if filepath.Ext(path) != ".go" {
return nil
}
// 解析 Go 文件,构建 AST
fset := token.NewFileSet()
node, err := parser.ParseFile(fset, path, nil, parser.AllErrors)
if err != nil {
return err
}
// 遍历 AST找到所有类型声明
for _, decl := range node.Decls {
genDecl, ok := decl.(*ast.GenDecl)
if !ok || genDecl.Tok != token.TYPE {
continue
}
// 遍历所有类型声明,找到结构体类型
for _, spec := range genDecl.Specs {
typeSpec, ok := spec.(*ast.TypeSpec)
if !ok {
continue
}
// 检查是否为结构体类型
_, ok = typeSpec.Type.(*ast.StructType)
if ok {
// 创建结构体的零值并添加到结果中
structName := typeSpec.Name.Name
instance, err := createStructInstance(structName, container)
if err != nil {
fmt.Println(err.Error())
}
if instance != nil {
structs = append(structs, instance)
}
}
}
}
return nil
})
return structs, err
}
// createStructInstance 使用反射创建结构体的实例
func createStructInstance(structName string, container framework.Container) (interface{}, error) {
typeRegister := container.MustMake(contract.TypeRegisterKey).(contract.TypeRegisterService)
// 假设结构体已导入,使用反射获取类型
structType, b := typeRegister.GetType(structName)
if b {
instance := reflect.New(structType).Interface()
return instance, nil
}
return nil, errors.New(structName + "类型没有注册")
}
func AutoMigrateStructs(db *gorm.DB, pkgPath string, container framework.Container) error {
// 扫描包路径下的所有结构体
structs, err := ScanStructsInPackage(pkgPath, container)
if err != nil {
return err
}
// 使用 GORM 进行自动迁移
for _, model := range structs {
if err := db.AutoMigrate(model); err != nil {
return fmt.Errorf("自动迁移失败: %v", err)
}
fmt.Printf("成功迁移模型:%T\n", model)
}
return nil
}