Resolves #34. This change extends the capabilities of the Option class that is leveraged by JsonDiffPatch to apply diff patches. This change introduces an ExcludePaths property that allows you to specify the paths of the properties that you want the patch process to ignore. This is useful for preventing Id or other sensitive fields from being updated. This change also introduces a DiffBehaviors property that allows you to modify the behavior of the diff patch process. Specifying a behavior of IgnoreMissingProperties will prevent the patch process from deleting properties from the source object that aren't specified in the patch object, creating an avenue for partial updates to be applied. Specifying a behavior of IgnoreNewProperties will pevent properties that exist in the patch object but not in the source object from being applied to the source object. The implementation is applied exactly in accordance to the comment I made on issue #34 - https://github.com/wbish/jsondiffpatch.net/issues/34
parent
a0508be76a
commit
c40cf5dcff
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
@ -296,6 +297,6 @@ namespace JsonDiffPatchDotNet.UnitTests
|
|||
Assert.AreEqual(2, array.Count);
|
||||
Assert.AreEqual(left, array[0]);
|
||||
Assert.AreEqual(right, array[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
@ -246,6 +247,61 @@ namespace JsonDiffPatchDotNet.UnitTests
|
|||
var patched = jdp.Patch(left, patch);
|
||||
|
||||
Assert.IsTrue(JToken.DeepEquals(right.ToString(), patched.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_ExcludePaths_ValidPatch()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options { ExcludePaths = new List<string>() { "id", "nested.id" } });
|
||||
var left = JObject.Parse(@"{ ""id"": ""pid"", ""p"": ""old"", ""nested"": { ""id"":""nid"", ""p"":""old"" } }");
|
||||
var right = JObject.Parse(@"{ ""id"": ""pid2"", ""p"": ""new"", ""nested"": { ""id"":""nid2"", ""p"":""new"" } }");
|
||||
var expected = JObject.Parse(@"{ ""id"": ""pid"", ""p"": ""new"", ""nested"": { ""id"":""nid"", ""p"":""new"" } }");
|
||||
var patch = jdp.Diff(left, right);
|
||||
var patched = jdp.Patch(left, patch) as JObject;
|
||||
|
||||
Assert.AreEqual(expected.ToString(), patched.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_Behaviors_IgnoreMissingProperties_ValidPatch()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options { DiffBehaviors = DiffBehavior.IgnoreMissingProperties });
|
||||
var left = JObject.Parse(@"{ ""id"": ""pid"", ""p"": ""old"", ""nested"": { ""id"":""nid"", ""p"":""old"" } }");
|
||||
var right = JObject.Parse(@"{ ""p"": ""new"", ""nested"": { ""p"":""new"" }, ""newP"": ""new"" }");
|
||||
var expected = JObject.Parse(@"{ ""id"": ""pid"", ""p"": ""new"", ""nested"": { ""id"":""nid"", ""p"":""new"" }, ""newP"": ""new"" }");
|
||||
var patch = jdp.Diff(left, right);
|
||||
var patched = jdp.Patch(left, patch) as JObject;
|
||||
|
||||
Assert.AreEqual(expected.ToString(), patched.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_Behaviors_IgnoreNewProperties_ValidPatch()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options { DiffBehaviors = DiffBehavior.IgnoreNewProperties });
|
||||
var left = JObject.Parse(@"{ ""id"": ""pid"", ""p"": ""old"", ""nested"": { ""id"":""nid"", ""p"":""old"" } }");
|
||||
var right = JObject.Parse(@"{ ""id"": ""pid2"", ""p"": ""new"", ""nested"": { ""id"":""nid2"", ""p"":""new"" }, ""newP"": ""new"" }");
|
||||
var expected = JObject.Parse(@"{ ""id"": ""pid2"", ""p"": ""new"", ""nested"": { ""id"":""nid2"", ""p"":""new"" } }");
|
||||
var patch = jdp.Diff(left, right);
|
||||
var patched = jdp.Patch(left, patch) as JObject;
|
||||
|
||||
Assert.AreEqual(expected.ToString(), patched.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Diff_ExludeAndBehaviors_ExcludeIgnoreMissingIgnoreNew_ValidPatch()
|
||||
{
|
||||
var jdp = new JsonDiffPatch(new Options {
|
||||
ExcludePaths = new List<string>() { "id", "nested.id" },
|
||||
DiffBehaviors = DiffBehavior.IgnoreMissingProperties | DiffBehavior.IgnoreNewProperties
|
||||
});
|
||||
var left = JObject.Parse(@"{ ""id"": ""pid"", ""p"": ""old"", ""nested"": { ""id"":""nid"", ""p"":""old"" } }");
|
||||
var right = JObject.Parse(@"{ ""id"": ""pid2"", ""nested"": { ""id"":""nid2"" }, ""newP"": ""new"" }");
|
||||
var expected = JObject.Parse(@"{ ""id"": ""pid"", ""p"": ""old"", ""nested"": { ""id"":""nid"", ""p"":""old"" } }");
|
||||
var patch = jdp.Diff(left, right);
|
||||
var patched = jdp.Patch(left, patch) as JObject;
|
||||
|
||||
Assert.AreEqual(expected.ToString(), patched.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace JsonDiffPatchDotNet
|
||||
{
|
||||
[Flags]
|
||||
public enum DiffBehavior
|
||||
{
|
||||
/// <summary>
|
||||
/// Default behavior
|
||||
/// </summary>
|
||||
None,
|
||||
/// <summary>
|
||||
/// If the patch document is missing properties that are in the source document, leave the existing properties in place instead of deleting them
|
||||
/// </summary>
|
||||
IgnoreMissingProperties,
|
||||
/// <summary>
|
||||
/// If the patch document contains properties that aren't defined in the source document, ignore them instead of adding them
|
||||
/// </summary>
|
||||
IgnoreNewProperties
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using DiffMatchPatch;
|
||||
|
@ -43,15 +44,15 @@ namespace JsonDiffPatchDotNet
|
|||
right = new JValue("");
|
||||
|
||||
if (left.Type == JTokenType.Object && right.Type == JTokenType.Object)
|
||||
{
|
||||
return ObjectDiff((JObject)left, (JObject)right);
|
||||
{
|
||||
return ObjectDiff((JObject)left, (JObject)right);
|
||||
}
|
||||
|
||||
if (_options.ArrayDiff == ArrayDiffMode.Efficient
|
||||
&& left.Type == JTokenType.Array
|
||||
&& right.Type == JTokenType.Array)
|
||||
{
|
||||
return ArrayDiff((JArray)left, (JArray)right);
|
||||
{
|
||||
return ArrayDiff((JArray)left, (JArray)right);
|
||||
}
|
||||
|
||||
if (_options.TextDiff == TextDiffMode.Efficient
|
||||
|
@ -66,8 +67,10 @@ namespace JsonDiffPatchDotNet
|
|||
: null;
|
||||
}
|
||||
|
||||
if (!JToken.DeepEquals(left, right))
|
||||
return new JArray(left, right);
|
||||
if (!JToken.DeepEquals(left, right))
|
||||
{
|
||||
return new JArray(left, right);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -324,10 +327,21 @@ namespace JsonDiffPatchDotNet
|
|||
|
||||
// Find properties modified or deleted
|
||||
foreach (var lp in left.Properties())
|
||||
{
|
||||
JProperty rp = right.Property(lp.Name);
|
||||
{
|
||||
//Skip property if in path exclustions
|
||||
if (_options.ExcludePaths.Count > 0 && _options.ExcludePaths.Any(p => p.Equals(lp.Path, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
JProperty rp = right.Property(lp.Name);
|
||||
|
||||
// Property deleted
|
||||
if (rp == null && (_options.DiffBehaviors & DiffBehavior.IgnoreMissingProperties) == DiffBehavior.IgnoreMissingProperties)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Property deleted
|
||||
if (rp == null)
|
||||
{
|
||||
diffPatch.Add(new JProperty(lp.Name, new JArray(lp.Value, 0, (int)DiffOperation.Deleted)));
|
||||
|
@ -343,8 +357,8 @@ namespace JsonDiffPatchDotNet
|
|||
|
||||
// Find properties that were added
|
||||
foreach (var rp in right.Properties())
|
||||
{
|
||||
if (left.Property(rp.Name) != null)
|
||||
{
|
||||
if (left.Property(rp.Name) != null || (_options.DiffBehaviors & DiffBehavior.IgnoreNewProperties) == DiffBehavior.IgnoreNewProperties)
|
||||
continue;
|
||||
|
||||
diffPatch.Add(new JProperty(rp.Name, new JArray(rp.Value)));
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
namespace JsonDiffPatchDotNet
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace JsonDiffPatchDotNet
|
||||
{
|
||||
public sealed class Options
|
||||
{
|
||||
{
|
||||
public Options()
|
||||
{
|
||||
ArrayDiff = ArrayDiffMode.Efficient;
|
||||
|
@ -23,6 +27,16 @@
|
|||
/// The minimum string length required to use Efficient text diff. If the minimum
|
||||
/// length is not met, simple text diff will be used. The default length is 50 characters.
|
||||
/// </summary>
|
||||
public long MinEfficientTextDiffLength { get; set; }
|
||||
public long MinEfficientTextDiffLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies which paths to exclude from the diff patch set
|
||||
/// </summary>
|
||||
public List<string> ExcludePaths { get; set; } = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Specifies behaviors to apply to the diff patch set
|
||||
/// </summary>
|
||||
public DiffBehavior DiffBehaviors { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue