Skip to content

Commit bafd209

Browse files
Merge pull request #2333 from augustolima1/fix/mysql-compat-lid
fix(mysql): compatibilidade da coluna lid e queries RAW
2 parents 7fd7219 + ce51b13 commit bafd209

File tree

6 files changed

+359
-154
lines changed

6 files changed

+359
-154
lines changed

prisma/mysql-migrations/20250918183910_add_kafka_integration/migration.sql

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,7 @@ ALTER TABLE `IntegrationSession` MODIFY `createdAt` TIMESTAMP NULL DEFAULT CURRE
131131
MODIFY `updatedAt` TIMESTAMP NOT NULL;
132132

133133
-- AlterTable
134-
ALTER TABLE `IsOnWhatsapp` DROP COLUMN `lid`,
135-
MODIFY `createdAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
134+
ALTER TABLE `IsOnWhatsapp` MODIFY `createdAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
136135
MODIFY `updatedAt` TIMESTAMP NOT NULL;
137136

138137
-- AlterTable
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
-- Re-add lid column that was incorrectly dropped by previous migration
2+
-- This migration ensures backward compatibility for existing installations
3+
4+
-- Check if column exists before adding
5+
SET @dbname = DATABASE();
6+
SET @tablename = 'IsOnWhatsapp';
7+
SET @columnname = 'lid';
8+
SET @preparedStatement = (SELECT IF(
9+
(
10+
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
11+
WHERE
12+
(table_name = @tablename)
13+
AND (table_schema = @dbname)
14+
AND (column_name = @columnname)
15+
) > 0,
16+
'SELECT 1',
17+
CONCAT('ALTER TABLE `', @tablename, '` ADD COLUMN `', @columnname, '` VARCHAR(100);')
18+
));
19+
PREPARE alterIfNotExists FROM @preparedStatement;
20+
EXECUTE alterIfNotExists;
21+
DEALLOCATE PREPARE alterIfNotExists;

prisma/mysql-schema.prisma

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,7 @@ model IsOnWhatsapp {
655655
id String @id @default(cuid())
656656
remoteJid String @unique @db.VarChar(100)
657657
jidOptions String
658+
lid String? @db.VarChar(100)
658659
createdAt DateTime @default(dbgenerated("CURRENT_TIMESTAMP")) @db.Timestamp
659660
updatedAt DateTime @updatedAt @db.Timestamp
660661
}

src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts

Lines changed: 167 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -567,12 +567,27 @@ export class BaileysStartupService extends ChannelStartupService {
567567

568568
private async getMessage(key: proto.IMessageKey, full = false) {
569569
try {
570-
// Use raw SQL to avoid JSON path issues
571-
const webMessageInfo = (await this.prismaRepository.$queryRaw`
572-
SELECT * FROM "Message"
573-
WHERE "instanceId" = ${this.instanceId}
574-
AND "key"->>'id' = ${key.id}
575-
`) as proto.IWebMessageInfo[];
570+
const provider = this.configService.get<Database>('DATABASE').PROVIDER;
571+
572+
let webMessageInfo: proto.IWebMessageInfo[];
573+
574+
if (provider === 'mysql') {
575+
// MySQL version
576+
webMessageInfo = (await this.prismaRepository.$queryRaw`
577+
SELECT * FROM Message
578+
WHERE instanceId = ${this.instanceId}
579+
AND JSON_UNQUOTE(JSON_EXTRACT(\`key\`, '$.id')) = ${key.id}
580+
LIMIT 1
581+
`) as proto.IWebMessageInfo[];
582+
} else {
583+
// PostgreSQL version
584+
webMessageInfo = (await this.prismaRepository.$queryRaw`
585+
SELECT * FROM "Message"
586+
WHERE "instanceId" = ${this.instanceId}
587+
AND "key"->>'id' = ${key.id}
588+
LIMIT 1
589+
`) as proto.IWebMessageInfo[];
590+
}
576591

577592
if (full) {
578593
return webMessageInfo[0];
@@ -1687,29 +1702,25 @@ export class BaileysStartupService extends ChannelStartupService {
16871702
}
16881703

16891704
const searchId = originalMessageId || key.id;
1690-
1691-
let retries = 0;
1692-
const maxRetries = 3;
1693-
const retryDelay = 500; // 500ms delay to avoid blocking for too long
1694-
1695-
while (retries < maxRetries) {
1696-
const messages = (await this.prismaRepository.$queryRaw`
1705+
const dbProvider = this.configService.get<Database>('DATABASE').PROVIDER;
1706+
1707+
let messages: any[];
1708+
if (dbProvider === 'mysql') {
1709+
messages = (await this.prismaRepository.$queryRaw`
1710+
SELECT * FROM Message
1711+
WHERE instanceId = ${this.instanceId}
1712+
AND JSON_UNQUOTE(JSON_EXTRACT(\`key\`, '$.id')) = ${searchId}
1713+
LIMIT 1
1714+
`) as any[];
1715+
} else {
1716+
messages = (await this.prismaRepository.$queryRaw`
16971717
SELECT * FROM "Message"
16981718
WHERE "instanceId" = ${this.instanceId}
16991719
AND "key"->>'id' = ${searchId}
17001720
LIMIT 1
17011721
`) as any[];
1702-
findMessage = messages[0] || null;
1703-
1704-
if (findMessage?.id) {
1705-
break;
1706-
}
1707-
1708-
retries++;
1709-
if (retries < maxRetries) {
1710-
await delay(retryDelay);
1711-
}
17121722
}
1723+
findMessage = messages[0] || null;
17131724

17141725
if (!findMessage?.id) {
17151726
this.logger.verbose(
@@ -4835,16 +4846,32 @@ export class BaileysStartupService extends ChannelStartupService {
48354846
private async updateMessagesReadedByTimestamp(remoteJid: string, timestamp?: number): Promise<number> {
48364847
if (timestamp === undefined || timestamp === null) return 0;
48374848

4838-
// Use raw SQL to avoid JSON path issues
4839-
const result = await this.prismaRepository.$executeRaw`
4840-
UPDATE "Message"
4841-
SET "status" = ${status[4]}
4842-
WHERE "instanceId" = ${this.instanceId}
4843-
AND "key"->>'remoteJid' = ${remoteJid}
4844-
AND ("key"->>'fromMe')::boolean = false
4845-
AND "messageTimestamp" <= ${timestamp}
4846-
AND ("status" IS NULL OR "status" = ${status[3]})
4847-
`;
4849+
const provider = this.configService.get<Database>('DATABASE').PROVIDER;
4850+
let result: number;
4851+
4852+
if (provider === 'mysql') {
4853+
// MySQL version
4854+
result = await this.prismaRepository.$executeRaw`
4855+
UPDATE Message
4856+
SET status = ${status[4]}
4857+
WHERE instanceId = ${this.instanceId}
4858+
AND JSON_UNQUOTE(JSON_EXTRACT(\`key\`, '$.remoteJid')) = ${remoteJid}
4859+
AND JSON_UNQUOTE(JSON_EXTRACT(\`key\`, '$.fromMe')) = 'false'
4860+
AND messageTimestamp <= ${timestamp}
4861+
AND (status IS NULL OR status = ${status[3]})
4862+
`;
4863+
} else {
4864+
// PostgreSQL version
4865+
result = await this.prismaRepository.$executeRaw`
4866+
UPDATE "Message"
4867+
SET "status" = ${status[4]}
4868+
WHERE "instanceId" = ${this.instanceId}
4869+
AND "key"->>'remoteJid' = ${remoteJid}
4870+
AND ("key"->>'fromMe')::boolean = false
4871+
AND "messageTimestamp" <= ${timestamp}
4872+
AND ("status" IS NULL OR "status" = ${status[3]})
4873+
`;
4874+
}
48484875

48494876
if (result) {
48504877
if (result > 0) {
@@ -4858,16 +4885,33 @@ export class BaileysStartupService extends ChannelStartupService {
48584885
}
48594886

48604887
private async updateChatUnreadMessages(remoteJid: string): Promise<number> {
4861-
const [chat, unreadMessages] = await Promise.all([
4862-
this.prismaRepository.chat.findFirst({ where: { remoteJid } }),
4863-
// Use raw SQL to avoid JSON path issues
4864-
this.prismaRepository.$queryRaw`
4888+
const provider = this.configService.get<Database>('DATABASE').PROVIDER;
4889+
4890+
let unreadMessagesPromise: Promise<number>;
4891+
4892+
if (provider === 'mysql') {
4893+
// MySQL version
4894+
unreadMessagesPromise = this.prismaRepository.$queryRaw`
4895+
SELECT COUNT(*) as count FROM Message
4896+
WHERE instanceId = ${this.instanceId}
4897+
AND JSON_UNQUOTE(JSON_EXTRACT(\`key\`, '$.remoteJid')) = ${remoteJid}
4898+
AND JSON_UNQUOTE(JSON_EXTRACT(\`key\`, '$.fromMe')) = 'false'
4899+
AND status = ${status[3]}
4900+
`.then((result: any[]) => Number(result[0]?.count) || 0);
4901+
} else {
4902+
// PostgreSQL version
4903+
unreadMessagesPromise = this.prismaRepository.$queryRaw`
48654904
SELECT COUNT(*)::int as count FROM "Message"
48664905
WHERE "instanceId" = ${this.instanceId}
48674906
AND "key"->>'remoteJid' = ${remoteJid}
48684907
AND ("key"->>'fromMe')::boolean = false
48694908
AND "status" = ${status[3]}
4870-
`.then((result: any[]) => result[0]?.count || 0),
4909+
`.then((result: any[]) => result[0]?.count || 0);
4910+
}
4911+
4912+
const [chat, unreadMessages] = await Promise.all([
4913+
this.prismaRepository.chat.findFirst({ where: { remoteJid } }),
4914+
unreadMessagesPromise,
48714915
]);
48724916

48734917
if (chat && chat.unreadMessages !== unreadMessages) {
@@ -4879,50 +4923,95 @@ export class BaileysStartupService extends ChannelStartupService {
48794923

48804924
private async addLabel(labelId: string, instanceId: string, chatId: string) {
48814925
const id = cuid();
4882-
4883-
await this.prismaRepository.$executeRawUnsafe(
4884-
`INSERT INTO "Chat" ("id", "instanceId", "remoteJid", "labels", "createdAt", "updatedAt")
4885-
VALUES ($4, $2, $3, to_jsonb(ARRAY[$1]::text[]), NOW(), NOW()) ON CONFLICT ("instanceId", "remoteJid")
4886-
DO
4887-
UPDATE
4888-
SET "labels" = (
4889-
SELECT to_jsonb(array_agg(DISTINCT elem))
4890-
FROM (
4891-
SELECT jsonb_array_elements_text("Chat"."labels") AS elem
4892-
UNION
4893-
SELECT $1::text AS elem
4894-
) sub
4895-
),
4896-
"updatedAt" = NOW();`,
4897-
labelId,
4898-
instanceId,
4899-
chatId,
4900-
id,
4901-
);
4926+
const provider = this.configService.get<Database>('DATABASE').PROVIDER;
4927+
4928+
if (provider === 'mysql') {
4929+
// MySQL version - use INSERT ... ON DUPLICATE KEY UPDATE
4930+
await this.prismaRepository.$executeRawUnsafe(
4931+
`INSERT INTO Chat (id, instanceId, remoteJid, labels, createdAt, updatedAt)
4932+
VALUES (?, ?, ?, JSON_ARRAY(?), NOW(), NOW())
4933+
ON DUPLICATE KEY UPDATE
4934+
labels = JSON_ARRAY_APPEND(
4935+
COALESCE(labels, JSON_ARRAY()),
4936+
'$',
4937+
?
4938+
),
4939+
updatedAt = NOW()`,
4940+
id,
4941+
instanceId,
4942+
chatId,
4943+
labelId,
4944+
labelId,
4945+
);
4946+
} else {
4947+
// PostgreSQL version
4948+
await this.prismaRepository.$executeRawUnsafe(
4949+
`INSERT INTO "Chat" ("id", "instanceId", "remoteJid", "labels", "createdAt", "updatedAt")
4950+
VALUES ($4, $2, $3, to_jsonb(ARRAY[$1]::text[]), NOW(), NOW()) ON CONFLICT ("instanceId", "remoteJid")
4951+
DO
4952+
UPDATE
4953+
SET "labels" = (
4954+
SELECT to_jsonb(array_agg(DISTINCT elem))
4955+
FROM (
4956+
SELECT jsonb_array_elements_text("Chat"."labels") AS elem
4957+
UNION
4958+
SELECT $1::text AS elem
4959+
) sub
4960+
),
4961+
"updatedAt" = NOW();`,
4962+
labelId,
4963+
instanceId,
4964+
chatId,
4965+
id,
4966+
);
4967+
}
49024968
}
49034969

49044970
private async removeLabel(labelId: string, instanceId: string, chatId: string) {
49054971
const id = cuid();
4906-
4907-
await this.prismaRepository.$executeRawUnsafe(
4908-
`INSERT INTO "Chat" ("id", "instanceId", "remoteJid", "labels", "createdAt", "updatedAt")
4909-
VALUES ($4, $2, $3, '[]'::jsonb, NOW(), NOW()) ON CONFLICT ("instanceId", "remoteJid")
4910-
DO
4911-
UPDATE
4912-
SET "labels" = COALESCE (
4913-
(
4914-
SELECT jsonb_agg(elem)
4915-
FROM jsonb_array_elements_text("Chat"."labels") AS elem
4916-
WHERE elem <> $1
4917-
),
4918-
'[]'::jsonb
4919-
),
4920-
"updatedAt" = NOW();`,
4921-
labelId,
4922-
instanceId,
4923-
chatId,
4924-
id,
4925-
);
4972+
const provider = this.configService.get<Database>('DATABASE').PROVIDER;
4973+
4974+
if (provider === 'mysql') {
4975+
// MySQL version - use INSERT ... ON DUPLICATE KEY UPDATE
4976+
await this.prismaRepository.$executeRawUnsafe(
4977+
`INSERT INTO Chat (id, instanceId, remoteJid, labels, createdAt, updatedAt)
4978+
VALUES (?, ?, ?, JSON_ARRAY(), NOW(), NOW())
4979+
ON DUPLICATE KEY UPDATE
4980+
labels = COALESCE(
4981+
JSON_REMOVE(
4982+
labels,
4983+
JSON_UNQUOTE(JSON_SEARCH(labels, 'one', ?))
4984+
),
4985+
JSON_ARRAY()
4986+
),
4987+
updatedAt = NOW()`,
4988+
id,
4989+
instanceId,
4990+
chatId,
4991+
labelId,
4992+
);
4993+
} else {
4994+
// PostgreSQL version
4995+
await this.prismaRepository.$executeRawUnsafe(
4996+
`INSERT INTO "Chat" ("id", "instanceId", "remoteJid", "labels", "createdAt", "updatedAt")
4997+
VALUES ($4, $2, $3, '[]'::jsonb, NOW(), NOW()) ON CONFLICT ("instanceId", "remoteJid")
4998+
DO
4999+
UPDATE
5000+
SET "labels" = COALESCE (
5001+
(
5002+
SELECT jsonb_agg(elem)
5003+
FROM jsonb_array_elements_text("Chat"."labels") AS elem
5004+
WHERE elem <> $1
5005+
),
5006+
'[]'::jsonb
5007+
),
5008+
"updatedAt" = NOW();`,
5009+
labelId,
5010+
instanceId,
5011+
chatId,
5012+
id,
5013+
);
5014+
}
49265015
}
49275016

49285017
public async baileysOnWhatsapp(jid: string) {

0 commit comments

Comments
 (0)