diff --git a/internal/db/migrations/013_cleanup_invalid_booleans.go b/internal/db/migrations/013_cleanup_invalid_booleans.go new file mode 100644 index 0000000..bbde9e6 --- /dev/null +++ b/internal/db/migrations/013_cleanup_invalid_booleans.go @@ -0,0 +1,91 @@ +package migrations + +import ( + "fmt" + + "github.com/go-gormigrate/gormigrate/v2" + "gorm.io/gorm" +) + +// CleanupInvalidBooleans updates boolean columns represented as integers +// to ensure they only contain valid values (0, 1, or NULL). +func CleanupInvalidBooleans() *gormigrate.Migration { + return &gormigrate.Migration{ + ID: "013_cleanup_invalid_booleans", + Migrate: func(tx *gorm.DB) error { + fmt.Println("Running migration 013: Cleaning up invalid boolean values...") + + // Target: transfer_configs.delete_after_transfer + // Set any non-NULL value that is not 0 or 1 to 0 (false) + sql := `UPDATE transfer_configs + SET delete_after_transfer = 0 + WHERE delete_after_transfer IS NOT NULL AND delete_after_transfer NOT IN (0, 1);` + + if err := tx.Exec(sql).Error; err != nil { + return fmt.Errorf("failed to cleanup delete_after_transfer in transfer_configs: %w", err) + } + fmt.Println("Cleaned up invalid values in transfer_configs.delete_after_transfer.") + + // Target: transfer_configs.archive_enabled + sql = `UPDATE transfer_configs + SET archive_enabled = 0 + WHERE archive_enabled IS NOT NULL AND archive_enabled NOT IN (0, 1);` + if err := tx.Exec(sql).Error; err != nil { + return fmt.Errorf("failed to cleanup archive_enabled in transfer_configs: %w", err) + } + fmt.Println("Cleaned up invalid values in transfer_configs.archive_enabled.") + + // Target: transfer_configs.skip_processed_files + sql = `UPDATE transfer_configs + SET skip_processed_files = 0 + WHERE skip_processed_files IS NOT NULL AND skip_processed_files NOT IN (0, 1);` + if err := tx.Exec(sql).Error; err != nil { + return fmt.Errorf("failed to cleanup skip_processed_files in transfer_configs: %w", err) + } + fmt.Println("Cleaned up invalid values in transfer_configs.skip_processed_files.") + + // Target: notification_services.is_enabled + sql = `UPDATE notification_services + SET is_enabled = 0 + WHERE is_enabled IS NOT NULL AND is_enabled NOT IN (0, 1);` + if err := tx.Exec(sql).Error; err != nil { + // Check if the table exists before failing hard + var tableExists int + tx.Raw("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='notification_services'").Scan(&tableExists) + if tableExists == 0 { + fmt.Println("Skipping cleanup for notification_services.is_enabled: table does not exist.") + } else { + return fmt.Errorf("failed to cleanup is_enabled in notification_services: %w", err) + } + } else { + fmt.Println("Cleaned up invalid values in notification_services.is_enabled.") + } + + // Target: auth_providers.enabled + sql = `UPDATE auth_providers + SET enabled = 0 + WHERE enabled IS NOT NULL AND enabled NOT IN (0, 1);` + if err := tx.Exec(sql).Error; err != nil { + // Check if the table exists before failing hard + var tableExists int + tx.Raw("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='auth_providers'").Scan(&tableExists) + if tableExists == 0 { + fmt.Println("Skipping cleanup for auth_providers.enabled: table does not exist.") + } else { + return fmt.Errorf("failed to cleanup enabled in auth_providers: %w", err) + } + } else { + fmt.Println("Cleaned up invalid values in auth_providers.enabled.") + } + + fmt.Println("Migration 013 completed successfully.") + return nil + }, + Rollback: func(tx *gorm.DB) error { + // This migration cleans up data. Rolling back doesn't make sense + // as we don't know the original invalid values. + fmt.Println("Rollback for migration 013_cleanup_invalid_booleans is not applicable.") + return nil + }, + } +} diff --git a/internal/db/migrations/migrations.go b/internal/db/migrations/migrations.go index 4bfbaa2..be953b6 100644 --- a/internal/db/migrations/migrations.go +++ b/internal/db/migrations/migrations.go @@ -23,6 +23,7 @@ func GetMigrations(db *gorm.DB) *gormigrate.Gormigrate { AddRcloneCommandToConfig(), // 010 AddAuthProviders(), // 011 AlterBooleanDefaults(), // 012 + CleanupInvalidBooleans(), // 013 ) return gormigrate.New(db, gormigrate.DefaultOptions, migrations)