/** * Parses an event by comparing old and new data to determine which fields have changed. * * This function analyzes the differences between previous (`oldData`) and current (`newData`) * data states to identify changed fields. It determines if the event is a new entry or an update * and returns details about changed fields, the event type, and associated metadata. * * @param {Object} options - Configuration options for parsing the event. * @param {Object} [options.oldData] - The previous state of the data (undefined for new entries). * @param {Object} options.newData - The current state of the data. * @param {string} options.trigger - The type of event trigger (e.g., 'INSERT', 'UPDATE'). * @param {string} options.table - The name of the table associated with the event. * @param {string} [options.jobId] - The job ID, if already extracted by the caller (optional). * @returns {Object} An object containing the parsed event details: * - {Array} changedFieldNames - List of field names that have changed. * - {Object} changedFields - Map of changed fields with their old and new values. * - {boolean} isNew - True if the event is a new entry (no oldData provided). * - {Object} data - The current data state (`newData`). * - {string} trigger - The event trigger type. * - {string} table - The table name. * - {string|null} jobId - The provided jobId or null if not provided. */ const eventParser = async ({ oldData, newData, trigger, table, jobId = null }) => { const isNew = !oldData; // True if no old data exists, indicating a new entry let changedFields = {}; let changedFieldNames = []; if (isNew) { // For new entries, all fields in newData are considered "changed" (from undefined to their value) changedFields = Object.fromEntries( Object.entries(newData).map(([key, value]) => [key, { old: undefined, new: value }]) ); changedFieldNames = Object.keys(newData); // All keys are new } else { // Compare oldData and newData to detect updates for (const key in newData) { if (Object.prototype.hasOwnProperty.call(newData, key)) { // Check if the field is new or its value has changed if ( !Object.prototype.hasOwnProperty.call(oldData, key) || // Field didn’t exist before JSON.stringify(oldData[key]) !== JSON.stringify(newData[key]) // Values differ (deep comparison) ) { changedFields[key] = { old: oldData[key], // Undefined if field wasn’t in oldData new: newData[key] }; changedFieldNames.push(key); } } } // Identify fields removed in newData (present in oldData but absent in newData) for (const key in oldData) { if (Object.prototype.hasOwnProperty.call(oldData, key) && !Object.prototype.hasOwnProperty.call(newData, key)) { changedFields[key] = { old: oldData[key], new: null // Mark as removed }; changedFieldNames.push(key); } } } return { changedFieldNames, // Array of fields that changed changedFields, // Object with old/new values for changed fields isNew, // Boolean indicating if this is a new entry data: newData, // Current data state trigger, // Event trigger (e.g., 'INSERT', 'UPDATE') table, // Associated table name jobId // Provided jobId or null }; }; module.exports = eventParser;