Skip to content

Commit

Permalink
Add TryGetNestedPropertyValue in DeltaOfT
Browse files Browse the repository at this point in the history
  • Loading branch information
xuzhg committed Jan 7, 2022
1 parent ed424ce commit c6ed979
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 25 deletions.
54 changes: 40 additions & 14 deletions src/Microsoft.AspNetCore.OData/Deltas/DeltaOfT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -174,18 +174,8 @@ public override bool TryGetPropertyValue(string name, out object value)
}
}

if (_deltaNestedResources.ContainsKey(name))
if (TryGetNestedPropertyValue(name, out value))
{
// If this is a nested resource, get the value from the dictionary of nested resources.
object deltaNestedResource = _deltaNestedResources[name];

Contract.Assert(deltaNestedResource != null, "deltaNestedResource != null");
Contract.Assert(DeltaHelper.IsDeltaOfT(deltaNestedResource.GetType()));

// Get the Delta<{NestedResourceType}>._instance using Reflection.
FieldInfo field = deltaNestedResource.GetType().GetField("_instance", BindingFlags.NonPublic | BindingFlags.Instance);
Contract.Assert(field != null, "field != null");
value = field.GetValue(deltaNestedResource);
return true;
}
else
Expand All @@ -203,6 +193,42 @@ public override bool TryGetPropertyValue(string name, out object value)
return false;
}

/// <summary>
/// Attempts to get the value of the nested Property called <paramref name="name"/> from the underlying resource.
/// <remarks>
/// Only properties that exist on Entity can be retrieved.
/// Only modified nested properties can be retrieved.
/// The nested Property type will be <see cref="IDelta"/> of its defined type.
/// </remarks>
/// </summary>
/// <param name="name">The name of the nested Property</param>
/// <param name="value">The value of the nested Property</param>
/// <returns><c>True</c> if the Property was found and is a nested Property</returns>
public bool TryGetNestedPropertyValue(string name, out object value)
{
if (name == null)
{
throw Error.ArgumentNull(nameof(name));
}

if (!_deltaNestedResources.ContainsKey(name))
{
value = null;
return false;
}

// This is a nested resource, the value returned must be an IDelta<T>
// from the dictionary of nested resources to allow the traversal of
// hierarchies of Delta<T>.
object deltaNestedResource = _deltaNestedResources[name];

Contract.Assert(deltaNestedResource != null, "deltaNestedResource != null");
Contract.Assert(DeltaHelper.IsDeltaOfT(deltaNestedResource.GetType()));

value = deltaNestedResource;
return true;
}

/// <inheritdoc/>
public override bool TryGetPropertyType(string name, out Type type)
{
Expand Down Expand Up @@ -291,7 +317,7 @@ public void CopyChangedValues(T original)
// to prevent unrecognizable information from being applied to original resource.
if (!_structuredType.IsAssignableFrom(original.GetType()))
{
throw Error.Argument("original", SRResources.DeltaTypeMismatch, _structuredType, original.GetType());
throw Error.Argument(nameof(original), SRResources.DeltaTypeMismatch, _structuredType, original.GetType());
}

RuntimeHelpers.EnsureSufficientExecutionStack();
Expand Down Expand Up @@ -354,7 +380,7 @@ public void CopyUnchangedValues(T original)

if (!_structuredType.IsInstanceOfType(original))
{
throw Error.Argument("original", SRResources.DeltaTypeMismatch, _structuredType, original.GetType());
throw Error.Argument(nameof(original), SRResources.DeltaTypeMismatch, _structuredType, original.GetType());
}

IEnumerable<PropertyAccessor<T>> propertiesToCopy = GetUnchangedPropertyNames().Select(s => _allProperties[s]);
Expand Down Expand Up @@ -472,7 +498,7 @@ private void Reset(Type structuralType)
{
if (structuralType == null)
{
throw Error.ArgumentNull("structuralType");
throw Error.ArgumentNull(nameof(structuralType));
}

if (!typeof(T).IsAssignableFrom(structuralType))
Expand Down
13 changes: 13 additions & 0 deletions src/Microsoft.AspNetCore.OData/Microsoft.AspNetCore.OData.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1631,6 +1631,19 @@
<member name="M:Microsoft.AspNetCore.OData.Deltas.Delta`1.TryGetPropertyValue(System.String,System.Object@)">
<inheritdoc/>
</member>
<member name="M:Microsoft.AspNetCore.OData.Deltas.Delta`1.TryGetNestedPropertyValue(System.String,System.Object@)">
<summary>
Attempts to get the value of the nested Property called <paramref name="name"/> from the underlying resource.
<remarks>
Only properties that exist on Entity can be retrieved.
Only modified nested properties can be retrieved.
The nested Property type will be <see cref="T:Microsoft.AspNetCore.OData.Deltas.IDelta"/> of its defined type.
</remarks>
</summary>
<param name="name">The name of the nested Property</param>
<param name="value">The value of the nested Property</param>
<returns><c>True</c> if the Property was found and is a nested Property</returns>
</member>
<member name="M:Microsoft.AspNetCore.OData.Deltas.Delta`1.TryGetPropertyType(System.String,System.Type@)">
<inheritdoc/>
</member>
Expand Down
1 change: 1 addition & 0 deletions src/Microsoft.AspNetCore.OData/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ Microsoft.AspNetCore.OData.Deltas.Delta<T>.Delta(System.Type structuralType, Sys
Microsoft.AspNetCore.OData.Deltas.Delta<T>.GetInstance() -> T
Microsoft.AspNetCore.OData.Deltas.Delta<T>.Patch(T original) -> void
Microsoft.AspNetCore.OData.Deltas.Delta<T>.Put(T original) -> void
Microsoft.AspNetCore.OData.Deltas.Delta<T>.TryGetNestedPropertyValue(string name, out object value) -> bool
Microsoft.AspNetCore.OData.Deltas.Delta<T>.UpdatableProperties.get -> System.Collections.Generic.IList<string>
Microsoft.AspNetCore.OData.Deltas.DeltaDeletedResource<T>
Microsoft.AspNetCore.OData.Deltas.DeltaDeletedResource<T>.DeltaDeletedResource() -> void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,11 @@ public IActionResult Patch(int key, Delta<Bill> delta)
Assert.Equal(6.24, weight);

Assert.True(delta.TryGetPropertyValue("HomeAddress", out object homeAddressObj));
Address homeAddress = Assert.IsType<Address>(homeAddressObj);
Assert.Equal("YouStreet", homeAddress.Street);
Assert.Equal("YouCity", homeAddress.City);
Delta<Address> homeAddress = Assert.IsType<Delta<Address>>(homeAddressObj);
Address originalHomeAddress = new Address();
homeAddress.Patch(originalHomeAddress);
Assert.Equal("YouStreet", originalHomeAddress.Street);
Assert.Equal("YouCity", originalHomeAddress.City);

Assert.True(delta.TryGetPropertyValue("Addresses", out object addressesObj));
Assert.Collection((IList<Address>)addressesObj,
Expand Down
39 changes: 38 additions & 1 deletion test/Microsoft.AspNetCore.OData.Tests/Deltas/DeltaTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,14 @@ public void TryGetPropertyType_ThrowsArgumentNull_original()
ExceptionAssert.ThrowsArgumentNull(() => delta.TryGetPropertyType(null, out _), "name");
}

[Fact]
public void TryGetNestedPropertyValue_ThrowsArgumentNull_original()
{
// Arrange & Act
Delta<Base> delta = new Delta<Base>();
ExceptionAssert.ThrowsArgumentNull(() => delta.TryGetNestedPropertyValue(null, out _), "name");
}

[Theory]
[MemberData(nameof(DeltaModelPropertyNamesData))]
public void RoundTrip_Properties(string propertyName, object value)
Expand Down Expand Up @@ -227,11 +235,40 @@ public void CanGetChangedNestedDeltaPropertyNames()

// read the nested property back
Assert.True(ideltaCustomer.TryGetPropertyValue("Address", out dynamic nestedAddress));
Assert.IsAssignableFrom<AddressEntity>(nestedAddress);
Assert.IsAssignableFrom<Delta<AddressEntity>>(nestedAddress);
Assert.Equal("Sammamish", nestedAddress.City);
Assert.Equal("23213 NE 15th Ct", nestedAddress.StreetAddress);
}

[Fact]
public void CannotGetChangedNestedDeltaPropertyNames()
{
dynamic deltaCustomer = new Delta<CustomerEntity>();
IDelta ideltaCustomer = deltaCustomer as IDelta;

AddressEntity address = new AddressEntity();

// modify
address.City = "Sammamish";
address.StreetAddress = "23213 NE 15th Ct";

// modify the nested property
ideltaCustomer.TrySetPropertyValue("Address", address);
Assert.Single(ideltaCustomer.GetChangedPropertyNames());
Assert.Equal("Address", ideltaCustomer.GetChangedPropertyNames().Single());
Assert.Equal(3, ideltaCustomer.GetUnchangedPropertyNames().Count());

// read the not nested property back using legacy API
Assert.True(ideltaCustomer.TryGetPropertyValue("Address", out dynamic deltaAddressEntity));
Assert.IsAssignableFrom<AddressEntity>(deltaAddressEntity);
AddressEntity addressEntity = deltaAddressEntity as AddressEntity;
Assert.Equal("23213 NE 15th Ct", addressEntity.StreetAddress);
Assert.Equal("Sammamish", addressEntity.City);

// read the not nested property back using nested API
Assert.False(deltaCustomer.TryGetNestedPropertyValue("Address", out dynamic deltaNestedAddress));
}

[Fact]
public void CanGetChangedPropertyNamesButOnlyUpdatable()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,7 @@ public class Microsoft.AspNetCore.OData.Deltas.Delta`1 : Microsoft.AspNetCore.OD
public virtual System.Collections.Generic.IEnumerable`1[[System.String]] GetUnchangedPropertyNames ()
public void Patch (T original)
public void Put (T original)
public bool TryGetNestedPropertyValue (string name, out System.Object& value)
public virtual bool TryGetPropertyType (string name, out System.Type& type)
public virtual bool TryGetPropertyValue (string name, out System.Object& value)
public virtual bool TrySetPropertyValue (string name, object value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,7 @@ public class Microsoft.AspNetCore.OData.Deltas.Delta`1 : Microsoft.AspNetCore.OD
public virtual System.Collections.Generic.IEnumerable`1[[System.String]] GetUnchangedPropertyNames ()
public void Patch (T original)
public void Put (T original)
public bool TryGetNestedPropertyValue (string name, out System.Object& value)
public virtual bool TryGetPropertyType (string name, out System.Type& type)
public virtual bool TryGetPropertyValue (string name, out System.Object& value)
public virtual bool TrySetPropertyValue (string name, object value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -560,15 +560,16 @@ public IActionResult PatchToAddress(int key, Delta<OpenAddress> address)
Assert.NotNull(addressInstance.LineA.PhoneInfo);
Assert.Equal(7654321, addressInstance.LineA.PhoneInfo.PhoneNumber);

object lineAValue;
// Fetch LineA property using TryGetPropertyValue
Assert.True(address.TryGetPropertyValue("LineA", out lineAValue));
LineDetails lineA = lineAValue as LineDetails;
Assert.NotNull(lineA);
object nestedLineAValue;
// Fetch LineA property using TryGetNestedPropertyValue
Assert.True(address.TryGetNestedPropertyValue("LineA", out nestedLineAValue));
Delta<LineDetails> deltaLineA = nestedLineAValue as Delta<LineDetails>;
Assert.NotNull(deltaLineA);

// Nested complex property
Assert.NotNull(lineA.PhoneInfo);
Assert.Equal(7654321, lineA.PhoneInfo.PhoneNumber);
dynamic nestedLineA = deltaLineA;
Assert.NotNull(nestedLineA.PhoneInfo);
Assert.Equal(7654321, nestedLineA.PhoneInfo.PhoneNumber);
break;
default:
// Error
Expand Down

0 comments on commit c6ed979

Please sign in to comment.