Arag / app /models /platform_listing.py
AuthorBot
Fetch list prices during platform presence scans where retailers allow it.
4737249
Raw
History Blame Contribute Delete
1.9 kB
"""Author RAG — Book platform listing model (admin-only discovery links)."""
from datetime import datetime
from sqlalchemy import Boolean, DateTime, Float, ForeignKey, String, UniqueConstraint
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.models.base import Base, TimestampMixin, generate_uuid
class BookPlatformListing(Base, TimestampMixin):
"""Discovered retailer listing for a book — hidden from widget by default."""
__tablename__ = "book_platform_listings"
__table_args__ = (
UniqueConstraint("book_id", "platform_id", name="uq_book_platform"),
)
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
)
book_id: Mapped[str] = mapped_column(
String(36), ForeignKey("books.id", ondelete="CASCADE"), nullable=False, index=True
)
platform_id: Mapped[str] = mapped_column(String(50), nullable=False)
status: Mapped[str] = mapped_column(String(20), nullable=False, default="not_found")
confidence: Mapped[float] = mapped_column(Float, nullable=False, default=0.0)
listing_url: Mapped[str | None] = mapped_column(String(2000), nullable=True)
list_price: Mapped[str | None] = mapped_column(String(32), nullable=True)
price_currency: Mapped[str | None] = mapped_column(String(8), nullable=True)
visible_in_widget: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
last_scanned_at: Mapped[datetime | None] = mapped_column(
DateTime(timezone=True), nullable=True
)
book: Mapped["Book"] = relationship("Book", back_populates="platform_listings")
def __repr__(self) -> str:
return f"<BookPlatformListing book={self.book_id} platform={self.platform_id} status={self.status}>"