""" Photo Model — ORM + Pydantic Schemas ORM: Photo (SQLAlchemy table: photos) Schemas: PhotoCreate, PhotoResponse """ import uuid from datetime import datetime from typing import Optional from sqlalchemy import String, Text, BigInteger, DateTime, ForeignKey, func from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import Mapped, mapped_column, relationship from pydantic import BaseModel, Field, ConfigDict from models.base import Base # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # ORM Model # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ class Photo(Base): """SQLAlchemy ORM model for the 'photos' table.""" __tablename__ = "photos" id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), primary_key=True, default=uuid.uuid4 ) visit_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("visits.id", ondelete="CASCADE"), nullable=False, ) checklist_id: Mapped[Optional[uuid.UUID]] = mapped_column( UUID(as_uuid=True), ForeignKey("checklists.id", ondelete="SET NULL"), nullable=True, ) assessment_id: Mapped[Optional[uuid.UUID]] = mapped_column( UUID(as_uuid=True), ForeignKey("assessments.id", ondelete="SET NULL"), nullable=True, comment="Linked assessment item (for per-item photo gallery)" ) file_path: Mapped[str] = mapped_column(String(500), nullable=False) file_name: Mapped[str] = mapped_column(String(255), nullable=False) file_size: Mapped[Optional[int]] = mapped_column(BigInteger, nullable=True) mime_type: Mapped[Optional[str]] = mapped_column(String(100), nullable=True) caption: Mapped[Optional[str]] = mapped_column(Text, nullable=True) uploaded_at: Mapped[datetime] = mapped_column( DateTime, server_default=func.now() ) created_at: Mapped[datetime] = mapped_column( DateTime, server_default=func.now() ) # Relationships visit = relationship("Visit", back_populates="photos") checklist = relationship("Checklist", back_populates="photos", foreign_keys=[checklist_id]) assessment = relationship("Assessment", back_populates="photos", foreign_keys=[assessment_id]) def __repr__(self) -> str: return f"" # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # Pydantic Schemas # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ class PhotoCreate(BaseModel): """Schema for photo upload metadata.""" checklist_id: Optional[uuid.UUID] = Field( None, description="Optional linked checklist item" ) assessment_id: Optional[uuid.UUID] = Field( None, description="Optional linked assessment item (per-item photo)" ) caption: Optional[str] = Field(None, description="Photo caption") class PhotoResponse(BaseModel): """Schema for a single photo in API responses.""" model_config = ConfigDict(from_attributes=True) id: uuid.UUID visit_id: uuid.UUID checklist_id: Optional[uuid.UUID] assessment_id: Optional[uuid.UUID] file_path: str file_name: str file_size: Optional[int] mime_type: Optional[str] caption: Optional[str] uploaded_at: datetime created_at: datetime