from __future__ import annotations from typing import Optional import enum import uuid from datetime import datetime from sqlalchemy import DateTime, Enum, ForeignKey, String, Text, UniqueConstraint, func from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import Mapped, mapped_column, relationship from app.db.base_class import Base class DocumentScopeType(str, enum.Enum): GLOBAL = "GLOBAL" SITE = "SITE" DERIVED = "DERIVED" class DocumentStatus(str, enum.Enum): DRAFT = "DRAFT" ACTIVE = "ACTIVE" ARCHIVED = "ARCHIVED" class Document(Base): __tablename__ = "documents" __table_args__ = (UniqueConstraint("trial_id", "doc_no", name="uq_documents_trial_doc_no"),) id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) trial_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("studies.id"), nullable=False) site_id: Mapped[Optional[uuid.UUID]] = mapped_column(UUID(as_uuid=True), ForeignKey("sites.id"), nullable=True) doc_no: Mapped[str] = mapped_column(String(50), nullable=False) doc_type: Mapped[str] = mapped_column(String(50), nullable=False) title: Mapped[str] = mapped_column(String(200), nullable=False) scope_type: Mapped[DocumentScopeType] = mapped_column( Enum(DocumentScopeType, name="document_scope_type"), nullable=False, server_default=DocumentScopeType.GLOBAL.value, ) owner_id: Mapped[Optional[uuid.UUID]] = mapped_column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=True) status: Mapped[DocumentStatus] = mapped_column( Enum(DocumentStatus, name="document_status"), nullable=False, server_default=DocumentStatus.ACTIVE.value, ) current_effective_version_id: Mapped[Optional[uuid.UUID]] = mapped_column( UUID(as_uuid=True), ForeignKey("document_versions.id"), nullable=True, ) description: Mapped[Optional[str]] = mapped_column(Text, 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(), ) versions = relationship( "DocumentVersion", back_populates="document", cascade="all, delete-orphan", foreign_keys="DocumentVersion.document_id", ) current_effective_version = relationship( "DocumentVersion", foreign_keys=[current_effective_version_id], post_update=True, )