Skip to content

Commit fb4bb5e

Browse files
authored
Fixes reading restriction annotations for entity types defining navigation properties (#223)
* Read restrictions annotations for entity types annotated out of line * Refactor code; add test to validate out of line restriction annotation * Remove unnecessary code * Update csproj with release note
1 parent 33efcb0 commit fb4bb5e

File tree

3 files changed

+59
-8
lines changed

3 files changed

+59
-8
lines changed

src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
<RepositoryUrl>https://github.com/Microsoft/OpenAPI.NET.OData</RepositoryUrl>
2323
<PackageReleaseNotes>
2424
- Adds list of all derived types for discriminator mapping #219
25+
- Fixes reading restriction annotations for entity types defining navigation properties #220
2526
</PackageReleaseNotes>
2627
<AssemblyName>Microsoft.OpenApi.OData.Reader</AssemblyName>
2728
<AssemblyOriginatorKeyFile>..\..\tool\Microsoft.OpenApi.OData.snk</AssemblyOriginatorKeyFile>

src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,10 @@ internal class NavigationPropertyPathItemHandler : PathItemHandler
4444
/// </summary>
4545
protected bool LastSegmentIsRefSegment { get; private set; }
4646

47-
/// <inheritdoc/>
48-
protected override void SetOperations(OpenApiPathItem item)
47+
private IEdmEntityType _entityType;
48+
49+
/// <inheritdoc/>
50+
protected override void SetOperations(OpenApiPathItem item)
4951
{
5052
IEdmEntitySet entitySet = NavigationSource as IEdmEntitySet;
5153
IEdmVocabularyAnnotatable target = entitySet;
@@ -78,12 +80,16 @@ protected override void SetOperations(OpenApiPathItem item)
7880
{
7981
if (LastSegmentIsKeySegment)
8082
{
81-
AddUpdateOperation(item, restriction);
83+
UpdateRestrictionsType updateEntity = Context.Model.GetRecord<UpdateRestrictionsType>(_entityType);
84+
if (updateEntity?.IsUpdatable ?? true)
85+
{
86+
AddUpdateOperation(item, restriction);
87+
}
8288
}
8389
else
8490
{
8591
InsertRestrictionsType insert = restriction?.InsertRestrictions;
86-
if (insert == null || insert.IsInsertable)
92+
if (insert?.IsInsertable ?? true)
8793
{
8894
AddOperation(item, OperationType.Post);
8995
}
@@ -121,7 +127,8 @@ private void AddGetOperation(OpenApiPathItem item, NavigationPropertyRestriction
121127
}
122128
else
123129
{
124-
if (read.IsReadable)
130+
ReadRestrictionsType readEntity = Context.Model.GetRecord<ReadRestrictionsType>(_entityType);
131+
if (readEntity?.IsReadable ?? true)
125132
{
126133
AddOperation(item, OperationType.Get);
127134
}
@@ -155,13 +162,17 @@ private void AddDeleteOperation(OpenApiPathItem item, NavigationPropertyRestrict
155162
}
156163

157164
DeleteRestrictionsType delete = restriction?.DeleteRestrictions;
158-
if (delete == null || delete.IsDeletable)
165+
DeleteRestrictionsType deleteEntity = Context.Model.GetRecord<DeleteRestrictionsType>(_entityType);
166+
bool isDeletableDefault = delete == null && deleteEntity == null;
167+
168+
if (isDeletableDefault ||
169+
(delete?.IsDeletable ?? false) ||
170+
(deleteEntity?.IsDeletable ?? false))
159171
{
160172
if (NavigationProperty.TargetMultiplicity() != EdmMultiplicity.Many || LastSegmentIsKeySegment)
161173
{
162174
AddOperation(item, OperationType.Delete);
163175
}
164-
165176
return;
166177
}
167178
}
@@ -193,6 +204,7 @@ protected override void Initialize(ODataContext context, ODataPath path)
193204
LastSegmentIsKeySegment = path.LastSegment.Kind == ODataSegmentKind.Key;
194205
LastSegmentIsRefSegment = path.LastSegment.Kind == ODataSegmentKind.Ref;
195206
NavigationProperty = path.OfType<ODataNavigationPropertySegment>().Last().NavigationProperty;
207+
_entityType = NavigationProperty.ToEntityType();
196208
}
197209

198210
/// <inheritdoc/>

test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/NavigationPropertyPathItemHandlerTests.cs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// ------------------------------------------------------------
1+
// ------------------------------------------------------------
22
// Copyright (c) Microsoft Corporation. All rights reserved.
33
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
44
// ------------------------------------------------------------
@@ -14,6 +14,7 @@
1414
using Microsoft.OpenApi.Models;
1515
using Microsoft.OpenApi.OData.Edm;
1616
using Microsoft.OpenApi.OData.Properties;
17+
using Microsoft.OpenApi.OData.Tests;
1718
using Xunit;
1819

1920
namespace Microsoft.OpenApi.OData.PathItem.Tests
@@ -471,6 +472,43 @@ public void CreatePathItemForNavigationPropertyAndUpdateMethodUpdateRestrictions
471472
Assert.Equal(expected, pathItem.Operations.Select(o => o.Key));
472473
}
473474

475+
[Fact]
476+
public void CreatePathItemForNavigationPropertyWithOutOfLineRestrictionAnnotations()
477+
{
478+
// Arrange
479+
IEdmModel model = EdmModelHelper.GraphBetaModel;
480+
OpenApiConvertSettings settings = new()
481+
{
482+
ExpandDerivedTypesNavigationProperties = false
483+
};
484+
ODataContext context = new(model, settings);
485+
IEdmSingleton ipSingleton = model.EntityContainer.FindSingleton("informationProtection");
486+
Assert.NotNull(ipSingleton);
487+
IEdmEntityType ipEntity = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "informationProtection");
488+
Assert.NotNull(ipEntity);
489+
IEdmNavigationProperty bitlockerNavProp = ipEntity.DeclaredNavigationProperties().First(c => c.Name == "bitlocker");
490+
Assert.NotNull(bitlockerNavProp);
491+
IEdmEntityType bitlockerEntity = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "bitlocker");
492+
Assert.NotNull(bitlockerEntity);
493+
IEdmNavigationProperty rkNavProp = bitlockerEntity.DeclaredNavigationProperties().First(c => c.Name == "recoveryKeys");
494+
Assert.NotNull(rkNavProp);
495+
496+
ODataPath path = new(new ODataNavigationSourceSegment(ipSingleton),
497+
new ODataNavigationPropertySegment(bitlockerNavProp),
498+
new ODataNavigationPropertySegment(rkNavProp),
499+
new ODataKeySegment(rkNavProp.ToEntityType()));
500+
Assert.NotNull(path);
501+
502+
// Act
503+
var pathItem = _pathItemHandler.CreatePathItem(context, path);
504+
505+
// Assert
506+
Assert.NotNull(pathItem);
507+
Assert.NotNull(pathItem.Operations);
508+
Assert.Single(pathItem.Operations);
509+
Assert.Equal(OperationType.Get, pathItem.Operations.FirstOrDefault().Key);
510+
}
511+
474512
[Fact]
475513
public void CreateNavigationPropertyPathItemAddsCustomAttributeValuesToPathExtensions()
476514
{

0 commit comments

Comments
 (0)