Skip to content

Commit 488f915

Browse files
committed
Add new database models
1 parent 2392a85 commit 488f915

File tree

8 files changed

+155
-96
lines changed

8 files changed

+155
-96
lines changed

api/database.py

-96
This file was deleted.

api/models/orm/__init__.py

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
"""Database models."""
2+
3+
from .infraction import Infraction # noqa: F401
4+
from .jam import Jam # noqa: F401
5+
from .team import Team # noqa: F401
6+
from .team_has_users import team_has_users_table # noqa: F401
7+
from .user import JamSpecificDetail, User # noqa: F401

api/models/orm/base.py

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
"""The base classes for ORM models."""
2+
3+
from pydantic import BaseModel
4+
from sqlalchemy.orm import DeclarativeBase
5+
from sqlalchemy.schema import MetaData
6+
7+
# See https://docs.sqlalchemy.org/en/14/core/constraints.html#constraint-naming-conventions
8+
NAMING_CONVENTIONS = {
9+
"ix": "%(column_0_label)s_ix",
10+
"uq": "%(table_name)s_%(column_0_name)s_uq",
11+
"ck": "%(table_name)s_%(constraint_name)s_ck",
12+
"fk": "%(table_name)s_%(column_0_name)s_%(referred_table_name)s_fk",
13+
"pk": "%(table_name)s_pk",
14+
}
15+
16+
17+
class Base(DeclarativeBase):
18+
"""Classes that inherit this class will be automatically mapped using declarative mapping."""
19+
20+
metadata = MetaData(naming_convention=NAMING_CONVENTIONS)
21+
22+
def patch_from_pydantic(self, pydantic_model: BaseModel) -> None:
23+
"""Patch this model using the given pydantic model, unspecified attributes remain the same."""
24+
for key, value in pydantic_model.dict(exclude_unset=True).items():
25+
setattr(self, key, value)

api/models/orm/infraction.py

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from typing import Literal
2+
3+
from sqlalchemy import Enum, ForeignKey, String
4+
from sqlalchemy.orm import Mapped, mapped_column
5+
6+
from api.models.orm import Jam, User
7+
from api.models.orm.base import Base
8+
9+
InfractionType = Literal["note", "ban", "warning"]
10+
11+
12+
class Infraction(Base):
13+
"""An infraction that was applied to a user."""
14+
15+
__tablename__ = "infractions"
16+
17+
infraction_id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
18+
user_id: Mapped[int] = mapped_column(ForeignKey(User.user_id))
19+
issued_in_jam_id: Mapped[int] = mapped_column(ForeignKey(Jam.jam_id))
20+
infraction_type: Mapped[InfractionType] = mapped_column(
21+
Enum(*InfractionType.__args__, name="infraction_type_enum"),
22+
nullable=False,
23+
)
24+
reason: Mapped[str] = mapped_column(String(), nullable=False)

api/models/orm/jam.py

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from sqlalchemy import Boolean, String
2+
from sqlalchemy.orm import Mapped, mapped_column, relationship
3+
4+
from api.models.orm import Team
5+
from api.models.orm.base import Base
6+
7+
8+
class Jam(Base):
9+
"""A code jam."""
10+
11+
__tablename__ = "jams"
12+
13+
jam_id: Mapped[int] = mapped_column(primary_key=True)
14+
name: Mapped[str] = mapped_column(String(), nullable=False)
15+
ongoing: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
16+
17+
teams: Mapped[list[Team]] = relationship()

api/models/orm/team.py

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from sqlalchemy import BigInteger, Boolean, ForeignKey, Index, String, text
2+
from sqlalchemy.orm import Mapped, mapped_column, relationship
3+
4+
from api.models.orm import Jam, User, team_has_users_table
5+
from api.models.orm.base import Base
6+
7+
8+
class Team(Base):
9+
"""A team participating in a code jam."""
10+
11+
__tablename__ = "teams"
12+
13+
team_id: Mapped[int] = mapped_column(primary_key=True)
14+
jam_id: Mapped[int] = mapped_column(ForeignKey(Jam.jam_id))
15+
leader_id: Mapped[int] = mapped_column(ForeignKey(User.user_id))
16+
name: Mapped[str] = mapped_column(String(), nullable=False)
17+
discord_role_id: Mapped[int] = mapped_column(BigInteger)
18+
discord_channel_id: Mapped[int] = mapped_column(BigInteger)
19+
20+
winner: Mapped[bool] = mapped_column(Boolean, nullable=True)
21+
first_place_winner: Mapped[bool] = mapped_column(Boolean, nullable=True)
22+
23+
users: Mapped[list[User]] = relationship(
24+
secondary=team_has_users_table,
25+
back_populates="teams",
26+
)
27+
__table_args__ = Index("team_name_jam_unique", text("lower(name)"), "jam_id", unique=True)

api/models/orm/team_has_users.py

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from sqlalchemy import Column, ForeignKey, Table
2+
3+
from api.models.orm.base import Base
4+
5+
team_has_users_table = Table(
6+
"team_has_users",
7+
Base.metadata,
8+
Column("team_id", ForeignKey("teams.id"), primary_key=True),
9+
Column("user_id", ForeignKey("users.id"), primary_key=True),
10+
)

api/models/orm/user.py

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from typing import Literal
2+
3+
from sqlalchemy import BigInteger, Boolean, Enum, ForeignKey, String
4+
from sqlalchemy.orm import Mapped, mapped_column, relationship
5+
6+
from api.models.orm import Jam, Team, team_has_users_table
7+
from api.models.orm.base import Base
8+
9+
ExperienceLevels = Literal["beginner", "decent", "expierienced", "very_expierienced"]
10+
11+
12+
class User(Base):
13+
"""A user who has participated in a code jam."""
14+
15+
__tablename__ = "users"
16+
17+
user_id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=False)
18+
19+
teams: Mapped[list[Team]] = relationship(
20+
secondary=team_has_users_table,
21+
back_populates="users",
22+
)
23+
jam_specific_details: Mapped[list["JamSpecificDetail"]] = relationship()
24+
25+
26+
class JamSpecificDetail(Base):
27+
"""Jam specific details that a user fills for each code jam."""
28+
29+
__tablename__ = "jam_specific_details"
30+
31+
jam_specific_detail_id: Mapped[int] = mapped_column(primary_key=True)
32+
user_id: Mapped[int] = mapped_column(ForeignKey(User.id))
33+
jam_id: Mapped[int] = mapped_column(ForeignKey(Jam.jam_id))
34+
experience_level_git: Mapped[ExperienceLevels] = mapped_column(
35+
Enum(*ExperienceLevels.__args__, name="experience_level_git_enum"),
36+
nullable=False,
37+
)
38+
experience_level_python: Mapped[ExperienceLevels] = mapped_column(
39+
Enum(*ExperienceLevels.__args__, name="experience_level_python_enum"),
40+
nullable=False,
41+
)
42+
time_zone: Mapped[str] = mapped_column(String())
43+
willing_to_lead: Mapped[bool] = mapped_column(Boolean)
44+
45+
user: Mapped[User] = relationship(back_populates="jam_specific_details")

0 commit comments

Comments
 (0)