"""Declarative base + shared mixins for all ORM models.""" from __future__ import annotations import uuid from datetime import UTC, datetime from sqlalchemy import DateTime from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column def utcnow() -> datetime: return datetime.now(UTC) def ensure_aware_utc(value: datetime) -> datetime: """SQLite's `DateTime(timezone=True)` silently drops tzinfo on read back (Postgres does not). Anything read from the DB and compared against an aware `datetime.now(UTC)` must go through this first so the app behaves identically on both backends.""" if value.tzinfo is None: return value.replace(tzinfo=UTC) return value class Base(DeclarativeBase): pass class UUIDPrimaryKeyMixin: id: Mapped[uuid.UUID] = mapped_column(primary_key=True, default=uuid.uuid4, unique=True) class TimestampMixin: created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), default=utcnow, onupdate=utcnow )