58 lines
1.9 KiB
Python
58 lines
1.9 KiB
Python
"""Document model — uploaded PDFs with soft-delete support."""
|
|
|
|
import uuid
|
|
from datetime import datetime, timezone
|
|
|
|
from sqlalchemy import Index, Integer, Text
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
|
|
from app.db import Base
|
|
|
|
|
|
def _uuid() -> str:
|
|
return str(uuid.uuid4())
|
|
|
|
|
|
def _now_iso() -> str:
|
|
return datetime.now(timezone.utc).isoformat()
|
|
|
|
|
|
class Document(Base):
|
|
"""
|
|
A single uploaded PDF document.
|
|
|
|
Supports soft deletion via `deleted_at` — when set, the document
|
|
is in the trash and can be restored or permanently purged.
|
|
"""
|
|
|
|
__tablename__ = "documents"
|
|
|
|
id: Mapped[str] = mapped_column(Text, primary_key=True, default=_uuid)
|
|
title: Mapped[str] = mapped_column(Text, nullable=False)
|
|
original_filename: Mapped[str] = mapped_column(Text, nullable=False)
|
|
file_path: Mapped[str] = mapped_column(Text, nullable=False)
|
|
thumbnail_path: Mapped[str | None] = mapped_column(Text, nullable=True, default=None)
|
|
size_bytes: Mapped[int] = mapped_column(Integer, nullable=False)
|
|
page_count: Mapped[int] = mapped_column(Integer, nullable=False)
|
|
created_at: Mapped[str] = mapped_column(Text, default=_now_iso)
|
|
updated_at: Mapped[str] = mapped_column(Text, default=_now_iso, onupdate=_now_iso)
|
|
deleted_at: Mapped[str | None] = mapped_column(Text, nullable=True, default=None)
|
|
|
|
# Relationships
|
|
annotation_state: Mapped["AnnotationState"] = relationship(
|
|
"AnnotationState",
|
|
back_populates="document",
|
|
uselist=False,
|
|
cascade="all, delete-orphan",
|
|
)
|
|
versions: Mapped[list["Version"]] = relationship(
|
|
"Version",
|
|
back_populates="document",
|
|
cascade="all, delete-orphan",
|
|
order_by="Version.created_at.desc()",
|
|
)
|
|
|
|
__table_args__ = (
|
|
Index("ix_documents_updated_at", "updated_at"),
|
|
Index("ix_documents_deleted_at", "deleted_at"),
|
|
)
|