Starcounter-Jack / JSON-Patch

Lean and mean Javascript implementation of the JSON-Patch standard (RFC 6902). Update JSON documents using delta patches.
MIT License
1.79k stars 215 forks source link

compare() on child objects, replace as complete objects #243

Open lwestfall opened 4 years ago

lwestfall commented 4 years ago

I'm experiencing behavior that my API isn't handling well when I pass my patch document to it, I've narrowed it down to compare()'s tendency to "deep compare" only, and by that I mean it's comparing atomic properties of child objects, and generating individual replace operations deeper into the path. What I'd rather have is a single replace operation for a given child object if any property of the child is different, with the path being only a single level deep. I hope that makes sense. Is there a way to get my desired behavior? Thanks in advance.

Example case:

const objA = {
  complexProp: {
    firstName: 'john',
    lastName: 'doe',
    emailAddress: null
  }
};

const objB = {
  complexProp: {
    firstName: 'mike',
    lastName: 'smith',
    emailAddress: null
  }
};

console.log(JSON.stringify(compare(objA, objB)));

yields

[{"op":"replace","path":"/complexProp/lastName","value":"smith"},
{"op":"replace","path":"/complexProp/firstName","value":"mike"}]

Desired would be:

[{"op":"replace","path":"/complexProp","value":{ "lastName":"smith", "firstName":"mike"}}]
kresli commented 4 years ago

I dont think this is a bug but correct behaviour. Think of it a way where your desired behaviour will create a new object but actually you just replacing values of object.

lwestfall commented 4 years ago

I'm not necessarily suggesting this is a bug, but rather an opportunity to accommodate some backend ORMs. Edit: In other words, it'd be very nice to add a switch or an overload that would form the patch json in the way I desire.

To clarify, my child object will have an id (I didn't include in my example) which my backend will look up. So it won't create a new object assuming that id is present and valid.

I don't think RFC 5789 is explicit enough to say that one method is "more correct" than the other. What I can say though is that .Net Core's JsonPatchDocument and EF Core really do not seem to like these atomic replace operations on tracked entities (it thinks you want to change the properties of the tracked entity rather than replace the entire entity completely, which is very undesirable). I don't discount the possibility that I'm just doing it wrong, however.

For now I've decided to just add end points for every property (including those that are child objects) on my back end to handle the updates. It'd be nice to take advantage of patch and have a single endpoint but unfortunately JSON-Patch nor other similar libraries are able do what I'm looking for.