import uuid from datetime import datetime from typing import Generic, Optional, TypeVar import pytz from pydantic import BaseModel, SecretStr from sqlalchemy import Column, DateTime, String, event from sqlalchemy.dialects.postgresql import UUID from src.config import TIMEZONE from src.enums import ResponseStatus class TimeStampMixin(object): created_at = Column(DateTime(timezone=True), default=datetime.now(pytz.timezone(TIMEZONE))) created_at._creation_order = 9998 updated_at = Column(DateTime(timezone=True), default=datetime.now(pytz.timezone(TIMEZONE))) updated_at._creation_order = 9998 @staticmethod def _updated_at(mapper, connection, target): target.updated_at = datetime.now(pytz.timezone(TIMEZONE)) @classmethod def __declare_last__(cls): event.listen(cls, 'before_update', cls._updated_at) class UUIDMixin: id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, unique=True, nullable=False) class SoftDeleteMixin: deleted_at = Column(DateTime(timezone=True), nullable=True, default=None) deleted_at._creation_order = 9999 class DefaultMixin(SoftDeleteMixin, TimeStampMixin, UUIDMixin): pass class IdentityMixin: created_by = Column(String(100), nullable=True) updated_by = Column(String(100), nullable=True) class DefultBase(BaseModel): class Config: from_attributes = True validate_assignment = True arbitrary_types_allowed = True str_strip_whitespace = True populate_by_name = True extra = 'forbid' json_encoders = {datetime: lambda v: v.strftime('%Y-%m-%dT%H:%M:%S.%fZ') if v else None, SecretStr: lambda v: v.get_secret_value() if v else None} class Pagination(DefultBase): itemsPerPage: int totalPages: int page: int total: int class PrimaryKeyModel(BaseModel): id: uuid.UUID T = TypeVar('T') class StandardResponse(BaseModel, Generic[T]): data: Optional[T] = None message: str = 'Success' status: ResponseStatus = ResponseStatus.SUCCESS