from sqlalchemy import inspect, text from app.db.base import engine from app.db.dialect import bool_literal def run_migrations() -> None: inspector = inspect(engine) if "pomodoro_sessions" in inspector.get_table_names(): columns = {col["name"] for col in inspector.get_columns("pomodoro_sessions")} with engine.begin() as conn: if "phase" not in columns: conn.execute( text("ALTER TABLE pomodoro_sessions ADD COLUMN phase VARCHAR(32) DEFAULT 'work'") ) if "completion_notified" not in columns: conn.execute( text( "ALTER TABLE pomodoro_sessions " f"ADD COLUMN completion_notified BOOLEAN DEFAULT {bool_literal(engine, False)}" ) ) if "messages" in inspector.get_table_names(): columns = {col["name"] for col in inspector.get_columns("messages")} with engine.begin() as conn: if "reasoning_json" not in columns: conn.execute(text("ALTER TABLE messages ADD COLUMN reasoning_json TEXT")) if "pomodoro_cycles" not in inspector.get_table_names(): _migrate_documents(inspector) return columns = {col["name"] for col in inspector.get_columns("pomodoro_cycles")} with engine.begin() as conn: if "chat_notify_seq" not in columns: conn.execute( text("ALTER TABLE pomodoro_cycles ADD COLUMN chat_notify_seq INTEGER DEFAULT 0") ) _migrate_documents(inspector) def _add_column_if_missing(table: str, columns: set[str], column: str, ddl: str) -> None: if column in columns: return with engine.begin() as conn: conn.execute(text(ddl)) def _migrate_documents(inspector) -> None: table_names = inspector.get_table_names() if "documents" in table_names: columns = {col["name"] for col in inspector.get_columns("documents")} _add_column_if_missing( "documents", columns, "mime_type", "ALTER TABLE documents ADD COLUMN mime_type VARCHAR(128) DEFAULT ''", ) _add_column_if_missing( "documents", columns, "chunk_count", "ALTER TABLE documents ADD COLUMN chunk_count INTEGER DEFAULT 0", ) _add_column_if_missing( "documents", columns, "index_status", "ALTER TABLE documents ADD COLUMN index_status VARCHAR(32) DEFAULT 'indexed'", ) if "document_chunks" in table_names: columns = {col["name"] for col in inspector.get_columns("document_chunks")} _add_column_if_missing( "document_chunks", columns, "source_filename", "ALTER TABLE document_chunks ADD COLUMN source_filename VARCHAR(255) DEFAULT ''", ) _add_column_if_missing( "document_chunks", columns, "mime_type", "ALTER TABLE document_chunks ADD COLUMN mime_type VARCHAR(128) DEFAULT ''", ) _add_column_if_missing( "document_chunks", columns, "page_start", "ALTER TABLE document_chunks ADD COLUMN page_start INTEGER", ) _add_column_if_missing( "document_chunks", columns, "page_end", "ALTER TABLE document_chunks ADD COLUMN page_end INTEGER", ) _add_column_if_missing( "document_chunks", columns, "section_title", "ALTER TABLE document_chunks ADD COLUMN section_title VARCHAR(500) DEFAULT ''", ) _add_column_if_missing( "document_chunks", columns, "section_path", "ALTER TABLE document_chunks ADD COLUMN section_path TEXT DEFAULT ''", ) _add_column_if_missing( "document_chunks", columns, "paragraph_index", "ALTER TABLE document_chunks ADD COLUMN paragraph_index INTEGER", ) _add_column_if_missing( "document_chunks", columns, "source_ref", "ALTER TABLE document_chunks ADD COLUMN source_ref VARCHAR(500) DEFAULT ''", )