From 319923fb40f3201edd43d8e5acbf7db51850120a Mon Sep 17 00:00:00 2001 From: Anish Sarkar <104695310+AnishSarkar22@users.noreply.github.com> Date: Sun, 10 May 2026 22:40:29 +0530 Subject: [PATCH] fix: add checks for existing tables and indexes before creating them in alembic migrations for idempotency --- .../versions/130_add_agent_action_log.py | 4 ++ .../versions/131_add_document_revisions.py | 17 ++++++ .../132_add_agent_permission_rules.py | 4 ++ .../135_action_log_correlation_ids.py | 52 +++++++++++-------- .../137_unique_reverse_of_in_action_log.py | 7 +++ .../141_unique_chat_message_turn_role.py | 5 ++ 6 files changed, 68 insertions(+), 21 deletions(-) diff --git a/surfsense_backend/alembic/versions/130_add_agent_action_log.py b/surfsense_backend/alembic/versions/130_add_agent_action_log.py index f86a8a3b5..5978848d0 100644 --- a/surfsense_backend/alembic/versions/130_add_agent_action_log.py +++ b/surfsense_backend/alembic/versions/130_add_agent_action_log.py @@ -26,6 +26,10 @@ depends_on: str | Sequence[str] | None = None def upgrade() -> None: + bind = op.get_bind() + if sa.inspect(bind).has_table("agent_action_log"): + return + op.create_table( "agent_action_log", sa.Column("id", sa.Integer(), primary_key=True, index=True), diff --git a/surfsense_backend/alembic/versions/131_add_document_revisions.py b/surfsense_backend/alembic/versions/131_add_document_revisions.py index 95ce0e032..c1e9b6068 100644 --- a/surfsense_backend/alembic/versions/131_add_document_revisions.py +++ b/surfsense_backend/alembic/versions/131_add_document_revisions.py @@ -29,6 +29,21 @@ depends_on: str | Sequence[str] | None = None def upgrade() -> None: + bind = op.get_bind() + inspector = sa.inspect(bind) + + if inspector.has_table("document_revisions") and inspector.has_table( + "folder_revisions" + ): + return + + if not inspector.has_table("document_revisions"): + _create_document_revisions() + if not inspector.has_table("folder_revisions"): + _create_folder_revisions() + + +def _create_document_revisions() -> None: op.create_table( "document_revisions", sa.Column("id", sa.Integer(), primary_key=True, index=True), @@ -74,6 +89,8 @@ def upgrade() -> None: ), ) + +def _create_folder_revisions() -> None: op.create_table( "folder_revisions", sa.Column("id", sa.Integer(), primary_key=True, index=True), diff --git a/surfsense_backend/alembic/versions/132_add_agent_permission_rules.py b/surfsense_backend/alembic/versions/132_add_agent_permission_rules.py index ff5b52e18..1ee3cd2f0 100644 --- a/surfsense_backend/alembic/versions/132_add_agent_permission_rules.py +++ b/surfsense_backend/alembic/versions/132_add_agent_permission_rules.py @@ -26,6 +26,10 @@ depends_on: str | Sequence[str] | None = None def upgrade() -> None: + bind = op.get_bind() + if sa.inspect(bind).has_table("agent_permission_rules"): + return + op.create_table( "agent_permission_rules", sa.Column("id", sa.Integer(), primary_key=True, index=True), diff --git a/surfsense_backend/alembic/versions/135_action_log_correlation_ids.py b/surfsense_backend/alembic/versions/135_action_log_correlation_ids.py index 9ae368b81..e40c4fb26 100644 --- a/surfsense_backend/alembic/versions/135_action_log_correlation_ids.py +++ b/surfsense_backend/alembic/versions/135_action_log_correlation_ids.py @@ -50,29 +50,39 @@ depends_on: str | Sequence[str] | None = None def upgrade() -> None: - op.add_column( - "agent_action_log", - sa.Column("tool_call_id", sa.String(length=64), nullable=True), - ) - op.add_column( - "agent_action_log", - sa.Column("chat_turn_id", sa.String(length=64), nullable=True), - ) + bind = op.get_bind() + inspector = sa.inspect(bind) + columns = {c["name"] for c in inspector.get_columns("agent_action_log")} + indexes = {i["name"] for i in inspector.get_indexes("agent_action_log")} - op.create_index( - "ix_agent_action_log_tool_call_id", - "agent_action_log", - ["tool_call_id"], - ) - op.create_index( - "ix_agent_action_log_chat_turn_id", - "agent_action_log", - ["chat_turn_id"], - ) + if "tool_call_id" not in columns: + op.add_column( + "agent_action_log", + sa.Column("tool_call_id", sa.String(length=64), nullable=True), + ) + if "chat_turn_id" not in columns: + op.add_column( + "agent_action_log", + sa.Column("chat_turn_id", sa.String(length=64), nullable=True), + ) - op.execute( - "UPDATE agent_action_log SET tool_call_id = turn_id WHERE tool_call_id IS NULL" - ) + if "ix_agent_action_log_tool_call_id" not in indexes: + op.create_index( + "ix_agent_action_log_tool_call_id", + "agent_action_log", + ["tool_call_id"], + ) + if "ix_agent_action_log_chat_turn_id" not in indexes: + op.create_index( + "ix_agent_action_log_chat_turn_id", + "agent_action_log", + ["chat_turn_id"], + ) + + if "turn_id" in columns: + op.execute( + "UPDATE agent_action_log SET tool_call_id = turn_id WHERE tool_call_id IS NULL" + ) def downgrade() -> None: diff --git a/surfsense_backend/alembic/versions/137_unique_reverse_of_in_action_log.py b/surfsense_backend/alembic/versions/137_unique_reverse_of_in_action_log.py index d606a00f9..47421e712 100644 --- a/surfsense_backend/alembic/versions/137_unique_reverse_of_in_action_log.py +++ b/surfsense_backend/alembic/versions/137_unique_reverse_of_in_action_log.py @@ -27,6 +27,8 @@ from __future__ import annotations from collections.abc import Sequence +import sqlalchemy as sa + from alembic import op revision: str = "137" @@ -39,6 +41,11 @@ _INDEX_NAME = "ux_agent_action_log_reverse_of" def upgrade() -> None: + bind = op.get_bind() + indexes = {i["name"] for i in sa.inspect(bind).get_indexes("agent_action_log")} + if _INDEX_NAME in indexes: + return + # Defensively de-dup any pre-existing double-revert rows before # adding the unique index. Keeps the OLDEST row (smallest id) and # NULLs out the duplicates' ``reverse_of`` so they survive as audit diff --git a/surfsense_backend/alembic/versions/141_unique_chat_message_turn_role.py b/surfsense_backend/alembic/versions/141_unique_chat_message_turn_role.py index 9a27e7ed0..1226a59b4 100644 --- a/surfsense_backend/alembic/versions/141_unique_chat_message_turn_role.py +++ b/surfsense_backend/alembic/versions/141_unique_chat_message_turn_role.py @@ -53,6 +53,11 @@ TABLE_NAME = "new_chat_messages" def upgrade() -> None: + bind = op.get_bind() + indexes = {i["name"] for i in sa.inspect(bind).get_indexes(TABLE_NAME)} + if INDEX_NAME in indexes: + return + op.create_index( INDEX_NAME, TABLE_NAME,