""" Migration: Make job_reservations.end_date nullable for TBD support SQLite doesn't support ALTER COLUMN, so we need to: 1. Create a new table with the correct schema 2. Copy data 3. Drop old table 4. Rename new table """ import sqlite3 import sys from pathlib import Path def migrate(db_path: str): """Run the migration.""" print(f"Migrating database: {db_path}") conn = sqlite3.connect(db_path) cursor = conn.cursor() try: # Check if job_reservations table exists cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='job_reservations'") if not cursor.fetchone(): print("job_reservations table does not exist. Skipping migration.") return # Check current schema cursor.execute("PRAGMA table_info(job_reservations)") columns = cursor.fetchall() col_info = {row[1]: row for row in columns} # Check if end_date is already nullable (notnull=0) if 'end_date' in col_info and col_info['end_date'][3] == 0: print("end_date is already nullable. Skipping table recreation.") return print("Recreating job_reservations table with nullable end_date...") # Create new table with correct schema cursor.execute(""" CREATE TABLE job_reservations_new ( id TEXT PRIMARY KEY, name TEXT NOT NULL, project_id TEXT, start_date DATE NOT NULL, end_date DATE, estimated_end_date DATE, end_date_tbd BOOLEAN DEFAULT 0, assignment_type TEXT NOT NULL DEFAULT 'quantity', device_type TEXT DEFAULT 'seismograph', quantity_needed INTEGER, notes TEXT, color TEXT DEFAULT '#3B82F6', created_at DATETIME, updated_at DATETIME ) """) # Copy existing data cursor.execute(""" INSERT INTO job_reservations_new SELECT id, name, project_id, start_date, end_date, COALESCE(estimated_end_date, NULL) as estimated_end_date, COALESCE(end_date_tbd, 0) as end_date_tbd, assignment_type, device_type, quantity_needed, notes, color, created_at, updated_at FROM job_reservations """) # Drop old table cursor.execute("DROP TABLE job_reservations") # Rename new table cursor.execute("ALTER TABLE job_reservations_new RENAME TO job_reservations") # Recreate index cursor.execute("CREATE INDEX IF NOT EXISTS ix_job_reservations_id ON job_reservations (id)") cursor.execute("CREATE INDEX IF NOT EXISTS ix_job_reservations_project_id ON job_reservations (project_id)") conn.commit() print("Migration completed successfully!") except Exception as e: print(f"Migration failed: {e}") conn.rollback() raise finally: conn.close() if __name__ == "__main__": # Default to dev database db_path = "./data-dev/seismo_fleet.db" if len(sys.argv) > 1: db_path = sys.argv[1] if not Path(db_path).exists(): print(f"Database not found: {db_path}") sys.exit(1) migrate(db_path)