from datetime import datetime from enum import Enum from typing import TYPE_CHECKING from sqlalchemy import DateTime, Enum as SAEnum, ForeignKey, String, UniqueConstraint, func from sqlalchemy.orm import Mapped, mapped_column, relationship from app.database.base import Base if TYPE_CHECKING: from app.messages.models import Message from app.users.models import User class ChatType(str, Enum): PRIVATE = "private" GROUP = "group" CHANNEL = "channel" class ChatMemberRole(str, Enum): OWNER = "owner" ADMIN = "admin" MEMBER = "member" class Chat(Base): __tablename__ = "chats" id: Mapped[int] = mapped_column(primary_key=True, index=True) type: Mapped[ChatType] = mapped_column(SAEnum(ChatType), nullable=False, index=True) title: Mapped[str | None] = mapped_column(String(255), nullable=True) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), nullable=False) members: Mapped[list["ChatMember"]] = relationship(back_populates="chat", cascade="all, delete-orphan") messages: Mapped[list["Message"]] = relationship(back_populates="chat", cascade="all, delete-orphan") class ChatMember(Base): __tablename__ = "chat_members" __table_args__ = (UniqueConstraint("chat_id", "user_id", name="uq_chat_members_chat_id_user_id"),) id: Mapped[int] = mapped_column(primary_key=True, index=True) chat_id: Mapped[int] = mapped_column(ForeignKey("chats.id", ondelete="CASCADE"), nullable=False, index=True) user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True) role: Mapped[ChatMemberRole] = mapped_column(SAEnum(ChatMemberRole), nullable=False, default=ChatMemberRole.MEMBER) joined_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), nullable=False) chat: Mapped["Chat"] = relationship(back_populates="members") user: Mapped["User"] = relationship(back_populates="memberships")