Use surrogate keys for PlayerTeam models
parent
061499b822
commit
ba2b568259
|
@ -0,0 +1,34 @@
|
|||
"""Add availability index
|
||||
|
||||
Revision ID: 47f0722b02b0
|
||||
Revises: 7361c978e53d
|
||||
Create Date: 2024-11-21 13:10:45.098947
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '47f0722b02b0'
|
||||
down_revision = '7361c978e53d'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('players_teams_availability', schema=None) as batch_op:
|
||||
batch_op.create_index(batch_op.f('ix_players_teams_availability_end_time'), ['end_time'], unique=False)
|
||||
batch_op.create_index(batch_op.f('ix_players_teams_availability_start_time'), ['start_time'], unique=False)
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('players_teams_availability', schema=None) as batch_op:
|
||||
batch_op.drop_index(batch_op.f('ix_players_teams_availability_start_time'))
|
||||
batch_op.drop_index(batch_op.f('ix_players_teams_availability_end_time'))
|
||||
|
||||
# ### end Alembic commands ###
|
|
@ -0,0 +1,64 @@
|
|||
"""Add surrogate key to player_team and others
|
||||
|
||||
Revision ID: 6296c347731b
|
||||
Revises: 5debac4cdf37
|
||||
Create Date: 2024-11-21 10:30:09.333087
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '6296c347731b'
|
||||
down_revision = '5debac4cdf37'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('players_teams', schema=None) as batch_op:
|
||||
batch_op.add_column(sa.Column('player_team_id', sa.Integer(), autoincrement=True, nullable=False))
|
||||
|
||||
with op.batch_alter_table('players_teams_availability', schema=None) as batch_op:
|
||||
batch_op.add_column(sa.Column('player_team_id', sa.Integer(), nullable=False))
|
||||
batch_op.drop_constraint(None, type_='foreignkey')
|
||||
batch_op.create_foreign_key(None, 'players_teams', ['player_team_id'], ['player_team_id'])
|
||||
batch_op.drop_column('team_id')
|
||||
batch_op.drop_column('player_id')
|
||||
|
||||
with op.batch_alter_table('players_teams_roles', schema=None) as batch_op:
|
||||
batch_op.add_column(sa.Column('player_team_role_id', sa.Integer(), autoincrement=True, nullable=False))
|
||||
batch_op.add_column(sa.Column('player_team_id', sa.Integer(), nullable=False))
|
||||
batch_op.create_unique_constraint(None, ['player_team_id', 'role'])
|
||||
batch_op.drop_constraint(None, type_='foreignkey')
|
||||
batch_op.create_foreign_key(None, 'players_teams', ['player_team_id'], ['player_team_id'])
|
||||
batch_op.drop_column('team_id')
|
||||
batch_op.drop_column('player_id')
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('players_teams_roles', schema=None) as batch_op:
|
||||
batch_op.add_column(sa.Column('player_id', sa.INTEGER(), nullable=False))
|
||||
batch_op.add_column(sa.Column('team_id', sa.INTEGER(), nullable=False))
|
||||
batch_op.drop_constraint(None, type_='foreignkey')
|
||||
batch_op.create_foreign_key(None, 'players_teams', ['player_id', 'team_id'], ['player_id', 'team_id'])
|
||||
batch_op.drop_constraint(None, type_='unique')
|
||||
batch_op.drop_column('player_team_id')
|
||||
batch_op.drop_column('player_team_role_id')
|
||||
|
||||
with op.batch_alter_table('players_teams_availability', schema=None) as batch_op:
|
||||
batch_op.add_column(sa.Column('player_id', sa.INTEGER(), nullable=False))
|
||||
batch_op.add_column(sa.Column('team_id', sa.INTEGER(), nullable=False))
|
||||
batch_op.drop_constraint(None, type_='foreignkey')
|
||||
batch_op.create_foreign_key(None, 'players_teams', ['player_id', 'team_id'], ['player_id', 'team_id'])
|
||||
batch_op.drop_column('player_team_id')
|
||||
|
||||
with op.batch_alter_table('players_teams', schema=None) as batch_op:
|
||||
batch_op.drop_column('player_team_id')
|
||||
|
||||
# ### end Alembic commands ###
|
|
@ -0,0 +1,50 @@
|
|||
"""Change player_team surrogate key name
|
||||
|
||||
Revision ID: 6e9d70f835d7
|
||||
Revises: 6296c347731b
|
||||
Create Date: 2024-11-21 12:13:44.989797
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '6e9d70f835d7'
|
||||
down_revision = '6296c347731b'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('players_teams', schema=None) as batch_op:
|
||||
batch_op.add_column(sa.Column('id', sa.Integer(), autoincrement=True, nullable=False))
|
||||
batch_op.drop_column('player_team_id')
|
||||
|
||||
with op.batch_alter_table('players_teams_availability', schema=None) as batch_op:
|
||||
batch_op.drop_constraint(None, type_='foreignkey')
|
||||
batch_op.create_foreign_key(None, 'players_teams', ['player_team_id'], ['id'])
|
||||
|
||||
with op.batch_alter_table('players_teams_roles', schema=None) as batch_op:
|
||||
batch_op.drop_constraint(None, type_='foreignkey')
|
||||
batch_op.create_foreign_key(None, 'players_teams', ['player_team_id'], ['id'])
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('players_teams_roles', schema=None) as batch_op:
|
||||
batch_op.drop_constraint(None, type_='foreignkey')
|
||||
batch_op.create_foreign_key(None, 'players_teams', ['player_team_id'], ['player_team_id'])
|
||||
|
||||
with op.batch_alter_table('players_teams_availability', schema=None) as batch_op:
|
||||
batch_op.drop_constraint(None, type_='foreignkey')
|
||||
batch_op.create_foreign_key(None, 'players_teams', ['player_team_id'], ['player_team_id'])
|
||||
|
||||
with op.batch_alter_table('players_teams', schema=None) as batch_op:
|
||||
batch_op.add_column(sa.Column('player_team_id', sa.INTEGER(), nullable=False))
|
||||
batch_op.drop_column('id')
|
||||
|
||||
# ### end Alembic commands ###
|
|
@ -0,0 +1,40 @@
|
|||
"""Fix integrity
|
||||
|
||||
Revision ID: 7361c978e53d
|
||||
Revises: 6e9d70f835d7
|
||||
Create Date: 2024-11-21 12:43:01.786598
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
import app_db
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '7361c978e53d'
|
||||
down_revision = '6e9d70f835d7'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('players_teams_availability', schema=None, naming_convention=app_db.convention) as batch_op:
|
||||
batch_op.create_foreign_key(batch_op.f("fk_players_teams_availability_player_team_id_players_teams"), 'players_teams', ['player_team_id'], ['id'])
|
||||
|
||||
with op.batch_alter_table('players_teams_roles', schema=None) as batch_op:
|
||||
batch_op.create_foreign_key(batch_op.f("fk_players_teams_roles_player_team_id_players_teams"), 'players_teams', ['player_team_id'], ['id'])
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('players_teams_roles', schema=None, naming_convention=app_db.convention) as batch_op:
|
||||
batch_op.drop_constraint(None, type_='foreignkey')
|
||||
|
||||
with op.batch_alter_table('players_teams_availability', schema=None) as batch_op:
|
||||
batch_op.drop_constraint(None, type_='foreignkey')
|
||||
|
||||
# ### end Alembic commands ###
|
|
@ -4,7 +4,7 @@ from sqlalchemy.orm import mapped_column, relationship
|
|||
from sqlalchemy.orm.attributes import Mapped
|
||||
from sqlalchemy.orm.properties import ForeignKey
|
||||
from sqlalchemy.sql import func
|
||||
from sqlalchemy.types import TIMESTAMP, Boolean, Enum, Interval
|
||||
from sqlalchemy.types import TIMESTAMP, Boolean, Enum, Integer, Interval
|
||||
import app_db
|
||||
import spec
|
||||
|
||||
|
@ -16,8 +16,16 @@ class PlayerTeam(app_db.BaseModel):
|
|||
Player = 0
|
||||
CoachMentor = 1
|
||||
|
||||
player_id: Mapped[int] = mapped_column(ForeignKey("players.steam_id"), primary_key=True)
|
||||
team_id: Mapped[int] = mapped_column(ForeignKey("teams.id"), primary_key=True)
|
||||
# surrogate key
|
||||
id: Mapped[int] = mapped_column(
|
||||
Integer,
|
||||
autoincrement=True,
|
||||
primary_key=True,
|
||||
)
|
||||
|
||||
# primary key
|
||||
player_id: Mapped[int] = mapped_column(ForeignKey("players.steam_id"))
|
||||
team_id: Mapped[int] = mapped_column(ForeignKey("teams.id"))
|
||||
|
||||
player: Mapped["Player"] = relationship(back_populates="teams")
|
||||
team: Mapped["Team"] = relationship(back_populates="players")
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
from datetime import datetime, timedelta
|
||||
|
||||
from sqlalchemy.orm.properties import ForeignKey
|
||||
|
||||
import spec
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from sqlalchemy.schema import ForeignKeyConstraint
|
||||
from sqlalchemy.types import Integer
|
||||
from sqlalchemy.types import BigInteger, Integer
|
||||
from sqlalchemy_utc import UtcDateTime
|
||||
import app_db
|
||||
|
||||
|
@ -10,25 +13,16 @@ import app_db
|
|||
class PlayerTeamAvailability(app_db.BaseModel):
|
||||
__tablename__ = "players_teams_availability"
|
||||
|
||||
player_id: Mapped[int] = mapped_column(primary_key=True)
|
||||
team_id: Mapped[int] = mapped_column(primary_key=True)
|
||||
start_time: Mapped[datetime] = mapped_column(UtcDateTime, primary_key=True)
|
||||
player_team_id = mapped_column(ForeignKey("players_teams.id"), primary_key=True)
|
||||
start_time: Mapped[datetime] = mapped_column(UtcDateTime, primary_key=True, index=True)
|
||||
|
||||
player_team: Mapped["PlayerTeam"] = relationship(
|
||||
"PlayerTeam", back_populates="availability")
|
||||
"PlayerTeam",
|
||||
back_populates="availability",
|
||||
)
|
||||
|
||||
availability: Mapped[int] = mapped_column(Integer, default=2)
|
||||
end_time: Mapped[datetime] = mapped_column(UtcDateTime)
|
||||
|
||||
|
||||
from models.player_team import PlayerTeam
|
||||
|
||||
__table_args__ = (
|
||||
ForeignKeyConstraint(
|
||||
[player_id, team_id],
|
||||
[PlayerTeam.player_id, PlayerTeam.team_id]
|
||||
),
|
||||
)
|
||||
end_time: Mapped[datetime] = mapped_column(UtcDateTime, index=True)
|
||||
|
||||
class AvailabilitySchema(spec.BaseModel):
|
||||
steam_id: str
|
||||
|
@ -48,7 +42,7 @@ class AvailabilitySchema(spec.BaseModel):
|
|||
|
||||
i = max(0, relative_start_hour)
|
||||
while i < window_size_hours and i < relative_end_hour:
|
||||
print(i, "=", region.availability)
|
||||
#print(i, "=", region.availability)
|
||||
self.availability[i] = region.availability
|
||||
i += 1
|
||||
|
||||
|
@ -60,3 +54,6 @@ class PlayerTeamAvailabilityRoleSchema(spec.BaseModel):
|
|||
playtime: int
|
||||
availability: int
|
||||
roles: list[RoleSchema]
|
||||
|
||||
|
||||
from models.player_team import PlayerTeam
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import enum
|
||||
|
||||
from sqlalchemy.orm.properties import ForeignKey
|
||||
|
||||
import spec
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
from sqlalchemy.schema import ForeignKeyConstraint
|
||||
from sqlalchemy.types import Boolean, Enum
|
||||
from sqlalchemy.schema import ForeignKeyConstraint, UniqueConstraint
|
||||
from sqlalchemy.types import BigInteger, Boolean, Enum, Integer
|
||||
import app_db
|
||||
|
||||
|
||||
|
@ -29,25 +31,29 @@ class PlayerTeamRole(app_db.BaseModel):
|
|||
Sniper = 12
|
||||
Spy = 13
|
||||
|
||||
player_id: Mapped[int] = mapped_column(primary_key=True)
|
||||
team_id: Mapped[int] = mapped_column(primary_key=True)
|
||||
# surrogate key
|
||||
player_team_role_id: Mapped[int] = mapped_column(
|
||||
Integer,
|
||||
autoincrement=True,
|
||||
primary_key=True,
|
||||
)
|
||||
|
||||
player_team: Mapped["PlayerTeam"] = relationship("PlayerTeam", back_populates="player_roles")
|
||||
# primary key
|
||||
player_team_id = mapped_column(ForeignKey("players_teams.id"), nullable=False)
|
||||
role: Mapped[Role] = mapped_column(Enum(Role), nullable=False)
|
||||
|
||||
#player: Mapped["Player"] = relationship(back_populates="teams")
|
||||
player_team: Mapped["PlayerTeam"] = relationship(
|
||||
"PlayerTeam",
|
||||
back_populates="player_roles"
|
||||
)
|
||||
|
||||
role: Mapped[Role] = mapped_column(Enum(Role), primary_key=True)
|
||||
is_main: Mapped[bool] = mapped_column(Boolean)
|
||||
|
||||
from models.player_team import PlayerTeam
|
||||
|
||||
__table_args__ = (
|
||||
ForeignKeyConstraint(
|
||||
[player_id, team_id],
|
||||
[PlayerTeam.player_id, PlayerTeam.team_id]
|
||||
),
|
||||
UniqueConstraint("player_team_id", "role"),
|
||||
)
|
||||
|
||||
|
||||
class RoleSchema(spec.BaseModel):
|
||||
role: str
|
||||
is_main: bool
|
||||
|
@ -55,3 +61,6 @@ class RoleSchema(spec.BaseModel):
|
|||
@classmethod
|
||||
def from_model(cls, role: PlayerTeamRole):
|
||||
return cls(role=role.role.name, is_main=role.is_main)
|
||||
|
||||
|
||||
from models.player_team import PlayerTeam
|
||||
|
|
|
@ -2,14 +2,14 @@ import datetime
|
|||
from typing import cast
|
||||
from flask import Blueprint, abort, jsonify, make_response, request
|
||||
from spectree import Response
|
||||
from sqlalchemy.orm import joinedload
|
||||
from sqlalchemy.sql import and_
|
||||
from sqlalchemy.orm import contains_eager, joinedload
|
||||
from sqlalchemy.sql import and_, select
|
||||
from app_db import db
|
||||
from models.player import Player, PlayerSchema
|
||||
from models.player_team import PlayerTeam
|
||||
from models.player_team_availability import AvailabilitySchema, PlayerTeamAvailability, PlayerTeamAvailabilityRoleSchema
|
||||
from models.player_team_role import PlayerTeamRole, RoleSchema
|
||||
from middleware import requires_authentication
|
||||
from middleware import requires_authentication, requires_team_membership
|
||||
from spec import spec, BaseModel
|
||||
|
||||
|
||||
|
@ -30,16 +30,15 @@ class ViewScheduleResponse(BaseModel):
|
|||
)
|
||||
)
|
||||
@requires_authentication
|
||||
def get(query: ViewScheduleForm, player: Player, **kwargs):
|
||||
@requires_team_membership(query_param="team_id")
|
||||
def get(query: ViewScheduleForm, player_team: PlayerTeam, **kwargs):
|
||||
window_start = query.window_start
|
||||
window_end = window_start + datetime.timedelta(days=query.window_size_days)
|
||||
|
||||
availability_regions = db.session.query(
|
||||
PlayerTeamAvailability
|
||||
).where(
|
||||
PlayerTeamAvailability.player_id == player.steam_id
|
||||
).where(
|
||||
PlayerTeamAvailability.team_id == query.team_id
|
||||
PlayerTeamAvailability.player_team_id == player_team.id
|
||||
).where(
|
||||
PlayerTeamAvailability.start_time.between(window_start, window_end) |
|
||||
PlayerTeamAvailability.end_time.between(window_start, window_end) |
|
||||
|
@ -101,7 +100,8 @@ def find_consecutive_blocks(arr: list[int]) -> list[tuple[int, int, int]]:
|
|||
@api_schedule.put("/")
|
||||
@spec.validate()
|
||||
@requires_authentication
|
||||
def put(json: PutScheduleForm, player: Player, **kwargs):
|
||||
@requires_team_membership(json_param="team_id")
|
||||
def put(player_team: PlayerTeam, json: PutScheduleForm, player: Player, **kwargs):
|
||||
window_start = json.window_start
|
||||
window_end = window_start + datetime.timedelta(days=json.window_size_days)
|
||||
|
||||
|
@ -114,9 +114,7 @@ def put(json: PutScheduleForm, player: Player, **kwargs):
|
|||
cur_availability = db.session.query(
|
||||
PlayerTeamAvailability
|
||||
).where(
|
||||
PlayerTeamAvailability.player_id == player.steam_id
|
||||
).where(
|
||||
PlayerTeamAvailability.team_id == json.team_id
|
||||
PlayerTeamAvailability.player_team == player_team
|
||||
).where(
|
||||
PlayerTeamAvailability.start_time.between(window_start, window_end) |
|
||||
PlayerTeamAvailability.end_time.between(window_start, window_end)
|
||||
|
@ -167,8 +165,7 @@ def put(json: PutScheduleForm, player: Player, **kwargs):
|
|||
new_availability.availability = availability_value
|
||||
new_availability.start_time = abs_start
|
||||
new_availability.end_time = abs_end
|
||||
new_availability.player_id = player.steam_id
|
||||
new_availability.team_id = json.team_id
|
||||
new_availability.player_team = player_team
|
||||
|
||||
availability_blocks.append(new_availability)
|
||||
|
||||
|
@ -206,6 +203,7 @@ def get_team_availability(query: ViewScheduleForm, player: Player, **kwargs):
|
|||
).outerjoin(
|
||||
PlayerTeamAvailability,
|
||||
and_(
|
||||
PlayerTeamAvailability.player_team_id == PlayerTeam.id,
|
||||
PlayerTeamAvailability.start_time.between(window_start, window_end) |
|
||||
PlayerTeamAvailability.end_time.between(window_start, window_end) |
|
||||
|
||||
|
@ -218,6 +216,12 @@ def get_team_availability(query: ViewScheduleForm, player: Player, **kwargs):
|
|||
Player
|
||||
).where(
|
||||
PlayerTeam.team_id == query.team_id
|
||||
).options(
|
||||
# only populate PlayerTeam.availability with the availability regions
|
||||
# that are within the window
|
||||
contains_eager(PlayerTeam.availability),
|
||||
joinedload(PlayerTeam.player),
|
||||
).populate_existing(
|
||||
).all()
|
||||
|
||||
ret: dict[str, AvailabilitySchema] = { }
|
||||
|
@ -264,7 +268,7 @@ def view_available_at_time(query: ViewAvailablePlayersQuery, player: Player, **k
|
|||
).join(
|
||||
PlayerTeamRole
|
||||
).where(
|
||||
PlayerTeamAvailability.team_id == query.team_id
|
||||
PlayerTeam.team_id == query.team_id
|
||||
).where(
|
||||
(PlayerTeamAvailability.start_time <= start_time) &
|
||||
(PlayerTeamAvailability.end_time > start_time)
|
||||
|
|
Loading…
Reference in New Issue