Get object diff

Date: 2019-05-21

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);
21880cookie-checkGet object diff