I have a function that takes in two objects as parameters, and then compares those two objects, recursively, to produce a new object. I am now setting up some tests for this function. If I want to add a node to the root of one of the objects, on the fly, in a succinct way, I can do this:
diff(oldObj, {...newObj, testRootProp: 'testValue'});
My question is, is there a succinct way I can add a node to the object when the node I want to add to is not at the root?
For instance, say I want to take this object:
{
id: 1,
name: "John"
associates: [
{name: "Samantha"},
{name: "Jonah"},
]
}
And produce this:
{
id: 1,
name: "John"
associates: [
{name: "Samantha"},
{name: "Jonah", member: false}, // this has changed
]
}
Is there a succinct way I can do that with my diff(oldObj, newObj) function, making this change on the fly by what I pass in, rather than having to pass the entire new object as the second parameter?
You could add a parameter to diff, which would specify where on the target object to put the extra value.
const location = {
name: 'Arbys',
hours: {
monday: {open: '8:00 AM', close: '10:00 PM'},
tuesday: {open: '8:00 AM', close: '10:00 PM'},
wednesday: {open: '8:00 AM', close: '10:00 PM'},
thursday: {open: '8:00 AM', close: '10:00 PM'},
friday: {open: '8:00 AM', close: '10:00 PM'},
saturday: {open: '8:00 AM', close: '10:00 PM'},
},
};
const newLocation = diff(
location,
{ open: "10:00 AM", close: "9:00 PM" },
{ path: 'hours.sunday' }
);
// newLocation
// {
// name: 'Arbys',
// hours: {
// monday: {open: '8:00 AM', close: '10:00 PM'},
// tuesday: {open: '8:00 AM', close: '10:00 PM'},
// wednesday: {open: '8:00 AM', close: '10:00 PM'},
// thursday: {open: '8:00 AM', close: '10:00 PM'},
// friday: {open: '8:00 AM', close: '10:00 PM'},
// saturday: {open: '8:00 AM', close: '10:00 PM'},
// sunday: { open: "10:00 AM", close: "9:00 PM" },
// },
// }
Your example is tricker because you need to change something inside an array.
const person = {
id: 1,
name: "John",
associates: [
{name: "Samantha"},
{name: "Jonah"},
],
};
const newPerson = diff(
person,
false,
{
path: '[associates].member',
finders: [
(node) => node['name'] === 'Jonah',
],
}
);
The third param specifies how to place the new false values. It says:
associates.finders array to find the object(s) we want to add to.member key to the found object(s) with the value false.In this way, you can specify any place on the target object to place the new value.
const college = {
students: [ /* ... */ ],
// ...
};
const mutatedCollege = diff(
college,
{ name: 'Randy', id: '12345' },
{
path: '[students].[courses].professor',
finders: [
(student) => student.isFullTime,
(course) => course.hours > 3,
],
},
);
Of course, the caller can still omit the third param and just merge the objects:
const a = {foo: 'x');
const b = {bar: 'y');
const c = diff(a, b);
// c
// {
// foo: 'x',
// bar: 'y',
// }