Files
scoreodonto.com/backend/dist/modules/chats/chat.repository.js
T

168 lines
6.9 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ChatRepository = void 0;
const prisma_1 = require("../../infra/database/prisma");
class ChatRepository {
async findAllByInstance(tenantId, instanceId, opts = {}) {
const { limit = 200, search, archived = false } = opts;
// ── Q1: chats (sem includes — bate o N+1) ────────────────────────────────
const chats = await prisma_1.prisma.chat.findMany({
where: {
tenantId,
instanceId,
isArchived: archived,
NOT: { OR: [
{ jid: { endsWith: '@lid' } },
{ jid: { contains: '@broadcast' } },
{ jid: { endsWith: '@newsletter' } },
] },
...(search
? {
OR: [
{ jid: { contains: search, mode: 'insensitive' } },
{ contact: { name: { contains: search, mode: 'insensitive' } } },
{ contact: { notify: { contains: search, mode: 'insensitive' } } },
{ contact: { phone: { contains: search, mode: 'insensitive' } } },
],
}
: {}),
},
orderBy: [
{ isPinned: 'desc' },
{ lastMessageAt: { sort: 'desc', nulls: 'last' } },
{ createdAt: 'desc' },
],
take: limit,
});
if (chats.length === 0) {
return [];
}
const chatIds = chats.map((c) => c.id);
const contactIds = Array.from(new Set(chats.map((c) => c.contactId).filter((x) => !!x)));
// ── Q2/Q3/Q4 em paralelo: contatos, protocols (1 por chat), last msg (1 por chat) ──
const [contacts, protocols, lastMsgs] = await Promise.all([
contactIds.length > 0
? prisma_1.prisma.contact.findMany({
where: { id: { in: contactIds } },
select: {
id: true,
name: true,
notify: true,
verifiedName: true,
phone: true,
avatarUrl: true,
scoreReputacao: true,
flagRestricao: true,
},
})
: Promise.resolve([]),
// DISTINCT ON: 1 query batch — pega o protocolo aberto mais recente por chat
prisma_1.prisma.$queryRaw `
SELECT DISTINCT ON ("chatId") "chatId", number, status::text AS status
FROM protocols
WHERE "chatId" = ANY(${chatIds}::text[])
AND status IN ('OPEN','IN_PROGRESS','WAITING_CLIENT','WAITING_AGENT')
ORDER BY "chatId", "createdAt" DESC
`,
// DISTINCT ON: 1 query batch — pega a última msg por chat
prisma_1.prisma.$queryRaw `
SELECT DISTINCT ON ("chatId") "chatId", body, "fromMe", status::text AS status, timestamp, type::text AS type, "pushName"
FROM messages
WHERE "chatId" = ANY(${chatIds}::text[])
ORDER BY "chatId", timestamp DESC
`,
]);
// ── Indexa para lookup O(1) ──────────────────────────────────────────────
const contactById = new Map(contacts.map((c) => [c.id, c]));
const protocolByChat = new Map(protocols.map((p) => [p.chatId, p]));
const lastMsgByChat = new Map(lastMsgs.map((m) => [m.chatId, m]));
// ── Re-monta a estrutura no formato esperado pelo chat.routes.ts ─────────
return chats.map((c) => {
const contact = c.contactId ? contactById.get(c.contactId) ?? null : null;
const protocol = protocolByChat.get(c.id);
const lastMsg = lastMsgByChat.get(c.id);
return {
...c,
contact: contact
? {
name: contact.name,
notify: contact.notify,
verifiedName: contact.verifiedName,
phone: contact.phone,
avatarUrl: contact.avatarUrl,
scoreReputacao: contact.scoreReputacao,
flagRestricao: contact.flagRestricao,
}
: null,
protocols: protocol
? [{ number: protocol.number, status: protocol.status }]
: [],
messages: lastMsg
? [{
body: lastMsg.body,
fromMe: lastMsg.fromMe,
status: lastMsg.status,
timestamp: lastMsg.timestamp,
type: lastMsg.type,
pushName: lastMsg.pushName,
}]
: [],
};
});
}
async findById(id, tenantId) {
return prisma_1.prisma.chat.findFirst({
where: { id, tenantId },
include: {
contact: true,
protocols: {
where: { status: { in: ['OPEN', 'IN_PROGRESS', 'WAITING_CLIENT', 'WAITING_AGENT'] } },
take: 1,
orderBy: { createdAt: 'desc' },
},
},
});
}
async findByJid(tenantId, instanceId, jid) {
return prisma_1.prisma.chat.findUnique({
where: { tenantId_instanceId_jid: { tenantId, instanceId, jid } },
include: { contact: true },
});
}
async clearUnread(id, tenantId) {
return prisma_1.prisma.chat.updateMany({
where: { id, tenantId },
data: { unreadCount: 0 },
});
}
async setArchived(id, tenantId, archived) {
return prisma_1.prisma.chat.updateMany({
where: { id, tenantId },
data: { isArchived: archived },
});
}
async setPinned(id, tenantId, pinned) {
return prisma_1.prisma.chat.updateMany({
where: { id, tenantId },
data: { isPinned: pinned },
});
}
async countUnreadByInstance(tenantId, instanceId) {
const result = await prisma_1.prisma.chat.aggregate({
where: {
tenantId,
instanceId,
isArchived: false,
NOT: { OR: [
{ jid: { endsWith: '@lid' } },
{ jid: { contains: '@broadcast' } },
{ jid: { endsWith: '@newsletter' } },
] }
},
_sum: { unreadCount: true },
});
return result._sum.unreadCount ?? 0;
}
}
exports.ChatRepository = ChatRepository;