"""Daemon model: daemons table, auth_tokens.daemon_id, portfolios.managed_by_daemon_id Revision ID: 20260513_0016 Revises: 20260511_0015 Create Date: 2026-05-13 00:00:00 """ from __future__ import annotations import sqlalchemy as sa from alembic import op from sqlalchemy import inspect revision = "20260513_0016" down_revision = "20260511_0015" branch_labels = None depends_on = None def _table_exists(inspector: sa.engine.Inspector, table_name: str) -> bool: return table_name in inspector.get_table_names() def _column_exists(inspector: sa.engine.Inspector, table_name: str, column_name: str) -> bool: if not _table_exists(inspector, table_name): return False return any(c["name"] == column_name for c in inspector.get_columns(table_name)) def upgrade() -> None: bind = op.get_bind() inspector = inspect(bind) # Step 1: Create daemons table if not _table_exists(inspector, "daemons"): op.create_table( "daemons", sa.Column("id", sa.Text(), nullable=False), sa.Column("owner_user_id", sa.Text(), nullable=False), sa.Column("daemon_slug", sa.Text(), nullable=False), sa.Column("display_name", sa.Text(), nullable=True), sa.Column("is_active", sa.Boolean(), nullable=False, server_default=sa.text("true")), sa.Column("created_at", sa.TIMESTAMP(timezone=True), nullable=False, server_default=sa.text("NOW()")), sa.Column("updated_at", sa.TIMESTAMP(timezone=True), nullable=False, server_default=sa.text("NOW()")), sa.PrimaryKeyConstraint("id"), sa.UniqueConstraint("owner_user_id", "daemon_slug", name="uq_daemons_owner_slug"), ) # Step 2: Add auth_tokens.daemon_id (nullable FK to daemons.id, no DB-level FK constraint — soft reference) if not _column_exists(inspector, "auth_tokens", "daemon_id"): op.add_column("auth_tokens", sa.Column("daemon_id", sa.Text(), nullable=True)) # Step 3: Add portfolios.managed_by_daemon_id (nullable soft reference to daemons.id) if not _column_exists(inspector, "portfolios", "managed_by_daemon_id"): op.add_column("portfolios", sa.Column("managed_by_daemon_id", sa.Text(), nullable=True)) def downgrade() -> None: bind = op.get_bind() inspector = inspect(bind) if _column_exists(inspector, "portfolios", "managed_by_daemon_id"): op.drop_column("portfolios", "managed_by_daemon_id") if _column_exists(inspector, "auth_tokens", "daemon_id"): op.drop_column("auth_tokens", "daemon_id") if _table_exists(inspector, "daemons"): op.drop_table("daemons")