diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/RecordExpressionExtensions.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/RecordExpressionExtensions.cs index 01cf7aea..5d8dc6d4 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/RecordExpressionExtensions.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/RecordExpressionExtensions.cs @@ -94,18 +94,30 @@ public static string GetString(this IEdmRecordExpression record, string property /// The property name. /// The Enum value or null. public static T? GetEnum(this IEdmRecordExpression record, string propertyName) - where T : struct + where T : struct, Enum { Utils.CheckArgumentNull(record, nameof(record)); Utils.CheckArgumentNull(propertyName, nameof(propertyName)); - return (record.Properties?.FirstOrDefault(e => propertyName.Equals(e.Name, StringComparison.Ordinal)) is IEdmPropertyConstructor property && + if (record.Properties?.FirstOrDefault(e => propertyName.Equals(e.Name, StringComparison.Ordinal)) + is IEdmPropertyConstructor property && property.Value is IEdmEnumMemberExpression value && value.EnumMembers != null && - value.EnumMembers.Any() && - Enum.TryParse(value.EnumMembers.First().Name, out T result)) ? - result : - null; + value.EnumMembers.Any()) + { + long combinedValue = 0; + foreach (var enumMember in value.EnumMembers) + { + if (Enum.TryParse(enumMember.Name, out T enumValue)) + { + combinedValue |= Convert.ToInt64(enumValue); + } + } + + return (T)Enum.ToObject(typeof(T), combinedValue); + } + + return null; } /// 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 4283a792..feae9f0d 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj +++ b/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj @@ -15,15 +15,16 @@ net8.0 Microsoft.OpenApi.OData true - 2.0.0-preview.1 + 2.0.0-preview.2 This package contains the codes you need to convert OData CSDL to Open API Document of Model. © Microsoft Corporation. All rights reserved. Microsoft OpenApi OData EDM https://github.com/Microsoft/OpenAPI.NET.OData - Upgraded to Microsoft.Odata.Edm 8.0.0 - - Cleaned up obsolete APIs - - Changed target framework to net8.0 + - Cleaned up obsolete APIs + - Changed target framework to net8.0 + - Adds support for retrieving collection of enum values from UpdateMethod property of UpdateRestrictions annotation #564 Microsoft.OpenApi.OData.Reader ..\..\tool\Microsoft.OpenApi.OData.snk diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/ComplexPropertyItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/ComplexPropertyItemHandler.cs index 866dcef3..b08a2289 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/ComplexPropertyItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/ComplexPropertyItemHandler.cs @@ -70,7 +70,12 @@ public void AddUpdateOperation(OpenApiPathItem item) if ((Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths && isUpdatable) || !Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths) { - if (updateRestrictions != null && updateRestrictions.IsUpdateMethodPut) + if (updateRestrictions?.IsUpdateMethodPutAndPatch == true) + { + AddOperation(item, OperationType.Put); + AddOperation(item, OperationType.Patch); + } + else if (updateRestrictions?.IsUpdateMethodPut == true) { AddOperation(item, OperationType.Put); } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/EntityPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/EntityPathItemHandler.cs index 243d6f3b..0cbbb54c 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/EntityPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/EntityPathItemHandler.cs @@ -40,7 +40,12 @@ protected override void SetOperations(OpenApiPathItem item) updateRestrictions ??= entityUpdateRestrictions; if (updateRestrictions?.IsUpdatable ?? true) { - if (updateRestrictions != null && updateRestrictions.IsUpdateMethodPut) + if (updateRestrictions?.IsUpdateMethodPutAndPatch == true) + { + AddOperation(item, OperationType.Put); + AddOperation(item, OperationType.Patch); + } + else if (updateRestrictions?.IsUpdateMethodPut == true) { AddOperation(item, OperationType.Put); } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs index 57b36119..e66675f7 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs @@ -243,17 +243,23 @@ private void AddDeleteOperation(OpenApiPathItem item, NavigationPropertyRestrict private void AddUpdateOperation(OpenApiPathItem item, UpdateRestrictionsType updateRestrictionsType) { - if (updateRestrictionsType == null || updateRestrictionsType.IsUpdatable) - { - if (updateRestrictionsType != null && updateRestrictionsType.IsUpdateMethodPut) - { - AddOperation(item, OperationType.Put); - } - else - { - AddOperation(item, OperationType.Patch); - } - } + if (updateRestrictionsType?.IsUpdatable ?? true) + { + if (updateRestrictionsType?.IsUpdateMethodPutAndPatch == true) + { + AddOperation(item, OperationType.Put); + AddOperation(item, OperationType.Patch); + } + else if (updateRestrictionsType?.IsUpdateMethodPut == true) + { + AddOperation(item, OperationType.Put); + } + else + { + AddOperation(item, OperationType.Patch); + } + } + } /// diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/UpdateRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/UpdateRestrictionsType.cs index 27e3e8f5..ff073e39 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/UpdateRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/UpdateRestrictionsType.cs @@ -3,6 +3,7 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System; using System.Collections.Generic; using System.Linq; using Microsoft.OData.Edm.Vocabularies; @@ -14,17 +15,18 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities /// /// Enumerates HTTP methods that can be used to update entities /// + [Flags] internal enum HttpMethod { /// /// The HTTP PATCH Method /// - PATCH, + PATCH = 1, /// /// The HTTP PUT Method /// - PUT + PUT = 2 } /// /// Complex Type: Org.OData.Capabilities.V1.UpdateRestrictionsType @@ -46,10 +48,10 @@ internal class UpdateRestrictionsType : IRecord /// /// Gets the value indicating Entities can be inserted, updated, and deleted via a PATCH request with a delta payload. /// - public bool? DeltaUpdateSupported { get; private set; } - + public bool? DeltaUpdateSupported { get; private set; } + /// - /// Gets the value indicating the HTTP Method (PUT or PATCH) for updating an entity. + /// Gets the values indicating the HTTP Method (PUT and/or PATCH) for updating an entity. /// If null, PATCH should be supported and PUT MAY be supported. /// public HttpMethod? UpdateMethod { get; private set; } @@ -124,10 +126,16 @@ public bool IsNonUpdatableNavigationProperty(string navigationPropertyPath) } /// - /// Tests whether the update method for the entity has been explicitly specified as PUT + /// Tests whether the update method for the target has been explicitly specified as PUT /// public bool IsUpdateMethodPut => UpdateMethod.HasValue && UpdateMethod.Value == HttpMethod.PUT; + /// + /// Tests whether the update method for the target has been explicitly specified as PATCH and PUT + /// + public bool IsUpdateMethodPutAndPatch => UpdateMethod.HasValue && + (UpdateMethod.Value & (HttpMethod.PUT | HttpMethod.PATCH)) == (HttpMethod.PUT | HttpMethod.PATCH); + /// /// Lists the media types acceptable for the request content /// @@ -157,7 +165,7 @@ public void Initialize(IEdmRecordExpression record) // DeltaUpdateSupported DeltaUpdateSupported = record.GetBoolean("DeltaUpdateSupported"); - // UpdateMethod + // UpdateMethod UpdateMethod = record.GetEnum("UpdateMethod"); // FilterSegmentSupported diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/NavigationPropertyPathItemHandlerTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/NavigationPropertyPathItemHandlerTests.cs index 20e9c066..31eddf46 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/NavigationPropertyPathItemHandlerTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/NavigationPropertyPathItemHandlerTests.cs @@ -452,7 +452,7 @@ public void CreatePathItemForNavigationPropertyAndUpdateMethodUpdateRestrictions - Org.OData.Capabilities.V1.HttpMethod/PUT + Org.OData.Capabilities.V1.HttpMethod/PUT Org.OData.Capabilities.V1.HttpMethod/PATCH @@ -488,21 +488,21 @@ public void CreatePathItemForNavigationPropertyAndUpdateMethodUpdateRestrictions if (isContainment) { expected = updatable - ? (new[] { OperationType.Get, OperationType.Put, OperationType.Delete }) - : (new[] { OperationType.Get, OperationType.Delete }); + ? ([OperationType.Get, OperationType.Put, OperationType.Patch, OperationType.Delete]) + : ([OperationType.Get, OperationType.Delete]); } else { expected = updatable - ? (new[] { OperationType.Get, OperationType.Put }) - : (new[] { OperationType.Get }); + ? ([OperationType.Get, OperationType.Put, OperationType.Patch,]) + : ([OperationType.Get]); } } else { expected = isContainment - ? (new[] { OperationType.Get, OperationType.Patch, OperationType.Delete }) - : (new[] { OperationType.Get }); + ? ([OperationType.Get, OperationType.Patch, OperationType.Delete]) + : ([OperationType.Get]); }