From 560ccb678400af800a63b35706832ea9d6e87f35 Mon Sep 17 00:00:00 2001 From: Neeraj Kashyap Date: Wed, 8 Nov 2023 16:19:27 -0800 Subject: [PATCH] Made models.py changes and created alembic migration --- ...3_added_leaderboard_versions_table_and_.py | 119 ++++++++++++++++++ engineapi/engineapi/models.py | 44 ++++++- 2 files changed, 161 insertions(+), 2 deletions(-) create mode 100644 engineapi/alembic/versions/cc80e886e153_added_leaderboard_versions_table_and_.py diff --git a/engineapi/alembic/versions/cc80e886e153_added_leaderboard_versions_table_and_.py b/engineapi/alembic/versions/cc80e886e153_added_leaderboard_versions_table_and_.py new file mode 100644 index 00000000..bdc773f6 --- /dev/null +++ b/engineapi/alembic/versions/cc80e886e153_added_leaderboard_versions_table_and_.py @@ -0,0 +1,119 @@ +"""Added leaderboard_versions table and corresponding constraints + +Revision ID: cc80e886e153 +Revises: 040f2dfde5a5 +Create Date: 2023-11-08 16:16:39.265150 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = "cc80e886e153" +down_revision = "040f2dfde5a5" +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table( + "leaderboard_versions", + sa.Column("leaderboard_id", sa.UUID(), nullable=False), + sa.Column("version_number", sa.DECIMAL(), nullable=False), + sa.Column("published", sa.Boolean(), nullable=False), + sa.Column( + "created_at", + sa.DateTime(timezone=True), + server_default=sa.text("TIMEZONE('utc', statement_timestamp())"), + nullable=False, + ), + sa.Column( + "updated_at", + sa.DateTime(timezone=True), + server_default=sa.text("TIMEZONE('utc', statement_timestamp())"), + nullable=False, + ), + sa.ForeignKeyConstraint( + ["leaderboard_id"], + ["leaderboards.id"], + name=op.f("fk_leaderboard_versions_leaderboard_id_leaderboards"), + ondelete="CASCADE", + ), + sa.PrimaryKeyConstraint( + "leaderboard_id", "version_number", name=op.f("pk_leaderboard_versions") + ), + sa.UniqueConstraint( + "leaderboard_id", + "version_number", + name=op.f("uq_leaderboard_versions_leaderboard_id"), + ), + ) + op.create_index( + op.f("ix_leaderboard_versions_created_at"), + "leaderboard_versions", + ["created_at"], + unique=False, + ) + op.add_column( + "leaderboard_scores", + sa.Column("leaderboard_version_number", sa.DECIMAL(), nullable=True), + ) + op.drop_constraint( + "fk_leaderboard_scores_leaderboard_id_leaderboards", + "leaderboard_scores", + type_="foreignkey", + ) + op.create_foreign_key( + op.f("fk_leaderboard_scores_leaderboard_id_leaderboard_versions"), + "leaderboard_scores", + "leaderboard_versions", + ["leaderboard_id", "leaderboard_version_number"], + ["leaderboard_id", "version_number"], + ondelete="CASCADE", + ) + # ### end Alembic commands ### + + # Insert version 0 for all existing leaderboards + op.execute( + """ + INSERT INTO leaderboard_versions (leaderboard_id, version_number, published) + SELECT id, 0, true FROM leaderboards + """ + ) + # Set the leaderboard_version_number for all existing scores to the version 0 + op.execute( + """ + UPDATE leaderboard_scores SET leaderboard_version_number = 0 + """ + ) + # Alter leaderboard_scores to make leaderboard_version_number non-nullable + op.alter_column( + "leaderboard_scores", + "leaderboard_version_number", + nullable=False, + ) + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_constraint( + op.f("fk_leaderboard_scores_leaderboard_id_leaderboard_versions"), + "leaderboard_scores", + type_="foreignkey", + ) + op.create_foreign_key( + "fk_leaderboard_scores_leaderboard_id_leaderboards", + "leaderboard_scores", + "leaderboards", + ["leaderboard_id"], + ["id"], + ondelete="CASCADE", + ) + op.drop_column("leaderboard_scores", "leaderboard_version_number") + op.drop_index( + op.f("ix_leaderboard_versions_created_at"), table_name="leaderboard_versions" + ) + op.drop_table("leaderboard_versions") + # ### end Alembic commands ### diff --git a/engineapi/engineapi/models.py b/engineapi/engineapi/models.py index 36cc975d..c60ee0de 100644 --- a/engineapi/engineapi/models.py +++ b/engineapi/engineapi/models.py @@ -13,6 +13,7 @@ from sqlalchemy import ( MetaData, String, UniqueConstraint, + ForeignKeyConstraint, ) from sqlalchemy.dialects.postgresql import JSONB, UUID from sqlalchemy.ext.compiler import compiles @@ -357,9 +358,45 @@ class Leaderboard(Base): # type: ignore ) +class LeaderboardVersion(Base): # type: ignore + __tablename__ = "leaderboard_versions" + __table_args__ = (UniqueConstraint("leaderboard_id", "version_number"),) + + leaderboard_id = Column( + UUID(as_uuid=True), + ForeignKey("leaderboards.id", ondelete="CASCADE"), + primary_key=True, + nullable=False, + ) + version_number = Column(DECIMAL, primary_key=True, nullable=False) + published = Column(Boolean, default=False, nullable=False) + created_at = Column( + DateTime(timezone=True), + server_default=utcnow(), + nullable=False, + index=True, + ) + updated_at = Column( + DateTime(timezone=True), + server_default=utcnow(), + onupdate=utcnow(), + nullable=False, + ) + + class LeaderboardScores(Base): # type: ignore __tablename__ = "leaderboard_scores" - __table_args__ = (UniqueConstraint("leaderboard_id", "address"),) + __table_args__ = ( + UniqueConstraint("leaderboard_id", "address"), + ForeignKeyConstraint( + ["leaderboard_id", "leaderboard_version_number"], + [ + "leaderboard_versions.leaderboard_id", + "leaderboard_versions.version_number", + ], + ondelete="CASCADE", + ), + ) id = Column( UUID(as_uuid=True), @@ -370,7 +407,10 @@ class LeaderboardScores(Base): # type: ignore ) leaderboard_id = Column( UUID(as_uuid=True), - ForeignKey("leaderboards.id", ondelete="CASCADE"), + nullable=False, + ) + leaderboard_version_number = Column( + DECIMAL, nullable=False, ) address = Column(VARCHAR(256), nullable=False, index=True)