@@ -65,73 +65,117 @@ interface ISaveOnWhatsappCacheParams {
6565 lid ?: 'lid' | undefined ;
6666}
6767
68+ function normalizeJid ( jid : string | null | undefined ) : string | null {
69+ if ( ! jid ) return null ;
70+ return jid . startsWith ( '+' ) ? jid . slice ( 1 ) : jid ;
71+ }
72+
6873export async function saveOnWhatsappCache ( data : ISaveOnWhatsappCacheParams [ ] ) {
69- if ( configService . get < Database > ( 'DATABASE' ) . SAVE_DATA . IS_ON_WHATSAPP ) {
70- for ( const item of data ) {
71- const remoteJid = item . remoteJid . startsWith ( '+' ) ? item . remoteJid . slice ( 1 ) : item . remoteJid ;
74+ if ( ! configService . get < Database > ( 'DATABASE' ) . SAVE_DATA . IS_ON_WHATSAPP ) {
75+ return ;
76+ }
7277
73- // TODO: Buscar registro existente PRIMEIRO para preservar dados
74- const allJids = [ remoteJid ] ;
78+ // Processa todos os itens em paralelo para melhor performance
79+ const processingPromises = data . map ( async ( item ) => {
80+ try {
81+ const remoteJid = normalizeJid ( item . remoteJid ) ;
82+ if ( ! remoteJid ) {
83+ logger . warn ( '[saveOnWhatsappCache] Item skipped, missing remoteJid.' ) ;
84+ return ;
85+ }
7586
76- const altJid =
77- item . remoteJidAlt && item . remoteJidAlt . includes ( '@lid' )
78- ? item . remoteJidAlt . startsWith ( '+' )
79- ? item . remoteJidAlt . slice ( 1 )
80- : item . remoteJidAlt
81- : null ;
87+ const altJidNormalized = normalizeJid ( item . remoteJidAlt ) ;
88+ const lidAltJid = altJidNormalized && altJidNormalized . includes ( '@lid' ) ? altJidNormalized : null ;
8289
83- if ( altJid ) {
84- allJids . push ( altJid ) ;
90+ const baseJids = [ remoteJid ] ; // Garante que o remoteJid esteja na lista inicial
91+ if ( lidAltJid ) {
92+ baseJids . push ( lidAltJid ) ;
8593 }
8694
87- const expandedJids = allJids . flatMap ( ( jid ) => getAvailableNumbers ( jid ) ) ;
95+ const expandedJids = baseJids . flatMap ( ( jid ) => getAvailableNumbers ( jid ) ) ;
8896
97+ // 1. Busca entrada por jidOptions e também remoteJid
98+ // Às vezes acontece do remoteJid atual NÃO ESTAR no jidOptions ainda, ocasionando o erro:
99+ // 'Unique constraint failed on the fields: (`remoteJid`)'
100+ // Isso acontece principalmente em grupos que possuem o número do criador no ID (ex.: '559911223345-1234567890@g.us')
89101 const existingRecord = await prismaRepository . isOnWhatsapp . findFirst ( {
90102 where : {
91- OR : expandedJids . map ( ( jid ) => ( { jidOptions : { contains : jid } } ) ) ,
103+ OR : [
104+ ...expandedJids . map ( ( jid ) => ( { jidOptions : { contains : jid } } ) ) ,
105+ { remoteJid : remoteJid } , // TODO: Descobrir o motivo que causa o remoteJid não estar (às vezes) incluso na lista de jidOptions
106+ ] ,
92107 } ,
93108 } ) ;
94109
95- logger . verbose ( `Register exists: ${ existingRecord ? existingRecord . remoteJid : 'não not found' } ` ) ;
110+ logger . verbose (
111+ `[saveOnWhatsappCache] Register exists for [${ expandedJids . join ( ',' ) } ]? => ${ existingRecord ? existingRecord . remoteJid : 'Not found' } ` ,
112+ ) ;
96113
97- const finalJidOptions = [ ...expandedJids ] ;
114+ // 2. Unifica todos os JIDs usando um Set para garantir valores únicos
115+ const finalJidOptions = new Set ( expandedJids ) ;
98116
99- if ( existingRecord ?. jidOptions ) {
100- const existingJids = existingRecord . jidOptions . split ( ',' ) ;
101- // TODO: Adicionar JIDs existentes que não estão na lista atual
102- existingJids . forEach ( ( jid ) => {
103- if ( ! finalJidOptions . includes ( jid ) ) {
104- finalJidOptions . push ( jid ) ;
105- }
106- } ) ;
117+ if ( lidAltJid ) {
118+ finalJidOptions . add ( lidAltJid ) ;
107119 }
108120
109- // TODO: Se tiver remoteJidAlt com @lid novo, adicionar
110- if ( altJid && ! finalJidOptions . includes ( altJid ) ) {
111- finalJidOptions . push ( altJid ) ;
121+ if ( existingRecord ?. jidOptions ) {
122+ existingRecord . jidOptions . split ( ',' ) . forEach ( ( jid ) => finalJidOptions . add ( jid ) ) ;
112123 }
113124
114- const uniqueNumbers = Array . from ( new Set ( finalJidOptions ) ) ;
115-
116- logger . verbose (
117- `Saving: remoteJid=${ remoteJid } , jidOptions=${ uniqueNumbers . join ( ',' ) } , lid=${ item . lid === 'lid' || item . remoteJid ?. includes ( '@lid' ) ? 'lid' : null } ` ,
118- ) ;
119-
120- await prismaRepository . isOnWhatsapp . upsert ( {
121- where : { remoteJid : remoteJid } ,
122-
123- update : {
124- jidOptions : uniqueNumbers . join ( ',' ) ,
125- lid : item . lid === 'lid' || item . remoteJid ?. includes ( '@lid' ) ? 'lid' : null ,
126- } ,
127- create : {
128- remoteJid : remoteJid ,
129- jidOptions : uniqueNumbers . join ( ',' ) ,
130- lid : item . lid === 'lid' || item . remoteJid ?. includes ( '@lid' ) ? 'lid' : null ,
131- } ,
132- } ) ;
125+ // 3. Prepara o payload final
126+ // Ordena os JIDs para garantir consistência na string final
127+ const sortedJidOptions = [ ...finalJidOptions ] . sort ( ) ;
128+ const newJidOptionsString = sortedJidOptions . join ( ',' ) ;
129+ const newLid = item . lid === 'lid' || item . remoteJid ?. includes ( '@lid' ) ? 'lid' : null ;
130+
131+ const dataPayload = {
132+ remoteJid : remoteJid ,
133+ jidOptions : newJidOptionsString ,
134+ lid : newLid ,
135+ } ;
136+
137+ // 4. Decide entre Criar ou Atualizar
138+ if ( existingRecord ) {
139+ // Compara a string de JIDs ordenada existente com a nova
140+ const existingJidOptionsString = existingRecord . jidOptions
141+ ? existingRecord . jidOptions . split ( ',' ) . sort ( ) . join ( ',' )
142+ : '' ;
143+
144+ const isDataSame =
145+ existingRecord . remoteJid === dataPayload . remoteJid &&
146+ existingJidOptionsString === dataPayload . jidOptions &&
147+ existingRecord . lid === dataPayload . lid ;
148+
149+ if ( isDataSame ) {
150+ logger . verbose ( `[saveOnWhatsappCache] Data for ${ remoteJid } is already up-to-date. Skipping update.` ) ;
151+ return ; // Pula para o próximo item
152+ }
153+
154+ // Os dados são diferentes, então atualiza
155+ logger . verbose (
156+ `[saveOnWhatsappCache] Register exists, updating: remoteJid=${ remoteJid } , jidOptions=${ dataPayload . jidOptions } , lid=${ dataPayload . lid } ` ,
157+ ) ;
158+ await prismaRepository . isOnWhatsapp . update ( {
159+ where : { id : existingRecord . id } ,
160+ data : dataPayload ,
161+ } ) ;
162+ } else {
163+ // Cria nova entrada
164+ logger . verbose (
165+ `[saveOnWhatsappCache] Register does not exist, creating: remoteJid=${ remoteJid } , jidOptions=${ dataPayload . jidOptions } , lid=${ dataPayload . lid } ` ,
166+ ) ;
167+ await prismaRepository . isOnWhatsapp . create ( {
168+ data : dataPayload ,
169+ } ) ;
170+ }
171+ } catch ( e ) {
172+ // Loga o erro mas não para a execução dos outros promises
173+ logger . error ( `[saveOnWhatsappCache] Error processing item for ${ item . remoteJid } : ` , e ) ;
133174 }
134- }
175+ } ) ;
176+
177+ // Espera todas as operações paralelas terminarem
178+ await Promise . allSettled ( processingPromises ) ;
135179}
136180
137181export async function getOnWhatsappCache ( remoteJids : string [ ] ) {
0 commit comments