This repository has been archived by the owner on Sep 6, 2024. It is now read-only.
generated from python-discord/code-jam-template
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #56 from ItsDrike/db-models
🗃️ Add basic models
- Loading branch information
Showing
5 changed files
with
236 additions
and
0 deletions.
There are no files selected for viewing
73 changes: 73 additions & 0 deletions
73
alembic-migrations/versions/2024_07_25_1814-8fc4b07d9adc_add_basic_models.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
"""Add basic models | ||
Revision ID: 8fc4b07d9adc | ||
Revises: c55da3c62644 | ||
Create Date: 2024-07-25 18:14:19.322905 | ||
""" | ||
|
||
from collections.abc import Sequence | ||
|
||
import sqlalchemy as sa | ||
from alembic import op | ||
|
||
# revision identifiers, used by Alembic. | ||
revision: str = "8fc4b07d9adc" | ||
down_revision: str | None = "c55da3c62644" | ||
branch_labels: str | Sequence[str] | None = None | ||
depends_on: str | Sequence[str] | None = None | ||
|
||
|
||
def upgrade() -> None: | ||
# ### commands auto generated by Alembic - please adjust! ### | ||
op.create_table("movies", sa.Column("tvdb_id", sa.Integer(), nullable=False), sa.PrimaryKeyConstraint("tvdb_id")) | ||
op.create_table("shows", sa.Column("tvdb_id", sa.Integer(), nullable=False), sa.PrimaryKeyConstraint("tvdb_id")) | ||
op.create_table( | ||
"users", sa.Column("discord_id", sa.Integer(), nullable=False), sa.PrimaryKeyConstraint("discord_id") | ||
) | ||
op.create_table( | ||
"episodes", | ||
sa.Column("tvdb_id", sa.Integer(), nullable=False), | ||
sa.Column("show_id", sa.Integer(), nullable=False), | ||
sa.ForeignKeyConstraint( | ||
["show_id"], | ||
["shows.tvdb_id"], | ||
), | ||
sa.PrimaryKeyConstraint("tvdb_id"), | ||
) | ||
op.create_table( | ||
"user_lists", | ||
sa.Column("id", sa.Integer(), autoincrement=True, nullable=False), | ||
sa.Column("user_id", sa.Integer(), nullable=False), | ||
sa.Column("name", sa.String(), nullable=False), | ||
sa.Column("item_kind", sa.Enum("SHOW", "MOVIE", "EPISODE", "MEDIA", "ANY", name="itemkind"), nullable=False), | ||
sa.ForeignKeyConstraint( | ||
["user_id"], | ||
["users.discord_id"], | ||
), | ||
sa.PrimaryKeyConstraint("id"), | ||
sa.UniqueConstraint("user_id", "name", name="unique_user_list_name"), | ||
) | ||
op.create_index("ix_user_lists_user_id_name", "user_lists", ["user_id", "name"], unique=True) | ||
op.create_table( | ||
"user_list_items", | ||
sa.Column("list_id", sa.Integer(), nullable=False), | ||
sa.Column("tvdb_id", sa.Integer(), nullable=False), | ||
sa.ForeignKeyConstraint( | ||
["list_id"], | ||
["user_lists.id"], | ||
), | ||
sa.PrimaryKeyConstraint("list_id", "tvdb_id"), | ||
) | ||
# ### end Alembic commands ### | ||
|
||
|
||
def downgrade() -> None: | ||
# ### commands auto generated by Alembic - please adjust! ### | ||
op.drop_table("user_list_items") | ||
op.drop_index("ix_user_lists_user_id_name", table_name="user_lists") | ||
op.drop_table("user_lists") | ||
op.drop_table("episodes") | ||
op.drop_table("users") | ||
op.drop_table("shows") | ||
op.drop_table("movies") | ||
# ### end Alembic commands ### |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
"""This file houses all tvdb media related database tables. | ||
Some of these tables only have one column (`tvdb_id`), which may seem like a mistake, but is intentional. | ||
That's because this provides better type safety and allows us to define proper foreign key relationships that | ||
refer to these tables instead of duplicating that data. | ||
It also may become useful if at any point we would | ||
want to store something extra that's global to each movie / show / episode. | ||
""" | ||
|
||
from sqlalchemy import ForeignKey | ||
from sqlalchemy.orm import Mapped, mapped_column | ||
|
||
from src.utils.database import Base | ||
|
||
|
||
class Movie(Base): | ||
"""Table to store movies.""" | ||
|
||
__tablename__ = "movies" | ||
|
||
tvdb_id: Mapped[int] = mapped_column(primary_key=True) | ||
|
||
|
||
class Series(Base): | ||
"""Table to store series.""" | ||
|
||
__tablename__ = "series" | ||
|
||
tvdb_id: Mapped[int] = mapped_column(primary_key=True) | ||
|
||
|
||
class Episode(Base): | ||
"""Table to store episodes of series.""" | ||
|
||
__tablename__ = "episodes" | ||
|
||
tvdb_id: Mapped[int] = mapped_column(primary_key=True) | ||
series_id: Mapped[int] = mapped_column(ForeignKey("series.tvdb_id")) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
from typing import TYPE_CHECKING | ||
|
||
from sqlalchemy.orm import Mapped, mapped_column, relationship | ||
|
||
from src.utils.database import Base | ||
|
||
# Prevent circular imports for relationships | ||
if TYPE_CHECKING: | ||
from src.db_tables.user_list import UserList | ||
|
||
|
||
class User(Base): | ||
"""Table to store users.""" | ||
|
||
__tablename__ = "users" | ||
|
||
discord_id: Mapped[int] = mapped_column(primary_key=True) | ||
|
||
lists: Mapped[list["UserList"]] = relationship("UserList", back_populates="user") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
from enum import Enum | ||
from typing import ClassVar, TYPE_CHECKING | ||
|
||
from sqlalchemy import ForeignKey, Index, UniqueConstraint | ||
from sqlalchemy.orm import Mapped, mapped_column, relationship | ||
|
||
from src.utils.database import Base | ||
|
||
# Prevent circular imports for relationships | ||
if TYPE_CHECKING: | ||
from src.db_tables.media import Episode, Movie, Series | ||
from src.db_tables.user import User | ||
|
||
|
||
class ItemKind(Enum): | ||
"""Enum to represent the kind of item in a user list.""" | ||
|
||
SERIES = "series" | ||
MOVIE = "movie" | ||
EPISODE = "episode" | ||
MEDIA = "media" # either series or movie | ||
ANY = "any" | ||
|
||
|
||
class UserList(Base): | ||
"""Table to store user lists. | ||
This provides a dynamic way to store various lists of media for the user, such as favorites, to watch, | ||
already watched, ... all tracked in the same table, instead of having to define tables for each such | ||
structure. | ||
""" | ||
|
||
__tablename__ = "user_lists" | ||
|
||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) | ||
user_id: Mapped[int] = mapped_column(ForeignKey("users.discord_id"), nullable=False) | ||
name: Mapped[str] = mapped_column(nullable=False) | ||
item_kind: Mapped[ItemKind] = mapped_column(nullable=False) | ||
|
||
user: Mapped["User"] = relationship("User", back_populates="lists") | ||
items: Mapped[list["UserListItem"]] = relationship("UserListItem", back_populates="user_list") | ||
|
||
__table_args__ = ( | ||
UniqueConstraint("user_id", "name", name="unique_user_list_name"), | ||
Index( | ||
"ix_user_lists_user_id_name", | ||
"user_id", | ||
"name", | ||
unique=True, | ||
), | ||
) | ||
|
||
|
||
class UserListItem(Base): | ||
"""Base class for items in a user list.""" | ||
|
||
__tablename__ = "user_list_items" | ||
list_id: Mapped[int] = mapped_column(ForeignKey("user_lists.id"), primary_key=True) | ||
tvdb_id: Mapped[int] = mapped_column(primary_key=True) | ||
|
||
user_list: Mapped["UserList"] = relationship("UserList", back_populates="items") | ||
|
||
__mapper_args__: ClassVar = {"polymorphic_on": tvdb_id, "polymorphic_identity": "base"} | ||
|
||
|
||
class UserListItemSeries(UserListItem): | ||
"""Represents a reference to a series in a user list.""" | ||
|
||
__mapper_args__: ClassVar = { | ||
"polymorphic_identity": "series", | ||
} | ||
|
||
tvdb_id: Mapped[int] = mapped_column( | ||
ForeignKey("series.tvdb_id"), nullable=False, use_existing_column=True, primary_key=True | ||
) | ||
series: Mapped["Series"] = relationship("Series") | ||
|
||
|
||
class UserListItemMovie(UserListItem): | ||
"""Represents a reference to a movie in a user list.""" | ||
|
||
__mapper_args__: ClassVar = { | ||
"polymorphic_identity": "movie", | ||
} | ||
|
||
tvdb_id: Mapped[int] = mapped_column( | ||
ForeignKey("movies.tvdb_id"), nullable=False, use_existing_column=True, primary_key=True | ||
) | ||
movie: Mapped["Movie"] = relationship("Movie") | ||
|
||
|
||
class UserListItemEpisode(UserListItem): | ||
"""Represents a reference to an episode in a user list.""" | ||
|
||
__mapper_args__: ClassVar = { | ||
"polymorphic_identity": "episode", | ||
} | ||
|
||
tvdb_id: Mapped[int] = mapped_column( | ||
ForeignKey("episodes.tvdb_id"), nullable=False, use_existing_column=True, primary_key=True | ||
) | ||
episode: Mapped["Episode"] = relationship("Episode") |