Adding lazy='raise' to relationships with cascade='all, delete-orphan' broke db.delete() — SQLAlchemy tried to lazy-load related objects for Python-side cascade but lazy='raise' blocked it with MissingGreenlet. Fix: Add passive_deletes=True to subtasks, comments, assignments, tasks, and members relationships. This tells SQLAlchemy to defer cascade to PostgreSQL's ondelete=CASCADE FK constraint instead of loading objects in Python. Both the FK and ORM cascade are now aligned. Also added onError handler to deleteTaskMutation so failures are visible via toast instead of failing silently. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
29 lines
1.6 KiB
Python
29 lines
1.6 KiB
Python
import sqlalchemy as sa
|
|
from sqlalchemy import Boolean, String, Text, Date, Integer, ForeignKey, func
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
from datetime import datetime, date
|
|
from typing import Optional, List
|
|
from app.database import Base
|
|
|
|
|
|
class Project(Base):
|
|
__tablename__ = "projects"
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True, index=True)
|
|
user_id: Mapped[int] = mapped_column(
|
|
Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
name: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
description: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
|
|
status: Mapped[str] = mapped_column(String(20), default="not_started")
|
|
color: Mapped[Optional[str]] = mapped_column(String(20), nullable=True)
|
|
due_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True)
|
|
is_tracked: Mapped[bool] = mapped_column(Boolean, default=False, server_default=sa.false())
|
|
created_at: Mapped[datetime] = mapped_column(default=func.now())
|
|
updated_at: Mapped[datetime] = mapped_column(default=func.now(), onupdate=func.now())
|
|
|
|
# Relationships — lazy="raise" to prevent N+1 (mirrors CalendarMember pattern)
|
|
tasks: Mapped[List["ProjectTask"]] = relationship(back_populates="project", cascade="all, delete-orphan", passive_deletes=True, lazy="raise")
|
|
todos: Mapped[List["Todo"]] = relationship(back_populates="project", lazy="raise")
|
|
members: Mapped[List["ProjectMember"]] = relationship(back_populates="project", cascade="all, delete-orphan", passive_deletes=True, lazy="raise")
|