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,
|
MessageOut,
|
||||||
ProjectFileOut,
|
ProjectFileOut,
|
||||||
StepOut,
|
StepOut,
|
||||||
|
SubtaskBrief,
|
||||||
TaskOut,
|
TaskOut,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -95,6 +96,25 @@ def message_out(m: Message) -> MessageOut:
|
|||||||
|
|
||||||
def task_out(t: Task, project_slug: str = "") -> TaskOut:
|
def task_out(t: Task, project_slug: str = "") -> TaskOut:
|
||||||
prefix = project_slug[:2].upper() if project_slug else "XX"
|
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(
|
return TaskOut(
|
||||||
id=str(t.id),
|
id=str(t.id),
|
||||||
project_id=str(t.project_id),
|
project_id=str(t.project_id),
|
||||||
@ -116,6 +136,9 @@ def task_out(t: Task, project_slug: str = "") -> TaskOut:
|
|||||||
position=t.position,
|
position=t.position,
|
||||||
time_spent=t.time_spent,
|
time_spent=t.time_spent,
|
||||||
steps=[step_out(s) for s in (t.steps or [])],
|
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 "",
|
created_at=t.created_at.isoformat() if t.created_at else "",
|
||||||
updated_at=t.updated_at.isoformat() if t.updated_at else "",
|
updated_at=t.updated_at.isoformat() if t.updated_at else "",
|
||||||
)
|
)
|
||||||
|
|||||||
@ -47,10 +47,21 @@ class TaskOut(BaseModel):
|
|||||||
position: int
|
position: int
|
||||||
time_spent: int
|
time_spent: int
|
||||||
steps: list[StepOut] = []
|
steps: list[StepOut] = []
|
||||||
|
subtasks: list["SubtaskBrief"] = []
|
||||||
|
parent_key: str | None = None
|
||||||
|
parent_title: str | None = None
|
||||||
created_at: str
|
created_at: str
|
||||||
updated_at: str
|
updated_at: str
|
||||||
|
|
||||||
|
|
||||||
|
class SubtaskBrief(BaseModel):
|
||||||
|
id: str
|
||||||
|
key: str
|
||||||
|
title: str
|
||||||
|
status: str
|
||||||
|
assignee: MemberBrief | None = None
|
||||||
|
|
||||||
|
|
||||||
class MessageOut(BaseModel):
|
class MessageOut(BaseModel):
|
||||||
id: str
|
id: str
|
||||||
chat_id: str | None = None
|
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))
|
select(Task).where(Task.id == uuid.UUID(task_id))
|
||||||
.options(
|
.options(
|
||||||
selectinload(Task.steps),
|
selectinload(Task.steps),
|
||||||
|
selectinload(Task.subtasks).joinedload(Task.assignee),
|
||||||
joinedload(Task.project),
|
joinedload(Task.project),
|
||||||
joinedload(Task.assignee),
|
joinedload(Task.assignee),
|
||||||
joinedload(Task.reviewer),
|
joinedload(Task.reviewer),
|
||||||
|
joinedload(Task.parent),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
task = result.scalar_one_or_none()
|
task = result.unique().scalar_one_or_none()
|
||||||
if not task:
|
if not task:
|
||||||
raise HTTPException(404, "Task not found")
|
raise HTTPException(404, "Task not found")
|
||||||
return task
|
return task
|
||||||
@ -221,9 +223,11 @@ async def list_tasks(
|
|||||||
):
|
):
|
||||||
q = select(Task).options(
|
q = select(Task).options(
|
||||||
selectinload(Task.steps),
|
selectinload(Task.steps),
|
||||||
|
selectinload(Task.subtasks).joinedload(Task.assignee),
|
||||||
joinedload(Task.project),
|
joinedload(Task.project),
|
||||||
joinedload(Task.assignee),
|
joinedload(Task.assignee),
|
||||||
joinedload(Task.reviewer),
|
joinedload(Task.reviewer),
|
||||||
|
joinedload(Task.parent),
|
||||||
)
|
)
|
||||||
if project_id:
|
if project_id:
|
||||||
q = q.where(Task.project_id == uuid.UUID(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.where(Task.labels.contains([label]))
|
||||||
q = q.order_by(Task.position, Task.created_at)
|
q = q.order_by(Task.position, Task.created_at)
|
||||||
result = await db.execute(q)
|
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)
|
@router.get("/tasks/{task_id}", response_model=TaskOut)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user