Spaces:
Running
Running
| """Author RAG Chatbot SaaS — Book Model.""" | |
| from __future__ import annotations | |
| from typing import TYPE_CHECKING | |
| from sqlalchemy import Boolean, ForeignKey, Integer, String, Text | |
| from sqlalchemy.orm import Mapped, mapped_column, relationship | |
| from app.models.base import Base, TimestampMixin, generate_uuid | |
| if TYPE_CHECKING: | |
| from app.models.user import User | |
| from app.models.document import Document | |
| from app.models.link import Link | |
| from app.models.platform_listing import BookPlatformListing | |
| class Book(Base, TimestampMixin): | |
| """A book in an author's catalog.""" | |
| __tablename__ = "books" | |
| id: Mapped[str] = mapped_column(String(36), primary_key=True, default=generate_uuid) | |
| author_id: Mapped[str] = mapped_column( | |
| String(36), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True | |
| ) | |
| # Metadata | |
| title: Mapped[str] = mapped_column(String(500), nullable=False) | |
| tagline: Mapped[str | None] = mapped_column(String(500), nullable=True) | |
| genre: Mapped[str | None] = mapped_column(String(300), nullable=True) # widened for long category strings | |
| description: Mapped[str | None] = mapped_column(Text, nullable=True) | |
| cover_path: Mapped[str | None] = mapped_column(String(500), nullable=True) # local file path | |
| cover_url: Mapped[str | None] = mapped_column(String(1000), nullable=True) # remote CDN URL (scraped) | |
| cover_thumbnail_path: Mapped[str | None] = mapped_column(String(500), nullable=True) | |
| cover_medium_path: Mapped[str | None] = mapped_column(String(500), nullable=True) | |
| ai_summary: Mapped[str | None] = mapped_column(Text, nullable=True) | |
| publish_year: Mapped[str | None] = mapped_column(String(4), nullable=True) | |
| # Processing | |
| status: Mapped[str] = mapped_column(String(50), default="created", nullable=False, index=True) | |
| error_message: Mapped[str | None] = mapped_column(Text, nullable=True) | |
| chroma_collection_id: Mapped[str | None] = mapped_column(String(100), nullable=True) | |
| chunk_count: Mapped[int] = mapped_column(Integer, default=0, nullable=False) | |
| page_count: Mapped[int] = mapped_column(Integer, default=0, nullable=False) | |
| # Display | |
| is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False) | |
| display_order: Mapped[int] = mapped_column(Integer, default=0, nullable=False) | |
| # Smart links | |
| buy_url: Mapped[str | None] = mapped_column(String(1000), nullable=True) | |
| preview_url: Mapped[str | None] = mapped_column(String(1000), nullable=True) | |
| # Import tracking | |
| source_url: Mapped[str | None] = mapped_column(String(1000), nullable=True) | |
| isbn: Mapped[str | None] = mapped_column(String(20), nullable=True) | |
| book_author: Mapped[str | None] = mapped_column(String(200), nullable=True) | |
| about_author: Mapped[str | None] = mapped_column(Text, nullable=True) | |
| language: Mapped[str | None] = mapped_column(String(50), nullable=True) | |
| rating: Mapped[str | None] = mapped_column(String(10), nullable=True) | |
| rating_count: Mapped[str | None] = mapped_column(String(20), nullable=True) | |
| # Relationships | |
| author: Mapped[User] = relationship("User", back_populates="books") | |
| documents: Mapped[list[Document]] = relationship("Document", back_populates="book", cascade="all, delete-orphan") | |
| links: Mapped[list[Link]] = relationship("Link", back_populates="book", cascade="all, delete-orphan") | |
| platform_listings: Mapped[list["BookPlatformListing"]] = relationship( | |
| "BookPlatformListing", back_populates="book", cascade="all, delete-orphan" | |
| ) | |
| def __repr__(self) -> str: | |
| return f"<Book id={self.id} title={self.title!r}>" | |