diff --git a/backend/alembic/env.py b/backend/alembic/env.py index d9411ca..27505ab 100644 --- a/backend/alembic/env.py +++ b/backend/alembic/env.py @@ -8,7 +8,7 @@ from sqlalchemy.ext.asyncio import create_async_engine from app.config import settings from app.database import Base -from app.models import user, session, world, asset # noqa: F401 +from app.models import user, session, world, asset, world_visit # noqa: F401 # this is the Alembic Config object, which provides # access to the values within the .ini file in use. diff --git a/backend/alembic/versions/0003_add_discovery_metadata.py b/backend/alembic/versions/0003_add_discovery_metadata.py new file mode 100644 index 0000000..dfd7c51 --- /dev/null +++ b/backend/alembic/versions/0003_add_discovery_metadata.py @@ -0,0 +1,104 @@ +"""add discovery metadata to worlds and create world_visits + +Revision ID: 0003_add_discovery_metadata +Revises: 0002_add_date_of_birth_to_users +Create Date: 2025-01-02 00:00: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 = "0003_add_discovery_metadata" +down_revision: Union[str, None] = "0002_add_date_of_birth_to_users" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + """Add discovery metadata columns to worlds and create world_visits.""" + # Add discovery metadata columns to worlds. + op.add_column( + "worlds", + sa.Column("category", sa.String(length=100), nullable=True), + ) + op.add_column( + "worlds", + sa.Column( + "tags", + postgresql.ARRAY(sa.String()), + nullable=True, + server_default="{}", + ), + ) + op.add_column( + "worlds", + sa.Column("play_count", sa.Integer(), nullable=False, server_default="0"), + ) + op.add_column( + "worlds", + sa.Column("last_played_at", sa.DateTime(timezone=True), nullable=True), + ) + + # B-tree index on category, GIN index on tags. + op.create_index( + "ix_worlds_category", + "worlds", + ["category"], + unique=False, + ) + op.create_index( + "ix_worlds_tags", + "worlds", + ["tags"], + unique=False, + postgresql_using="gin", + ) + + # Create world_visits table. + op.create_table( + "world_visits", + sa.Column("id", sa.Integer(), primary_key=True), + sa.Column("world_id", sa.Integer(), nullable=False), + sa.Column("user_id", sa.Integer(), nullable=True), + sa.Column("anonymous_token", sa.String(length=255), nullable=True), + sa.Column( + "visited_at", + sa.DateTime(timezone=True), + server_default=sa.func.now(), + ), + sa.ForeignKeyConstraint( + ["world_id"], ["worlds.id"], ondelete="CASCADE" + ), + sa.ForeignKeyConstraint( + ["user_id"], ["users.id"], ondelete="CASCADE" + ), + ) + op.create_index( + op.f("ix_world_visits_id"), "world_visits", ["id"], unique=False + ) + op.create_index( + "ix_world_visits_world_id_visited_at", + "world_visits", + ["world_id", "visited_at"], + unique=False, + ) + + +def downgrade() -> None: + """Drop world_visits and discovery metadata columns from worlds.""" + op.drop_index( + "ix_world_visits_world_id_visited_at", table_name="world_visits" + ) + op.drop_index(op.f("ix_world_visits_id"), table_name="world_visits") + op.drop_table("world_visits") + + op.drop_index("ix_worlds_tags", table_name="worlds") + op.drop_index("ix_worlds_category", table_name="worlds") + op.drop_column("worlds", "last_played_at") + op.drop_column("worlds", "play_count") + op.drop_column("worlds", "tags") + op.drop_column("worlds", "category")