mirror of
https://github.com/stashapp/stash.git
synced 2026-02-27 01:32:57 +01:00
143 lines
3.3 KiB
Go
143 lines
3.3 KiB
Go
package migrations
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
|
|
"github.com/jmoiron/sqlx"
|
|
"github.com/stashapp/stash/pkg/logger"
|
|
"github.com/stashapp/stash/pkg/sqlite"
|
|
"github.com/stashapp/stash/pkg/utils"
|
|
)
|
|
|
|
type schema78Migrator struct {
|
|
migrator
|
|
}
|
|
|
|
func post78(ctx context.Context, db *sqlx.DB) error {
|
|
logger.Info("Running post-migration for schema version 78")
|
|
|
|
m := schema78Migrator{
|
|
migrator: migrator{
|
|
db: db,
|
|
},
|
|
}
|
|
|
|
if err := m.migrateCareerLength(ctx); err != nil {
|
|
return fmt.Errorf("migrating career_length: %w", err)
|
|
}
|
|
|
|
if err := m.dropCareerLength(); err != nil {
|
|
return fmt.Errorf("dropping career_length column: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (m *schema78Migrator) migrateCareerLength(ctx context.Context) error {
|
|
logger.Info("Migrating career_length to career_start/career_end")
|
|
|
|
const limit = 1000
|
|
|
|
lastID := 0
|
|
parsed := 0
|
|
unparseable := 0
|
|
|
|
for {
|
|
gotSome := false
|
|
|
|
if err := m.withTxn(ctx, func(tx *sqlx.Tx) error {
|
|
query := `SELECT id, career_length FROM performers
|
|
WHERE career_length IS NOT NULL AND career_length != ''`
|
|
|
|
if lastID != 0 {
|
|
query += fmt.Sprintf(" AND id > %d", lastID)
|
|
}
|
|
|
|
query += fmt.Sprintf(" ORDER BY id LIMIT %d", limit)
|
|
|
|
rows, err := tx.Query(query)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer rows.Close()
|
|
|
|
for rows.Next() {
|
|
var (
|
|
id int
|
|
careerLength string
|
|
)
|
|
|
|
if err := rows.Scan(&id, &careerLength); err != nil {
|
|
return err
|
|
}
|
|
|
|
lastID = id
|
|
gotSome = true
|
|
|
|
start, end, err := utils.ParseYearRangeString(careerLength)
|
|
if err != nil {
|
|
logger.Warnf("Could not parse career_length %q for performer %d: %v — preserving as custom field", careerLength, id, err)
|
|
|
|
if err := m.preserveAsCustomField(tx, id, careerLength); err != nil {
|
|
return fmt.Errorf("preserving career_length for performer %d: %w", id, err)
|
|
}
|
|
unparseable++
|
|
continue
|
|
}
|
|
|
|
if err := m.updateCareerFields(tx, id, start, end); err != nil {
|
|
return fmt.Errorf("updating career fields for performer %d: %w", id, err)
|
|
}
|
|
parsed++
|
|
}
|
|
|
|
return rows.Err()
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
|
|
if !gotSome {
|
|
break
|
|
}
|
|
}
|
|
|
|
logger.Infof("Career length migration complete: %d parsed, %d unparseable (preserved as custom fields)", parsed, unparseable)
|
|
return nil
|
|
}
|
|
|
|
func (m *schema78Migrator) updateCareerFields(tx *sqlx.Tx, id int, start *int, end *int) error {
|
|
_, err := tx.Exec(
|
|
"UPDATE performers SET career_start = ?, career_end = ? WHERE id = ?",
|
|
start, end, id,
|
|
)
|
|
return err
|
|
}
|
|
|
|
func (m *schema78Migrator) preserveAsCustomField(tx *sqlx.Tx, id int, value string) error {
|
|
// check if a career_length custom field already exists
|
|
var existing sql.NullString
|
|
err := tx.Get(&existing, "SELECT value FROM performer_custom_fields WHERE performer_id = ? AND field = 'career_length'", id)
|
|
if err == nil {
|
|
logger.Debugf("career_length custom field already exists for performer %d, skipping", id)
|
|
return nil
|
|
}
|
|
|
|
_, err = tx.Exec(
|
|
"INSERT INTO performer_custom_fields (performer_id, field, value) VALUES (?, 'career_length', ?)",
|
|
id, value,
|
|
)
|
|
return err
|
|
}
|
|
|
|
func (m *schema78Migrator) dropCareerLength() error {
|
|
logger.Info("Dropping career_length column from performers table")
|
|
return m.execAll([]string{
|
|
"ALTER TABLE performers DROP COLUMN career_length",
|
|
})
|
|
}
|
|
|
|
func init() {
|
|
sqlite.RegisterPostMigration(78, post78)
|
|
}
|