from __future__ import annotations from datetime import datetime from enum import Enum from typing import TYPE_CHECKING, List from sqlalchemy import DateTime, Enum as SQLEnum, Integer, String, Text from sqlalchemy.orm import Mapped, mapped_column, relationship from sqlalchemy.sql import func from config.database import Base if TYPE_CHECKING: # pragma: no cover from .scenario import Scenario class MiningOperationType(str, Enum): """Supported mining operation categories.""" OPEN_PIT = "open_pit" UNDERGROUND = "underground" IN_SITU_LEACH = "in_situ_leach" PLACER = "placer" QUARRY = "quarry" MOUNTAINTOP_REMOVAL = "mountaintop_removal" OTHER = "other" class Project(Base): """Top-level mining project grouping multiple scenarios.""" __tablename__ = "projects" id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True) name: Mapped[str] = mapped_column(String(255), nullable=False, unique=True) location: Mapped[str | None] = mapped_column(String(255), nullable=True) operation_type: Mapped[MiningOperationType] = mapped_column( SQLEnum(MiningOperationType), nullable=False, default=MiningOperationType.OTHER ) description: Mapped[str | None] = 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() ) scenarios: Mapped[List["Scenario"]] = relationship( "Scenario", back_populates="project", cascade="all, delete-orphan", passive_deletes=True, ) def __repr__(self) -> str: # pragma: no cover - helpful for debugging return f"Project(id={self.id!r}, name={self.name!r})"