refactor: changed the findTasksByTaskPhase to include task info like remark, etc
This commit is contained in:
@@ -49,26 +49,21 @@ export class TaskRepository extends Repository<TMTask> {
|
|||||||
.getOne();
|
.getOne();
|
||||||
}
|
}
|
||||||
|
|
||||||
async findTasksByTaskPhase(
|
async findTasksByTaskPhase(taskPhaseId: string, pagination: CursorPaginationDto): Promise<{ items: TMTask[]; hasMore: boolean }> {
|
||||||
taskPhaseId: string,
|
|
||||||
pagination: CursorPaginationDto,
|
|
||||||
): Promise<{ items: TMTask[]; hasMore: boolean }> {
|
|
||||||
const limit = pagination.limit || 10;
|
const limit = pagination.limit || 10;
|
||||||
const isBackward = pagination.direction === CursorDirection.PREV;
|
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 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 })
|
.where("task.taskPhaseId = :taskPhaseId", { taskPhaseId })
|
||||||
.limit(limit + 1); // fetch one extra to check whether there's a further page
|
.limit(limit + 1); // fetch one extra to check whether there's a further page
|
||||||
|
|
||||||
if (isBackward) {
|
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 {
|
} 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) {
|
if (pagination.cursor) {
|
||||||
@@ -76,7 +71,7 @@ export class TaskRepository extends Repository<TMTask> {
|
|||||||
const priorityOp = isBackward ? ">" : "<";
|
const priorityOp = isBackward ? ">" : "<";
|
||||||
const seekOp = isBackward ? "<" : ">";
|
const seekOp = isBackward ? "<" : ">";
|
||||||
|
|
||||||
queryBuilder.andWhere(
|
seekQuery.andWhere(
|
||||||
`(task.priority ${priorityOp} :cursorPriority
|
`(task.priority ${priorityOp} :cursorPriority
|
||||||
OR (task.priority = :cursorPriority AND ${createdAtExpr} ${seekOp} :cursorCreatedAt)
|
OR (task.priority = :cursorPriority AND ${createdAtExpr} ${seekOp} :cursorCreatedAt)
|
||||||
OR (task.priority = :cursorPriority AND ${createdAtExpr} = :cursorCreatedAt AND task.id ${seekOp} :cursorId))`,
|
OR (task.priority = :cursorPriority AND ${createdAtExpr} = :cursorCreatedAt AND task.id ${seekOp} :cursorId))`,
|
||||||
@@ -84,13 +79,32 @@ export class TaskRepository extends Repository<TMTask> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const rows = await queryBuilder.getMany();
|
const seekRows = await seekQuery.getMany();
|
||||||
const hasMore = rows.length > limit;
|
const hasMore = seekRows.length > limit;
|
||||||
if (hasMore) rows.pop();
|
if (hasMore) seekRows.pop();
|
||||||
|
|
||||||
// backward queries fetch in reverse order to seek from the cursor, so flip back to
|
// backward queries fetch in reverse order to seek from the cursor, so flip back to
|
||||||
// the normal display order before returning
|
// 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 };
|
return { items, hasMore };
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user