diff --git a/src/Microsoft.AspNetCore.OData/Query/Expressions/QueryBinder.cs b/src/Microsoft.AspNetCore.OData/Query/Expressions/QueryBinder.cs index 71008b4f6..f7be5ba94 100644 --- a/src/Microsoft.AspNetCore.OData/Query/Expressions/QueryBinder.cs +++ b/src/Microsoft.AspNetCore.OData/Query/Expressions/QueryBinder.cs @@ -1034,7 +1034,7 @@ protected Expression GetFlattenedPropertyExpression(string propertyPath, QueryBi } #endregion - internal string GetFullPropertyPath(SingleValueNode node) + internal static string GetFullPropertyPath(SingleValueNode node) { string path = null; SingleValueNode parent = null; diff --git a/test/Microsoft.AspNetCore.OData.Tests/Models/ModelBuilderHelpers.cs b/test/Microsoft.AspNetCore.OData.Tests/Models/ModelBuilderHelpers.cs index 9436a362f..656dc23e5 100644 --- a/test/Microsoft.AspNetCore.OData.Tests/Models/ModelBuilderHelpers.cs +++ b/test/Microsoft.AspNetCore.OData.Tests/Models/ModelBuilderHelpers.cs @@ -83,7 +83,6 @@ public static ODataModelBuilder Add_Address_ComplexType(this ODataModelBuilder b address.Property(a => a.Street); address.Property(a => a.City); address.Property(a => a.State); - address.HasDynamicProperties(a => a.DynamicProperties); return builder; } diff --git a/test/Microsoft.AspNetCore.OData.Tests/Query/Expressions/QueryBinderTests.cs b/test/Microsoft.AspNetCore.OData.Tests/Query/Expressions/QueryBinderTests.cs index e580c2f1f..22af6b1ef 100644 --- a/test/Microsoft.AspNetCore.OData.Tests/Query/Expressions/QueryBinderTests.cs +++ b/test/Microsoft.AspNetCore.OData.Tests/Query/Expressions/QueryBinderTests.cs @@ -161,6 +161,161 @@ public void GetPropertyExpression_Works_ForAggregateOrNonAggregate(bool isAggreg Assert.NotNull(expression); Assert.Equal(expected, expression.ToString()); } + + [Fact] + public void GetFullPropertyPath_WithSingleComplexNode() + { + // Arrange + Mock structuredType = new Mock(); + Mock navigationSource = new Mock(); + ResourceRangeVariable rangeVariable = new ResourceRangeVariable("$it", structuredType.Object, navigationSource.Object); + ResourceRangeVariableReferenceNode source = new ResourceRangeVariableReferenceNode("$it", rangeVariable); + + Mock type = new Mock(); + + Mock property = new Mock(); + property.Setup(p => p.Name).Returns("Address"); + property.Setup(p => p.PropertyKind).Returns(EdmPropertyKind.Structural); + property.Setup(p => p.Type).Returns(type.Object); + + SingleComplexNode node = new SingleComplexNode(source, property.Object); + + // Act + string fullPropertyPath = QueryBinder.GetFullPropertyPath(node); + + // Assert + Assert.Equal("Address", fullPropertyPath); + } + + [Fact] + public void GetFullPropertyPath_WithSingleValuePropertyAccessNode() + { + // Arrange + Mock structuredType = new Mock(); + Mock navigationSource = new Mock(); + ResourceRangeVariable rangeVariable = new ResourceRangeVariable("$it", structuredType.Object, navigationSource.Object); + ResourceRangeVariableReferenceNode source = new ResourceRangeVariableReferenceNode("$it", rangeVariable); + + Mock type = new Mock(); + + Mock property = new Mock(); + property.Setup(p => p.Name).Returns("ZipCode"); + property.Setup(p => p.PropertyKind).Returns(EdmPropertyKind.Structural); + property.Setup(p => p.Type).Returns(type.Object); + + SingleValuePropertyAccessNode node = new SingleValuePropertyAccessNode(source, property.Object); + + // Act + string fullPropertyPath = QueryBinder.GetFullPropertyPath(node); + + // Assert + Assert.Equal("ZipCode", fullPropertyPath); + } + + [Fact] + public void GetFullPropertyPath_WithSingleNavigationNode() + { + // Arrange + Mock structuredType = new Mock(); + Mock navigationSource = new Mock(); + ResourceRangeVariable rangeVariable = new ResourceRangeVariable("$it", structuredType.Object, navigationSource.Object); + ResourceRangeVariableReferenceNode source = new ResourceRangeVariableReferenceNode("$it", rangeVariable); + + Mock type = new Mock(); + + Mock property = new Mock(); + property.Setup(p => p.Name).Returns("Address"); + property.Setup(p => p.Type).Returns(type.Object); + + Mock bindingPath = new Mock(); + + SingleNavigationNode node = new SingleNavigationNode(source, property.Object, bindingPath.Object); + + // Act + string fullPropertyPath = QueryBinder.GetFullPropertyPath(node); + + // Assert + Assert.Equal("Address", fullPropertyPath); + } + + [Fact] + public void GetFullPropertyPath_WithSingleValueOpenPropertyAccess() + { + // Arrange + Mock structuredType = new Mock(); + Mock navigationSource = new Mock(); + ResourceRangeVariable rangeVariable = new ResourceRangeVariable("$it", structuredType.Object, navigationSource.Object); + ResourceRangeVariableReferenceNode source = new ResourceRangeVariableReferenceNode("$it", rangeVariable); + + SingleValueOpenPropertyAccessNode node = new SingleValueOpenPropertyAccessNode(source, "ZipCode"); + + // Act + string fullPropertyPath = QueryBinder.GetFullPropertyPath(node); + + // Assert + Assert.Equal("ZipCode", fullPropertyPath); + } + + [Fact] + public void GetFullPropertyPath_WithSingleValuePropertyAccessNodeInSingleComplexNode() + { + // Arrange + Mock structuredType = new Mock(); + Mock navigationSource = new Mock(); + ResourceRangeVariable rangeVariable = new ResourceRangeVariable("$it", structuredType.Object, navigationSource.Object); + ResourceRangeVariableReferenceNode source = new ResourceRangeVariableReferenceNode("$it", rangeVariable); + + Mock complexType = new Mock(); + + Mock complexProperty = new Mock(); + complexProperty.Setup(p => p.Name).Returns("Address"); + complexProperty.Setup(p => p.PropertyKind).Returns(EdmPropertyKind.Structural); + complexProperty.Setup(p => p.Type).Returns(complexType.Object); + + SingleComplexNode complexNode = new SingleComplexNode(source, complexProperty.Object); + + Mock type = new Mock(); + + Mock property = new Mock(); + property.Setup(p => p.Name).Returns("ZipCode"); + property.Setup(p => p.PropertyKind).Returns(EdmPropertyKind.Structural); + property.Setup(p => p.Type).Returns(type.Object); + + SingleValuePropertyAccessNode node = new SingleValuePropertyAccessNode(complexNode, property.Object); + + // Act + string fullPropertyPath = QueryBinder.GetFullPropertyPath(node); + + // Assert + Assert.Equal("Address\\ZipCode", fullPropertyPath); + } + + [Fact] + public void GetFullPropertyPath_WithSingleValueOpenPropertyAccessNodeInSingleComplexNode() + { + // Arrange + Mock structuredType = new Mock(); + Mock navigationSource = new Mock(); + ResourceRangeVariable rangeVariable = new ResourceRangeVariable("$it", structuredType.Object, navigationSource.Object); + ResourceRangeVariableReferenceNode source = new ResourceRangeVariableReferenceNode("$it", rangeVariable); + + Mock complexType = new Mock(); + + Mock complexProperty = new Mock(); + complexProperty.Setup(p => p.Name).Returns("Address"); + complexProperty.Setup(p => p.PropertyKind).Returns(EdmPropertyKind.Structural); + complexProperty.Setup(p => p.Type).Returns(complexType.Object); + + SingleComplexNode complexNode = new SingleComplexNode(source, complexProperty.Object); + + SingleValueOpenPropertyAccessNode node = new SingleValueOpenPropertyAccessNode(complexNode, "ZipCode"); + + // Act + string fullPropertyPath = QueryBinder.GetFullPropertyPath(node); + + // Assert + Assert.Equal("Address\\ZipCode", fullPropertyPath); + } } public class MyQueryBinder : QueryBinder diff --git a/test/Microsoft.AspNetCore.OData.Tests/Query/Query/ApplyQueryOptionTest.cs b/test/Microsoft.AspNetCore.OData.Tests/Query/Query/ApplyQueryOptionTest.cs index 9d4169b3b..17d519d63 100644 --- a/test/Microsoft.AspNetCore.OData.Tests/Query/Query/ApplyQueryOptionTest.cs +++ b/test/Microsoft.AspNetCore.OData.Tests/Query/Query/ApplyQueryOptionTest.cs @@ -1303,9 +1303,15 @@ public void ApplyTo_Returns_Correct_Queryable(string filter, List(); + addressType.HasDynamicProperties(a => a.DynamicProperties); + + var customerType = modelBuilder.EntityType(); + customerType.ComplexProperty(c => c.Address); + + var model = modelBuilder.GetEdmModel(); var context = new ODataQueryContext(model, typeof(Customer));