2021-11-21 14:05:07 +01:00
|
|
|
package entity
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"time"
|
|
|
|
|
2021-11-28 13:52:27 +01:00
|
|
|
"github.com/jinzhu/gorm"
|
|
|
|
|
2021-11-21 14:05:07 +01:00
|
|
|
"github.com/photoprism/photoprism/internal/migrate"
|
2022-04-15 09:42:07 +02:00
|
|
|
"github.com/photoprism/photoprism/pkg/clean"
|
2021-11-21 14:05:07 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
type Tables map[string]interface{}
|
|
|
|
|
|
|
|
// Entities contains database entities and their table names.
|
|
|
|
var Entities = Tables{
|
|
|
|
migrate.Migration{}.TableName(): &migrate.Migration{},
|
2022-09-02 21:30:50 +02:00
|
|
|
Error{}.TableName(): &Error{},
|
|
|
|
Password{}.TableName(): &Password{},
|
|
|
|
User{}.TableName(): &User{},
|
2022-09-28 09:01:17 +02:00
|
|
|
UserDetails{}.TableName(): &UserDetails{},
|
|
|
|
UserSettings{}.TableName(): &UserSettings{},
|
|
|
|
Session{}.TableName(): &Session{},
|
2022-10-15 21:54:11 +02:00
|
|
|
Service{}.TableName(): &Service{},
|
2022-09-02 21:30:50 +02:00
|
|
|
Folder{}.TableName(): &Folder{},
|
|
|
|
Duplicate{}.TableName(): &Duplicate{},
|
2021-11-21 14:05:07 +01:00
|
|
|
File{}.TableName(): &File{},
|
2022-09-02 21:30:50 +02:00
|
|
|
FileShare{}.TableName(): &FileShare{},
|
|
|
|
FileSync{}.TableName(): &FileSync{},
|
2021-11-21 14:05:07 +01:00
|
|
|
Photo{}.TableName(): &Photo{},
|
2022-10-02 22:09:02 +02:00
|
|
|
PhotoUser{}.TableName(): &PhotoUser{},
|
2022-09-02 21:30:50 +02:00
|
|
|
Details{}.TableName(): &Details{},
|
2021-11-21 14:05:07 +01:00
|
|
|
Place{}.TableName(): &Place{},
|
|
|
|
Cell{}.TableName(): &Cell{},
|
2022-09-02 21:30:50 +02:00
|
|
|
Camera{}.TableName(): &Camera{},
|
|
|
|
Lens{}.TableName(): &Lens{},
|
|
|
|
Country{}.TableName(): &Country{},
|
|
|
|
Album{}.TableName(): &Album{},
|
2022-10-02 22:09:02 +02:00
|
|
|
AlbumUser{}.TableName(): &AlbumUser{},
|
2022-09-02 21:30:50 +02:00
|
|
|
PhotoAlbum{}.TableName(): &PhotoAlbum{},
|
|
|
|
Label{}.TableName(): &Label{},
|
|
|
|
Category{}.TableName(): &Category{},
|
|
|
|
PhotoLabel{}.TableName(): &PhotoLabel{},
|
|
|
|
Keyword{}.TableName(): &Keyword{},
|
|
|
|
PhotoKeyword{}.TableName(): &PhotoKeyword{},
|
|
|
|
Link{}.TableName(): &Link{},
|
2021-11-21 14:05:07 +01:00
|
|
|
Subject{}.TableName(): &Subject{},
|
|
|
|
Face{}.TableName(): &Face{},
|
|
|
|
Marker{}.TableName(): &Marker{},
|
2022-09-28 09:01:17 +02:00
|
|
|
Reaction{}.TableName(): &Reaction{},
|
2022-10-04 00:54:39 +02:00
|
|
|
UserShare{}.TableName(): &UserShare{},
|
2021-11-21 14:05:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// WaitForMigration waits for the database migration to be successful.
|
2021-11-28 13:52:27 +01:00
|
|
|
func (list Tables) WaitForMigration(db *gorm.DB) {
|
2021-11-21 14:05:07 +01:00
|
|
|
type RowCount struct {
|
|
|
|
Count int
|
|
|
|
}
|
|
|
|
|
|
|
|
attempts := 100
|
|
|
|
for name := range list {
|
|
|
|
for i := 0; i <= attempts; i++ {
|
|
|
|
count := RowCount{}
|
2021-11-28 13:52:27 +01:00
|
|
|
if err := db.Raw(fmt.Sprintf("SELECT COUNT(*) AS count FROM %s", name)).Scan(&count).Error; err == nil {
|
2022-04-15 09:42:07 +02:00
|
|
|
log.Tracef("migrate: %s migrated", clean.Log(name))
|
2021-11-21 14:05:07 +01:00
|
|
|
break
|
|
|
|
} else {
|
2022-10-15 21:54:11 +02:00
|
|
|
log.Tracef("migrate: waiting for %s migration (%s)", clean.Log(name), err.Error())
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
2021-11-21 14:05:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if i == attempts {
|
|
|
|
panic("migration failed")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Truncate removes all data from tables without dropping them.
|
2021-11-28 13:52:27 +01:00
|
|
|
func (list Tables) Truncate(db *gorm.DB) {
|
2022-09-02 21:30:50 +02:00
|
|
|
var name string
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
log.Errorf("migrate: %s in %s (truncate)", r, name)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
for name = range list {
|
2021-11-28 13:52:27 +01:00
|
|
|
if err := db.Exec(fmt.Sprintf("DELETE FROM %s WHERE 1", name)).Error; err == nil {
|
2021-11-21 14:05:07 +01:00
|
|
|
// log.Debugf("entity: removed all data from %s", name)
|
|
|
|
break
|
|
|
|
} else if err.Error() != "record not found" {
|
2022-04-15 09:42:07 +02:00
|
|
|
log.Debugf("migrate: %s in %s", err, clean.Log(name))
|
2021-11-21 14:05:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Migrate migrates all database tables of registered entities.
|
2022-10-15 21:54:11 +02:00
|
|
|
func (list Tables) Migrate(db *gorm.DB, opt migrate.Options) {
|
2022-09-02 21:30:50 +02:00
|
|
|
var name string
|
|
|
|
var entity interface{}
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
log.Errorf("migrate: %s in %s (panic)", r, name)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2023-02-09 13:14:56 +01:00
|
|
|
log.Infof("migrate: running database migrations")
|
|
|
|
|
2022-10-15 21:54:11 +02:00
|
|
|
// Run pre-migrations, if any.
|
|
|
|
if err := migrate.Run(db, opt.Pre()); err != nil {
|
|
|
|
log.Error(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run auto migrations.
|
|
|
|
if opt.AutoMigrate {
|
2022-09-02 21:30:50 +02:00
|
|
|
for name, entity = range list {
|
2022-03-30 20:36:25 +02:00
|
|
|
if err := db.AutoMigrate(entity).Error; err != nil {
|
2022-04-04 14:21:43 +02:00
|
|
|
log.Debugf("migrate: %s (waiting 1s)", err.Error())
|
2021-11-21 14:05:07 +01:00
|
|
|
|
2022-03-30 20:36:25 +02:00
|
|
|
time.Sleep(time.Second)
|
2021-11-21 14:05:07 +01:00
|
|
|
|
2022-09-02 21:30:50 +02:00
|
|
|
if err = db.AutoMigrate(entity).Error; err != nil {
|
2022-04-15 09:42:07 +02:00
|
|
|
log.Errorf("migrate: failed migrating %s", clean.Log(name))
|
2022-03-30 20:36:25 +02:00
|
|
|
panic(err)
|
|
|
|
}
|
2021-11-21 14:05:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-15 21:54:11 +02:00
|
|
|
// Run manual migrations, if any.
|
|
|
|
if err := migrate.Run(db, opt); err != nil {
|
2021-11-21 14:05:07 +01:00
|
|
|
log.Error(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Drop drops all database tables of registered entities.
|
2021-11-28 13:52:27 +01:00
|
|
|
func (list Tables) Drop(db *gorm.DB) {
|
2021-11-21 14:05:07 +01:00
|
|
|
for _, entity := range list {
|
2021-11-28 13:52:27 +01:00
|
|
|
if err := db.DropTableIfExists(entity).Error; err != nil {
|
2021-11-21 14:05:07 +01:00
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|