You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
synctv/internal/db/update.go

177 lines
4.1 KiB
Go

package db
import (
"fmt"
log "github.com/sirupsen/logrus"
"github.com/synctv-org/synctv/cmd/flags"
"github.com/synctv-org/synctv/internal/conf"
"github.com/synctv-org/synctv/internal/model"
"gorm.io/gorm"
)
type dbVersion struct {
Upgrade func(*gorm.DB) error
NextVersion string
}
const CurrentVersion = "0.0.13"
var models = []any{
new(model.Setting),
new(model.User),
new(model.UserProvider),
new(model.Room),
new(model.RoomSettings),
new(model.RoomMember),
new(model.Movie),
new(model.BilibiliVendor),
new(model.AlistVendor),
new(model.EmbyVendor),
new(model.VendorBackend),
}
var dbVersions = map[string]dbVersion{
"0.0.1": {
NextVersion: "0.0.2",
},
"0.0.2": {
NextVersion: "0.0.3",
Upgrade: func(db *gorm.DB) error {
// alist and emby movies path are changed, so we need to delete them
_ = db.Exec("DELETE FROM movies WHERE base_vendor_info_vendor IN ('alist', 'emby')").Error
_ = db.Migrator().DropTable("alist_vendors", "emby_vendors")
// delete all vendors, because we are going to change the more vendor table, e.g. bilibili_vendors
_ = db.Migrator().DropTable("streaming_vendor_infos")
return autoMigrate(
new(model.AlistVendor),
new(model.EmbyVendor),
)
},
},
"0.0.3": {
NextVersion: "0.0.4",
},
"0.0.4": {
NextVersion: "0.0.5",
},
"0.0.5": {
NextVersion: "0.0.6",
},
"0.0.6": {
NextVersion: "0.0.7",
Upgrade: func(d *gorm.DB) error {
// delete all emby vendors records
_ = d.Exec("DELETE FROM emby_vendors").Error
return nil
},
},
"0.0.7": {
NextVersion: "0.0.8",
},
"0.0.8": {
NextVersion: "0.0.9",
},
"0.0.9": {
NextVersion: "0.0.10",
},
"0.0.10": {
NextVersion: "0.0.11",
},
"0.0.11": {
NextVersion: "0.0.12",
},
"0.0.12": {
NextVersion: "0.0.13",
},
"0.0.13": {
NextVersion: "",
},
}
func UpgradeDatabase() error {
if !db.Migrator().HasTable(&model.Setting{}) {
return autoMigrate(models...)
}
setting := model.Setting{
Name: "database_version",
Type: model.SettingTypeString,
Group: model.SettingGroupDatabase,
Value: CurrentVersion,
}
err := FirstOrCreateSettingItemValue(&setting)
if err != nil {
return err
}
currentVersion := setting.Value
log.Infof("current database version: %s", currentVersion)
if flags.Global.ForceAutoMigrate || currentVersion != CurrentVersion {
err = autoMigrate(models...)
if err != nil {
log.Fatalf("failed to auto migrate database: %s", err.Error())
}
}
for currentVersion != "" {
version, ok := dbVersions[currentVersion]
if !ok {
break
}
if version.NextVersion != "" {
log.Infof("Upgrading database to version %s", version.NextVersion)
if version.Upgrade != nil {
err := version.Upgrade(db)
if err != nil {
return err
}
}
err := UpdateSettingItemValue("database_version", version.NextVersion)
if err != nil {
return err
}
}
currentVersion = version.NextVersion
}
return nil
}
func autoMigrate(dst ...any) error {
log.Info("migrating database...")
switch conf.Conf.Database.Type {
case conf.DatabaseTypeMysql:
if err := db.Exec("SET FOREIGN_KEY_CHECKS = 0").Error; err != nil {
return err
}
defer func() {
err := db.Exec("SET FOREIGN_KEY_CHECKS = 1").Error
if err != nil {
log.Fatalf("failed to set foreign key checks: %s", err.Error())
}
}()
return db.Set("gorm:table_options", "ENGINE=InnoDB CHARSET=utf8mb4").AutoMigrate(dst...)
case conf.DatabaseTypeSqlite3:
if err := db.Exec("PRAGMA foreign_keys = OFF").Error; err != nil {
return err
}
defer func() {
err := db.Exec("PRAGMA foreign_keys = ON").Error
if err != nil {
log.Fatalf("failed to set foreign key checks: %s", err.Error())
}
}()
return db.AutoMigrate(dst...)
case conf.DatabaseTypePostgres:
if err := db.Exec("SET CONSTRAINTS ALL DEFERRED").Error; err != nil {
return err
}
defer func() {
err := db.Exec("SET CONSTRAINTS ALL IMMEDIATE").Error
if err != nil {
log.Fatalf("failed to set foreign key checks: %s", err.Error())
}
}()
return db.AutoMigrate(dst...)
default:
return fmt.Errorf("unknown database type: %s", conf.Conf.Database.Type)
}
}