diff --git a/alembic/versions/010_add_foreign_key_constraints.py b/alembic/versions/010_add_foreign_key_constraints.py deleted file mode 100644 index ce6ca3870..000000000 --- a/alembic/versions/010_add_foreign_key_constraints.py +++ /dev/null @@ -1,190 +0,0 @@ -"""add foreign key constraints and missing indexes - -Revision ID: 010 -Revises: 009 -Create Date: 2026-06-28 - -Summary: -- Add ForeignKey constraints to all 35 logical FK columns across 16 tables -- ON DELETE CASCADE for parent-child relationships (project → children) -- ON DELETE SET NULL for optional user references (created_by, assignee, etc.) -- Add missing indexes on 10 FK columns -- Alter columns from NOT NULL to nullable where SET NULL is needed -""" - -from alembic import op -import sqlalchemy as sa - -revision = "010" -down_revision = "009" -branch_labels = None -depends_on = None - - -def upgrade() -> None: - # ── projects ────────────────────────────────────────────── - op.create_foreign_key("fk_projects_owner_user_id", "projects", "users", ["owner_user_id"], ["id"], ondelete="CASCADE") - - # ── asset_libraries ─────────────────────────────────────── - op.create_foreign_key("fk_asset_libraries_project_id", "asset_libraries", "projects", ["project_id"], ["id"], ondelete="CASCADE") - - # ── assets ──────────────────────────────────────────────── - # uploaded_by_user_id: nullable=False → nullable=True for SET NULL - op.alter_column("assets", "uploaded_by_user_id", existing_type=sa.String(36), nullable=True) - op.create_foreign_key("fk_assets_project_id", "assets", "projects", ["project_id"], ["id"], ondelete="CASCADE") - op.create_foreign_key("fk_assets_asset_library_id", "assets", "asset_libraries", ["asset_library_id"], ["id"], ondelete="CASCADE") - op.create_foreign_key("fk_assets_uploaded_by_user_id", "assets", "users", ["uploaded_by_user_id"], ["id"], ondelete="SET NULL") - # Add missing index - op.create_index("ix_assets_uploaded_by_user_id", "assets", ["uploaded_by_user_id"]) - - # ── project_titles ──────────────────────────────────────── - # created_by_user_id: nullable=False → nullable=True for SET NULL - op.alter_column("project_titles", "created_by_user_id", existing_type=sa.String(36), nullable=True) - op.create_foreign_key("fk_project_titles_project_id", "project_titles", "projects", ["project_id"], ["id"], ondelete="CASCADE") - op.create_foreign_key("fk_project_titles_created_by_user_id", "project_titles", "users", ["created_by_user_id"], ["id"], ondelete="SET NULL") - # Add missing index - op.create_index("ix_project_titles_created_by_user_id", "project_titles", ["created_by_user_id"]) - - # ── edit_templates ──────────────────────────────────────── - # created_by_user_id: nullable=False → nullable=True for SET NULL - op.alter_column("edit_templates", "created_by_user_id", existing_type=sa.String(32), nullable=True) - op.create_foreign_key("fk_edit_templates_project_id", "edit_templates", "projects", ["project_id"], ["id"], ondelete="CASCADE") - op.create_foreign_key("fk_edit_templates_created_by_user_id", "edit_templates", "users", ["created_by_user_id"], ["id"], ondelete="SET NULL") - - # ── edit_plans ──────────────────────────────────────────── - # title_id: nullable=False → nullable=True for SET NULL - # created_by_user_id: nullable=False → nullable=True for SET NULL - op.alter_column("edit_plans", "title_id", existing_type=sa.String(32), nullable=True) - op.alter_column("edit_plans", "created_by_user_id", existing_type=sa.String(32), nullable=True) - op.create_foreign_key("fk_edit_plans_project_id", "edit_plans", "projects", ["project_id"], ["id"], ondelete="CASCADE") - op.create_foreign_key("fk_edit_plans_template_id", "edit_plans", "edit_templates", ["template_id"], ["id"], ondelete="CASCADE") - op.create_foreign_key("fk_edit_plans_asset_library_id", "edit_plans", "asset_libraries", ["asset_library_id"], ["id"], ondelete="CASCADE") - op.create_foreign_key("fk_edit_plans_title_id", "edit_plans", "project_titles", ["title_id"], ["id"], ondelete="SET NULL") - op.create_foreign_key("fk_edit_plans_created_by_user_id", "edit_plans", "users", ["created_by_user_id"], ["id"], ondelete="SET NULL") - - # ── edit_plan_clips ─────────────────────────────────────── - op.create_foreign_key("fk_edit_plan_clips_edit_plan_id", "edit_plan_clips", "edit_plans", ["edit_plan_id"], ["id"], ondelete="CASCADE") - op.create_foreign_key("fk_edit_plan_clips_asset_id", "edit_plan_clips", "assets", ["asset_id"], ["id"], ondelete="CASCADE") - - # ── ingest_jobs ─────────────────────────────────────────── - # result_asset_id: nullable=False → nullable=True for SET NULL - op.alter_column("ingest_jobs", "result_asset_id", existing_type=sa.String(32), nullable=True) - op.create_foreign_key("fk_ingest_jobs_project_id", "ingest_jobs", "projects", ["project_id"], ["id"], ondelete="CASCADE") - op.create_foreign_key("fk_ingest_jobs_library_id", "ingest_jobs", "asset_libraries", ["library_id"], ["id"], ondelete="CASCADE") - op.create_foreign_key("fk_ingest_jobs_result_asset_id", "ingest_jobs", "assets", ["result_asset_id"], ["id"], ondelete="SET NULL") - - # ── classification_jobs ─────────────────────────────────── - op.create_foreign_key("fk_classification_jobs_project_id", "classification_jobs", "projects", ["project_id"], ["id"], ondelete="CASCADE") - op.create_foreign_key("fk_classification_jobs_asset_id", "classification_jobs", "assets", ["asset_id"], ["id"], ondelete="CASCADE") - - # ── generation_tasks ────────────────────────────────────── - # edit_plan_id: nullable=False → nullable=True for SET NULL - # created_by_user_id: nullable=False → nullable=True for SET NULL - op.alter_column("generation_tasks", "edit_plan_id", existing_type=sa.String(32), nullable=True) - op.alter_column("generation_tasks", "created_by_user_id", existing_type=sa.String(32), nullable=True) - op.create_foreign_key("fk_generation_tasks_project_id", "generation_tasks", "projects", ["project_id"], ["id"], ondelete="CASCADE") - op.create_foreign_key("fk_generation_tasks_asset_library_id", "generation_tasks", "asset_libraries", ["asset_library_id"], ["id"], ondelete="CASCADE") - op.create_foreign_key("fk_generation_tasks_edit_plan_id", "generation_tasks", "edit_plans", ["edit_plan_id"], ["id"], ondelete="SET NULL") - op.create_foreign_key("fk_generation_tasks_created_by_user_id", "generation_tasks", "users", ["created_by_user_id"], ["id"], ondelete="SET NULL") - - # ── generated_videos ────────────────────────────────────── - op.create_foreign_key("fk_generated_videos_project_id", "generated_videos", "projects", ["project_id"], ["id"], ondelete="CASCADE") - op.create_foreign_key("fk_generated_videos_generation_task_id", "generated_videos", "generation_tasks", ["generation_task_id"], ["id"], ondelete="CASCADE") - op.create_foreign_key("fk_generated_videos_duplicate_of", "generated_videos", "generated_videos", ["duplicate_of"], ["id"], ondelete="SET NULL") - - # ── tasks ───────────────────────────────────────────────── - # parent_task_id: nullable=False → nullable=True for SET NULL - # assignee_user_id: nullable=False → nullable=True for SET NULL - op.alter_column("tasks", "parent_task_id", existing_type=sa.String(32), nullable=True) - op.alter_column("tasks", "assignee_user_id", existing_type=sa.String(32), nullable=True) - op.create_foreign_key("fk_tasks_project_id", "tasks", "projects", ["project_id"], ["id"], ondelete="CASCADE") - op.create_foreign_key("fk_tasks_parent_task_id", "tasks", "tasks", ["parent_task_id"], ["id"], ondelete="SET NULL") - op.create_foreign_key("fk_tasks_assignee_user_id", "tasks", "users", ["assignee_user_id"], ["id"], ondelete="SET NULL") - - # ── milestones ──────────────────────────────────────────── - op.create_foreign_key("fk_milestones_project_id", "milestones", "projects", ["project_id"], ["id"], ondelete="CASCADE") - - # ── task_issues ─────────────────────────────────────────── - # created_by_user_id: nullable=False → nullable=True for SET NULL - op.alter_column("task_issues", "created_by_user_id", existing_type=sa.String(32), nullable=True) - op.create_foreign_key("fk_task_issues_task_id", "task_issues", "tasks", ["task_id"], ["id"], ondelete="CASCADE") - op.create_foreign_key("fk_task_issues_project_id", "task_issues", "projects", ["project_id"], ["id"], ondelete="CASCADE") - op.create_foreign_key("fk_task_issues_created_by_user_id", "task_issues", "users", ["created_by_user_id"], ["id"], ondelete="SET NULL") - - -def downgrade() -> None: - # ── task_issues ─────────────────────────────────────────── - op.drop_constraint("fk_task_issues_created_by_user_id", "task_issues", type_="foreignkey") - op.drop_constraint("fk_task_issues_project_id", "task_issues", type_="foreignkey") - op.drop_constraint("fk_task_issues_task_id", "task_issues", type_="foreignkey") - op.alter_column("task_issues", "created_by_user_id", existing_type=sa.String(32), nullable=False) - - # ── milestones ──────────────────────────────────────────── - op.drop_constraint("fk_milestones_project_id", "milestones", type_="foreignkey") - - # ── tasks ───────────────────────────────────────────────── - op.drop_constraint("fk_tasks_assignee_user_id", "tasks", type_="foreignkey") - op.drop_constraint("fk_tasks_parent_task_id", "tasks", type_="foreignkey") - op.drop_constraint("fk_tasks_project_id", "tasks", type_="foreignkey") - op.alter_column("tasks", "assignee_user_id", existing_type=sa.String(32), nullable=False) - op.alter_column("tasks", "parent_task_id", existing_type=sa.String(32), nullable=False) - - # ── generated_videos ────────────────────────────────────── - op.drop_constraint("fk_generated_videos_duplicate_of", "generated_videos", type_="foreignkey") - op.drop_constraint("fk_generated_videos_generation_task_id", "generated_videos", type_="foreignkey") - op.drop_constraint("fk_generated_videos_project_id", "generated_videos", type_="foreignkey") - - # ── generation_tasks ────────────────────────────────────── - op.drop_constraint("fk_generation_tasks_created_by_user_id", "generation_tasks", type_="foreignkey") - op.drop_constraint("fk_generation_tasks_edit_plan_id", "generation_tasks", type_="foreignkey") - op.drop_constraint("fk_generation_tasks_asset_library_id", "generation_tasks", type_="foreignkey") - op.drop_constraint("fk_generation_tasks_project_id", "generation_tasks", type_="foreignkey") - op.alter_column("generation_tasks", "created_by_user_id", existing_type=sa.String(32), nullable=False) - op.alter_column("generation_tasks", "edit_plan_id", existing_type=sa.String(32), nullable=False) - - # ── classification_jobs ─────────────────────────────────── - op.drop_constraint("fk_classification_jobs_asset_id", "classification_jobs", type_="foreignkey") - op.drop_constraint("fk_classification_jobs_project_id", "classification_jobs", type_="foreignkey") - - # ── ingest_jobs ─────────────────────────────────────────── - op.drop_constraint("fk_ingest_jobs_result_asset_id", "ingest_jobs", type_="foreignkey") - op.drop_constraint("fk_ingest_jobs_library_id", "ingest_jobs", type_="foreignkey") - op.drop_constraint("fk_ingest_jobs_project_id", "ingest_jobs", type_="foreignkey") - op.alter_column("ingest_jobs", "result_asset_id", existing_type=sa.String(32), nullable=False) - - # ── edit_plan_clips ─────────────────────────────────────── - op.drop_constraint("fk_edit_plan_clips_asset_id", "edit_plan_clips", type_="foreignkey") - op.drop_constraint("fk_edit_plan_clips_edit_plan_id", "edit_plan_clips", type_="foreignkey") - - # ── edit_plans ──────────────────────────────────────────── - op.drop_constraint("fk_edit_plans_created_by_user_id", "edit_plans", type_="foreignkey") - op.drop_constraint("fk_edit_plans_title_id", "edit_plans", type_="foreignkey") - op.drop_constraint("fk_edit_plans_asset_library_id", "edit_plans", type_="foreignkey") - op.drop_constraint("fk_edit_plans_template_id", "edit_plans", type_="foreignkey") - op.drop_constraint("fk_edit_plans_project_id", "edit_plans", type_="foreignkey") - op.alter_column("edit_plans", "created_by_user_id", existing_type=sa.String(32), nullable=False) - op.alter_column("edit_plans", "title_id", existing_type=sa.String(32), nullable=False) - - # ── edit_templates ──────────────────────────────────────── - op.drop_constraint("fk_edit_templates_created_by_user_id", "edit_templates", type_="foreignkey") - op.drop_constraint("fk_edit_templates_project_id", "edit_templates", type_="foreignkey") - op.alter_column("edit_templates", "created_by_user_id", existing_type=sa.String(32), nullable=False) - - # ── project_titles ──────────────────────────────────────── - op.drop_index("ix_project_titles_created_by_user_id", table_name="project_titles") - op.drop_constraint("fk_project_titles_created_by_user_id", "project_titles", type_="foreignkey") - op.drop_constraint("fk_project_titles_project_id", "project_titles", type_="foreignkey") - op.alter_column("project_titles", "created_by_user_id", existing_type=sa.String(36), nullable=False) - - # ── assets ──────────────────────────────────────────────── - op.drop_index("ix_assets_uploaded_by_user_id", table_name="assets") - op.drop_constraint("fk_assets_uploaded_by_user_id", "assets", type_="foreignkey") - op.drop_constraint("fk_assets_asset_library_id", "assets", type_="foreignkey") - op.drop_constraint("fk_assets_project_id", "assets", type_="foreignkey") - op.alter_column("assets", "uploaded_by_user_id", existing_type=sa.String(36), nullable=False) - - # ── asset_libraries ─────────────────────────────────────── - op.drop_constraint("fk_asset_libraries_project_id", "asset_libraries", type_="foreignkey") - - # ── projects ────────────────────────────────────────────── - op.drop_constraint("fk_projects_owner_user_id", "projects", type_="foreignkey")