perf(sse+tasks): индекс SSE-соединений, getTaskTree на recursive CTE, батчи N+1
Шаги 1.4 и 1.5 плана production-готовности: - SseConnectionIndex (byOrg/byUser), один heartbeat-таймер, протокол SSE не тронут - getTaskTree/getTaskParentChain: WITH RECURSIVE CTE (было 1+2N запросов) - sync initial/delta: Promise.all по формам - embedding queue/reindex: батч-предзагрузки вместо поштучных запросов - 8 новых тестов (96/96)
This commit is contained in:
@@ -2,7 +2,7 @@ import { users, forms, tasks, taskMessages, messageReads, bots, roles, taskViews
|
||||
import { taskRelations } from "@shared/schema";
|
||||
import { taskAssignees, type TaskAssignee } from "@shared/schema";
|
||||
import { db } from "../db";
|
||||
import { eq, and, desc, exists, sql, gt } from "drizzle-orm";
|
||||
import { eq, and, desc, exists, sql, gt, inArray } from "drizzle-orm";
|
||||
import { formatUserName } from "../utils/formatUserName";
|
||||
import { TasksCoreStorage } from "./tasks-core.storage";
|
||||
import { fieldConditionsMatch, resolveFieldDisplayText } from "../utils/field-conditions";
|
||||
@@ -398,6 +398,32 @@ export class TasksStorage extends TasksCoreStorage {
|
||||
};
|
||||
}
|
||||
|
||||
/** Батч-загрузка сообщений по списку id одним IN-запросом (сырые строки, tenant-фильтр) */
|
||||
async getTaskMessagesByIds(messageIds: number[], organizationId: number): Promise<TaskMessage[]> {
|
||||
if (messageIds.length === 0) return [];
|
||||
return await db
|
||||
.select()
|
||||
.from(taskMessages)
|
||||
.innerJoin(tasks, eq(taskMessages.taskId, tasks.id))
|
||||
.innerJoin(forms, eq(tasks.formId, forms.id))
|
||||
.where(and(inArray(taskMessages.id, messageIds), eq(forms.organizationId, organizationId)))
|
||||
.orderBy(taskMessages.createdAt)
|
||||
.then(results => results.map(r => r.task_messages));
|
||||
}
|
||||
|
||||
/** Батч-загрузка сообщений для списка задач одним IN-запросом (сырые строки, tenant-фильтр) */
|
||||
async getTaskMessagesByTaskIds(taskIds: number[], organizationId: number): Promise<TaskMessage[]> {
|
||||
if (taskIds.length === 0) return [];
|
||||
return await db
|
||||
.select()
|
||||
.from(taskMessages)
|
||||
.innerJoin(tasks, eq(taskMessages.taskId, tasks.id))
|
||||
.innerJoin(forms, eq(tasks.formId, forms.id))
|
||||
.where(and(inArray(taskMessages.taskId, taskIds), eq(forms.organizationId, organizationId)))
|
||||
.orderBy(taskMessages.createdAt)
|
||||
.then(results => results.map(r => r.task_messages));
|
||||
}
|
||||
|
||||
async createTaskMessage(insertMessage: any, organizationId: number): Promise<any> {
|
||||
const taskExists = await db
|
||||
.select({ id: tasks.id })
|
||||
|
||||
Reference in New Issue
Block a user