41 lines
2.0 KiB
Python
41 lines
2.0 KiB
Python
"""Merge legacy heads, add cashiers, prevent duplicate entries and prize places."""
|
|
from alembic import op
|
|
import sqlalchemy as sa
|
|
|
|
revision = "20260913_staff_concurrency"
|
|
down_revision = ("20260701_perf_indexes", "41aae82e631b")
|
|
branch_labels = None
|
|
depends_on = None
|
|
|
|
|
|
def upgrade():
|
|
connection = op.get_bind()
|
|
# Stop safely on ambiguous historical results; never silently delete prizes.
|
|
checks = (
|
|
("participations", "lottery_id, account_number", "account_number IS NOT NULL"),
|
|
("participations", "lottery_id, user_id", "account_number IS NULL AND user_id IS NOT NULL"),
|
|
("winners", "lottery_id, place", "1=1"),
|
|
)
|
|
for table, columns, predicate in checks:
|
|
duplicate = connection.execute(sa.text(
|
|
f"SELECT 1 FROM {table} WHERE {predicate} GROUP BY {columns} HAVING COUNT(*) > 1 LIMIT 1"
|
|
)).first()
|
|
if duplicate:
|
|
raise RuntimeError(f"Duplicate {table} ({columns}); review duplicates before migrating. No data removed.")
|
|
op.add_column("users", sa.Column("is_cashier", sa.Boolean(), server_default=sa.false(), nullable=False))
|
|
with op.batch_alter_table("participations") as batch:
|
|
batch.create_unique_constraint("uq_participation_account", ["lottery_id", "account_number"])
|
|
op.create_index("uq_participation_user", "participations", ["lottery_id", "user_id"], unique=True,
|
|
postgresql_where=sa.text("account_number IS NULL"), sqlite_where=sa.text("account_number IS NULL"))
|
|
with op.batch_alter_table("winners") as batch:
|
|
batch.create_unique_constraint("uq_winner_place", ["lottery_id", "place"])
|
|
|
|
|
|
def downgrade():
|
|
with op.batch_alter_table("winners") as batch:
|
|
batch.drop_constraint("uq_winner_place", type_="unique")
|
|
op.drop_index("uq_participation_user", table_name="participations")
|
|
with op.batch_alter_table("participations") as batch:
|
|
batch.drop_constraint("uq_participation_account", type_="unique")
|
|
op.drop_column("users", "is_cashier")
|