Subtasks: load subtasks + parent in task_out
Some checks failed
Deploy Tracker / deploy (push) Failing after 3s
Some checks failed
Deploy Tracker / deploy (push) Failing after 3s
- selectinload(Task.subtasks), joinedload(Task.parent) in _get_task + list_tasks - SubtaskBrief schema: id, key, title, status, assignee - TaskOut: subtasks list, parent_key, parent_title - .unique() for joinedload dedup
This commit is contained in:
parent
502b55b5a9
commit
a4ac2a6471
@ -10,6 +10,7 @@ from .schemas import (
|
||||
MessageOut,
|
||||
ProjectFileOut,
|
||||
StepOut,
|
||||
SubtaskBrief,
|
||||
TaskOut,
|
||||
)
|
||||
|
||||
@ -95,6 +96,25 @@ def message_out(m: Message) -> MessageOut:
|
||||
|
||||
def task_out(t: Task, project_slug: str = "") -> TaskOut:
|
||||
prefix = project_slug[:2].upper() if project_slug else "XX"
|
||||
|
||||
# Subtasks
|
||||
subtasks = []
|
||||
for sub in (t.subtasks or []):
|
||||
subtasks.append(SubtaskBrief(
|
||||
id=str(sub.id),
|
||||
key=f"{prefix}-{sub.number}",
|
||||
title=sub.title,
|
||||
status=sub.status,
|
||||
assignee=member_brief(sub.assignee) if sub.assignee else None,
|
||||
))
|
||||
|
||||
# Parent info
|
||||
parent_key = None
|
||||
parent_title = None
|
||||
if t.parent:
|
||||
parent_key = f"{prefix}-{t.parent.number}"
|
||||
parent_title = t.parent.title
|
||||
|
||||
return TaskOut(
|
||||
id=str(t.id),
|
||||
project_id=str(t.project_id),
|
||||
@ -116,6 +136,9 @@ def task_out(t: Task, project_slug: str = "") -> TaskOut:
|
||||
position=t.position,
|
||||
time_spent=t.time_spent,
|
||||
steps=[step_out(s) for s in (t.steps or [])],
|
||||
subtasks=subtasks,
|
||||
parent_key=parent_key,
|
||||
parent_title=parent_title,
|
||||
created_at=t.created_at.isoformat() if t.created_at else "",
|
||||
updated_at=t.updated_at.isoformat() if t.updated_at else "",
|
||||
)
|
||||
|
||||
@ -47,10 +47,21 @@ class TaskOut(BaseModel):
|
||||
position: int
|
||||
time_spent: int
|
||||
steps: list[StepOut] = []
|
||||
subtasks: list["SubtaskBrief"] = []
|
||||
parent_key: str | None = None
|
||||
parent_title: str | None = None
|
||||
created_at: str
|
||||
updated_at: str
|
||||
|
||||
|
||||
class SubtaskBrief(BaseModel):
|
||||
id: str
|
||||
key: str
|
||||
title: str
|
||||
status: str
|
||||
assignee: MemberBrief | None = None
|
||||
|
||||
|
||||
class MessageOut(BaseModel):
|
||||
id: str
|
||||
chat_id: str | None = None
|
||||
|
||||
@ -189,12 +189,14 @@ async def _get_task(task_id: str, db: AsyncSession) -> Task:
|
||||
select(Task).where(Task.id == uuid.UUID(task_id))
|
||||
.options(
|
||||
selectinload(Task.steps),
|
||||
selectinload(Task.subtasks).joinedload(Task.assignee),
|
||||
joinedload(Task.project),
|
||||
joinedload(Task.assignee),
|
||||
joinedload(Task.reviewer),
|
||||
joinedload(Task.parent),
|
||||
)
|
||||
)
|
||||
task = result.scalar_one_or_none()
|
||||
task = result.unique().scalar_one_or_none()
|
||||
if not task:
|
||||
raise HTTPException(404, "Task not found")
|
||||
return task
|
||||
@ -221,9 +223,11 @@ async def list_tasks(
|
||||
):
|
||||
q = select(Task).options(
|
||||
selectinload(Task.steps),
|
||||
selectinload(Task.subtasks).joinedload(Task.assignee),
|
||||
joinedload(Task.project),
|
||||
joinedload(Task.assignee),
|
||||
joinedload(Task.reviewer),
|
||||
joinedload(Task.parent),
|
||||
)
|
||||
if project_id:
|
||||
q = q.where(Task.project_id == uuid.UUID(project_id))
|
||||
@ -235,7 +239,7 @@ async def list_tasks(
|
||||
q = q.where(Task.labels.contains([label]))
|
||||
q = q.order_by(Task.position, Task.created_at)
|
||||
result = await db.execute(q)
|
||||
return [task_out(t, t.project.slug if t.project else "") for t in result.scalars()]
|
||||
return [task_out(t, t.project.slug if t.project else "") for t in result.unique().scalars()]
|
||||
|
||||
|
||||
@router.get("/tasks/{task_id}", response_model=TaskOut)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user