69 lines
3.0 KiB
Python
69 lines
3.0 KiB
Python
"""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"<User(id={self.id}, tg_user_id={self.tg_user_id}, username={self.username})>"
|
|
|
|
|
|
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"<Reminder(id={self.id}, user_id={self.user_id}, text='{self.text[:30]}...', "
|
|
f"interval={self.days_interval}, active={self.is_active})>"
|
|
)
|