fix(api): modifica fetchChats para trazer mensagens de contatos não salvos

- 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
This commit is contained in:
Leandro Rocha 2025-04-21 00:30:48 -03:00
parent 2ded19752f
commit b94b452597

View File

@ -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;
}