From 4263d7118e9c8b88da496bd4985507574815bc4a Mon Sep 17 00:00:00 2001 From: realrafi Date: Tue, 14 Jul 2026 21:28:09 +0330 Subject: [PATCH] refactor: changed the findTasksByTaskPhase to include task info like remark, etc --- .../repositories/task.repository.ts | 44 ++++++++++++------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/src/modules/task-manager/repositories/task.repository.ts b/src/modules/task-manager/repositories/task.repository.ts index 0911473..78c8d90 100644 --- a/src/modules/task-manager/repositories/task.repository.ts +++ b/src/modules/task-manager/repositories/task.repository.ts @@ -49,26 +49,21 @@ export class TaskRepository extends Repository { .getOne(); } - async findTasksByTaskPhase( - taskPhaseId: string, - pagination: CursorPaginationDto, - ): Promise<{ items: TMTask[]; hasMore: boolean }> { + async findTasksByTaskPhase(taskPhaseId: string, pagination: CursorPaginationDto): Promise<{ items: TMTask[]; hasMore: boolean }> { const limit = pagination.limit || 10; const isBackward = pagination.direction === CursorDirection.PREV; - // truncated to milliseconds because a JS Date (and therefore the encoded cursor) only - // has millisecond precision, while Postgres timestamptz stores microseconds - comparing - // the raw column against the cursor would otherwise re-match the boundary row itself. const createdAtExpr = `date_trunc('milliseconds', task.createdAt)`; - const queryBuilder = this.createQueryBuilder("task") + const seekQuery = this.createQueryBuilder("task") + .select(["task.id", "task.priority", "task.createdAt"]) .where("task.taskPhaseId = :taskPhaseId", { taskPhaseId }) .limit(limit + 1); // fetch one extra to check whether there's a further page if (isBackward) { - queryBuilder.orderBy("task.priority", "ASC").addOrderBy(createdAtExpr, "DESC").addOrderBy("task.id", "DESC"); + seekQuery.orderBy("task.priority", "ASC").addOrderBy(createdAtExpr, "DESC").addOrderBy("task.id", "DESC"); } else { - queryBuilder.orderBy("task.priority", "DESC").addOrderBy(createdAtExpr, "ASC").addOrderBy("task.id", "ASC"); + seekQuery.orderBy("task.priority", "DESC").addOrderBy(createdAtExpr, "ASC").addOrderBy("task.id", "ASC"); } if (pagination.cursor) { @@ -76,7 +71,7 @@ export class TaskRepository extends Repository { const priorityOp = isBackward ? ">" : "<"; const seekOp = isBackward ? "<" : ">"; - queryBuilder.andWhere( + seekQuery.andWhere( `(task.priority ${priorityOp} :cursorPriority OR (task.priority = :cursorPriority AND ${createdAtExpr} ${seekOp} :cursorCreatedAt) OR (task.priority = :cursorPriority AND ${createdAtExpr} = :cursorCreatedAt AND task.id ${seekOp} :cursorId))`, @@ -84,13 +79,32 @@ export class TaskRepository extends Repository { ); } - const rows = await queryBuilder.getMany(); - const hasMore = rows.length > limit; - if (hasMore) rows.pop(); + const seekRows = await seekQuery.getMany(); + const hasMore = seekRows.length > limit; + if (hasMore) seekRows.pop(); // backward queries fetch in reverse order to seek from the cursor, so flip back to // the normal display order before returning - const items = isBackward ? rows.reverse() : rows; + const orderedRows = isBackward ? seekRows.reverse() : seekRows; + const ids = orderedRows.map((row) => row.id); + + if (!ids.length) return { items: [], hasMore }; + + // Detail query: hydrates exactly the ids picked above with the relations/counts the + // response needs. IN (:...ids) doesn't preserve order, so re-order to match seekQuery. + const detailRows = await this.createQueryBuilder("task") + .leftJoinAndSelect("task.remarks", "remark") + .loadRelationCountAndMap("task.attachmentCount", "task.attachments") + .loadRelationCountAndMap("task.checkListItemCount", "task.checkListItems") + .loadRelationCountAndMap("task.completedCheckListItemCount", "task.checkListItems", "completedCheckListItems", (qb) => + qb.where("completedCheckListItems.isDone = :isDone", { isDone: true }), + ) + .select(["task", "remark.id", "remark.title", "remark.color"]) + .where("task.id IN (:...ids)", { ids }) + .getMany(); + + const detailById = new Map(detailRows.map((task) => [task.id, task])); + const items = ids.map((id) => detailById.get(id)).filter((task): task is TMTask => task !== undefined); return { items, hasMore }; }