"""SeriesPage — ordered image membership for a series-kind Tag. A series IS a Tag with kind='series'; series_page gives it a SINGLE flat, series-global ordered run of pages (FC-6.x divider reframe). An image belongs to at most one series (UNIQUE image_id). Reading order is `page_number` alone — a series-wide ordering key (not unique), rewritten 1..N wholesale on reorder so a reorder can't transiently collide on an index. Chapters are cosmetic DIVIDERS anchored to a page (see SeriesChapter); they do NOT own pages, so there is no chapter_id here — a page's chapter is derived at read time as the nearest preceding divider. stated_page carries the printed page number parsed from the source post, nullable when unknown. """ from datetime import datetime from sqlalchemy import ( DateTime, ForeignKey, Integer, String, UniqueConstraint, func, ) from sqlalchemy.orm import Mapped, mapped_column from .base import Base class SeriesPage(Base): __tablename__ = "series_page" __table_args__ = ( # alembic 0005 named this `uq_series_page_image`; a bare `unique=True` # on the column renders `uq_series_page_image_id` under the naming # convention, which is a different object from the one the database # has (#3275). UniqueConstraint("image_id", name="uq_series_page_image"), ) id: Mapped[int] = mapped_column(Integer, primary_key=True) series_tag_id: Mapped[int] = mapped_column( ForeignKey("tag.id", ondelete="CASCADE"), nullable=False, index=True ) # UNIQUE lives in __table_args__ above, under the name 0005 gave it. image_id: Mapped[int] = mapped_column( ForeignKey("image_record.id", ondelete="CASCADE"), nullable=False, ) # 'placed' = in the series-global run (page_number set); 'pending' = staged # from a post awaiting the operator's sort (page_number NULL). (#789 P2) status: Mapped[str] = mapped_column( String(16), nullable=False, server_default="placed" ) page_number: Mapped[int | None] = mapped_column(Integer, nullable=True) stated_page: Mapped[int | None] = mapped_column(Integer, nullable=True) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, server_default=func.now() ) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, server_default=func.now(), onupdate=func.now(), )