|
|
@@ -1,10 +1,15 @@
|
|
|
-// Package: migrate 操作对象
|
|
|
+// Package migrate 操作对象
|
|
|
// 负责创建 migrations 数据表,以及执行迁移操作。
|
|
|
package migrate
|
|
|
|
|
|
import (
|
|
|
- "github.com/runningwater/gohub/pkg/database"
|
|
|
+ "os"
|
|
|
+
|
|
|
"gorm.io/gorm"
|
|
|
+
|
|
|
+ "github.com/runningwater/gohub/pkg/console"
|
|
|
+ "github.com/runningwater/gohub/pkg/database"
|
|
|
+ "github.com/runningwater/gohub/pkg/file"
|
|
|
)
|
|
|
|
|
|
// Migrator 结构体用于存储迁移器的相关信息。
|
|
|
@@ -19,7 +24,10 @@ func (m *Migrator) createMigrationsTable() {
|
|
|
|
|
|
if !m.Migrator.HasTable(&migration) {
|
|
|
// 如果表不存在,则创建表
|
|
|
- m.Migrator.CreateTable(&migration)
|
|
|
+ if err := m.Migrator.CreateTable(&migration); err != nil {
|
|
|
+ console.ExitIf(err)
|
|
|
+ return
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -41,3 +49,89 @@ func NewMigrator() *Migrator {
|
|
|
|
|
|
return migrator
|
|
|
}
|
|
|
+
|
|
|
+// Up 执行所有未执行的迁移文件。
|
|
|
+func (m *Migrator) Up() {
|
|
|
+
|
|
|
+ // 读取所有迁移文件, 确保按照时间排序
|
|
|
+ migrateFiles := m.readAllMigrationFiles()
|
|
|
+ batch := m.getBatch()
|
|
|
+
|
|
|
+ // 获取所有迁移数据
|
|
|
+ migrations := []Migration{}
|
|
|
+ m.DB.Find(&migrations)
|
|
|
+
|
|
|
+ // 可以通过此值来判断数据库是否已是最新
|
|
|
+ runed := false
|
|
|
+
|
|
|
+ // 遍历迁移文件,执行未执行的迁移文件
|
|
|
+ for _, mfile := range migrateFiles {
|
|
|
+
|
|
|
+ if mfile.isNotMigrated(migrations) {
|
|
|
+ m.runUpMigration(mfile, batch)
|
|
|
+ runed = true
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if !runed {
|
|
|
+ console.Success("database is up to date")
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 获取当前这个批次的值
|
|
|
+func (m *Migrator) getBatch() int {
|
|
|
+
|
|
|
+ batch := 1
|
|
|
+
|
|
|
+ lastMigration := Migration{}
|
|
|
+ m.DB.Order("id desc").First(&lastMigration)
|
|
|
+
|
|
|
+ // 如果有值的话,加一
|
|
|
+ if lastMigration.ID > 0 {
|
|
|
+ batch = lastMigration.Batch + 1
|
|
|
+ }
|
|
|
+
|
|
|
+ return batch
|
|
|
+}
|
|
|
+
|
|
|
+// 从文件目录读取文件,保证正确的时间排序
|
|
|
+func (m *Migrator) readAllMigrationFiles() []MigrationFile {
|
|
|
+ // 读取 database/migrations 目录下的所有迁移文件
|
|
|
+ files, err := os.ReadDir(m.Folder)
|
|
|
+ console.ExitIf(err)
|
|
|
+
|
|
|
+ var migrateFiles []MigrationFile
|
|
|
+ // 遍历所有迁移文件
|
|
|
+ for _, f := range files {
|
|
|
+
|
|
|
+ // 去除文件后缀 .go
|
|
|
+ fileName := file.NameWithoutExtension(f.Name())
|
|
|
+ // 通过迁移文件名称获取[MigrationFile]结构体
|
|
|
+ mfile := getMigrationFile(fileName)
|
|
|
+ if len(mfile.FileName) > 0 {
|
|
|
+ migrateFiles = append(migrateFiles, mfile)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return migrateFiles
|
|
|
+}
|
|
|
+
|
|
|
+// 插入一条记录到数据库,同时执行迁移操作
|
|
|
+// 此方法会在 Up 方法中被调用
|
|
|
+// mfile 是迁移文件的结构体,batch 是批次号,用于区分不同的迁移批次。
|
|
|
+// 此方法会执行迁移操作,同时插入一条记录到数据库。
|
|
|
+// 如果迁移操作成功,会输出一条成功信息;如果迁移操作失败,会输出一条错误信息,并退出程序。
|
|
|
+func (m *Migrator) runUpMigration(mfile MigrationFile, batch int) {
|
|
|
+
|
|
|
+ if mfile.Up != nil {
|
|
|
+ console.Warning("migrating " + mfile.FileName)
|
|
|
+ // 执行迁移操作
|
|
|
+ mfile.Up(database.DB.Migrator(), database.SQLDB)
|
|
|
+ console.Success("migrated " + mfile.FileName)
|
|
|
+ }
|
|
|
+ // 插入一条记录到数据库
|
|
|
+ err := m.DB.Create(&Migration{
|
|
|
+ Migration: mfile.FileName,
|
|
|
+ Batch: batch,
|
|
|
+ }).Error
|
|
|
+ console.ExitIf(err)
|
|
|
+}
|