"""Declarative base + shared mixins/enums. Every table uses an integer surrogate PK and carries ``created_at``/``updated_at`` (spec ยง7). Statuses/types are Python enums stored as strings. """ from __future__ import annotations import enum from datetime import datetime, timezone from sqlalchemy import DateTime, func from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column class Base(DeclarativeBase): pass def _utcnow() -> datetime: return datetime.now(timezone.utc) class TimestampMixin: created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), default=_utcnow, server_default=func.now() ) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), default=_utcnow, onupdate=_utcnow, server_default=func.now(), ) # ---- Enums (stored as their string values) ---- class UserRole(str, enum.Enum): owner = "owner" finder = "finder" admin = "admin" class KnownDogStatus(str, enum.Enum): home = "home" lost = "lost" reunited = "reunited" class UnknownDogStatus(str, enum.Enum): pending = "pending" # finder has the dog in their own custody at_shelter = "at_shelter" # dropped at a shelter/vet claimed = "claimed" # matched & resolved reunited = "reunited" class DogSize(str, enum.Enum): small = "small" medium = "medium" large = "large" class CaseType(str, enum.Enum): lost = "lost" found = "found" class CaseStatus(str, enum.Enum): open = "open" matched = "matched" resolved = "resolved" closed = "closed" class SubjectType(str, enum.Enum): known = "known" unknown = "unknown" class MatchStatus(str, enum.Enum): pending = "pending" confirmed = "confirmed" rejected = "rejected" class NotificationChannel(str, enum.Enum): email = "email" sms = "sms" class NotificationStatus(str, enum.Enum): queued = "queued" sent = "sent" failed = "failed" class DatasetType(str, enum.Enum): test_known = "test_known" test_found = "test_found" known = "known" unknown = "unknown"