"""social graph: friendships, follows, blocks Revision ID: 0002_social_graph Revises: 0001_initial Create Date: 2026-08-18 00:00:00.000000 """ from typing import Sequence, Union from alembic import op import sqlalchemy as sa # revision identifiers, used by Alembic. revision: str = "0002_social_graph" down_revision: Union[str, None] = "0001_initial" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: """Create friendships, follows, and blocks tables.""" op.create_table( "friendships", sa.Column("id", sa.Integer(), nullable=False), sa.Column("requester_id", sa.Integer(), nullable=False), sa.Column("addressee_id", sa.Integer(), nullable=False), sa.Column("status", sa.String(length=20), nullable=False), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False), sa.Column("updated_at", sa.DateTime(timezone=True), nullable=True), sa.CheckConstraint( "status IN ('pending', 'accepted')", name="ck_friendships_status", ), sa.CheckConstraint( "requester_id <> addressee_id", name="ck_friendships_no_self", ), sa.ForeignKeyConstraint( ["addressee_id"], ["users.id"], ondelete="CASCADE", ), sa.ForeignKeyConstraint( ["requester_id"], ["users.id"], ondelete="CASCADE", ), sa.PrimaryKeyConstraint("id"), sa.UniqueConstraint( "requester_id", "addressee_id", name="uq_friendships_pair", ), ) op.create_index(op.f("ix_friendships_id"), "friendships", ["id"], unique=False) op.create_index(op.f("ix_friendships_addressee_id"), "friendships", ["addressee_id"], unique=False) op.create_index(op.f("ix_friendships_requester_id"), "friendships", ["requester_id"], unique=False) op.create_table( "follows", sa.Column("follower_id", sa.Integer(), nullable=False), sa.Column("followed_id", sa.Integer(), nullable=False), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False), sa.CheckConstraint( "follower_id <> followed_id", name="ck_follows_no_self", ), sa.ForeignKeyConstraint( ["followed_id"], ["users.id"], ondelete="CASCADE", ), sa.ForeignKeyConstraint( ["follower_id"], ["users.id"], ondelete="CASCADE", ), sa.PrimaryKeyConstraint("follower_id", "followed_id"), sa.UniqueConstraint( "follower_id", "followed_id", name="uq_follows_pair", ), ) op.create_index(op.f("ix_follows_followed_id"), "follows", ["followed_id"], unique=False) op.create_table( "blocks", sa.Column("blocker_id", sa.Integer(), nullable=False), sa.Column("blocked_id", sa.Integer(), nullable=False), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False), sa.CheckConstraint( "blocker_id <> blocked_id", name="ck_blocks_no_self", ), sa.ForeignKeyConstraint( ["blocked_id"], ["users.id"], ondelete="CASCADE", ), sa.ForeignKeyConstraint( ["blocker_id"], ["users.id"], ondelete="CASCADE", ), sa.PrimaryKeyConstraint("blocker_id", "blocked_id"), sa.UniqueConstraint( "blocker_id", "blocked_id", name="uq_blocks_pair", ), ) op.create_index(op.f("ix_blocks_blocked_id"), "blocks", ["blocked_id"], unique=False) def downgrade() -> None: """Drop friendships, follows, and blocks tables.""" op.drop_index(op.f("ix_blocks_blocked_id"), table_name="blocks") op.drop_table("blocks") op.drop_index(op.f("ix_follows_followed_id"), table_name="follows") op.drop_table("follows") op.drop_index(op.f("ix_friendships_requester_id"), table_name="friendships") op.drop_index(op.f("ix_friendships_addressee_id"), table_name="friendships") op.drop_index(op.f("ix_friendships_id"), table_name="friendships") op.drop_table("friendships")