Tixit / odiff

Gets a list of differences between two javascript values.
MIT License
88 stars 13 forks source link

Filter diff operation by path #9

Open thenikso opened 5 years ago

thenikso commented 5 years ago

I came to a point in a project I am developing where I'd need odiff to "ignore" an object entirely. ie:

// Original
{
  normal: { a: 1, b: 2 },
  ignore: { a: 1, b: 2 }
}

// New
{
  normal: { a: 1, b: 999 },
  ignore: { a: 1, b: 999 }
}

The odiff of those might look like:

[
  { type: 'SET', path: ['normal', 'b'], val: 999 },
  { type: 'SET', path: ['ignore', 'b'], val: 999 },
]

While I'd need to "ignore" the ignore path to produce something like this:

[
  { type: 'SET', path: ['normal', 'b'], val: 999 },
  { type: 'SET', path: ['ignore'], val:  { a: 1, b: 999 } },
]

I believe that deep-diff has a prefilter option to do that. Is there any way to do that with odiff as it is today? Would it make sense instead to attempt a PR to add the "prefilter" thingy?

Thanks!

fresheneesz commented 5 years ago

Hm, so you want some ability to configure odiff to have special behavior on pre-determined paths? What's the core reason for your use case? Is it that those objects are huge? Or do they have cycles? Something else?

I could imagine one might want to do some custom differencing in a similar way. What if we had an API like:

odiff(a,b, {customDiff: function(path, aValue, bValue) {
  // Returns no differences, essentially treating aValue and bValue as the same.
  return [] 
  // "Ignores" the objects (in I think the way you were describing) by treating bValue as a new value set 
  // on the object.
  return [{type:'set', path:path, val:bValue}] 
  // You could return some other array of items, potentially custom items with different structures than the
  // ones created by odiff itself. 
  return [
    ... 
  ]
}})

I'd be open to something like this. Thoughts on that?

thenikso commented 5 years ago

To give some context, my use case is quite specific as I am using odiff to send changes to the server and this particular subfield is stored in JSON but treated like an object client side.

More generally speaking what I am looking for is for odiff to treat some values as scalars even if they are object/arrays. In fact a "workaround" that I was attempting now was to convert that path to JSON in both objects before odiffing.

The API you proposed should definitely do the trick. In fact being able to manually provide a diff could enable even more convoluted use cases (ie: you want to send only an ID of an object if it has changes).

That said I would suggest to allow the customDiff function to return true/false to say:

This would be to simplify the usage of that particular API.

UPDATE: I have currently fixed this problem with a smarter logic on my server. That is I compute the partial diff for that sub-object starting from the stored value.

fresheneesz commented 5 years ago

I have currently fixed this problem with a smarter logic on my server.

Ah ok. Well I'm happy to accept a PR with code for your suggestion on top of my suggestion. But it sounds like maybe you don't need it now?