- adds unit test for Cast operation handler & cast path item handler
- adds support for query parameters when in navigation properties Signed-off-by: Vincent Biret <vibiret@microsoft.com>
This commit is contained in:
parent
7eee372958
commit
4ee8e9e5eb
|
@ -7,10 +7,12 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.OData.Edm;
|
||||
using Microsoft.OpenApi.Any;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Microsoft.OpenApi.OData.Common;
|
||||
using Microsoft.OpenApi.OData.Edm;
|
||||
using Microsoft.OpenApi.OData.Generator;
|
||||
using Microsoft.OpenApi.OData.Vocabulary.Capabilities;
|
||||
|
||||
namespace Microsoft.OpenApi.OData.Operation;
|
||||
|
||||
|
@ -28,6 +30,8 @@ internal class ODataTypeCastGetOperationHandler : OperationHandler
|
|||
/// </summary>
|
||||
internal ODataSegment LastSecondSegment { get; set; }
|
||||
|
||||
private NavigationPropertyRestriction restriction;
|
||||
private IEdmNavigationProperty navigationProperty;
|
||||
private IEdmEntityType parentEntityType;
|
||||
private IEdmEntityType targetEntityType;
|
||||
private const int SecondLastSegmentIndex = 2;
|
||||
|
@ -42,6 +46,30 @@ internal class ODataTypeCastGetOperationHandler : OperationHandler
|
|||
LastSecondSegment = path.Segments.ElementAt(count - SecondLastSegmentIndex);
|
||||
|
||||
parentEntityType = LastSecondSegment.EntityType;
|
||||
if(LastSecondSegment is ODataNavigationPropertySegment navigationPropertySegment)
|
||||
{
|
||||
navigationProperty = navigationPropertySegment.NavigationProperty;
|
||||
var navigationPropertyPath = string.Join("/",
|
||||
Path.Segments.Where(s => !(s is ODataKeySegment || s is ODataNavigationSourceSegment
|
||||
|| s is ODataStreamContentSegment || s is ODataStreamPropertySegment)).Select(e => e.Identifier));
|
||||
|
||||
if(path.FirstSegment is ODataNavigationSourceSegment navigationSourceSegment)
|
||||
{
|
||||
NavigationRestrictionsType navigation = navigationSourceSegment.NavigationSource switch {
|
||||
IEdmEntitySet entitySet => Context.Model.GetRecord<NavigationRestrictionsType>(entitySet, CapabilitiesConstants.NavigationRestrictions),
|
||||
IEdmSingleton singleton => Context.Model.GetRecord<NavigationRestrictionsType>(singleton, CapabilitiesConstants.NavigationRestrictions),
|
||||
_ => null
|
||||
};
|
||||
|
||||
if (navigation?.RestrictedProperties != null)
|
||||
{
|
||||
restriction = navigation.RestrictedProperties.FirstOrDefault(r => r.NavigationProperty != null && r.NavigationProperty == navigationPropertyPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
//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;
|
||||
|
@ -140,7 +168,130 @@ internal class ODataTypeCastGetOperationHandler : OperationHandler
|
|||
|
||||
base.SetResponses(operation);
|
||||
}
|
||||
//TODO query parameters?
|
||||
//TODO extensions?
|
||||
}
|
||||
//TODO unit tests
|
||||
/// <inheritdoc/>
|
||||
protected override void SetTags(OpenApiOperation operation)
|
||||
{
|
||||
IList<string> items = new List<string>
|
||||
{
|
||||
parentEntityType.Name,
|
||||
targetEntityType.Name,
|
||||
};
|
||||
|
||||
string name = string.Join(".", items);
|
||||
OpenApiTag tag = new()
|
||||
{
|
||||
Name = name
|
||||
};
|
||||
tag.Extensions.Add(Constants.xMsTocType, new OpenApiString("page"));
|
||||
operation.Tags.Add(tag);
|
||||
|
||||
Context.AppendTag(tag);
|
||||
|
||||
base.SetTags(operation);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
protected override void SetParameters(OpenApiOperation operation)
|
||||
{
|
||||
base.SetParameters(operation);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
OpenApiParameter parameter = Context.CreateSelect(navigationProperty);
|
||||
if (parameter != null)
|
||||
{
|
||||
operation.Parameters.Add(parameter);
|
||||
}
|
||||
|
||||
parameter = Context.CreateExpand(navigationProperty);
|
||||
if (parameter != null)
|
||||
{
|
||||
operation.Parameters.Add(parameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void SetSecurity(OpenApiOperation operation)
|
||||
{
|
||||
if (restriction == null || restriction.ReadRestrictions == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ReadRestrictionsBase readBase = restriction.ReadRestrictions;
|
||||
|
||||
operation.Security = Context.CreateSecurityRequirements(readBase.Permissions).ToList();
|
||||
}
|
||||
|
||||
protected override void SetExtensions(OpenApiOperation operation)
|
||||
{
|
||||
if (Context.Settings.EnablePagination)
|
||||
{
|
||||
if (navigationProperty != null && navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many)
|
||||
{
|
||||
OpenApiObject extension = new()
|
||||
{
|
||||
{ "nextLinkName", new OpenApiString("@odata.nextLink")},
|
||||
{ "operationName", new OpenApiString(Context.Settings.PageableOperationName)}
|
||||
};
|
||||
|
||||
operation.Extensions.Add(Constants.xMsPageable, extension);
|
||||
}
|
||||
}
|
||||
|
||||
base.SetExtensions(operation);
|
||||
}
|
||||
}
|
|
@ -22,5 +22,3 @@ internal class ODataTypeCastPathItemHandler : PathItemHandler
|
|||
AddOperation(item, OperationType.Get);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO unit test for the ODataTypeCastPathItemHandler
|
|
@ -0,0 +1,72 @@
|
|||
// ------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
using System.Linq;
|
||||
using Microsoft.OData.Edm;
|
||||
using Microsoft.OpenApi.Extensions;
|
||||
using Microsoft.OpenApi.OData.Edm;
|
||||
using Microsoft.OpenApi.OData.PathItem.Tests;
|
||||
using Microsoft.OpenApi.OData.Tests;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.OpenApi.OData.Operation.Tests;
|
||||
public class ODataTypeCastGetOperationHandlerTests
|
||||
{
|
||||
private readonly ODataTypeCastGetOperationHandler _operationHandler = new ();
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void CreateODataTypeCastGetOperationReturnsCorrectOperation(bool enableOperationId)
|
||||
{
|
||||
// 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");
|
||||
IEdmNavigationProperty navProperty = person.DeclaredNavigationProperties().First(c => c.Name == "Friends");
|
||||
ODataPath path = new(new ODataNavigationSourceSegment(people),
|
||||
new ODataKeySegment(people.EntityType()),
|
||||
new ODataNavigationPropertySegment(navProperty),
|
||||
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(9, 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 entity set
|
||||
//TODO test on cast cast key
|
||||
//TODO test on cast on single nav property
|
||||
}
|
|
@ -22,6 +22,7 @@ namespace Microsoft.OpenApi.OData.PathItem.Tests
|
|||
[InlineData(ODataPathKind.MediaEntity, typeof(MediaEntityPathItemHandler))]
|
||||
[InlineData(ODataPathKind.Metadata, typeof(MetadataPathItemHandler))]
|
||||
[InlineData(ODataPathKind.DollarCount, typeof(DollarCountPathItemHandler))]
|
||||
[InlineData(ODataPathKind.TypeCast, typeof(ODataTypeCastPathItemHandler))]
|
||||
public void GetHandlerReturnsCorrectHandlerType(ODataPathKind pathKind, Type handlerType)
|
||||
{
|
||||
// Arrange
|
||||
|
|
Loading…
Reference in a new issue