from datetime import datetime, timezone from sqlalchemy import DateTime, Text from sqlalchemy.orm import Mapped, mapped_column class SoftDeleteMixin: """Recoverable-delete columns. NULL deleted_at = live row. deleted_batch_id groups rows soft-deleted in one operation so a cascade restores as a unit.""" deleted_at: Mapped[datetime | None] = mapped_column( DateTime(timezone=True), nullable=True, default=None ) deleted_batch_id: Mapped[str | None] = mapped_column(Text, nullable=True, default=None) class TimestampMixin: created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), default=lambda: datetime.now(timezone.utc) ) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc), ) class CreatedAtMixin: created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), default=lambda: datetime.now(timezone.utc) )