import { BaseMigration } from './base-migration.ts'; import type { TQueryFunction } from '../types.ts'; export class Migration012GfsRetention extends BaseMigration { readonly version = 12; readonly description = 'GFS retention policy schema'; up(query: TQueryFunction): void { // Recreate backup_schedules with GFS retention columns query(` CREATE TABLE backup_schedules_new ( id INTEGER PRIMARY KEY AUTOINCREMENT, scope_type TEXT NOT NULL DEFAULT 'service', scope_pattern TEXT, service_id INTEGER, service_name TEXT, cron_expression TEXT NOT NULL, retention_hourly INTEGER NOT NULL DEFAULT 0, retention_daily INTEGER NOT NULL DEFAULT 7, retention_weekly INTEGER NOT NULL DEFAULT 4, retention_monthly INTEGER NOT NULL DEFAULT 12, enabled INTEGER NOT NULL DEFAULT 1, last_run_at REAL, next_run_at REAL, last_status TEXT, last_error TEXT, created_at REAL NOT NULL, updated_at REAL NOT NULL, FOREIGN KEY (service_id) REFERENCES services(id) ON DELETE CASCADE ) `); // Migrate existing data - convert old retention_tier to new format query(` INSERT INTO backup_schedules_new ( id, scope_type, scope_pattern, service_id, service_name, cron_expression, retention_hourly, retention_daily, retention_weekly, retention_monthly, enabled, last_run_at, next_run_at, last_status, last_error, created_at, updated_at ) SELECT id, scope_type, scope_pattern, service_id, service_name, cron_expression, 0, CASE WHEN retention_tier = 'daily' THEN 7 ELSE 0 END, CASE WHEN retention_tier IN ('daily', 'weekly') THEN 4 ELSE 0 END, CASE WHEN retention_tier IN ('daily', 'weekly', 'monthly') THEN 12 WHEN retention_tier = 'yearly' THEN 24 ELSE 12 END, enabled, last_run_at, next_run_at, last_status, last_error, created_at, updated_at FROM backup_schedules `); query('DROP TABLE backup_schedules'); query('ALTER TABLE backup_schedules_new RENAME TO backup_schedules'); query( 'CREATE INDEX IF NOT EXISTS idx_backup_schedules_service ON backup_schedules(service_id)', ); query( 'CREATE INDEX IF NOT EXISTS idx_backup_schedules_enabled ON backup_schedules(enabled)', ); query( 'CREATE INDEX IF NOT EXISTS idx_backup_schedules_scope ON backup_schedules(scope_type)', ); // Recreate backups table without retention_tier column query(` CREATE TABLE backups_new ( id INTEGER PRIMARY KEY AUTOINCREMENT, service_id INTEGER NOT NULL, service_name TEXT NOT NULL, filename TEXT NOT NULL, size_bytes INTEGER NOT NULL, created_at REAL NOT NULL, includes_image INTEGER NOT NULL, platform_resources TEXT NOT NULL DEFAULT '[]', checksum TEXT NOT NULL, schedule_id INTEGER REFERENCES backup_schedules(id) ON DELETE SET NULL, FOREIGN KEY (service_id) REFERENCES services(id) ON DELETE CASCADE ) `); query(` INSERT INTO backups_new ( id, service_id, service_name, filename, size_bytes, created_at, includes_image, platform_resources, checksum, schedule_id ) SELECT id, service_id, service_name, filename, size_bytes, created_at, includes_image, platform_resources, checksum, schedule_id FROM backups `); query('DROP TABLE backups'); query('ALTER TABLE backups_new RENAME TO backups'); query('CREATE INDEX IF NOT EXISTS idx_backups_service ON backups(service_id)'); query('CREATE INDEX IF NOT EXISTS idx_backups_created ON backups(created_at DESC)'); query('CREATE INDEX IF NOT EXISTS idx_backups_schedule ON backups(schedule_id)'); } }