From b94b4525975d37ff201a43ed4f54bf6565173215 Mon Sep 17 00:00:00 2001 From: Leandro Rocha Date: Mon, 21 Apr 2025 00:30:48 -0300 Subject: [PATCH] =?UTF-8?q?fix(api):=20modifica=20fetchChats=20para=20traz?= =?UTF-8?q?er=20mensagens=20de=20contatos=20n=C3=A3o=20salvos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Muda tabela base da consulta de Contact para Message - Altera INNER JOIN para LEFT JOIN entre Message e Contact - Usa COALESCE para campos que podem estar vazios - Adiciona flag isSaved para identificar contatos salvos/não salvos - Preserva toda funcionalidade de filtros existente Resolve issue #1376 --- src/api/services/channel.service.ts | 146 +++++++++++++--------------- 1 file changed, 68 insertions(+), 78 deletions(-) diff --git a/src/api/services/channel.service.ts b/src/api/services/channel.service.ts index 6d03856e..d58997c6 100644 --- a/src/api/services/channel.service.ts +++ b/src/api/services/channel.service.ts @@ -682,13 +682,6 @@ export class ChannelStartupService { : createJid(query.where?.remoteJid) : null; - const limit = - query.offset && !query.page - ? Prisma.sql` LIMIT ${query.offset}` - : query.offset && query.page - ? Prisma.sql` LIMIT ${query.offset} OFFSET ${((query.page as number) - 1) * query.offset}` - : Prisma.sql``; - const where = { instanceId: this.instanceId, }; @@ -700,91 +693,88 @@ export class ChannelStartupService { const timestampFilter = query?.where?.messageTimestamp?.gte && query?.where?.messageTimestamp?.lte ? Prisma.sql` - AND "Message"."messageTimestamp" >= ${Math.floor(new Date(query.where.messageTimestamp.gte).getTime() / 1000)} - AND "Message"."messageTimestamp" <= ${Math.floor(new Date(query.where.messageTimestamp.lte).getTime() / 1000)}` + AND "Message"."messageTimestamp" >= ${Math.floor(new Date(query.where.messageTimestamp.gte).getTime() / 1000)} + AND "Message"."messageTimestamp" <= ${Math.floor(new Date(query.where.messageTimestamp.lte).getTime() / 1000)}` : Prisma.sql``; const results = await this.prismaRepository.$queryRaw` - WITH rankedMessages AS ( - SELECT DISTINCT ON ("Contact"."remoteJid") - "Contact"."id", - "Contact"."remoteJid", - "Contact"."pushName", - "Contact"."profilePicUrl", - COALESCE( - to_timestamp("Message"."messageTimestamp"::double precision), - "Contact"."updatedAt" - ) as "updatedAt", - "Chat"."name" as "chatName", - "Chat"."createdAt" as "windowStart", - "Chat"."createdAt" + INTERVAL '24 hours' as "windowExpires", - CASE - WHEN "Chat"."createdAt" + INTERVAL '24 hours' > NOW() THEN true - ELSE false - END as "windowActive", - "Message"."id" AS lastMessageId, - "Message"."key" AS lastMessage_key, - "Message"."pushName" AS lastMessagePushName, - "Message"."participant" AS lastMessageParticipant, - "Message"."messageType" AS lastMessageMessageType, - "Message"."message" AS lastMessageMessage, - "Message"."contextInfo" AS lastMessageContextInfo, - "Message"."source" AS lastMessageSource, - "Message"."messageTimestamp" AS lastMessageMessageTimestamp, - "Message"."instanceId" AS lastMessageInstanceId, - "Message"."sessionId" AS lastMessageSessionId, - "Message"."status" AS lastMessageStatus - FROM "Contact" - INNER JOIN "Message" ON "Message"."key"->>'remoteJid' = "Contact"."remoteJid" - LEFT JOIN "Chat" ON "Chat"."remoteJid" = "Contact"."remoteJid" - AND "Chat"."instanceId" = "Contact"."instanceId" - WHERE - "Contact"."instanceId" = ${this.instanceId} - AND "Message"."instanceId" = ${this.instanceId} - ${remoteJid ? Prisma.sql`AND "Contact"."remoteJid" = ${remoteJid}` : Prisma.sql``} - ${timestampFilter} - ORDER BY - "Contact"."remoteJid", - "Message"."messageTimestamp" DESC - ${limit} - ) - SELECT * FROM rankedMessages - ORDER BY "updatedAt" DESC NULLS LAST; + WITH rankedMessages AS ( + SELECT DISTINCT ON ("Message"."key"->>'remoteJid') + "Contact"."id" as "contactId", + "Message"."key"->>'remoteJid' as "remoteJid", + COALESCE("Contact"."pushName", "Message"."pushName") as "pushName", + "Contact"."profilePicUrl", + COALESCE( + to_timestamp("Message"."messageTimestamp"::double precision), + "Contact"."updatedAt" + ) as "updatedAt", + "Chat"."createdAt" as "windowStart", + "Chat"."createdAt" + INTERVAL '24 hours' as "windowExpires", + CASE WHEN "Chat"."createdAt" + INTERVAL '24 hours' > NOW() THEN true ELSE false END as "windowActive", + "Message"."id" AS lastMessageId, + "Message"."key" AS lastMessage_key, + "Message"."pushName" AS lastMessagePushName, + "Message"."participant" AS lastMessageParticipant, + "Message"."messageType" AS lastMessageMessageType, + "Message"."message" AS lastMessageMessage, + "Message"."contextInfo" AS lastMessageContextInfo, + "Message"."source" AS lastMessageSource, + "Message"."messageTimestamp" AS lastMessageMessageTimestamp, + "Message"."instanceId" AS lastMessageInstanceId, + "Message"."sessionId" AS lastMessageSessionId, + "Message"."status" AS lastMessageStatus + FROM "Message" + LEFT JOIN "Contact" ON "Contact"."remoteJid" = "Message"."key"->>'remoteJid' AND "Contact"."instanceId" = "Message"."instanceId" + LEFT JOIN "Chat" ON "Chat"."remoteJid" = "Message"."key"->>'remoteJid' AND "Chat"."instanceId" = "Message"."instanceId" + WHERE "Message"."instanceId" = ${this.instanceId} + ${remoteJid ? Prisma.sql`AND "Message"."key"->>'remoteJid' = ${remoteJid}` : Prisma.sql``} + ${timestampFilter} + ORDER BY "Message"."key"->>'remoteJid', "Message"."messageTimestamp" DESC + ) + SELECT * FROM rankedMessages + ORDER BY "updatedAt" DESC NULLS LAST; `; - if (results && isArray(results) && results.length > 0) { - const mappedResults = results.map((contact) => { - const lastMessage = contact.lastMessageId + if (results && Array.isArray(results) && results.length > 0) { + const mappedResults = results.map((item) => { + const lastMessage = item.lastMessageId ? { - id: contact.lastMessageId, - key: contact.lastMessageKey, - pushName: contact.lastMessagePushName, - participant: contact.lastMessageParticipant, - messageType: contact.lastMessageMessageType, - message: contact.lastMessageMessage, - contextInfo: contact.lastMessageContextInfo, - source: contact.lastMessageSource, - messageTimestamp: contact.lastMessageMessageTimestamp, - instanceId: contact.lastMessageInstanceId, - sessionId: contact.lastMessageSessionId, - status: contact.lastMessageStatus, + id: item.lastMessageId, + key: item.lastMessage_key, + pushName: item.lastMessagePushName, + participant: item.lastMessageParticipant, + messageType: item.lastMessageMessageType, + message: item.lastMessageMessage, + contextInfo: item.lastMessageContextInfo, + source: item.lastMessageSource, + messageTimestamp: item.lastMessageMessageTimestamp, + instanceId: item.lastMessageInstanceId, + sessionId: item.lastMessageSessionId, + status: item.lastMessageStatus, } : undefined; return { - id: contact.id, - remoteJid: contact.remoteJid, - pushName: contact.pushName, - chatName: contact.chatName, - profilePicUrl: contact.profilePicUrl, - updatedAt: contact.updatedAt, - windowStart: contact.windowStart, - windowExpires: contact.windowExpires, - windowActive: contact.windowActive, + id: item.contactId || null, + remoteJid: item.remoteJid, + pushName: item.pushName, + profilePicUrl: item.profilePicUrl, + updatedAt: item.updatedAt, + windowStart: item.windowStart, + windowExpires: item.windowExpires, + windowActive: item.windowActive, lastMessage: lastMessage ? this.cleanMessageData(lastMessage) : undefined, + unreadCount: 0, + isSaved: !!item.contactId, }; }); + if (query?.take && query?.skip) { + const skip = query.skip || 0; + const take = query.take || 20; + return mappedResults.slice(skip, skip + take); + } + return mappedResults; }