crud-object-diff
Version:
Helper utilities to compare objects or arrays for obtaining created, updated, & deleted values.
146 lines (132 loc) • 5.07 kB
text/typescript
import { isEqualObject } from './helpers';
import { handleCompareObjectInputValidation } from './validation';
/**
* Compare two arrays of objects, to get the created, updated, and deleted values
* @param {Array.<Object>} toCompareVals The first array item must be the original array of objects.
* [originalArray, stateUpdatedArray]
* @param {?string|Array.<string>} key The related key between the objects
* @returns {{createdVals: ?Array.<Object>, updatedVals: ?Array.<Object>, deletedVals: ?Array.<Object>}}
* Three objects with the corresponding created, updated, and deleted values
* respectively. Returns null for one of the corresponding values if it doesn't exist.
*/
function compareObjectVals<T extends object> (
toCompareVals: [T[], T[]], key?: string|string[]) :
{ createdVals: T[]|null, updatedVals: T[]|null, deletedVals: T[]|null } {
handleCompareObjectInputValidation(toCompareVals, key);
var createdVals: any[] | null = [];
var updatedVals: any[] | null = [];
var deletedVals: any[] | null = [];
var originalItem = toCompareVals[0];
var activeItem = toCompareVals[1];
var i: number = 0, j: number = 0;
if (!originalItem.length) {
return {
createdVals: activeItem.length ? activeItem : null,
updatedVals: null,
deletedVals: null
};
}
var originalSameKeyValue: Boolean = false,
activeSameKeyValue: Boolean[] = [];
while (i < originalItem.length) {
j = 0;
while (j < activeItem.length) {
var sameKeyVal: Boolean = false;
if (!key) {
if (
typeof originalItem[i] == 'object' &&
!Array.isArray(originalItem[i])
) {
for (var prop in originalItem[i]) {
if (activeItem[j].hasOwnProperty(prop)) {
sameKeyVal = isEqualObject(originalItem[i][prop], activeItem[j][prop]);
if (sameKeyVal) break;
}
}
} else {
throw new TypeError('Original item array must consist of only objects!');
}
}
else if (Array.isArray(key)) {
var z = 0, combinedKeyTruthyVal = true;
while (z < key.length) {
if (
!originalItem[i].hasOwnProperty(key[z]) ||
!activeItem[j].hasOwnProperty(key[z])) {
combinedKeyTruthyVal = false;
} else {
combinedKeyTruthyVal =
isEqualObject(originalItem[i][key[z]], activeItem[j][key[z]]) &&
combinedKeyTruthyVal;
}
z++;
}
sameKeyVal = combinedKeyTruthyVal;
}
else {
sameKeyVal = isEqualObject(originalItem[i][key], activeItem[j][key]);
}
originalSameKeyValue = sameKeyVal || originalSameKeyValue;
// create a boolean key tracker (activeSameKeyValue) for each inner row
// key every time the outer row is ran to obtain whether or not a value was created.
activeSameKeyValue[j] = sameKeyVal || activeSameKeyValue[j] || false;
var isLastOriginalItemRun = i === originalItem.length - 1;
if (isLastOriginalItemRun && !activeSameKeyValue[j]) {
createdVals.push(activeItem[j]);
}
else if (
sameKeyVal &&
!isEqualObject(originalItem[i], activeItem[j])) {
updatedVals.push(activeItem[j]);
}
j++;
}
if (!originalSameKeyValue) {
deletedVals.push(originalItem[i]);
}
originalSameKeyValue = false;
i++;
}
return {
createdVals: createdVals.length ? createdVals : null,
updatedVals: updatedVals.length ? updatedVals : null,
deletedVals: deletedVals.length ? deletedVals : null
};
}
/**
* Compare two arrays, to get the created & deleted values
* @param {Array.<Array.<*>, Array.<*>>} toCompareVals The first array item must be the original array.
* [originalArray, stateUpdatedArray]
* @returns {{ createdVals: ?Array.<*>, deletedVals: ?Array.<*> }}
* Returns two arrays corresponding to the created and deleted values
* respectively. Returns null for one of the corresponding values if it doesn't exist.
*/
function compareArrayVals<T> (toCompareVals: [T[], T[]]) : { createdVals: T[] | null, deletedVals: T[] | null } {
if (toCompareVals.length !== 2) {
throw new Error('ToCompareVal arguments are of the wrong length!');
}
var originalItem = toCompareVals[0];
var activeItem = toCompareVals[1];
if (!originalItem || !originalItem.length) {
return {
createdVals: activeItem && activeItem.length ? activeItem : null,
deletedVals: null
};
} else if (!activeItem || !activeItem.length) {
return {
createdVals: null,
deletedVals: originalItem
}
}
var deletedVals = originalItem.filter(function (v) {
return activeItem.indexOf(v) === -1;
});
var createdVals = activeItem.filter(function (v) {
return originalItem.indexOf(v) === -1;
});
return {
createdVals: createdVals.length ? createdVals : null,
deletedVals: deletedVals.length ? deletedVals : null
};
}
export { compareObjectVals, compareArrayVals };