import enum from datetime import datetime from typing import Optional, TYPE_CHECKING from uuid import UUID from sqlalchemy import ForeignKey, BigInteger, Enum, Uuid from sqlalchemy.orm import Mapped, mapped_column, relationship from models import BaseModel, User if TYPE_CHECKING: from models import Client, Card class TgUser(BaseModel): __tablename__ = 'tg_users' id: Mapped[int] = mapped_column( BigInteger(), primary_key=True, comment='Telegram user ID', ) username: Mapped[str] = mapped_column( index=True, nullable=False, unique=True, ) first_name: Mapped[str] = mapped_column(nullable=True) last_name: Mapped[str] = mapped_column(nullable=True) messages: Mapped['Message'] = relationship( 'Message', lazy='noload', back_populates='tg_sender', ) class TgGroup(BaseModel): __tablename__ = 'tg_groups' id: Mapped[UUID] = mapped_column(Uuid, primary_key=True) tg_group_id: Mapped[int] = mapped_column( BigInteger(), nullable=False, unique=True, ) tg_invite_link: Mapped[str] = mapped_column(nullable=False) client_id: Mapped[Optional[int]] = mapped_column( ForeignKey('clients.id'), unique=True, ) client: Mapped[Optional['Client']] = relationship( 'Client', lazy='joined', back_populates='tg_group', ) chats: Mapped[list['Chat']] = relationship( 'Chat', lazy='noload', back_populates='tg_group', ) class Chat(BaseModel): __tablename__ = 'chats' id: Mapped[int] = mapped_column(primary_key=True) tg_topic_id: Mapped[int] = mapped_column(nullable=False) card_id: Mapped[Optional[int]] = mapped_column( ForeignKey('cards.id'), unique=True, ) card: Mapped[Optional['Card']] = relationship( 'Card', lazy='joined', back_populates='chat', ) client_id: Mapped[Optional[int]] = mapped_column( ForeignKey('clients.id'), unique=True, ) client: Mapped[Optional['Client']] = relationship( 'Client', lazy='joined', back_populates='chat', ) tg_group_id: Mapped[UUID] = mapped_column( ForeignKey('tg_groups.id'), nullable=False, ) tg_group: Mapped[TgGroup] = relationship( 'TgGroup', lazy='joined', back_populates='chats', ) messages: Mapped[list['Message']] = relationship( 'Message', lazy='selectin', back_populates='chat', order_by='Message.created_at.desc()', ) class MessageFile(BaseModel): __tablename__ = 'message_files' id: Mapped[int] = mapped_column(primary_key=True) file_path: Mapped[str] = mapped_column(nullable=False) type: Mapped[Optional[str]] = mapped_column(nullable=True) file_name: Mapped[str] = mapped_column(nullable=False) file_size: Mapped[int] = mapped_column(BigInteger(), nullable=True, comment='Размер файла в байтах') message_id: Mapped[int] = mapped_column(ForeignKey('messages.id')) message: Mapped['Message'] = relationship( 'Message', lazy='noload', back_populates='file', ) class MessageStatus(enum.Enum): sending = 'SENDING' success = 'SUCCESS' error = 'ERROR' class Message(BaseModel): __tablename__ = 'messages' id: Mapped[int] = mapped_column(primary_key=True) tg_message_id: Mapped[Optional[int]] = mapped_column(nullable=True) text: Mapped[str] = mapped_column(nullable=False) created_at: Mapped[datetime] = mapped_column(nullable=False) status: Mapped[MessageStatus] = mapped_column(Enum(MessageStatus), nullable=False) is_deleted: Mapped[bool] = mapped_column(default=False, server_default='0', nullable=False) is_edited: Mapped[bool] = mapped_column(default=False, server_default='0', nullable=False) tg_sender_id: Mapped[Optional[int]] = mapped_column( ForeignKey('tg_users.id'), nullable=True, ) tg_sender: Mapped[TgUser] = relationship( 'TgUser', lazy='selectin', back_populates='messages', ) crm_sender_id: Mapped[Optional[int]] = mapped_column( ForeignKey('users.id'), nullable=True, ) crm_sender: Mapped[Optional['User']] = relationship( 'User', lazy='selectin', back_populates='messages', ) chat_id: Mapped[int] = mapped_column(ForeignKey('chats.id')) chat: Mapped[Chat] = relationship( 'Chat', lazy='noload', back_populates='messages', ) file: Mapped[Optional[MessageFile]] = relationship( 'MessageFile', back_populates='message', lazy='selectin', )