import enum from datetime import datetime, time from sqlalchemy import Enum, ForeignKey, Integer, SmallInteger, String, Time from sqlalchemy.orm import Mapped, mapped_column, relationship from sqlalchemy.sql import func from app.database import Base ALL_WEEKDAYS_MASK = 0b1111111 # 월~일 전부 (bit0=월 ... bit6=일) class HabitType(str, enum.Enum): BUILD = "build" # 만들고 싶은 습관 QUIT = "quit" # 멈추고 싶은 습관 class HabitStatus(str, enum.Enum): ACTIVE = "active" COMPLETED = "completed" class Habit(Base): __tablename__ = "habit" id: Mapped[int] = mapped_column(Integer, primary_key=True) user_id: Mapped[int | None] = mapped_column( ForeignKey("user.id", ondelete="CASCADE"), nullable=True ) name: Mapped[str] = mapped_column(String(200), nullable=False) habit_type: Mapped[HabitType] = mapped_column(Enum(HabitType, native_enum=False, length=20), nullable=False) status: Mapped[HabitStatus] = mapped_column( Enum(HabitStatus, native_enum=False, length=20), nullable=False, default=HabitStatus.ACTIVE ) weekdays_mask: Mapped[int] = mapped_column(SmallInteger, nullable=False, default=ALL_WEEKDAYS_MASK) condition_text: Mapped[str | None] = mapped_column(String(300), nullable=True) reminder_time: Mapped[time | None] = mapped_column(Time, nullable=True) sort_order: Mapped[int | None] = mapped_column(Integer, nullable=True) created_at: Mapped[datetime] = mapped_column(server_default=func.now(), nullable=False) completed_at: Mapped[datetime | None] = mapped_column(nullable=True) logs: Mapped[list["HabitLog"]] = relationship( back_populates="habit", cascade="all, delete-orphan", passive_deletes=True ) def is_scheduled_on(self, weekday: int) -> bool: """weekday: Python date.weekday() 기준 (월=0 ... 일=6)""" return bool(self.weekdays_mask & (1 << weekday))