// @ts-check
/**
* Key Comparison Utilities
*
* Provides functions for comparing objects and detecting changes, with special handling
* for encrypted fields like accounts.
*
* @module utils/keyCompare
*/
import { accountsEqual } from "./crypto.js"
import { filterKeys } from './objectfilter/filters/filterPerson.js'
/**
* Compares two objects and returns the differences
*
* Compares all keys in newData with oldData and identifies:
* - Modified values (different in newData vs oldData)
* - Deleted keys (present in oldData but undefined in newData)
*
* @param {Object} oldData - Original object data
* @param {Object} newData - New object data to compare against
* @returns {Object} Object containing only the changed or deleted keys
*/
export const keysCompare = (oldData, newData) => {
// takes all new keys and checks, if they are the same in oldData
const diff = {}
Object.entries(newData).forEach(([key, value]) => {
if (!oldData || !oldData[key] || JSON.stringify(value) !== JSON.stringify(oldData[key]))
diff[key] = value
})
// now add all deleted keys in oldData with value null
if (oldData) {
Object.keys(oldData).forEach(key => {
if (newData[key] === undefined)
diff[key] = undefined
})
}
return diff
}
/**
* Compares two objects for equality and returns detailed change information
*
* Performs deep comparison with special handling for encrypted accounts field.
* Returns a tuple containing:
* 1. Boolean indicating if objects are equal
* 2. Object containing all differences
* 3. Object containing only filter-relevant differences (or null if none)
*
* Special handling:
* - Accounts are compared using accountsEqual (decrypted comparison)
* - Only changes to filterKeys properties are included in filterDiff
*
* @param {Object} oldData - Original object data
* @param {Object} newData - New object data to compare against
* @returns {[boolean, Object, Object|null]} Tuple: [isEqual, allDifferences, filterRelevantDifferences]
*/
export const keysEqual = (oldData, newData) => {
// accounts are encryped and may look different, but are equal
// we compare the data deeply and return an array with the boolean equality and the diff
const myDiff = keysCompare(oldData, newData)
let filterDiff = {...myDiff}
const myDiffLength = Object.keys(myDiff).length
if (myDiffLength === 0) {
return [true, {}, null]
}
else if (myDiff.accounts) {
if (accountsEqual(oldData.accounts, newData.accounts)) {
delete myDiff.accounts
delete filterDiff.accounts
}
}
// only trigger list checks for changes which are used in object filters
// so delete in filterDiff the keys, which are not in filterKeys
Object.keys(myDiff).forEach(key => {
if (!Object.keys(filterKeys).includes(key))
delete filterDiff[key]
})
// If no filter-relevant changes remain, set filterDiff to null
if (Object.keys(filterDiff).length === 0) {
filterDiff = null
}
return [false, myDiff, filterDiff]
}