"""SeriesChapter — a cosmetic chapter DIVIDER within a series (FC-6.x reframe). A series is ONE flat, series-global ordered run of SeriesPages. A chapter is NOT a container — it owns no pages. It is a labeled divider anchored to the page that BEGINS the chapter (anchor_page_id → series_page): "a new chapter starts here." A page's chapter is derived at read time as the nearest preceding divider. Dividers never affect page ordering or the series-global page numbers; they stay pinned to their anchor page across reorders. anchor_page_id is UNIQUE — at most one chapter begins at a given page — and FK-cascades, so removing the anchor page from the series drops the divider (the chapter merges into the preceding run). title is the optional chapter name; stated_part is the optional operator-facing "Part N" label (shown instead of a derived ordinal when set). """ from datetime import datetime from sqlalchemy import DateTime, ForeignKey, Integer, Text, func from sqlalchemy.orm import Mapped, mapped_column from .base import Base class SeriesChapter(Base): __tablename__ = "series_chapter" 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 ) anchor_page_id: Mapped[int] = mapped_column( ForeignKey("series_page.id", ondelete="CASCADE"), nullable=False, unique=True, ) title: Mapped[str | None] = mapped_column(Text, nullable=True) stated_part: 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(), )