Compare JSON object properties for new/changed/deleted
(_ => {
function filterUnique() {
const keys = new Set();
return (key) => !keys.has(key) ? keys.add(key) || true : false;
}
function* fullOuterJoin(left, right, keyFn, selectFn) {
const leftLookup = {};
const rightLookup = {};
left.forEach(x => leftLookup[keyFn(x)] = x);
right.forEach(x => rightLookup[keyFn(x)] = x);
const unique = filterUnique();
const keys = [...left.map(x => keyFn(x)), ...right.map(x => keyFn(x))].filter(unique);
for (const key of keys) {
const l = leftLookup[key];
const r = rightLookup[key];
yield selectFn(l, r, key);
}
}
function flattenObject(obj) {
const result = {};
for (const [k, v] of Object.entries(obj)) {
if (typeof v === "object" && v) {
for (const [x, y] of Object.entries(flattenObject(v))) {
result[k + "." + x] = y;
}
continue;
}
result[k] = v;
}
return result;
}
const mapkv = x => ({key: x[0], value: x[1]});
const left = Object.entries(flattenObject(nl)).map(mapkv);
const right = Object.entries(flattenObject(en)).map(mapkv);
const changes = Array.from(fullOuterJoin(left, right, a => a.key, (l, r, k) => ({ l, r, key: k }))).filter(x => !x.l || !x.r);
console.table(changes.map(x => ({ key: x.key, left: x.l?.value, right: x.r?.value })));
})();
const getNew = (oldList: any[], newList: any[], equals: Function) => newList.filter(i => !oldList.some(o => equals(o, i)));
const getChanged = (oldList: any[], newList: any[], equals: Function, changed: Function) => {
return newList.reduce((arr, curr) => {
const old = oldList.filter(o => equals(o, curr))[0];
if (old && changed(curr, old)) {
arr.push({ key: curr.key, oldvalue: old.value, value: curr.value });
}
return arr;
}, []);
};
const getUnchanged = (oldList: any[], newList: any[], equals: Function, changed: Function) => {
return newList.reduce((arr, curr) => {
const old = oldList.filter(o => equals(o, curr))[0];
if (!(old && changed(curr, old))) {
arr.push({ key: curr.key, value: curr.value });
}
return arr;
}, []);
};
// deleted items is just the lists reversed
const getDeleted = (oldList: any[], newList: any[], equals) => getNew(newList, oldList, equals);
const flattenObject = (obj: object): any => {
const result = {};
for (const [k, v] of Object.entries(obj)) {
if (typeof v === "object" && v) {
const flatObject = flattenObject(v);
for (const [x, y] of Object.entries(flatObject)) {
result[k + "." + x] = y;
}
} else {
result[k] = v;
}
}
return result;
};
const mapkv = x => ({key: x[0], value: x[1]});
const currentJsonValues = JSON.parse(currentVersion.entityValueJson);
const previousJsonValues = JSON.parse(previousVersion.entityValueJson);
const currentEntries = Object.entries(flattenObject(currentJsonValues)).map(mapkv);
const previousEntries = Object.entries(flattenObject(previousJsonValues)).map(mapkv);
const equal = (a, b) => a.key === b.key;
const changed = (a, b) => a.value !== b.value;
const addedProps = getNew(previousEntries, currentEntries, equal);
const changedProps = getChanged(previousEntries, currentEntries, equal, changed);
const deletedProps = getDeleted(previousEntries, currentEntries, equal);
const unchangedProps = getUnchanged(previousEntries, currentEntries, equal, changed);
218800cookie-checkGet object diff