- adds support for entity set down cast

Signed-off-by: Vincent Biret <vibiret@microsoft.com>
This commit is contained in:
Vincent Biret 2021-11-25 15:00:15 -05:00
parent 4ee8e9e5eb
commit d0b3e2079f
No known key found for this signature in database
GPG key ID: 32426322EDFFB7E3
3 changed files with 104 additions and 53 deletions

View file

@ -190,6 +190,15 @@ namespace Microsoft.OpenApi.OData.Edm
if(count?.Countable ?? true)
CreateCountPath(path, convertSettings);
//TODO read the cast restrictions annotation
var derivedTypes = _model
.FindAllDerivedTypes(entitySet.EntityType())
.Where(x => x.TypeKind == EdmTypeKind.Entity)
.OfType<IEdmEntityType>()
.ToArray();
if(derivedTypes.Any())
CreateTypeCastPaths(path, convertSettings, derivedTypes);
path.Push(new ODataKeySegment(entityType));
AppendPath(path.Clone());
}

View file

@ -7,6 +7,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
@ -31,6 +32,7 @@ internal class ODataTypeCastGetOperationHandler : OperationHandler
internal ODataSegment LastSecondSegment { get; set; }
private NavigationPropertyRestriction restriction;
private IEdmEntitySet entitySet;
private IEdmNavigationProperty navigationProperty;
private IEdmEntityType parentEntityType;
private IEdmEntityType targetEntityType;
@ -67,9 +69,17 @@ internal class ODataTypeCastGetOperationHandler : OperationHandler
}
}
}
else if(LastSecondSegment is ODataNavigationSourceSegment sourceSegment && sourceSegment.NavigationSource is IEdmEntitySet eSet)
{
entitySet = eSet;
NavigationRestrictionsType navigation = Context.Model.GetRecord<NavigationRestrictionsType>(eSet, CapabilitiesConstants.NavigationRestrictions);
if (navigation?.RestrictedProperties != null)
{
restriction = navigation.RestrictedProperties.FirstOrDefault(r => r.NavigationProperty == null);
}
}
//TODO previous segment is a key
//TODO previous segment is a single nav property
//TODO previous segment is an entity set
if(path.Last() is ODataTypeCastSegment oDataTypeCastSegment)
{
targetEntityType = oDataTypeCastSegment.EntityType;
@ -197,55 +207,16 @@ internal class ODataTypeCastGetOperationHandler : OperationHandler
if(navigationProperty != null) {
if (navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many)
{
// Need to verify that TopSupported or others should be applied to navigation source.
// So, how about for the navigation property.
OpenApiParameter parameter = Context.CreateTop(navigationProperty);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
parameter = Context.CreateSkip(navigationProperty);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
parameter = Context.CreateSearch(navigationProperty);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
parameter = Context.CreateFilter(navigationProperty);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
parameter = Context.CreateCount(navigationProperty);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
parameter = Context.CreateOrderBy(navigationProperty);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
parameter = Context.CreateSelect(navigationProperty);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
parameter = Context.CreateExpand(navigationProperty);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
CreateParametersForAnnotableOfMany(operation, navigationProperty)
.Union(
new OpenApiParameter[] {
Context.CreateOrderBy(navigationProperty),
Context.CreateSelect(navigationProperty),
Context.CreateExpand(navigationProperty),
})
.Where(x => x != null)
.ToList()
.ForEach(p => operation.Parameters.Add(p));
}
else
{
@ -262,6 +233,31 @@ internal class ODataTypeCastGetOperationHandler : OperationHandler
}
}
}
else if(entitySet != null)
{
CreateParametersForAnnotableOfMany(operation, entitySet)
.Union(
new OpenApiParameter[] {
Context.CreateOrderBy(entitySet),
Context.CreateSelect(entitySet),
Context.CreateExpand(entitySet),
})
.Where(x => x != null)
.ToList()
.ForEach(p => operation.Parameters.Add(p));
}
}
private IEnumerable<OpenApiParameter> CreateParametersForAnnotableOfMany(OpenApiOperation operation, IEdmVocabularyAnnotatable annotable)
{
// Need to verify that TopSupported or others should be applied to navigation source.
// So, how about for the navigation property.
return new OpenApiParameter[] {
Context.CreateTop(annotable),
Context.CreateSkip(annotable),
Context.CreateSearch(annotable),
Context.CreateFilter(annotable),
Context.CreateCount(annotable),
};
}
protected override void SetSecurity(OpenApiOperation operation)

View file

@ -19,8 +19,8 @@ public class ODataTypeCastGetOperationHandlerTests
[Theory]
[InlineData(true)]
[InlineData(false)]
public void CreateODataTypeCastGetOperationReturnsCorrectOperation(bool enableOperationId)
{
public void CreateODataTypeCastGetOperationReturnsCorrectOperationForCollectionNavigationProperty(bool enableOperationId)
{// ../People/{id}/Friends/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Employee
// Arrange
IEdmModel model = EdmModelHelper.TripServiceModel;
OpenApiConvertSettings settings = new()
@ -66,7 +66,53 @@ public class ODataTypeCastGetOperationHandlerTests
Assert.Null(operation.OperationId);
}
}
//TODO test on entity set
[Theory]
[InlineData(true)]
[InlineData(false)]
public void CreateODataTypeCastGetOperationReturnsCorrectOperationForEntitySet(bool enableOperationId)
{// .../People/Microsoft.OData.Service.Sample.TrippinInMemory.Models.Employee
// Arrange
IEdmModel model = EdmModelHelper.TripServiceModel;
OpenApiConvertSettings settings = new()
{
EnableOperationId = enableOperationId
};
ODataContext context = new(model, settings);
IEdmEntitySet people = model.EntityContainer.FindEntitySet("People");
Assert.NotNull(people);
IEdmEntityType person = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Person");
IEdmEntityType employee = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Employee");
ODataPath path = new(new ODataNavigationSourceSegment(people),
new ODataTypeCastSegment(employee));
// Act
var operation = _operationHandler.CreateOperation(context, path);
// Assert
Assert.NotNull(operation);
Assert.Equal("Get the items of type Microsoft.OData.Service.Sample.TrippinInMemory.Models.Employee in the Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person collection", operation.Summary);
Assert.NotNull(operation.Tags);
var tag = Assert.Single(operation.Tags);
Assert.Equal("Person.Employee", tag.Name);
Assert.NotNull(operation.Parameters);
Assert.Equal(8, operation.Parameters.Count);
Assert.Null(operation.RequestBody);
Assert.Equal(2, operation.Responses.Count);
Assert.Equal(new string[] { "200", "default" }, operation.Responses.Select(e => e.Key));
if (enableOperationId)
{
Assert.Equal("Get.Microsoft.OData.Service.Sample.TrippinInMemory.Models.Person.As.Microsoft.OData.Service.Sample.TrippinInMemory.Models.Employee", operation.OperationId);
}
else
{
Assert.Null(operation.OperationId);
}
}
//TODO test on cast cast key
//TODO test on cast on single nav property
}