diff --git a/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj b/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj index c9dfa666..f5033171 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj +++ b/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj @@ -26,6 +26,7 @@ - Adds a delete operation and a required @id query parameter to collection-valued navigation property paths with $ref #453 - Fixes inconsistency of nullability of schemas of properties that are a collection of structured types #467 - Generates $expand query parameter for operations whose return type is a collection #481 +- Adds delete operation for non-contained navigation properties only if explicitly allowed via annotation #483 Microsoft.OpenApi.OData.Reader ..\..\tool\Microsoft.OpenApi.OData.snk diff --git a/src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs b/src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs index 7445d5e2..47bc6d4b 100644 --- a/src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs +++ b/src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs @@ -247,7 +247,7 @@ public string PathPrefix /// /// Gets/Sets a value indicating whether or not to expand derived types to retrieve their declared navigation properties. /// - [Obsolete("Use RetrieveDerivedTypesProperties to Get or Set the value.")] + [Obsolete("Use GenerateDerivedTypesProperties to Get or Set the value.")] public bool ExpandDerivedTypesNavigationProperties { get => GenerateDerivedTypesProperties; @@ -299,7 +299,7 @@ public bool ExpandDerivedTypesNavigationProperties public bool RequireRestrictionAnnotationsToGenerateComplexPropertyPaths { get; set; } = true; /// - /// Gets/sets a dictionary containing a mapping of custom atttribute names and extension names. + /// Gets/sets a dictionary containing a mapping of custom attribute names and extension names. /// public Dictionary CustomXMLAttributesMapping { get; set; } = new(); diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs index a95743e1..37084b61 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------ +// ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ @@ -197,31 +197,26 @@ private void AddDeleteOperation(OpenApiPathItem item, NavigationPropertyRestrict Debug.Assert(!LastSegmentIsRefSegment); DeleteRestrictionsType navPropDeleteRestriction = restriction?.DeleteRestrictions ?? - Context.Model.GetRecord(NavigationProperty); - - if (NavigationProperty.ContainsTarget) - { - DeleteRestrictionsType entityDeleteRestriction = Context.Model.GetRecord(_navPropEntityType); - bool isDeletableDefault = navPropDeleteRestriction == null && entityDeleteRestriction == null; - - if (isDeletableDefault || - ((entityDeleteRestriction?.IsDeletable ?? true) && - (navPropDeleteRestriction?.IsDeletable ?? true))) - { - if (NavigationProperty.TargetMultiplicity() != EdmMultiplicity.Many || LastSegmentIsKeySegment) - { - AddOperation(item, OperationType.Delete); - } - } + Context.Model.GetRecord(NavigationProperty); + + if (!(NavigationProperty.TargetMultiplicity() != EdmMultiplicity.Many || LastSegmentIsKeySegment)) + return; + + DeleteRestrictionsType entityDeleteRestriction = Context.Model.GetRecord(_navPropEntityType); + bool isDeletable = + (navPropDeleteRestriction == null && entityDeleteRestriction == null) || + ((entityDeleteRestriction?.IsDeletable ?? true) && + (navPropDeleteRestriction?.IsDeletable ?? true)); + + if (NavigationProperty.ContainsTarget && isDeletable) + { + AddOperation(item, OperationType.Delete); } - else - { - if ((navPropDeleteRestriction?.IsDeletable ?? false) && - (NavigationProperty.TargetMultiplicity() != EdmMultiplicity.Many || - LastSegmentIsKeySegment)) - { - AddOperation(item, OperationType.Delete); - } + else if (navPropDeleteRestriction?.Deletable ?? false) + { + // Add delete operation for non-contained nav. props only if explicitly set to true via annotation + // Note: Use Deletable and NOT IsDeletable + AddOperation(item, OperationType.Delete); } return; diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/NavigationPropertyPathItemHandlerTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/NavigationPropertyPathItemHandlerTests.cs index e06ce16d..66aedac9 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/NavigationPropertyPathItemHandlerTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/NavigationPropertyPathItemHandlerTests.cs @@ -61,12 +61,22 @@ public void CreatePathItemThrowsForNonNavigationPropertyPath() [Theory] [InlineData(true, true, new OperationType[] { OperationType.Get, OperationType.Patch, OperationType.Delete })] [InlineData(true, false, new OperationType[] { OperationType.Get, OperationType.Post })] - [InlineData(false, true, new OperationType[] { OperationType.Get })] + [InlineData(false, true, new OperationType[] { OperationType.Get, OperationType.Delete })] // Deletablity explicitly set via annotation [InlineData(false, false, new OperationType[] { OperationType.Get})] public void CreateCollectionNavigationPropertyPathItemReturnsCorrectPathItem(bool containment, bool keySegment, OperationType[] expected) { + string annotation = + containment ? + "" : + @" + + + + +"; + // Arrange - IEdmModel model = GetEdmModel(""); + IEdmModel model = GetEdmModel(annotation: "", annotation2: annotation); ODataContext context = new ODataContext(model); IEdmEntitySet entitySet = model.EntityContainer.FindEntitySet("Customers"); Assert.NotNull(entitySet); // guard @@ -591,7 +601,7 @@ public void CreateNavigationPropertyPathItemAddsCustomAttributeValuesToPathExten Assert.Equal("true", isHiddenValue); } - public static IEdmModel GetEdmModel(string annotation) + public static IEdmModel GetEdmModel(string annotation, string annotation2 = "") { const string template = @" @@ -629,11 +639,14 @@ public static IEdmModel GetEdmModel(string annotation) {0} + + {1} + "; - string modelText = string.Format(template, annotation); + string modelText = string.Format(template, annotation, annotation2); IEdmModel model; IEnumerable errors;