in edge-util/src/Microsoft.Azure.Devices.Edge.Util/JsonEx.cs [99:174]
public static JObject Diff(JToken fromToken, JToken toToken)
{
var patch = new JObject();
// both 'from' and 'to' must be objects
if (fromToken.Type != JTokenType.Object || toToken.Type != JTokenType.Object)
{
return patch;
}
var from = (JObject)fromToken;
var to = (JObject)toToken;
foreach (JProperty fromProp in from.Properties())
{
if (IsValidToken(fromProp.Value))
{
JProperty toProp = to.Property(fromProp.Name);
if (toProp != null)
{
// if this property exists in 'to' and is an object then do a
// recursive deep diff
if (fromProp.Value.Type == JTokenType.Object && toProp.Value.Type == JTokenType.Object)
{
JObject obj = Diff(fromProp.Value, toProp.Value);
// if something was added in 'obj' then there's a diff to be
// patched in this sub-object
if (obj.HasValues)
{
patch.Add(fromProp.Name, obj);
}
}
// if this property exists in 'to' but has a different value
// then add the prop from 'to' to 'patch'
else if (fromProp.Value.Type != toProp.Value.Type || !JToken.DeepEquals(fromProp.Value, toProp.Value))
{
patch.Add(fromProp.Name, toProp.Value);
}
}
// if a property exists in 'from' but not in 'to' then that
// is to be deleted
else
{
patch.Add(fromProp.Name, JValue.CreateNull());
}
}
else
{
throw new InvalidOperationException($"Property {fromProp.Name} has a value of unsupported type. Valid types are integer, float, string, bool, null and nested object");
}
}
foreach (JProperty toProp in to.Properties())
{
if (IsValidToken(toProp.Value))
{
JProperty fromProp = from.Property(toProp.Name);
// if this property exists in 'to' but not in 'from' then
// add it to 'patch'
if (fromProp == null)
{
patch.Add(toProp.Name, toProp.Value);
}
}
else
{
throw new InvalidOperationException($"Property {toProp.Name} has a value of unsupported type. Valid types are integer, float, string, bool, null and nested object");
}
}
return patch;
}