/
githubmirror
/
photoprism
Обзор
Документация
Войти
/
githubmirror
/
photoprism
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
develop
internal/entity/entity_tables.go
194 строки
6 KB
Michael Mayer
Tests: Fix the Go unit test suite on MariaDB #5753
25 июл 2026, 21:06
25 июл 2026, 21:06
5efb48e
Код
Авторство
О чём код?
package entity import ( "errors" "fmt" "time" "github.com/jinzhu/gorm" "github.com/photoprism/photoprism/internal/entity/migrate" "github.com/photoprism/photoprism/pkg/clean" "github.com/photoprism/photoprism/pkg/dsn" ) type Tables map[string]any // schemaTables contains the tables that record the schema migration state. // Truncate keeps them, as the schema remains migrated when only data is removed. var schemaTables = map[string]bool{ migrate.Migration{}.TableName(): true, migrate.Version{}.TableName(): true, } // Entities contains database entities and their table names. var Entities = Tables{ migrate.Migration{}.TableName(): &migrate.Migration{}, migrate.Version{}.TableName(): &migrate.Version{}, Error{}.TableName(): &Error{}, Password{}.TableName(): &Password{}, Passcode{}.TableName(): &Passcode{}, User{}.TableName(): &User{}, UserDetails{}.TableName(): &UserDetails{}, UserSettings{}.TableName(): &UserSettings{}, Session{}.TableName(): &Session{}, Client{}.TableName(): &Client{}, Service{}.TableName(): &Service{}, Folder{}.TableName(): &Folder{}, Duplicate{}.TableName(): &Duplicate{}, File{}.TableName(): &File{}, FileShare{}.TableName(): &FileShare{}, FileSync{}.TableName(): &FileSync{}, Photo{}.TableName(): &Photo{}, PhotoUser{}.TableName(): &PhotoUser{}, Details{}.TableName(): &Details{}, Place{}.TableName(): &Place{}, Cell{}.TableName(): &Cell{}, Camera{}.TableName(): &Camera{}, Lens{}.TableName(): &Lens{}, Country{}.TableName(): &Country{}, Album{}.TableName(): &Album{}, AlbumUser{}.TableName(): &AlbumUser{}, PhotoAlbum{}.TableName(): &PhotoAlbum{}, Label{}.TableName(): &Label{}, Category{}.TableName(): &Category{}, PhotoLabel{}.TableName(): &PhotoLabel{}, Keyword{}.TableName(): &Keyword{}, PhotoKeyword{}.TableName(): &PhotoKeyword{}, Link{}.TableName(): &Link{}, Subject{}.TableName(): &Subject{}, Face{}.TableName(): &Face{}, Marker{}.TableName(): &Marker{}, Reaction{}.TableName(): &Reaction{}, UserShare{}.TableName(): &UserShare{}, } // WaitForMigration waits for the database migration to be successful and returns an error otherwise. func (list Tables) WaitForMigration(db *gorm.DB) error { type RowCount struct { Count int } attempts := 100 for name := range list { for i := 0; i <= attempts; i++ { count := RowCount{} if err := db.Raw(fmt.Sprintf("SELECT COUNT(*) AS count FROM %s", name)).Scan(&count).Error; err == nil { log.Tracef("migrate: %s migrated", clean.Log(name)) break } else { log.Tracef("migrate: waiting for %s migration (%s)", clean.Log(name), err.Error()) time.Sleep(100 * time.Millisecond) } if i == attempts { return errors.New("some database tables are missing") } } } return nil } // Truncate removes all data from tables without dropping them, except for the // schemaTables that record the migration state. func (list Tables) Truncate(db *gorm.DB) { var name string defer func() { if r := recover(); r != nil { log.Errorf("migrate: %s in %s (truncate)", r, name) } }() for name = range list { if schemaTables[name] { continue } else if err := truncateTable(db, name); err != nil && err.Error() != "record not found" { log.Debugf("migrate: %s in %s", err, clean.Log(name)) } } } // truncateTable removes all rows from the table with the specified name. // // TRUNCATE is preferred as it also resets AUTO_INCREMENT counters, so that // generated IDs match those in a newly created database. DELETE serves as a // fallback for SQLite and for accounts without the required privileges. func truncateTable(db *gorm.DB, name string) error { if db.Dialect().GetName() != dsn.DriverSQLite3 { if err := db.Exec(fmt.Sprintf("TRUNCATE TABLE %s", name)).Error; err == nil { return nil } } return db.Exec(fmt.Sprintf("DELETE FROM %s WHERE 1", name)).Error } // Migrate migrates all database tables of registered entities. func (list Tables) Migrate(db *gorm.DB, opt migrate.Options) { var name string var entity any defer func() { if r := recover(); r != nil { log.Errorf("migrate: %s in %s (panic)", r, name) } }() log.Debugf("migrate: running database migrations") // Run pre migrations, if any. if err := migrate.Run(db, opt.Pre()); err != nil { log.Error(err) } // Run ORM auto migrations. if opt.AutoMigrate { // Check if the DBMS AuthID fix has been applied? version := migrate.FirstOrCreateVersion(db, migrate.NewVersion("DBMS AuthID Fix", "Any Editions")) if version.NeedsMigration() { if err := migrate.ConvertDBMSAuthIDDataTypes(db); err != nil { log.Errorf("migrate: could not apply dbms auth_id fix : %v", err) version.Error = err.Error() if saveErr := version.Save(db); saveErr != nil { log.Errorf("migrate: could not save dbms auth_id fix status: %v", saveErr) } } else { if migratedErr := version.Migrated(db); migratedErr != nil { log.Errorf("migrate: could not persist dbms auth_id fix status: %v", migratedErr) } log.Debug("migrate: DBMS AuthID fix migrated") } } else { log.Debug("migrate: DBMS AuthID fix skipped") } for name, entity = range list { if err := db.AutoMigrate(entity).Error; err != nil { log.Debugf("migrate: %s (waiting 1s)", err.Error()) time.Sleep(time.Second) if err = db.AutoMigrate(entity).Error; err != nil { log.Errorf("migrate: failed migrating %s", clean.Log(name)) panic(err) } } } } // Run main migrations, if any. if err := migrate.Run(db, opt); err != nil { log.Error(err) } } // Drop drops all database tables of registered entities. func (list Tables) Drop(db *gorm.DB) { for _, entity := range list { if err := db.DropTableIfExists(entity).Error; err != nil { panic(err) } } }