from datetime import datetime from uuid import uuid4 from sqlalchemy import DateTime, func from sqlalchemy.orm import DeclarativeBase, Mapped, MappedAsDataclass, mapped_column from libs.datetime_utils import naive_utc_now from libs.uuid_utils import uuidv7 from .engine import metadata from .types import StringUUID class Base(DeclarativeBase): metadata = metadata class TypeBase(MappedAsDataclass, DeclarativeBase): """ This is for adding type, after all finished, rename to Base. """ metadata = metadata class DefaultFieldsMixin: """Mixin for models that inherit from Base (non-dataclass).""" id: Mapped[str] = mapped_column( StringUUID, primary_key=True, # NOTE: The default serve as fallback mechanisms. # The application can generate the `id` before saving to optimize # the insertion process (especially for interdependent models) # and reduce database roundtrips. default=lambda: str(uuidv7()), ) created_at: Mapped[datetime] = mapped_column( DateTime, nullable=False, default=naive_utc_now, server_default=func.current_timestamp(), ) updated_at: Mapped[datetime] = mapped_column( DateTime, nullable=False, default=naive_utc_now, server_default=func.current_timestamp(), onupdate=func.current_timestamp(), ) def __repr__(self) -> str: return f"<{self.__class__.__name__}(id={self.id})>" class DefaultFieldsDCMixin(MappedAsDataclass): """Mixin for models that inherit from TypeBase (MappedAsDataclass).""" __abstract__ = True id: Mapped[str] = mapped_column( StringUUID, primary_key=True, insert_default=lambda: str(uuidv7()), default_factory=lambda: str(uuidv7()), init=False, ) created_at: Mapped[datetime] = mapped_column( DateTime, nullable=False, insert_default=naive_utc_now, default_factory=naive_utc_now, init=False, server_default=func.current_timestamp(), ) updated_at: Mapped[datetime] = mapped_column( DateTime, nullable=False, insert_default=naive_utc_now, default_factory=naive_utc_now, init=False, server_default=func.current_timestamp(), onupdate=func.current_timestamp(), ) def __repr__(self) -> str: return f"<{self.__class__.__name__}(id={self.id})>" def gen_uuidv4_string() -> str: """gen_uuidv4_string generate a UUIDv4 string. NOTE: This function exists only for historical reasons. New models should use uuidv7 for primary key generation. """ return str(uuid4()) def gen_uuidv7_string() -> str: """gen_uuidv4_string generate a UUIDv4 string.""" return str(uuidv7())