"""Initial schema — users, games, versions, build_jobs. Revision ID: 0001 Revises: Create Date: 2026-06-07 """ from __future__ import annotations from collections.abc import Sequence import sqlalchemy as sa from alembic import op revision: str = "0001" down_revision: str | None = None branch_labels: str | Sequence[str] | None = None depends_on: str | Sequence[str] | None = None def upgrade() -> None: op.create_table( "users", sa.Column("id", sa.Integer(), primary_key=True), sa.Column("username", sa.String(64), nullable=False, unique=True), sa.Column("password_hash", sa.String(255), nullable=False), sa.Column("is_admin", sa.Boolean(), nullable=False, server_default=sa.text("false")), sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()), ) op.create_index("ix_users_username", "users", ["username"], unique=True) op.create_table( "games", sa.Column("id", sa.Integer(), primary_key=True), sa.Column("title", sa.String(255), nullable=False, unique=True), sa.Column("app_id", sa.Integer(), nullable=True), sa.Column("description_override", sa.Text(), nullable=True), sa.Column("header_image_override", sa.String(1024), nullable=True), sa.Column("is_private", sa.Boolean(), nullable=False, server_default=sa.text("false")), sa.Column("deleted_at", sa.DateTime(timezone=True), nullable=True), sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()), ) op.create_index("ix_games_title", "games", ["title"], unique=True) op.create_index("ix_games_is_private", "games", ["is_private"]) op.create_index("ix_games_deleted_at", "games", ["deleted_at"]) op.create_table( "versions", sa.Column("id", sa.Integer(), primary_key=True), sa.Column("game_id", sa.Integer(), sa.ForeignKey("games.id", ondelete="CASCADE"), nullable=False), sa.Column("version_string", sa.String(64), nullable=False), sa.Column("ordinal", sa.Integer(), nullable=False), sa.Column("manifest_hash", sa.String(64), nullable=True), sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()), sa.UniqueConstraint("game_id", "version_string", name="uq_versions_game_id_version_string"), ) op.create_index("ix_versions_game_id_ordinal", "versions", ["game_id", "ordinal"]) build_job_kind = sa.Enum( "import_new_game", "push_update", "generate_direct_update", "generate_indirect_update", "prepare_full_game", name="buildjobkind", ) build_job_state = sa.Enum("pending", "running", "success", "failure", name="buildjobstate") op.create_table( "build_jobs", sa.Column("id", sa.Integer(), primary_key=True), sa.Column("celery_task_id", sa.String(128), nullable=True), sa.Column("game_id", sa.Integer(), sa.ForeignKey("games.id", ondelete="SET NULL"), nullable=True), sa.Column("kind", build_job_kind, nullable=False), sa.Column("state", build_job_state, nullable=False, server_default="pending"), sa.Column("detail", sa.Text(), nullable=True), sa.Column("error", sa.Text(), nullable=True), sa.Column("started_at", sa.DateTime(timezone=True), nullable=True), sa.Column("finished_at", sa.DateTime(timezone=True), nullable=True), sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()), ) op.create_index("ix_build_jobs_celery_task_id", "build_jobs", ["celery_task_id"]) def downgrade() -> None: op.drop_table("build_jobs") op.execute("DROP TYPE IF EXISTS buildjobstate") op.execute("DROP TYPE IF EXISTS buildjobkind") op.drop_table("versions") op.drop_table("games") op.drop_table("users")