from __future__ import annotations from typing import Optional import enum import uuid from datetime import datetime from sqlalchemy import BigInteger, 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 DocumentVersionStatus(str, enum.Enum): DRAFT = "DRAFT" SUBMITTED = "SUBMITTED" APPROVED = "APPROVED" EFFECTIVE = "EFFECTIVE" SUPERSEDED = "SUPERSEDED" ARCHIVED = "ARCHIVED" WITHDRAWN = "WITHDRAWN" class DocumentVersion(Base): __tablename__ = "document_versions" __table_args__ = (UniqueConstraint("document_id", "version_no", name="uq_document_versions_doc_no"),) id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) document_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("documents.id"), nullable=False) version_no: Mapped[str] = mapped_column(String(50), nullable=False) parent_version_id: Mapped[Optional[uuid.UUID]] = mapped_column( UUID(as_uuid=True), ForeignKey("document_versions.id"), nullable=True, ) derived_from_version_id: Mapped[Optional[uuid.UUID]] = mapped_column( UUID(as_uuid=True), ForeignKey("document_versions.id"), nullable=True, ) status: Mapped[DocumentVersionStatus] = mapped_column( Enum(DocumentVersionStatus, name="document_version_status"), nullable=False, server_default=DocumentVersionStatus.DRAFT.value, ) effective_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True) superseded_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True) file_uri: Mapped[str] = mapped_column(String(500), nullable=False) file_hash: Mapped[str] = mapped_column(String(128), nullable=False) file_size: Mapped[int] = mapped_column(BigInteger, nullable=False) mime_type: Mapped[Optional[str]] = mapped_column(String(100), nullable=True) change_summary: Mapped[Optional[str]] = mapped_column(Text, nullable=True) created_by: Mapped[Optional[uuid.UUID]] = mapped_column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=True) submitted_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True) approved_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True) withdrawn_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now()) document = relationship("Document", back_populates="versions", foreign_keys=[document_id]) parent_version = relationship("DocumentVersion", remote_side=[id], foreign_keys=[parent_version_id]) derived_from_version = relationship("DocumentVersion", remote_side=[id], foreign_keys=[derived_from_version_id]) distributions = relationship("Distribution", back_populates="version")