@casterradev/differify
v1.0.1
Published
Differify allows you to get the diff between two entities (objects diff, arrays diff, date diff, functions diff, number diff, etc) very easily, quickly and in a friendly way. This fork adds the KeepKeys parameter allowing you to easily keep certain keys i
Downloads
2
Maintainers
Readme
One of the Fastest deep object/array diff
Benchmarks with other popular packages on the same category: (This benchmark is using the original repo Here)
@netilon/differify x 1,045,377 ops/sec ±1.42% (93 runs sampled)
deep-object-diff x 184,838 ops/sec ±2.55% (85 runs sampled) recursive-diff x 108,276 ops/sec ±1.93% (94 runs sampled) Fastest is @netilon/differify
What this fork adds?
- KeepKeys - Allows you to keep certain keys in the returned object. Useful for database objects to keep the unique IDs, usernames, or emails to use in a find request then use the rest of the object for the update request.
- isObjectValueEmpty(obj, keepKeys) - Tells you if the object is empty skipping over keepKeys.
- Migrated from jest to vitest - Jest had a lot of config and ran slower. Vitest is faster & is a more streamlined, out-of-the-box testing package.
- Fixed Typescript signature issues - When this was forked the original had issues with typescript class signatures and some type exports.
This fork was made to easily keep certain keys in an object AND get the differences/additions/deletions for use in updating databases using those kept keys. If you need a pure JS object difference tool. Check out the original repo Here
Whats new?
- Completely rewritten
- The new version 4.x is x2 faster than the older versions (version < 3.0.0) and is now one of the Fastests deep object/array comparators.
- Typescript support added.
- Support for Node.js and Browsers (it works on both)
- Just 7.6K (gzipped 2K) weight (import)
- No dependencies
- New features were added! Now you can easily do more things with differify!
- new config option added. Now, you can decide whether you prefer to compare arrays, either in an
ordered
or in anunordered
way. Remember that, by default, you have an ordered comparison. - you can apply changes (merge) from
left to right
(applyRightChanges) orright to left
(applyLeftChanges) - you can just
keep the differences between two entities
It's very useful indeed! (see more in the Documentation about the diffOnly option ofapply[Right|Left]Changes
methods). - you can filter the diff result of
compare()
method by an specific status (ADDED
,MODIFIED
,DELETED
,EQUAL
).
- new config option added. Now, you can decide whether you prefer to compare arrays, either in an
Synopsis
Differify allows you to get the diff between two entities (objects diff, arrays diff, date diff, functions diff, number diff, etc) very easily, quickly and in a friendly way.
Your contribution is appreciated (thanks!)
Donate to the original author here! Check out the original repo Here
Index
Installation
npm install @casterradev/differify
How to use it
Comparing things with differify is very simple!
> Compare objects
const Differify = require('@casterradev/differify')
const differify = new Differify({mode: {object: 'DIFF', array: 'DIFF'}});
const A = {
id: 1,
role: 'developer',
name: 'Person1',
birthdate: 440305200000
}
const B = {
id: 2,
role: 'developer',
name: 'Person2',
birthdate: 533444400000
}
const diff = differify.compare(A,B);
> Object diff output
{
"_": {
"id": {
"original": 1,
"current" 2,
"status": "MODIFED",
"changes": 1
},
"role": {
"original": "developer",
"current" "developer",
"status": "EQUAL",
"changes": 0
},
"name": {
"original": "Person1",
"current" "Person2",
"status": "MODIFIED",
"changes": 1
},
"birthdate": {
"original": 440305200000,
"current" 533444400000,
"status": "MODIFIED",
"changes": 1
},
},
"status": "MODIFIED",
"changes": 3
}
> Easy access and use
const diff = differify.compare(A,B);
console.log(
`Property name
status is: ${diff._.name.status}
prev value is: ${diff._.name.original}
current value is: ${diff._.name.current}
// OUTPUT:
// Property name
// status is: MODIFIED
// prev value is: Person1
// current value is: Person2
> Compare arrays
const Differify = require('@casterradev/differify');
const differify = new Differify({mode: {object: 'DIFF', array: 'DIFF'}});
const A = [1, 2, 3];
const B = [1, 2, 4, 5];
const diff = differify.compare(A, B);
// OUTPUT
{
"_": [
{
"original": 1,
"current": 1,
"status": "EQUAL",
"changes": 0
},
{
"original": 2,
"current": 2,
"status": "EQUAL",
"changes": 0
},
{
"original": 3,
"current": 4,
"status": "MODIFIED",
"changes": 1
},
{
"original": null,
"current": 5,
"status": "ADDED",
"changes": 1
},
],
"status": "MODIFIED",
"changes": 2
Simple Structure
As you can see, there are two different kinds of structures that you can get from compare
method call.
For objects and arrays only, you will get this structure:
{ "_": ..., "status": "MODIFIED", "changes": 3 }
- The
_
property contains the detailed diff information (it's an underscore to improve the readability in complex nested objects property accesses) - The
status
property contains the global status of the comparison ('EQUAL', 'MODIFIED', 'DELETED', 'ADDED') - The
changes
property is the total changes found when the comparison was performed.
- The
For anything that
Object.prototype.toString.call()
does NOT return[object Array]
or[object Object]
(functions, dates, numbers, etc), you will get this structure:{ "original": 1, "current": 2, "status": "MODIFIED", "changes": 1 }
- The
original
property has the original value (left parameter incompare
method). - The
current
property has the current value (right parameter incompare
method). - The
status
property contains the current status of the comparison ('EQUAL', 'MODIFIED', 'DELETED', 'ADDED') - The
changes
property will be 1 or 0 depending if there was a change or not.
- The
> Apply changes
const differify = new Differify({mode: { object: 'DIFF', array: 'DIFF' }});
const A = {
id: 1,
role: ['developer', 'admin'],
name: 'Person1',
color: 'red',
birthdate: 440305200000
another: 'property from A'
}
const B = {
id: 2,
role: ['developer'],
name: 'Person2',
color: 'red',
birthdate: 533444400000
}
const diff = differify.compare(A, B);
console.log(differify.applyRightChanges(diff));
/* OUTPUT:
{
id: 2,
role: ['developer', 'admin'],
name: 'Person2',
color: 'red',
birthdate: 533444400000
another: 'property from A'
}
*/
console.log(differify.applyLeftChanges(diff));
/* OUTPUT:
{
id: 1,
role: ['developer', 'admin'],
name: 'Person1',
color: 'red',
birthdate: 440305200000
another: 'property from A'
}
*/
console.log(differify.applyLeftChanges(diff, true));
/*
JUST the diff (note that there is NO color property and NO 'developer' role, because both properties has the same value in both entities.
OUTPUT:
{
id: 1,
role: ['admin'],
name: 'Person1',
birthdate: 440305200000
another: 'property from A'
}
*/
Documentation
Methods
Method:
setConfig(object);
Description: It sets the configuration options that will be applied when compare() method is called.
Params:
Configuration Object (see the Configuration section).
Return: void
Method:
getConfig();
Description: It returns a copy of the current configuration object.
Return: Object
Method:
compare(any, any, keepKeys);
Description: It returns the difference between two entities.
Params:
Both parameters indicate the entities to be compared.
keepKeys?: string[] - Array of keep keys. Return object will mark these keys with status of 'KEPT'. If not given uses config.keepKeys. if config.keepKeys is not set uses empty array [].
Return: Object.
Method:
applyRightChanges(diffResult, diffOnly);
Description: It will apply the changes (merge both entities) and will keep the modified values from the right.
Params:
diffResult: Object - It is the Object returned by the compare()
method call.
diffOnly: boolean - (default: false) It returns just the difference (only the !== EQUAL
properties).
Return: Object.
Method:
applyLeftChanges(diffResult, diffOnly);
Description: It will apply the changes (merge both entities) and will keep the modified values from the left.
Params:
diffResult: Object - It is the Object returned by the compare()
method call.
diffOnly: boolean - (default: false) It returns just the difference (only the !== EQUAL
properties).
Return: Object.
Method:
filterDiffByStatus(diffResult, status, extendedInformation);
Description: It will return the changes that match the specified property status (second parameter) using the DIFF_MODES.DIFF in the configuration. IMPORTANT: If you use another diff mode (different than DIFF_MODES.DIFF), then you will get the corresponding value from original/current property (based on the status) without any filtering (you will get the raw value).
Params:
diffResult: Object - It is the Object returned by the compare()
method call.
status: string - one of the following (ADDED
|| MODIFIED
|| DELETED
|| EQUAL
|| KEPT
).
extendedInformation: boolean - if true, it will add more detail about the elements to the given output. Defaults to false.
Return: any || null - it depends on the input type. If there is no status matching, then null will be returned.
Method:
isObjectValuesEmpty(obj, keepKeys?);
Description: Tells if an object is empty not counting keepKeys keys.
Params:
obj: Object - Object to see if it's empty.
keepKeys?: string[] - Array of keep keys. If not given uses config.keepKeys. if config.keepKeys is not set uses empty array [].
Return: boolean - Returns true if empty. False if not empty.
Configuration
You can pass a config to the setConfig() method to change the behavior and adjust it to fit your needs. If you prefer, you can set it once and use it everywhere or you can change it when you need it.
| key | value | default | description |
| ---------------------- | ------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| mode.array | string | DIFF | DIFF: it will iterate over each element in the array A, and will compare each element against the element in the same index in the array B.REFERENCE: just compare the references of each array.STRING: only will check the array length and will do a toString comparison if necessary. |
| mode.object | string | DIFF | DIFF: it will iterate over each property in the object A and will compare each value with the same property value in the object B.REFERENCE: just compare the references of each object.STRING: only do a toString comparison. |
| mode.function | string | REFERENCE | REFERENCE: just compare the references of each function.STRING: only do a toString comparison (useful to compare the function bodies). |
| compareArraysInOrder | boolean | true | if it is true
, it will compare each element in both arrays one by one in an ordered way, assuming that each element, in the same index in both arrays, should be the same element that can have changes or not (see an example of this case). If the option is set to false
, then it will compare each element in both arrays and it will check if they are EQUAL
, ADDED
or DELETED
without keeping in mind the appearence order (there won't be details about the MODIFIED
status, it's only available if the option is set to true, since in that case, the order matters and we know that each element in the same index (but in different arrays), should be the same element that could have been changed or not) (see an example of this case). |
| keepKeys | string[] | [] | Array of keys to keep. Useful for keeping database IDs. The differify.compare
function also has a keepKeys parameter that will overwrite this setting.|
Configuration example:
const Differify = require('@casterradev/differify');
differify = new Differify({ mode: { object: 'DIFF', array: 'DIFF' } });
const diff = differify.compare(a, b);
if you dont specify any configuration, the default options are the following:
{
mode: {
array: 'DIFF',
object: 'DIFF',
function: 'REFERENCE',
},
compareArraysInOrder: true,
keepKeys: []
}
Typescript
To use the differify library with Typescript, you have to configure your tsconfig.json file and enable the following properties:
tsconfig.json
{
"compilerOptions": {
"allowJs": true,
"esModuleInterop": true,
}
}
then in your .ts file, you can import Differify this way:
import Differify, { DIFF_MODES } from '@casterradev/differify';
// See the examples section.
Examples
You have to know that the configuration you provide will change the behavior of the comparators and it will result in different outputs.
Just play around with it and use the configuration that fits your needs.
The following image, just represents the idea of what each option does, but is not the real implementation:
Eg:
with the option DIFF:
const testA = [1,2];
const testB = [1,3];
you will get this output (note that there is a detail for each element in the array A and B):
{
"_": [{
"original": 1,
"current": 1,
"status": "EQUAL",
"changes": 0
}, {
"original": 2,
"current": 3,
"status": "MODIFIED",
"changes": 1
}],
"status": "MODIFIED",
"changes": 1
}
with the option STRING or REFERENCE:
const testA = [1,2];
const testB = [1,3];
you will get this output (just a string comparison):
{
"original": [1,2],
"current": [1,3],
"status": "MODIFIED",
// always will be 1 or 0 because there is no
// deep checking (use the DIFF option if you want more information)
"changes": 1
}
Array comparison example, keeping the order (compareArraysInOrder: true)
const differify = new Differify({
compareArraysInOrder: true, //default value
mode: { object: 'DIFF', array: 'DIFF' },
});
const diff = differify.compare(['a', 'b'], ['a', 'z', 'b']);
/*
OUTPUT
{
"_": [{
"original": "a",
"current": "a",
"status": "EQUAL",
"changes": 0
}, {
"original": "b",
"current": "z",
"status": "MODIFIED",
"changes": 1
}, {
"original": null,
"current": "b",
"status": "ADDED",
"changes": 1
}],
"status": "MODIFIED",
"changes": 2
}
*/
Array comparison example, without having the order in mind (compareArraysInOrder: false)..
NOTE: In case you have Object elements inside the array and you are using compareArraysInOrder to false and array mode to true, then it will compare the objects as serialized strings to know if they are equal or not.
const differify = new Differify({
compareArraysInOrder: false,
mode: { object: 'DIFF', array: 'DIFF' },
});
const diff = differify.compare(['a', 'b'], ['a', 'z', 'b']);
/*
OUTPUT
{
"_": [{
"original": "a",
"current": "a",
"status": "EQUAL",
"changes": 0
}, {
"original": "b",
"current": "b",
"status": "EQUAL",
"changes": 0
}, {
"original": null,
"current": "z",
"status": "ADDED",
"changes": 1
}],
"status": "MODIFIED",
"changes": 1
}
*/
Your contribution is appreciated (thanks!)
Donate to the original author here! Check out the original repo Here