stash/pkg/sqlite/migrations/48_premigrate.go
WithoutPants 476688c84d
Database connection pool refactor (#5274)
* Move optimise out of RunAllMigrations
* Separate read and write database connections
* Enforce readonly connection constraint
* Fix migrations not using tx
* #5155 - allow setting cache size from environment
* Document new environment variable
2024-09-20 12:56:26 +10:00

150 lines
2.7 KiB
Go

package migrations
import (
"context"
"fmt"
"github.com/jmoiron/sqlx"
"github.com/stashapp/stash/pkg/logger"
"github.com/stashapp/stash/pkg/sqlite"
)
func pre48(ctx context.Context, db *sqlx.DB) error {
logger.Info("Running pre-migration for schema version 48")
m := schema48PreMigrator{
migrator: migrator{
db: db,
},
}
if err := m.validateScrapedItems(ctx); err != nil {
return err
}
if err := m.fixStudioNames(ctx); err != nil {
return err
}
return nil
}
type schema48PreMigrator struct {
migrator
}
func (m *schema48PreMigrator) validateScrapedItems(ctx context.Context) error {
var count int
row := m.db.QueryRowx("SELECT COUNT(*) FROM scraped_items")
err := row.Scan(&count)
if err != nil {
return err
}
if count == 0 {
return nil
}
return fmt.Errorf("found %d row(s) in scraped_items table, cannot migrate", count)
}
func (m *schema48PreMigrator) fixStudioNames(ctx context.Context) error {
// First remove NULL names
if err := m.withTxn(ctx, func(tx *sqlx.Tx) error {
_, err := tx.Exec("UPDATE studios SET name = 'NULL' WHERE name IS NULL")
return err
}); err != nil {
return err
}
// Then remove duplicate names
dupes := make(map[string][]int)
// collect names
if err := m.withTxn(ctx, func(tx *sqlx.Tx) error {
rows, err := tx.Query("SELECT id, name FROM studios ORDER BY name, id")
if err != nil {
return err
}
defer rows.Close()
first := true
var lastName string
for rows.Next() {
var (
id int
name string
)
err := rows.Scan(&id, &name)
if err != nil {
return err
}
if first {
first = false
lastName = name
continue
}
if lastName == name {
dupes[name] = append(dupes[name], id)
} else {
lastName = name
}
}
return rows.Err()
}); err != nil {
return err
}
// rename them
if err := m.withTxn(ctx, func(tx *sqlx.Tx) error {
for name, ids := range dupes {
i := 0
for _, id := range ids {
var newName string
for j := 0; ; j++ {
i++
newName = fmt.Sprintf("%s (%d)", name, i)
var count int
row := tx.QueryRowx("SELECT COUNT(*) FROM studios WHERE name = ?", newName)
err := row.Scan(&count)
if err != nil {
return err
}
if count == 0 {
break
}
// try up to 100 times to find a unique name
if j == 100 {
return fmt.Errorf("cannot make unique studio name for %s", name)
}
}
logger.Infof("Renaming duplicate studio id %d to %s", id, newName)
_, err := tx.Exec("UPDATE studios SET name = ? WHERE id = ?", newName, id)
if err != nil {
return err
}
}
}
return nil
}); err != nil {
return err
}
return nil
}
func init() {
sqlite.RegisterPreMigration(48, pre48)
}