"""Базовый класс моделей и общие типы колонок.""" from __future__ import annotations import uuid from datetime import datetime from sqlalchemy import DateTime, MetaData, func from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column # Явные шаблоны имён — без них Alembic генерирует безымянные constraint'ы, # которые потом невозможно удалить в миграции отката. NAMING_CONVENTION = { "ix": "ix_%(column_0_label)s", "uq": "uq_%(table_name)s_%(column_0_name)s", "ck": "ck_%(table_name)s_%(constraint_name)s", "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s", "pk": "pk_%(table_name)s", } class Base(DeclarativeBase): metadata = MetaData(naming_convention=NAMING_CONVENTION) class UUIDPrimaryKeyMixin: """PK-идентификатор, генерируемый приложением. Генерируем на стороне Python, а не в БД: для чеков UUID должен быть известен ДО обращения к Checkbox — он служит ключом идемпотентности. """ id: Mapped[uuid.UUID] = mapped_column(primary_key=True, default=uuid.uuid4) class TimestampMixin: created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), nullable=False ) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False, )