whatsapp-crm-common
Version:
Componentes compartidos para servicios de WhatsApp CRM - Common utilities and types for WhatsApp CRM system
303 lines • 13.1 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ChatRepository = void 0;
const baileys_1 = require("@whiskeysockets/baileys");
const base_repository_1 = __importDefault(require("./base-repository"));
const repository_errors_1 = require("../errors/repository-errors");
const logger_1 = __importDefault(require("../utils/logger"));
class ChatRepository extends base_repository_1.default {
/**
* Guarda múltiples chats en la base de datos en una sola operación
*/
async guardarChatsBulk(client, chats, tenantId, agentId) {
if (chats.length === 0)
return;
let valuesSql = [];
let paramCounter = 1;
let params = [];
for (const chatInfo of chats) {
const ultimoTimestamp = chatInfo.mensajes.length > 0
? Number(chatInfo.mensajes[chatInfo.mensajes.length - 1]
.messageTimestamp) || 0
: 0;
valuesSql.push(`($${paramCounter++}, $${paramCounter++}, $${paramCounter++}, $${paramCounter++}, $${paramCounter++}, $${paramCounter++}, $${paramCounter++})`);
params.push(chatInfo.chat.id, tenantId, agentId, chatInfo.chat.name || null, chatInfo.esGrupo, chatInfo.chat.unreadCount || 0, ultimoTimestamp);
}
const query = `
INSERT INTO chats (id, tenant_id, agent_id, name, is_group, unread_count, last_message_timestamp)
VALUES ${valuesSql.join(", ")}
ON CONFLICT (id, tenant_id, agent_id) DO UPDATE
SET name = EXCLUDED.name,
unread_count = EXCLUDED.unread_count,
last_message_timestamp = EXCLUDED.last_message_timestamp,
updated_at = CURRENT_TIMESTAMP
`;
await client.query(query, params);
}
/**
* Procesa inserciones o actualizaciones de chats
*/
async handleChatUpserts(chats, tenantId, agentId) {
if (chats.length === 0)
return;
const client = await this.pool.connect();
try {
await client.query("BEGIN");
for (const chat of chats) {
await this.handleSingleChatUpsert(tenantId, agentId, client, chat);
}
await client.query("COMMIT");
console.log(`Procesados ${chats.length} chats`);
}
catch (error) {
await client.query("ROLLBACK");
const repositoryError = new repository_errors_1.ChatRepositoryError({
tenantId,
agentId,
operation: 'handleChatUpserts',
details: {
chatCount: chats.length,
errorMessage: error instanceof Error ? error.message : String(error)
}
}, error instanceof Error ? error : new Error(String(error)));
logger_1.default.error('Failed to handle chat upserts', repositoryError.getLogContext());
throw repositoryError;
}
finally {
client.release();
}
}
/**
* Procesa una inserción o actualización individual de chat
*/
async handleSingleChatUpsert(tenantId, agentId, client, chat) {
const chatData = {
id: chat.id,
tenant_id: tenantId,
agent_id: agentId,
name: chat.name || null,
is_group: (0, baileys_1.isJidGroup)(chat.id),
unread_count: chat.unreadCount || 0,
conversation_timestamp: chat.conversationTimestamp,
archived: chat.archived || false,
pinned: chat.pinned || 0,
mute_end_time: chat.muteEndTime,
ephemeral_expiration: chat.ephemeralExpiration,
ephemeral_setting_timestamp: chat.ephemeralSettingTimestamp,
end_of_history_transfer_type: chat.endOfHistoryTransferType,
disappearing_mode: chat.disappearingMode
? JSON.stringify(chat.disappearingMode)
: null,
description: chat.description,
last_message_timestamp: chat.conversationTimestamp,
raw_data: JSON.stringify(chat),
};
// Upsert del chat
const upsertQuery = `
INSERT INTO public.chats
(id, tenant_id, agent_id, name, is_group, unread_count, conversation_timestamp,
archived, pinned, mute_end_time, ephemeral_expiration, ephemeral_setting_timestamp,
end_of_history_transfer_type, disappearing_mode, description,
last_message_timestamp, raw_data)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)
ON CONFLICT (id, tenant_id, agent_id)
DO UPDATE SET
name = COALESCE(EXCLUDED.name, chats.name),
unread_count = EXCLUDED.unread_count,
conversation_timestamp = COALESCE(EXCLUDED.conversation_timestamp, chats.conversation_timestamp),
archived = COALESCE(EXCLUDED.archived, chats.archived),
pinned = COALESCE(EXCLUDED.pinned, chats.pinned),
mute_end_time = COALESCE(EXCLUDED.mute_end_time, chats.mute_end_time),
ephemeral_expiration = COALESCE(EXCLUDED.ephemeral_expiration, chats.ephemeral_expiration),
ephemeral_setting_timestamp = COALESCE(EXCLUDED.ephemeral_setting_timestamp, chats.ephemeral_setting_timestamp),
end_of_history_transfer_type = COALESCE(EXCLUDED.end_of_history_transfer_type, chats.end_of_history_transfer_type),
disappearing_mode = COALESCE(EXCLUDED.disappearing_mode, chats.disappearing_mode),
description = COALESCE(EXCLUDED.description, chats.description),
last_message_timestamp = COALESCE(EXCLUDED.last_message_timestamp, chats.last_message_timestamp),
raw_data = EXCLUDED.raw_data,
updated_at = CURRENT_TIMESTAMP
`;
await client.query(upsertQuery, [
chatData.id,
chatData.tenant_id,
chatData.agent_id,
chatData.name,
chatData.is_group,
chatData.unread_count,
chatData.conversation_timestamp,
chatData.archived,
chatData.pinned,
chatData.mute_end_time,
chatData.ephemeral_expiration,
chatData.ephemeral_setting_timestamp,
chatData.end_of_history_transfer_type,
chatData.disappearing_mode,
chatData.description,
chatData.last_message_timestamp,
chatData.raw_data,
]);
}
/**
* Procesa actualizaciones de chats
*/
async handleChatUpdates(tenantId, agentId, updates) {
if (updates.length === 0)
return;
const client = await this.pool.connect();
try {
await client.query("BEGIN");
for (const update of updates) {
await this.handleSingleChatUpdate(tenantId, agentId, client, update);
}
await client.query("COMMIT");
console.log(`Procesadas ${updates.length} actualizaciones de chat`);
}
catch (error) {
await client.query("ROLLBACK");
const repositoryError = new repository_errors_1.ChatRepositoryError({
tenantId,
agentId,
operation: 'handleChatUpdates',
details: {
updateCount: updates.length,
errorMessage: error instanceof Error ? error.message : String(error)
}
}, error instanceof Error ? error : new Error(String(error)));
logger_1.default.error('Failed to handle chat updates', repositoryError.getLogContext());
throw repositoryError;
}
finally {
client.release();
}
}
/**
* Procesa una actualización individual de chat
*/
async handleSingleChatUpdate(tenantId, agentId, client, chatUpdate) {
const chatId = chatUpdate.id;
if (!chatId)
return;
const updateFields = {};
// 1. Actualización de contador de no leídos
if (typeof chatUpdate.unreadCount === "number") {
updateFields.unread_count = chatUpdate.unreadCount;
}
// 2. Estado de archivado
if (typeof chatUpdate.archived === "boolean") {
updateFields.archived = chatUpdate.archived;
}
// 3. Estado de silenciado
if (chatUpdate.muteEndTime !== undefined) {
updateFields.mute_end_time = chatUpdate.muteEndTime;
}
// 4. Estado de fijado
if (chatUpdate.pinned !== undefined) {
updateFields.pinned = chatUpdate.pinned;
}
// 5. Timestamp de conversación
if (chatUpdate.conversationTimestamp) {
updateFields.conversation_timestamp =
chatUpdate.conversationTimestamp;
updateFields.last_message_timestamp =
chatUpdate.conversationTimestamp;
}
// 6. Nombre del chat
if (chatUpdate.name) {
updateFields.name = chatUpdate.name;
}
// 7. Configuración efímera
if (chatUpdate.ephemeralExpiration !== undefined) {
updateFields.ephemeral_expiration = chatUpdate.ephemeralExpiration;
}
if (chatUpdate.ephemeralSettingTimestamp) {
updateFields.ephemeral_setting_timestamp =
chatUpdate.ephemeralSettingTimestamp;
}
// 8. Modo de desaparición
if (chatUpdate.disappearingMode) {
updateFields.disappearing_mode = JSON.stringify(chatUpdate.disappearingMode);
}
// 9. Descripción
if (chatUpdate.description !== undefined) {
updateFields.description = chatUpdate.description;
}
// 11. Datos raw completos
updateFields.raw_data = JSON.stringify(chatUpdate);
if (Object.keys(updateFields).length === 0)
return;
// Construir la consulta de actualización
const setClause = Object.keys(updateFields)
.map((key, index) => `${key} = $${index + 4}`)
.join(", ");
const values = [
chatId,
tenantId,
agentId,
...Object.values(updateFields),
];
const updateQuery = `
UPDATE public.chats
SET ${setClause}, updated_at = CURRENT_TIMESTAMP
WHERE id = $1 AND tenant_id = $2 AND agent_id = $3
`;
await client.query(updateQuery, values);
}
/**
* Procesa múltiples actualizaciones de chat en lote
*/
async handleBulkChatUpdates(tenantId, agentId, chatUpdates) {
if (chatUpdates.length === 0)
return;
const client = await this.pool.connect();
try {
await client.query("BEGIN");
// Agrupar actualizaciones por chat ID
const updatesByChat = chatUpdates.reduce((acc, update) => {
if (update.id) {
if (!acc[update.id]) {
acc[update.id] = [];
}
acc[update.id].push(update);
}
return acc;
}, {});
// Procesar cada chat con sus actualizaciones consolidadas
for (const [chatId, updates] of Object.entries(updatesByChat)) {
const consolidatedUpdate = this.consolidateChatUpdates(updates);
await this.handleSingleChatUpdate(tenantId, agentId, client, consolidatedUpdate);
}
await client.query("COMMIT");
console.log(`Procesadas ${chatUpdates.length} actualizaciones de chat en lote`);
}
catch (error) {
await client.query("ROLLBACK");
const repositoryError = new repository_errors_1.ChatRepositoryError({
tenantId,
agentId,
operation: 'handleBulkChatUpdates',
details: {
updateCount: chatUpdates.length,
errorMessage: error instanceof Error ? error.message : String(error)
}
}, error instanceof Error ? error : new Error(String(error)));
logger_1.default.error('Failed to handle bulk chat updates', repositoryError.getLogContext());
throw repositoryError;
}
finally {
client.release();
}
}
/**
* Consolida múltiples actualizaciones de chat en una sola
*/
consolidateChatUpdates(updates) {
return updates.reduce((consolidated, update) => {
return { ...consolidated, ...update };
}, { id: updates[0].id });
}
}
exports.ChatRepository = ChatRepository;
//# sourceMappingURL=chat-repository.js.map