"""partial-unique topic/rule titles (ignore soft-deleted rows)

Revision ID: 0061
Revises: 0060
Create Date: 2026-06-02

Topics and rules are soft-deleted (SoftDeleteMixin), but uq_topic_per_rulebook
and uq_rule_per_topic were plain UNIQUE constraints. Trashing a topic/rule
named "X" then creating a new "X" — or restoring into a reused title slot —
collided with the dead row and raised an unhandled 500. Replace the full
UNIQUE constraints with partial unique indexes that only consider live
(deleted_at IS NULL) rows.
"""
from alembic import op
import sqlalchemy as sa


revision = "0061"
down_revision = "0060"
branch_labels = None
depends_on = None


def upgrade() -> None:
    op.drop_constraint("uq_topic_per_rulebook", "rulebook_topics", type_="unique")
    op.create_index(
        "uq_topic_per_rulebook",
        "rulebook_topics",
        ["rulebook_id", "title"],
        unique=True,
        postgresql_where=sa.text("deleted_at IS NULL"),
    )
    op.drop_constraint("uq_rule_per_topic", "rules", type_="unique")
    op.create_index(
        "uq_rule_per_topic",
        "rules",
        ["topic_id", "title"],
        unique=True,
        postgresql_where=sa.text("deleted_at IS NULL"),
    )


def downgrade() -> None:
    op.drop_index("uq_rule_per_topic", table_name="rules")
    op.create_unique_constraint("uq_rule_per_topic", "rules", ["topic_id", "title"])
    op.drop_index("uq_topic_per_rulebook", table_name="rulebook_topics")
    op.create_unique_constraint(
        "uq_topic_per_rulebook", "rulebook_topics", ["rulebook_id", "title"]
    )
