Spaces:
Running
Running
| """ | |
| User table: app profile keyed by Supabase auth user id (UUID) | |
| id: UUID, primary key — use auth.users.id when using Supabase Auth | |
| email: optional, unique when set | |
| display_name: optional | |
| created_at / updated_at: datetime | |
| Manga table: stores manga metadata | |
| id: int, primary key | |
| provider_id: str | |
| manga_title: str | |
| created_at: datetime | |
| Chapter table: stores manga chapter info | |
| id: int, primary key | |
| chapter_id: int, foreign key → chapters.id | |
| page_number: int | |
| created_at: datetime | |
| Chapter table: chapter data scoped by provider (same umbrella manga can have chapters per source) | |
| Page / Segment tables: unchanged hierarchy under chapters | |
| ReadingListCollection: named list per user (e.g. "Want to read"). | |
| ReadingListItem: one row per named list + umbrella manga (manga_id). | |
| """ | |
| from datetime import datetime, timezone | |
| from typing import Optional | |
| from uuid import UUID | |
| from sqlalchemy import Index | |
| from sqlmodel import Field, SQLModel, UniqueConstraint | |
| def _utc_now() -> datetime: | |
| return datetime.now(timezone.utc) | |
| class Users(SQLModel, table=True): | |
| __table_args__ = ({"extend_existing": True},) | |
| id: UUID = Field(primary_key=True) | |
| email: Optional[str] = Field(default=None, unique=True) | |
| display_name: Optional[str] = Field(default=None) | |
| created_at: Optional[datetime] = Field(default_factory=_utc_now) | |
| updated_at: Optional[datetime] = Field(default_factory=_utc_now) | |
| class Manga(SQLModel, table=True): | |
| """Umbrella series; use MangaSource for per-provider external ids.""" | |
| __table_args__ = ({"extend_existing": True},) | |
| id: Optional[int] = Field(default=None, primary_key=True) | |
| manga_title: str = Field(index=True) | |
| created_at: Optional[datetime] = Field(default_factory=_utc_now) | |
| updated_at: Optional[datetime] = Field(default_factory=_utc_now) | |
| class MangaSource(SQLModel, table=True): | |
| """Links an umbrella manga to a provider catalog id (e.g. MangaDex UUID).""" | |
| __tablename__ = "manga_source" | |
| __table_args__ = ( | |
| UniqueConstraint("provider_id", "external_manga_id", name="uq_manga_source_provider_external"), | |
| UniqueConstraint("manga_id", "provider_id", name="uq_manga_source_manga_provider"), | |
| {"extend_existing": True}, | |
| ) | |
| id: Optional[int] = Field(default=None, primary_key=True) | |
| manga_id: int = Field(foreign_key="manga.id", index=True) | |
| provider_id: str = Field(index=True) | |
| external_manga_id: str = Field(index=True) #if there is no external manga id, it will be the same as the manga_id with local in front | |
| created_at: Optional[datetime] = Field(default_factory=_utc_now) | |
| class ReadingListCollection(SQLModel, table=True): | |
| """User-owned named reading list (container for manga).""" | |
| __tablename__ = "reading_list_collection" | |
| __table_args__ = ({"extend_existing": True},) | |
| id: Optional[int] = Field(default=None, primary_key=True) | |
| user_id: UUID = Field(foreign_key="users.id", index=True) | |
| name: str = Field(max_length=200) | |
| created_at: Optional[datetime] = Field(default_factory=_utc_now) | |
| updated_at: Optional[datetime] = Field(default_factory=_utc_now) | |
| class ReadingListItem(SQLModel, table=True): | |
| """One umbrella manga inside a named reading list.""" | |
| __tablename__ = "reading_list_item" | |
| __table_args__ = ( | |
| UniqueConstraint("reading_list_id", "manga_id", name="uq_rli_list_manga"), | |
| {"extend_existing": True}, | |
| ) | |
| id: Optional[int] = Field(default=None, primary_key=True) | |
| reading_list_id: int = Field(foreign_key="reading_list_collection.id", index=True) | |
| manga_id: int = Field(foreign_key="manga.id", index=True) | |
| last_chapter_number: Optional[float] = Field(default=None) | |
| created_at: Optional[datetime] = Field(default_factory=_utc_now) | |
| updated_at: Optional[datetime] = Field(default_factory=_utc_now) | |
| class Chapters(SQLModel, table=True): | |
| __table_args__ = ( | |
| UniqueConstraint("manga_id", "provider_id", "chapter_number", name="uq_chapters_manga_provider_chapter"), | |
| {"extend_existing": True}, | |
| ) | |
| id: Optional[int] = Field(default=None, primary_key=True) | |
| manga_id: int = Field(foreign_key="manga.id", index=True) | |
| provider_id: str = Field(index=True) | |
| chapter_number: float = Field(index=True) | |
| language_code: str | |
| created_at: Optional[datetime] = Field(default_factory=_utc_now) | |
| updated_at: Optional[datetime] = Field(default_factory=_utc_now) | |
| class Pages(SQLModel, table=True): | |
| __table_args__ = ( | |
| UniqueConstraint("chapter_id", "page_number", name="uq_pages_chapter_page"), | |
| {"extend_existing": True}, | |
| ) | |
| id: Optional[int] = Field(default=None, primary_key=True) | |
| chapter_id: int = Field(foreign_key="chapters.id", index=True) | |
| page_number: int = Field(index=True) | |
| created_at: Optional[datetime] = Field(default_factory=_utc_now) | |
| updated_at: Optional[datetime] = Field(default_factory=_utc_now) | |
| class Segments(SQLModel, table=True): | |
| __table_args__ = ( | |
| Index("ix_segments_page_segment", "page_id", "segment_index"), | |
| {"extend_existing": True}, | |
| ) | |
| id: Optional[int] = Field(default=None, primary_key=True) | |
| page_id: int = Field(foreign_key="pages.id", index=True) | |
| segment_index: int | |
| x1: float | |
| y1: float | |
| x2: float | |
| y2: float | |
| original_text: str | |
| translated_text: str | |
| created_at: Optional[datetime] = Field(default_factory=_utc_now) | |