"""ORM models for database tables.""" from datetime import datetime, time from typing import Optional from sqlalchemy import BigInteger, String, Boolean, Integer, DateTime, Time, Index, ForeignKey from sqlalchemy.orm import Mapped, mapped_column, relationship from bot.db.base import Base class User(Base): """User model - represents Telegram users.""" __tablename__ = "users" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) tg_user_id: Mapped[int] = mapped_column(BigInteger, unique=True, nullable=False, index=True) username: Mapped[Optional[str]] = mapped_column(String(255), nullable=True) first_name: Mapped[Optional[str]] = mapped_column(String(255), nullable=True) last_name: Mapped[Optional[str]] = mapped_column(String(255), nullable=True) created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, nullable=False) updated_at: Mapped[datetime] = mapped_column( DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False ) is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False) # Relationship reminders: Mapped[list["Reminder"]] = relationship("Reminder", back_populates="user", cascade="all, delete-orphan") def __repr__(self) -> str: return f"" class Reminder(Base): """Reminder model - represents recurring reminders.""" __tablename__ = "reminders" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) user_id: Mapped[int] = mapped_column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True) text: Mapped[str] = mapped_column(String(1000), nullable=False) days_interval: Mapped[int] = mapped_column(Integer, nullable=False) time_of_day: Mapped[time] = mapped_column(Time, nullable=False) next_run_at: Mapped[datetime] = mapped_column(DateTime, nullable=False, index=True) last_done_at: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True) is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False) created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, nullable=False) updated_at: Mapped[datetime] = mapped_column( DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False ) # Optional fields for statistics snooze_count: Mapped[int] = mapped_column(Integer, default=0, nullable=False) total_done_count: Mapped[int] = mapped_column(Integer, default=0, nullable=False) # Relationship user: Mapped["User"] = relationship("User", back_populates="reminders") # Composite index for scheduler queries __table_args__ = ( Index("ix_reminders_active_next_run", "is_active", "next_run_at"), ) def __repr__(self) -> str: return ( f"" )