Refactor sync service to handle conflicted category and note IDs during synchronization
Despliegue Automático / desplegar (push) Successful in 1m25s

This commit is contained in:
2026-08-18 09:23:18 +02:00
parent ded4c8fc03
commit 80f1b7ad28
+17 -10
View File
@@ -41,7 +41,6 @@ const buildStoredNoteData = (incomingNote, existingNote = null) => {
: (incomingNote.position ?? existingNote?.position ?? 0); : (incomingNote.position ?? existingNote?.position ?? 0);
return { return {
// categoryId eliminado de aquí
title: permanentDelete ? '' : incomingNote.title, title: permanentDelete ? '' : incomingNote.title,
body: permanentDelete ? '' : incomingNote.body, body: permanentDelete ? '' : incomingNote.body,
position, position,
@@ -73,6 +72,10 @@ class SyncService {
const incomingCategories = Array.isArray(changes.categories) ? changes.categories : []; const incomingCategories = Array.isArray(changes.categories) ? changes.categories : [];
const incomingNotes = Array.isArray(changes.notes) ? changes.notes : []; const incomingNotes = Array.isArray(changes.notes) ? changes.notes : [];
// ARRAYS PARA IDs DESFASADOS
const conflictedCategoryIds = [];
const conflictedNoteIds = [];
await sequelize.transaction(async (transaction) => { await sequelize.transaction(async (transaction) => {
// --- SINCRONIZACIÓN DE CATEGORÍAS --- // --- SINCRONIZACIÓN DE CATEGORÍAS ---
for (const incomingCategory of incomingCategories) { for (const incomingCategory of incomingCategories) {
@@ -109,6 +112,8 @@ class SyncService {
delete: Boolean(incomingCategory.delete), delete: Boolean(incomingCategory.delete),
serverVersion: serverVersion + 1 serverVersion: serverVersion + 1
}, { transaction }); }, { transaction });
} else if (serverVersion > incomingBaseVersion) {
conflictedCategoryIds.push(existingCategory.id);
} }
} }
@@ -116,7 +121,6 @@ class SyncService {
for (const incomingNote of incomingNotes) { for (const incomingNote of incomingNotes) {
const permanentDelete = Boolean(incomingNote.permanentDelete); const permanentDelete = Boolean(incomingNote.permanentDelete);
// Se verifica que sea 'string' para aceptar strings vacíos
if (!incomingNote.id || typeof incomingNote.title !== 'string' || typeof incomingNote.body !== 'string') { if (!incomingNote.id || typeof incomingNote.title !== 'string' || typeof incomingNote.body !== 'string') {
throw new Error("Cada nota debe incluir id, title y body"); throw new Error("Cada nota debe incluir id, title y body");
} }
@@ -138,7 +142,6 @@ class SyncService {
serverVersion: 1 serverVersion: 1
}, { transaction }); }, { transaction });
// 👇 Actualizar la relación de muchos a muchos al crear
if (Array.isArray(incomingNote.categoryIds)) { if (Array.isArray(incomingNote.categoryIds)) {
await newNote.setCategories(incomingNote.categoryIds, { transaction }); await newNote.setCategories(incomingNote.categoryIds, { transaction });
} }
@@ -155,12 +158,11 @@ class SyncService {
serverVersion: serverVersion + 1 serverVersion: serverVersion + 1
}, { transaction }); }, { transaction });
// 👇 Actualizar la relación de muchos a muchos al editar
if (Array.isArray(incomingNote.categoryIds)) { if (Array.isArray(incomingNote.categoryIds)) {
await existingNote.setCategories(incomingNote.categoryIds, { transaction }); await existingNote.setCategories(incomingNote.categoryIds, { transaction });
} }
} else if (serverVersion > incomingBaseVersion) { } else if (serverVersion > incomingBaseVersion) {
// Conflicto de versiones... (implementación de duplicados omitida por ahora) conflictedNoteIds.push(existingNote.id);
} else { } else {
throw new Error(`serverVersion inválida en la nota ${incomingNote.id}`); throw new Error(`serverVersion inválida en la nota ${incomingNote.id}`);
} }
@@ -172,20 +174,25 @@ class SyncService {
Category.findAll({ Category.findAll({
where: { where: {
userId, userId,
updatedAt: { [Op.gt]: lastSyncAt } [Op.or]: [
{ updatedAt: { [Op.gt]: lastSyncAt } },
{ id: { [Op.in]: conflictedCategoryIds } }
]
}, },
order: [['updatedAt', 'ASC']] order: [['updatedAt', 'ASC']]
}), }),
Note.findAll({ Note.findAll({
where: { where: {
userId, userId,
updatedAt: { [Op.gt]: lastSyncAt } [Op.or]: [
{ updatedAt: { [Op.gt]: lastSyncAt } },
{ id: { [Op.in]: conflictedNoteIds } }
]
}, },
// 👇 Le decimos a Sequelize que incluya la tabla Category para poder sacar los IDs
include: [{ include: [{
model: Category, model: Category,
attributes: ['id'], // Solo necesitamos el ID para el array de Flutter attributes: ['id'],
through: { attributes: [] } // Omite los datos de la tabla intermedia en el JSON final through: { attributes: [] }
}], }],
order: [['updatedAt', 'ASC']] order: [['updatedAt', 'ASC']]
}) })