"use strict"; /** * For CREATE — plain text array, no IDs needed * objectives: ["text1"] or [{ text: "text1" }] */ async function syncObjectivesCreate(Model, parentField, parentId, objectives, transaction) { if (!objectives?.length) return; await Model.bulkCreate( objectives.map((o, i) => ({ [parentField]: parentId, text: typeof o === "string" ? o : o.text, order_index: i, })), { transaction } ); } /** * For UPDATE — upsert by objective_id, hard delete removed ones * objectives: [{ objective_id: "123", text: "text1" }, { text: "new" }] */ async function syncObjectivesUpdate(Model, parentField, parentId, objectives, transaction) { if (!objectives?.length) { await Model.destroy({ where: { [parentField]: parentId }, force: true, transaction }); return; } const existing = await Model.findAll({ where: { [parentField]: parentId }, transaction }); const existingMap = new Map(existing.map((o) => [String(o.objective_id), o])); const incomingIds = new Set( objectives.filter((o) => o.objective_id).map((o) => String(o.objective_id)) ); // Hard delete removed const toDelete = existing.filter((o) => !incomingIds.has(String(o.objective_id))); if (toDelete.length) { await Model.destroy({ where: { objective_id: toDelete.map((o) => o.objective_id) }, force: true, transaction, }); } // Update existing or create new for (let i = 0; i < objectives.length; i++) { const item = objectives[i]; const record = item.objective_id ? existingMap.get(String(item.objective_id)) : null; if (record) { await record.update({ text: item.text, order_index: i }, { transaction }); } else { await Model.create( { [parentField]: parentId, text: item.text, order_index: i }, { transaction } ); } } } module.exports = { syncObjectivesCreate, syncObjectivesUpdate };