import enum from datetime import date from sqlalchemy import Date, ForeignKey, Index, Integer, Text from sqlalchemy.dialects.postgresql import ARRAY from sqlalchemy.orm import Mapped, mapped_column from fabledassistant.models import Base from fabledassistant.models.base import TimestampMixin class TaskStatus(str, enum.Enum): todo = "todo" in_progress = "in_progress" done = "done" class TaskPriority(str, enum.Enum): none = "none" low = "low" medium = "medium" high = "high" class Note(Base, TimestampMixin): __tablename__ = "notes" id: Mapped[int] = mapped_column(primary_key=True) user_id: Mapped[int | None] = mapped_column( Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=True ) title: Mapped[str] = mapped_column(Text, default="") body: Mapped[str] = mapped_column(Text, default="") tags: Mapped[list[str]] = mapped_column(ARRAY(Text), default=list) parent_id: Mapped[int | None] = mapped_column( Integer, ForeignKey("notes.id", ondelete="SET NULL"), nullable=True ) project_id: Mapped[int | None] = mapped_column( Integer, ForeignKey("projects.id", ondelete="SET NULL"), nullable=True ) milestone_id: Mapped[int | None] = mapped_column( Integer, ForeignKey("milestones.id", ondelete="SET NULL"), nullable=True ) status: Mapped[str | None] = mapped_column(Text, nullable=True) priority: Mapped[str | None] = mapped_column(Text, nullable=True) due_date: Mapped[date | None] = mapped_column(Date, nullable=True) __table_args__ = ( Index("ix_notes_tags", "tags", postgresql_using="gin"), Index("ix_notes_status", "status"), Index("ix_notes_title", "title"), Index("ix_notes_user_id", "user_id"), Index("ix_notes_project_id", "project_id"), Index("ix_notes_milestone_id", "milestone_id"), ) @property def is_task(self) -> bool: return self.status is not None def to_dict(self) -> dict: return { "id": self.id, "title": self.title, "body": self.body, "tags": self.tags or [], "parent_id": self.parent_id, "project_id": self.project_id, "milestone_id": self.milestone_id, "status": self.status, "priority": self.priority, "due_date": self.due_date.isoformat() if self.due_date else None, "is_task": self.is_task, "created_at": self.created_at.isoformat(), "updated_at": self.updated_at.isoformat(), }