diff --git a/src/database/database.js b/src/database/database.js index 3180dfa..357934a 100644 --- a/src/database/database.js +++ b/src/database/database.js @@ -1,5 +1,5 @@ import dotenv from 'dotenv'; -import { deleteAuditLog, expandObjectIds } from '../utils.js'; +import { deleteAuditLog, distributeDelete, expandObjectIds } from '../utils.js'; import log4js from 'log4js'; import { editAuditLog, distributeUpdate, newAuditLog, distributeNew } from '../utils.js'; @@ -38,17 +38,15 @@ export const listObjects = async ({ if (!sort || sort === '') { sort = 'createdAt'; } - // Translate parent._id to parent for Mongoose - if (filter['parent._id']) { - filter.parent = filter['parent._id']; - delete filter['parent._id']; - } - // Translate owner._id to owner for Mongoose - if (filter['owner._id']) { - filter.owner = filter['owner._id']; - delete filter['owner._id']; - } + // Translate any key ending with ._id to remove the ._id suffix for Mongoose + Object.keys(filter).forEach((key) => { + if (key.endsWith('._id')) { + const baseKey = key.slice(0, -4); // Remove '._id' suffix + filter[baseKey] = filter[key]; + delete filter[key]; + } + }); // Use find with population and filter let query = model @@ -280,7 +278,7 @@ export const getObject = async ({ model, id, populate }) => { return { error: 'Object not found.', code: 404 }; } - return result; + return expandObjectIds(result); } catch (error) { return { error: error, code: 500 }; } @@ -329,7 +327,7 @@ export const editObject = async ({ model, id, updateData, user, populate }) => { }; // Reusable function to create a new object -export const newObject = async ({ model, newData, user = null }) => { +export const newObject = async ({ model, newData, user = null }, distributeChanges = true) => { try { const parentType = model.modelName ? model.modelName : 'unknown'; @@ -337,10 +335,12 @@ export const newObject = async ({ model, newData, user = null }) => { if (!result || result.length === 0) { return { error: 'No object created.', code: 500 }; } - const created = result; + const created = expandObjectIds(result.toObject()); await newAuditLog(newData, created._id, parentType, user); - await distributeNew(created._id, parentType); + if (distributeChanges == true) { + await distributeNew(created, parentType); + } return created; } catch (error) { @@ -350,7 +350,7 @@ export const newObject = async ({ model, newData, user = null }) => { }; // Reusable function to delete an object by ID, with audit logging and distribution -export const deleteObject = async ({ model, id, user = null }) => { +export const deleteObject = async ({ model, id, user = null }, distributeChanges = true) => { try { const parentType = model.modelName ? model.modelName : 'unknown'; // Delete the object @@ -359,14 +359,46 @@ export const deleteObject = async ({ model, id, user = null }) => { if (!result) { return { error: `${parentType} not found.`, code: 404 }; } - // Audit log the deletion - await deleteAuditLog(result, id, parentType, user, 'delete'); - // Distribute the deletion event - await distributeUpdate({ deleted: true }, id, parentType); - return { deleted: true, id }; + const deleted = expandObjectIds(result.toObject()); + // Audit log the deletion + await deleteAuditLog(deleted, id, parentType, user, 'delete'); + + if (distributeChanges == true) { + await distributeDelete(deleted, parentType); + } + + return { deleted: true, object: deleted }; } catch (error) { logger.error('deleteObject error:', error); return { error: error.message, code: 500 }; } }; + +// Helper function to recursively delete objects and their children +export const recursivelyDeleteChildObjects = async ( + { model, id, user = null }, + distributeChanges = true +) => { + const deletedIds = []; + + // Find all objects that have this object as their parent + const childObjects = await model.find({ parent: id }); + + // Recursively delete all children first + for (const childObject of childObjects) { + const childDeletedIds = await recursivelyDeleteChildObjects( + { model, id: childObject._id, user }, + false + ); + deletedIds.push(...childDeletedIds); + } + + // Delete the current object + + await deleteObject({ model, id, user }, distributeChanges); + + deletedIds.push(id); + + return deletedIds; +};