Refactor database operations: Enhanced filtering logic to translate keys ending with ._id for Mongoose, added optional distribution for new and delete operations, and implemented a recursive deletion function for child objects. Updated audit logging to handle distributed changes more effectively.

This commit is contained in:
Tom Butcher 2025-09-05 23:23:26 +01:00
parent 8d497de203
commit 751c931e67

View File

@ -1,5 +1,5 @@
import dotenv from 'dotenv'; import dotenv from 'dotenv';
import { deleteAuditLog, expandObjectIds } from '../utils.js'; import { deleteAuditLog, distributeDelete, expandObjectIds } from '../utils.js';
import log4js from 'log4js'; import log4js from 'log4js';
import { editAuditLog, distributeUpdate, newAuditLog, distributeNew } from '../utils.js'; import { editAuditLog, distributeUpdate, newAuditLog, distributeNew } from '../utils.js';
@ -38,17 +38,15 @@ export const listObjects = async ({
if (!sort || sort === '') { if (!sort || sort === '') {
sort = 'createdAt'; 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 // Translate any key ending with ._id to remove the ._id suffix for Mongoose
if (filter['owner._id']) { Object.keys(filter).forEach((key) => {
filter.owner = filter['owner._id']; if (key.endsWith('._id')) {
delete filter['owner._id']; const baseKey = key.slice(0, -4); // Remove '._id' suffix
} filter[baseKey] = filter[key];
delete filter[key];
}
});
// Use find with population and filter // Use find with population and filter
let query = model let query = model
@ -280,7 +278,7 @@ export const getObject = async ({ model, id, populate }) => {
return { error: 'Object not found.', code: 404 }; return { error: 'Object not found.', code: 404 };
} }
return result; return expandObjectIds(result);
} catch (error) { } catch (error) {
return { error: error, code: 500 }; 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 // 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 { try {
const parentType = model.modelName ? model.modelName : 'unknown'; const parentType = model.modelName ? model.modelName : 'unknown';
@ -337,10 +335,12 @@ export const newObject = async ({ model, newData, user = null }) => {
if (!result || result.length === 0) { if (!result || result.length === 0) {
return { error: 'No object created.', code: 500 }; return { error: 'No object created.', code: 500 };
} }
const created = result; const created = expandObjectIds(result.toObject());
await newAuditLog(newData, created._id, parentType, user); await newAuditLog(newData, created._id, parentType, user);
await distributeNew(created._id, parentType); if (distributeChanges == true) {
await distributeNew(created, parentType);
}
return created; return created;
} catch (error) { } 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 // 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 { try {
const parentType = model.modelName ? model.modelName : 'unknown'; const parentType = model.modelName ? model.modelName : 'unknown';
// Delete the object // Delete the object
@ -359,14 +359,46 @@ export const deleteObject = async ({ model, id, user = null }) => {
if (!result) { if (!result) {
return { error: `${parentType} not found.`, code: 404 }; 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) { } catch (error) {
logger.error('deleteObject error:', error); logger.error('deleteObject error:', error);
return { error: error.message, code: 500 }; 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;
};