From d7cc46253bfb669281c894423278e6f3fe778afc Mon Sep 17 00:00:00 2001 From: Richie Cahill Date: Wed, 3 Jun 2026 20:27:03 -0400 Subject: [PATCH] adding audiobook data to DB --- ...udiobook_libreary_metadata_d7864d1ffc17.py | 93 +++++++++++++++++++ python/orm/richie/__init__.py | 4 + python/orm/richie/audiobook.py | 46 +++++++++ 3 files changed, 143 insertions(+) create mode 100644 python/alembic/richie/versions/2026_06_03-adding_audiobook_libreary_metadata_d7864d1ffc17.py create mode 100644 python/orm/richie/audiobook.py diff --git a/python/alembic/richie/versions/2026_06_03-adding_audiobook_libreary_metadata_d7864d1ffc17.py b/python/alembic/richie/versions/2026_06_03-adding_audiobook_libreary_metadata_d7864d1ffc17.py new file mode 100644 index 0000000..24bf858 --- /dev/null +++ b/python/alembic/richie/versions/2026_06_03-adding_audiobook_libreary_metadata_d7864d1ffc17.py @@ -0,0 +1,93 @@ +"""adding audiobook libreary metadata. + +Revision ID: d7864d1ffc17 +Revises: c8a794340928 +Create Date: 2026-06-03 20:24:09.200837 + +""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import sqlalchemy as sa +from alembic import op + +from python.orm import RichieBase + +if TYPE_CHECKING: + from collections.abc import Sequence + +# revision identifiers, used by Alembic. +revision: str = "d7864d1ffc17" +down_revision: str | None = "c8a794340928" +branch_labels: str | Sequence[str] | None = None +depends_on: str | Sequence[str] | None = None + +schema = RichieBase.schema_name + + +def upgrade() -> None: + """Upgrade.""" + # ### commands auto generated by Alembic - please adjust! ### + op.create_table( + "audiobook_author", + sa.Column("name", sa.String(), nullable=False), + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("created", sa.DateTime(timezone=True), server_default=sa.text("now()"), nullable=False), + sa.Column("updated", sa.DateTime(timezone=True), server_default=sa.text("now()"), nullable=False), + sa.PrimaryKeyConstraint("id", name=op.f("pk_audiobook_author")), + sa.UniqueConstraint("name", name=op.f("uq_audiobook_author_name")), + schema=schema, + ) + op.create_table( + "audiobook_series", + sa.Column("name", sa.String(), nullable=False), + sa.Column("author_id", sa.Integer(), nullable=False), + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("created", sa.DateTime(timezone=True), server_default=sa.text("now()"), nullable=False), + sa.Column("updated", sa.DateTime(timezone=True), server_default=sa.text("now()"), nullable=False), + sa.ForeignKeyConstraint( + ["author_id"], + [f"{schema}.audiobook_author.id"], + name=op.f("fk_audiobook_series_author_id_audiobook_author"), + ondelete="CASCADE", + ), + sa.PrimaryKeyConstraint("id", name=op.f("pk_audiobook_series")), + sa.UniqueConstraint("author_id", "name", name=op.f("uq_audiobook_series_author_id")), + schema=schema, + ) + op.create_table( + "audiobook", + sa.Column("title", sa.String(), nullable=False), + sa.Column("author_id", sa.Integer(), nullable=False), + sa.Column("series_id", sa.Integer(), nullable=True), + sa.Column("series_index", sa.Integer(), nullable=False), + sa.Column("id", sa.Integer(), nullable=False), + sa.Column("created", sa.DateTime(timezone=True), server_default=sa.text("now()"), nullable=False), + sa.Column("updated", sa.DateTime(timezone=True), server_default=sa.text("now()"), nullable=False), + sa.ForeignKeyConstraint( + ["author_id"], + [f"{schema}.audiobook_author.id"], + name=op.f("fk_audiobook_author_id_audiobook_author"), + ondelete="CASCADE", + ), + sa.ForeignKeyConstraint( + ["series_id"], + [f"{schema}.audiobook_series.id"], + name=op.f("fk_audiobook_series_id_audiobook_series"), + ondelete="SET NULL", + ), + sa.PrimaryKeyConstraint("id", name=op.f("pk_audiobook")), + schema=schema, + ) + # ### end Alembic commands ### + + +def downgrade() -> None: + """Downgrade.""" + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table("audiobook", schema=schema) + op.drop_table("audiobook_series", schema=schema) + op.drop_table("audiobook_author", schema=schema) + # ### end Alembic commands ### diff --git a/python/orm/richie/__init__.py b/python/orm/richie/__init__.py index ea7569f..47f601f 100644 --- a/python/orm/richie/__init__.py +++ b/python/orm/richie/__init__.py @@ -2,6 +2,7 @@ from __future__ import annotations +from python.orm.richie.audiobook import Audiobook, AudiobookAuthor, AudiobookSeries from python.orm.richie.base import RichieBase, TableBase, TableBaseBig, TableBaseSmall from python.orm.richie.contact import ( Contact, @@ -12,6 +13,9 @@ from python.orm.richie.contact import ( ) __all__ = [ + "Audiobook", + "AudiobookAuthor", + "AudiobookSeries", "Contact", "ContactNeed", "ContactRelationship", diff --git a/python/orm/richie/audiobook.py b/python/orm/richie/audiobook.py new file mode 100644 index 0000000..8ab78ea --- /dev/null +++ b/python/orm/richie/audiobook.py @@ -0,0 +1,46 @@ +"""Audiobook catalog models.""" + +from __future__ import annotations + +from sqlalchemy import ForeignKey, String, UniqueConstraint +from sqlalchemy.orm import Mapped, mapped_column, relationship + +from python.orm.richie.base import TableBase + + +class AudiobookAuthor(TableBase): + """Canonical audiobook author.""" + + __tablename__ = "audiobook_author" + + name: Mapped[str] = mapped_column(String, unique=True) + + books: Mapped[list[Audiobook]] = relationship("Audiobook", back_populates="author") + series: Mapped[list[AudiobookSeries]] = relationship("AudiobookSeries", back_populates="author") + + +class AudiobookSeries(TableBase): + """Canonical audiobook series.""" + + __tablename__ = "audiobook_series" + __table_args__ = (UniqueConstraint("author_id", "name"),) + + name: Mapped[str] = mapped_column(String) + author_id: Mapped[int] = mapped_column(ForeignKey("main.audiobook_author.id", ondelete="CASCADE")) + + author: Mapped[AudiobookAuthor] = relationship("AudiobookAuthor", back_populates="series") + books: Mapped[list[Audiobook]] = relationship("Audiobook", back_populates="series") + + +class Audiobook(TableBase): + """Canonical audiobook title.""" + + __tablename__ = "audiobook" + + title: Mapped[str] = mapped_column(String) + author_id: Mapped[int] = mapped_column(ForeignKey("main.audiobook_author.id", ondelete="CASCADE")) + series_id: Mapped[int | None] = mapped_column(ForeignKey("main.audiobook_series.id", ondelete="SET NULL")) + series_index: Mapped[int] = mapped_column(default=0) + + author: Mapped[AudiobookAuthor] = relationship("AudiobookAuthor", back_populates="books") + series: Mapped[AudiobookSeries | None] = relationship("AudiobookSeries", back_populates="books")