"""Add library tables (listening_history, liked_tracks) Revision ID: 001_add_library_tables Revises: Create Date: 2025-01-19 17:51:00.000000 """ from typing import Sequence, Union from alembic import op import sqlalchemy as sa from sqlalchemy.dialects import postgresql # revision identifiers, used by Alembic. revision: str = '001_add_library_tables' down_revision: Union[str, None] = None branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: """Create listening_history and liked_tracks tables with indexes.""" # Create listening_history table op.create_table( 'listening_history', sa.Column( 'id', postgresql.UUID(as_uuid=True), primary_key=True, nullable=False, server_default=sa.text('gen_random_uuid()') ), sa.Column( 'user_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('users.id', ondelete='CASCADE'), nullable=False ), sa.Column( 'track_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('tracks.id', ondelete='CASCADE'), nullable=False ), sa.Column( 'played_for', sa.Integer(), nullable=False, server_default='0', comment='Duration played in seconds' ), sa.Column( 'completed', sa.Boolean(), nullable=False, server_default='false', comment='Whether the track was played to completion' ), sa.Column( 'source', sa.String(length=50), nullable=True, comment='Playback source (library, playlist, search, etc.)' ), sa.Column( 'played_at', sa.DateTime(), nullable=False, server_default=sa.text('CURRENT_TIMESTAMP') ), sa.Column( 'created_at', sa.DateTime(), nullable=False, server_default=sa.text('CURRENT_TIMESTAMP') ), comment='Listening history representing user track listening records' ) # Create indexes for listening_history op.create_index( 'ix_listening_history_id', 'listening_history', ['id'] ) op.create_index( 'ix_listening_history_user_id', 'listening_history', ['user_id'] ) op.create_index( 'ix_listening_history_track_id', 'listening_history', ['track_id'] ) op.create_index( 'ix_listening_history_played_at', 'listening_history', ['played_at'] ) op.create_index( 'ix_listening_history_user_played', 'listening_history', ['user_id', 'played_at'] ) op.create_index( 'ix_listening_history_user_track', 'listening_history', ['user_id', 'track_id'] ) # Create liked_tracks table op.create_table( 'liked_tracks', sa.Column( 'id', postgresql.UUID(as_uuid=True), primary_key=True, nullable=False, server_default=sa.text('gen_random_uuid()') ), sa.Column( 'user_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('users.id', ondelete='CASCADE'), nullable=False ), sa.Column( 'track_id', postgresql.UUID(as_uuid=True), sa.ForeignKey('tracks.id', ondelete='CASCADE'), nullable=False ), sa.Column( 'notes', sa.String(length=1000), nullable=True, comment='User notes about the track' ), sa.Column( 'created_at', sa.DateTime(), nullable=False, server_default=sa.text('CURRENT_TIMESTAMP') ), sa.Column( 'updated_at', sa.DateTime(), nullable=False, server_default=sa.text('CURRENT_TIMESTAMP') ), comment='Liked tracks representing user favorited tracks' ) # Create indexes for liked_tracks op.create_index( 'ix_liked_tracks_id', 'liked_tracks', ['id'] ) op.create_index( 'ix_liked_tracks_user_id', 'liked_tracks', ['user_id'] ) op.create_index( 'ix_liked_tracks_track_id', 'liked_tracks', ['track_id'] ) op.create_index( 'ix_liked_tracks_user_track', 'liked_tracks', ['user_id', 'track_id'], unique=True ) def downgrade() -> None: """Drop liked_tracks and listening_history tables.""" # Drop liked_tracks table first (no foreign keys depend on it) op.drop_index('ix_liked_tracks_user_track', table_name='liked_tracks') op.drop_index('ix_liked_tracks_track_id', table_name='liked_tracks') op.drop_index('ix_liked_tracks_user_id', table_name='liked_tracks') op.drop_index('ix_liked_tracks_id', table_name='liked_tracks') op.drop_table('liked_tracks') # Drop listening_history table op.drop_index('ix_listening_history_user_track', table_name='listening_history') op.drop_index('ix_listening_history_user_played', table_name='listening_history') op.drop_index('ix_listening_history_played_at', table_name='listening_history') op.drop_index('ix_listening_history_track_id', table_name='listening_history') op.drop_index('ix_listening_history_user_id', table_name='listening_history') op.drop_index('ix_listening_history_id', table_name='listening_history') op.drop_table('listening_history')