From 1bc424cc2a5fcccaf343ff5b186383518eb30ceb Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Fri, 14 Mar 2025 14:50:34 -0400 Subject: [PATCH 01/24] feat: migrates to the latest preview of OAI.net Signed-off-by: Vincent Biret --- .../Edm/ODataContext.cs | 4 +- .../Generator/OpenApiDocumentGenerator.cs | 2 +- .../Generator/OpenApiPathItemGenerator.cs | 5 +- .../Generator/OpenApiTagGenerator.cs | 4 +- .../Microsoft.OpenAPI.OData.Reader.csproj | 2 +- .../ComplexPropertyGetOperationHandler.cs | 3 +- .../ComplexPropertyPatchOperationHandler.cs | 3 +- .../ComplexPropertyPostOperationHandler.cs | 3 +- .../ComplexPropertyPutOperationHandler.cs | 3 +- .../ComplexPropertyUpdateOperationHandler.cs | 3 +- .../DollarCountGetOperationHandler.cs | 3 +- .../EdmActionImportOperationHandler.cs | 3 +- .../Operation/EdmActionOperationHandler.cs | 3 +- .../EdmFunctionImportOperationHandler.cs | 3 +- .../Operation/EdmFunctionOperationHandler.cs | 3 +- .../Operation/EntityDeleteOperationHandler.cs | 3 +- .../Operation/EntityGetOperationHandler.cs | 3 +- .../Operation/EntityPatchOperationHandler.cs | 3 +- .../Operation/EntityPutOperationHandler.cs | 3 +- .../Operation/EntitySetGetOperationHandler.cs | 3 +- .../EntitySetPostOperationHandler.cs | 3 +- .../Operation/EntityUpdateOperationHandler.cs | 3 +- .../Operation/IOperationHandler.cs | 3 +- .../Operation/IOperationHandlerProvider.cs | 3 +- .../MediaEntityDeleteOperationHandler.cs | 3 +- .../MediaEntityGetOperationHandler.cs | 3 +- .../MediaEntityPutOperationHandler.cs | 3 +- .../Operation/MetadataGetOperationHandler.cs | 3 +- ...avigationPropertyDeleteOperationHandler.cs | 3 +- .../NavigationPropertyGetOperationHandler.cs | 3 +- ...NavigationPropertyPatchOperationHandler.cs | 3 +- .../NavigationPropertyPostOperationHandler.cs | 3 +- .../NavigationPropertyPutOperationHandler.cs | 3 +- ...avigationPropertyUpdateOperationHandler.cs | 3 +- .../ODataTypeCastGetOperationHandler.cs | 3 +- .../Operation/OperationHandler.cs | 15 +- .../Operation/OperationHandlerProvider.cs | 67 ++++----- .../Operation/RefDeleteOperationHandler.cs | 3 +- .../Operation/RefGetOperationHandler.cs | 3 +- .../Operation/RefPostOperationHandler.cs | 3 +- .../Operation/RefPutOperationHandler.cs | 3 +- .../Operation/SingletonGetOperationHandler.cs | 3 +- .../SingletonPatchOperationHandler.cs | 3 +- .../PathItem/ComplexPropertyItemHandler.cs | 13 +- .../PathItem/DollarCountPathItemHandler.cs | 3 +- .../PathItem/EntityPathItemHandler.cs | 13 +- .../PathItem/EntitySetPathItemHandler.cs | 5 +- .../PathItem/MediaEntityPathItemHandler.cs | 7 +- .../PathItem/MetadataPathItemHandler.cs | 3 +- .../NavigationPropertyPathItemHandler.cs | 25 ++-- .../PathItem/ODataTypeCastPathItemHandler.cs | 3 +- .../OperationImportPathItemHandler.cs | 5 +- .../PathItem/OperationPathItemHandler.cs | 5 +- .../PathItem/PathItemHandler.cs | 3 +- .../PathItem/RefPathItemHandler.cs | 9 +- .../PathItem/SingletonPathItemHandler.cs | 5 +- .../Capabilities/UpdateRestrictionsType.cs | 132 +++++++++--------- .../EdmModelOpenApiExtensionsTest.cs | 4 +- .../OpenApiDocumentGeneratorTests.cs | 2 +- ...icrosoft.OpenAPI.OData.Reader.Tests.csproj | 2 +- .../OperationHandlerProviderTests.cs | 53 +++---- .../ComplexPropertyPathItemHandlerTests.cs | 35 ++--- .../PathItem/EntityPathItemHandlerTests.cs | 43 +++--- .../PathItem/EntitySetPathItemHandlerTests.cs | 25 ++-- .../MediaEntityPathItemHandlerTests.cs | 47 ++++--- .../NavigationPropertyPathItemHandlerTests.cs | 70 +++++----- .../OperationImportPathItemHandlerTests.cs | 21 +-- .../PathItem/OperationPathItemHandlerTests.cs | 9 +- .../PathItem/RefPathItemHandlerTests.cs | 13 +- .../PathItem/SingletonPathItemHandlerTests.cs | 21 +-- 70 files changed, 422 insertions(+), 361 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataContext.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataContext.cs index 8f60d1876..300accc9f 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataContext.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataContext.cs @@ -135,7 +135,7 @@ public IEnumerable AllPaths /// /// Gets all tags. /// - public IList Tags { get; private set; } + public ISet Tags { get; private set; } /// /// Append tag. @@ -143,7 +143,7 @@ public IEnumerable AllPaths /// The tag item. internal void AppendTag(OpenApiTag tagItem) { - Tags ??= []; + Tags ??= new HashSet(); if (FindTagByName(tagItem.Name) is not null) { diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiDocumentGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiDocumentGenerator.cs index 273ae47f4..b2b606e53 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiDocumentGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiDocumentGenerator.cs @@ -38,7 +38,7 @@ public static OpenApiDocument CreateDocument(this ODataContext context) Servers = context.CreateServers(), - SecurityRequirements = null, + Security = null, ExternalDocs = null, }; diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiPathItemGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiPathItemGenerator.cs index 604b5676a..5aa19ad11 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiPathItemGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiPathItemGenerator.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; +using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; @@ -58,9 +59,9 @@ public static void AddPathItemsToDocument(this ODataContext context, OpenApiDocu { OpenApiPathItem rootPath = new() { - Operations = new Dictionary { + Operations = new Dictionary { { - OperationType.Get, new OpenApiOperation { + HttpMethod.Get, new OpenApiOperation { OperationId = "graphService.GetGraphService", Responses = new OpenApiResponses() { diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiTagGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiTagGenerator.cs index 83ffe828c..c96d76952 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiTagGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiTagGenerator.cs @@ -22,7 +22,7 @@ internal static class OpenApiTagGenerator /// /// The OData context. /// The created collection of object. - public static IList CreateTags(this ODataContext context) + public static ISet CreateTags(this ODataContext context) { Utils.CheckArgumentNull(context, nameof(context)); @@ -38,7 +38,7 @@ public static IList CreateTags(this ODataContext context) return context.Tags; } - IList tags = new List(); + var tags = new HashSet(); if (context.EntityContainer != null) { foreach (IEdmEntityContainerElement element in context.Model.EntityContainer.Elements) 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 cc8404e20..b3e53b2a9 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj +++ b/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj @@ -29,7 +29,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyGetOperationHandler.cs index b8e01cccd..6e873c83c 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyGetOperationHandler.cs @@ -4,6 +4,7 @@ // ------------------------------------------------------------ using System.Linq; +using System.Net.Http; using System.Text.Json.Nodes; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; @@ -28,7 +29,7 @@ public ComplexPropertyGetOperationHandler(OpenApiDocument document):base(documen } /// - public override OperationType OperationType => OperationType.Get; + public override HttpMethod OperationType => HttpMethod.Get; private ReadRestrictionsType _readRestrictions; diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPatchOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPatchOperationHandler.cs index 43aeafa43..a79a42eeb 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPatchOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPatchOperationHandler.cs @@ -3,6 +3,7 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Net.Http; using Microsoft.OpenApi.Models; namespace Microsoft.OpenApi.OData.Operation; @@ -18,5 +19,5 @@ public ComplexPropertyPatchOperationHandler(OpenApiDocument document):base(docum } /// - public override OperationType OperationType => OperationType.Patch; + public override HttpMethod OperationType => HttpMethod.Patch; } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPostOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPostOperationHandler.cs index 1d6c4e93a..a6734b032 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPostOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPostOperationHandler.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; @@ -41,7 +42,7 @@ protected override void Initialize(ODataContext context, ODataPath path) _insertRestrictions ??= complexPropertyInsertRestrictions; } /// - public override OperationType OperationType => OperationType.Post; + public override HttpMethod OperationType => HttpMethod.Post; private InsertRestrictionsType _insertRestrictions; diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPutOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPutOperationHandler.cs index 3ea9d2995..e8793d0e4 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPutOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPutOperationHandler.cs @@ -3,6 +3,7 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Net.Http; using Microsoft.OpenApi.Models; namespace Microsoft.OpenApi.OData.Operation; @@ -18,5 +19,5 @@ public ComplexPropertyPutOperationHandler(OpenApiDocument document) : base(docum } /// - public override OperationType OperationType => OperationType.Put; + public override HttpMethod OperationType => HttpMethod.Put; } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyUpdateOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyUpdateOperationHandler.cs index c05aa00d3..1ac6ce8da 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyUpdateOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyUpdateOperationHandler.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; +using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; @@ -50,7 +51,7 @@ protected override void SetBasicInfo(OpenApiOperation operation) // OperationId if (Context.Settings.EnableOperationId) { - string prefix = OperationType == OperationType.Patch ? "Update" : "Set"; + string prefix = OperationType == HttpMethod.Patch ? "Update" : "Set"; operation.OperationId = EdmModelHelper.GenerateComplexPropertyPathOperationId(Path, Context, prefix); } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/DollarCountGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/DollarCountGetOperationHandler.cs index 226f45015..fa22a713f 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/DollarCountGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/DollarCountGetOperationHandler.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OData.Edm.Vocabularies; using Microsoft.OpenApi.Any; @@ -33,7 +34,7 @@ public DollarCountGetOperationHandler(OpenApiDocument document) : base(document) } /// - public override OperationType OperationType => OperationType.Get; + public override HttpMethod OperationType => HttpMethod.Get; /// /// Gets/sets the segment before $count. diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionImportOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionImportOperationHandler.cs index 7d932f7e5..4111f9ddf 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionImportOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionImportOperationHandler.cs @@ -3,6 +3,7 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; @@ -25,7 +26,7 @@ public EdmActionImportOperationHandler(OpenApiDocument document):base(document) } /// - public override OperationType OperationType => OperationType.Post; + public override HttpMethod OperationType => HttpMethod.Post; protected override void SetRequestBody(OpenApiOperation operation) { diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionOperationHandler.cs index 39549df1f..057147b30 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionOperationHandler.cs @@ -3,6 +3,7 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; @@ -28,7 +29,7 @@ public EdmActionOperationHandler(OpenApiDocument document) : base(document) } /// - public override OperationType OperationType => OperationType.Post; + public override HttpMethod OperationType => HttpMethod.Post; /// protected override void SetBasicInfo(OpenApiOperation operation) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionImportOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionImportOperationHandler.cs index 94522cb92..50ec9a9f5 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionImportOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionImportOperationHandler.cs @@ -3,6 +3,7 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; @@ -25,7 +26,7 @@ public EdmFunctionImportOperationHandler(OpenApiDocument document) : base(docume } /// - public override OperationType OperationType => OperationType.Get; + public override HttpMethod OperationType => HttpMethod.Get; /// protected override void SetParameters(OpenApiOperation operation) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionOperationHandler.cs index 559663ebf..802ccbbf4 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionOperationHandler.cs @@ -3,6 +3,7 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; @@ -26,7 +27,7 @@ public EdmFunctionOperationHandler(OpenApiDocument document):base(document) } /// - public override OperationType OperationType => OperationType.Get; + public override HttpMethod OperationType => HttpMethod.Get; /// /// Gets the Edm Function. diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityDeleteOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityDeleteOperationHandler.cs index 343e8f997..8b2091f05 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityDeleteOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityDeleteOperationHandler.cs @@ -4,6 +4,7 @@ // ------------------------------------------------------------ using System.Linq; +using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; @@ -29,7 +30,7 @@ public EntityDeleteOperationHandler(OpenApiDocument document) : base(document) } /// - public override OperationType OperationType => OperationType.Delete; + public override HttpMethod OperationType => HttpMethod.Delete; private DeleteRestrictionsType _deleteRestrictions; diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityGetOperationHandler.cs index eca54745d..224c38333 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityGetOperationHandler.cs @@ -13,6 +13,7 @@ using Microsoft.OpenApi.OData.Edm; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Models.Interfaces; +using System.Net.Http; namespace Microsoft.OpenApi.OData.Operation { @@ -32,7 +33,7 @@ public EntityGetOperationHandler(OpenApiDocument document) : base(document) } /// - public override OperationType OperationType => OperationType.Get; + public override HttpMethod OperationType => HttpMethod.Get; private ReadRestrictionsType _readRestrictions; diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityPatchOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityPatchOperationHandler.cs index b99f6d559..aa003143b 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityPatchOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityPatchOperationHandler.cs @@ -3,6 +3,7 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Net.Http; using Microsoft.OpenApi.Models; namespace Microsoft.OpenApi.OData.Operation @@ -23,6 +24,6 @@ public EntityPatchOperationHandler(OpenApiDocument document) : base(document) } /// - public override OperationType OperationType => OperationType.Patch; + public override HttpMethod OperationType => HttpMethod.Patch; } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityPutOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityPutOperationHandler.cs index 7cb79f953..be418dbd8 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityPutOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityPutOperationHandler.cs @@ -3,6 +3,7 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Net.Http; using Microsoft.OpenApi.Models; namespace Microsoft.OpenApi.OData.Operation @@ -23,6 +24,6 @@ public EntityPutOperationHandler(OpenApiDocument document) : base(document) } /// - public override OperationType OperationType => OperationType.Put; + public override HttpMethod OperationType => HttpMethod.Put; } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetGetOperationHandler.cs index e4d4067c4..9dba9d979 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetGetOperationHandler.cs @@ -4,6 +4,7 @@ // ------------------------------------------------------------ using System.Linq; +using System.Net.Http; using System.Text.Json.Nodes; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; @@ -33,7 +34,7 @@ public EntitySetGetOperationHandler(OpenApiDocument document) : base(document) } /// - public override OperationType OperationType => OperationType.Get; + public override HttpMethod OperationType => HttpMethod.Get; private ReadRestrictionsType _readRestrictions; diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetPostOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetPostOperationHandler.cs index 4167d7d3b..046ba8380 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetPostOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetPostOperationHandler.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; +using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; @@ -33,7 +34,7 @@ public EntitySetPostOperationHandler(OpenApiDocument document) : base(document) } /// - public override OperationType OperationType => OperationType.Post; + public override HttpMethod OperationType => HttpMethod.Post; private InsertRestrictionsType _insertRestrictions; diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityUpdateOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityUpdateOperationHandler.cs index 01568a1b0..a34d6d9f2 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityUpdateOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityUpdateOperationHandler.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; +using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; @@ -60,7 +61,7 @@ protected override void SetBasicInfo(OpenApiOperation operation) if (Context.Settings.EnableOperationId) { string typeName = entityType.Name; - string prefix = OperationType == OperationType.Patch ? "Update" : "Set"; + string prefix = OperationType == HttpMethod.Patch ? "Update" : "Set"; string operationName = $"{prefix}{ Utils.UpperFirstChar(typeName)}"; if (keySegment.IsAlternateKey) { diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/IOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/IOperationHandler.cs index cd9d807dc..1faef29ab 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/IOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/IOperationHandler.cs @@ -3,6 +3,7 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Net.Http; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Edm; @@ -16,7 +17,7 @@ internal interface IOperationHandler /// /// The operation type. /// - OperationType OperationType { get; } + HttpMethod OperationType { get; } /// /// Create the . diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/IOperationHandlerProvider.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/IOperationHandlerProvider.cs index 0c311836c..be07c065f 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/IOperationHandlerProvider.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/IOperationHandlerProvider.cs @@ -3,6 +3,7 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Net.Http; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Edm; @@ -20,6 +21,6 @@ internal interface IOperationHandlerProvider /// The operation type. /// The Open API document to use to lookup references. /// The corresponding . - IOperationHandler GetHandler(ODataPathKind pathKind, OperationType operationType, OpenApiDocument document); + IOperationHandler GetHandler(ODataPathKind pathKind, HttpMethod operationType, OpenApiDocument document); } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityDeleteOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityDeleteOperationHandler.cs index fc71789a9..af94ff02c 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityDeleteOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityDeleteOperationHandler.cs @@ -5,6 +5,7 @@ using Microsoft.OpenApi.OData.Generator; using Microsoft.OpenApi.OData.Vocabulary.Capabilities; using System.Linq; +using System.Net.Http; namespace Microsoft.OpenApi.OData.Operation { @@ -19,7 +20,7 @@ public MediaEntityDeleteOperationHandler(OpenApiDocument document) : base(docume } /// - public override OperationType OperationType => OperationType.Delete; + public override HttpMethod OperationType => HttpMethod.Delete; private DeleteRestrictionsType _deleteRestrictions; diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityGetOperationHandler.cs index 60a95ccdc..1f6a695b7 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityGetOperationHandler.cs @@ -11,6 +11,7 @@ using Microsoft.OpenApi.OData.Generator; using Microsoft.OpenApi.OData.Vocabulary.Capabilities; using System.Linq; +using System.Net.Http; namespace Microsoft.OpenApi.OData.Operation { @@ -28,7 +29,7 @@ public MediaEntityGetOperationHandler(OpenApiDocument document) : base(document) } /// - public override OperationType OperationType => OperationType.Get; + public override HttpMethod OperationType => HttpMethod.Get; private ReadRestrictionsType _readRestrictions = null; protected override void Initialize(ODataContext context, ODataPath path) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityPutOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityPutOperationHandler.cs index a1b9649ab..0fde994a4 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityPutOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityPutOperationHandler.cs @@ -5,6 +5,7 @@ using System; using System.Linq; +using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OData.Edm.Vocabularies; using Microsoft.OpenApi.Models; @@ -30,7 +31,7 @@ public MediaEntityPutOperationHandler(OpenApiDocument document):base(document) } /// - public override OperationType OperationType => OperationType.Put; + public override HttpMethod OperationType => HttpMethod.Put; private UpdateRestrictionsType _updateRestrictions = null; diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/MetadataGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/MetadataGetOperationHandler.cs index 9cba74f5d..4ec24a1ee 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/MetadataGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/MetadataGetOperationHandler.cs @@ -4,6 +4,7 @@ // ------------------------------------------------------------ using System.Collections.Generic; +using System.Net.Http; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; @@ -23,7 +24,7 @@ public MetadataGetOperationHandler(OpenApiDocument document):base(document) } /// - public override OperationType OperationType => OperationType.Get; + public override HttpMethod OperationType => HttpMethod.Get; /// protected override void SetBasicInfo(OpenApiOperation operation) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyDeleteOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyDeleteOperationHandler.cs index 864c02ca8..2bedd562a 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyDeleteOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyDeleteOperationHandler.cs @@ -4,6 +4,7 @@ // ------------------------------------------------------------ using System.Linq; +using System.Net.Http; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; @@ -28,7 +29,7 @@ public NavigationPropertyDeleteOperationHandler(OpenApiDocument document):base(d } /// - public override OperationType OperationType => OperationType.Delete; + public override HttpMethod OperationType => HttpMethod.Delete; private DeleteRestrictionsType _deleteRestriction; diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs index 6ca66c765..0d01c013d 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; +using System.Net.Http; using System.Text.Json.Nodes; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; @@ -34,7 +35,7 @@ public NavigationPropertyGetOperationHandler(OpenApiDocument document) : base(do } /// - public override OperationType OperationType => OperationType.Get; + public override HttpMethod OperationType => HttpMethod.Get; private ReadRestrictionsType _readRestriction; diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPatchOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPatchOperationHandler.cs index 46eda3a6b..98218ea40 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPatchOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPatchOperationHandler.cs @@ -3,6 +3,7 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Net.Http; using Microsoft.OpenApi.Models; namespace Microsoft.OpenApi.OData.Operation @@ -23,6 +24,6 @@ public NavigationPropertyPatchOperationHandler(OpenApiDocument document):base(do } /// - public override OperationType OperationType => OperationType.Patch; + public override HttpMethod OperationType => HttpMethod.Patch; } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPostOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPostOperationHandler.cs index 2c4d1274e..065fcfe44 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPostOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPostOperationHandler.cs @@ -4,6 +4,7 @@ // ------------------------------------------------------------ using System.Linq; +using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; @@ -29,7 +30,7 @@ public NavigationPropertyPostOperationHandler(OpenApiDocument document):base(doc } /// - public override OperationType OperationType => OperationType.Post; + public override HttpMethod OperationType => HttpMethod.Post; private InsertRestrictionsType _insertRestriction; diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPutOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPutOperationHandler.cs index 09699293d..62ed631a6 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPutOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPutOperationHandler.cs @@ -3,6 +3,7 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Net.Http; using Microsoft.OpenApi.Models; namespace Microsoft.OpenApi.OData.Operation @@ -23,6 +24,6 @@ public NavigationPropertyPutOperationHandler(OpenApiDocument document) : base(do } /// - public override OperationType OperationType => OperationType.Put; + public override HttpMethod OperationType => HttpMethod.Put; } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyUpdateOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyUpdateOperationHandler.cs index 9daf7e5fe..3549480a6 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyUpdateOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyUpdateOperationHandler.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; +using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; @@ -49,7 +50,7 @@ protected override void SetBasicInfo(OpenApiOperation operation) // OperationId if (Context.Settings.EnableOperationId) { - string prefix = OperationType == OperationType.Patch ? "Update" : "Set"; + string prefix = OperationType == HttpMethod.Patch ? "Update" : "Set"; operation.OperationId = GetOperationId(prefix); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/ODataTypeCastGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/ODataTypeCastGetOperationHandler.cs index c51adf320..e158a8df2 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/ODataTypeCastGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/ODataTypeCastGetOperationHandler.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using System.Text.Json.Nodes; using Microsoft.OData.Edm; using Microsoft.OData.Edm.Vocabularies; @@ -35,7 +36,7 @@ public ODataTypeCastGetOperationHandler(OpenApiDocument document):base(document) } /// - public override OperationType OperationType => OperationType.Get; + public override HttpMethod OperationType => HttpMethod.Get; /// /// Gets/sets the segment before cast. diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandler.cs index 5d934cb4e..4f27692c6 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandler.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; +using System.Net.Http; using Microsoft.OpenApi.MicrosoftExtensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; @@ -34,7 +35,7 @@ protected OperationHandler(OpenApiDocument document) _document = document; } /// - public abstract OperationType OperationType { get; } + public abstract HttpMethod OperationType { get; } protected IDictionary> ParameterMappings; @@ -289,13 +290,13 @@ protected virtual void SetCustomLinkRelType() { if (Context.Settings.CustomHttpMethodLinkRelMapping != null) { - LinkRelKey? key = OperationType switch + LinkRelKey? key = OperationType.ToString().ToLowerInvariant() switch { - OperationType.Get => Path.LastSegment?.Kind == ODataSegmentKind.Key ? LinkRelKey.ReadByKey : LinkRelKey.List, - OperationType.Post => LinkRelKey.Create, - OperationType.Patch => LinkRelKey.Update, - OperationType.Put => LinkRelKey.Update, - OperationType.Delete => LinkRelKey.Delete, + "get" => Path.LastSegment?.Kind == ODataSegmentKind.Key ? LinkRelKey.ReadByKey : LinkRelKey.List, + "post" => LinkRelKey.Create, + "patch" => LinkRelKey.Update, + "put" => LinkRelKey.Update, + "delete" => LinkRelKey.Delete, _ => null, }; diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandlerProvider.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandlerProvider.cs index 92c4f131a..9f65fedf8 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandlerProvider.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandlerProvider.cs @@ -4,6 +4,7 @@ // ------------------------------------------------------------ using System.Collections.Generic; +using System.Net.Http; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Edm; @@ -15,65 +16,65 @@ namespace Microsoft.OpenApi.OData.Operation internal class OperationHandlerProvider : IOperationHandlerProvider { /// - public IOperationHandler GetHandler(ODataPathKind pathKind, OperationType operationType, OpenApiDocument document) + public IOperationHandler GetHandler(ODataPathKind pathKind, HttpMethod operationType, OpenApiDocument document) { - return (pathKind, operationType) switch + return (pathKind, operationType.ToString().ToLowerInvariant()) switch { // entity set (Get/Post) - (ODataPathKind.EntitySet, OperationType.Get) => new EntitySetGetOperationHandler(document), - (ODataPathKind.EntitySet, OperationType.Post) => new EntitySetPostOperationHandler(document), + (ODataPathKind.EntitySet, "get") => new EntitySetGetOperationHandler(document), + (ODataPathKind.EntitySet, "post") => new EntitySetPostOperationHandler(document), // entity (Get/Patch/Put/Delete) - (ODataPathKind.Entity, OperationType.Get) => new EntityGetOperationHandler(document), - (ODataPathKind.Entity, OperationType.Patch) => new EntityPatchOperationHandler(document), - (ODataPathKind.Entity, OperationType.Put) => new EntityPutOperationHandler(document), - (ODataPathKind.Entity, OperationType.Delete) => new EntityDeleteOperationHandler(document), + (ODataPathKind.Entity, "get") => new EntityGetOperationHandler(document), + (ODataPathKind.Entity, "patch") => new EntityPatchOperationHandler(document), + (ODataPathKind.Entity, "put") => new EntityPutOperationHandler(document), + (ODataPathKind.Entity, "delete") => new EntityDeleteOperationHandler(document), // singleton (Get/Patch) - (ODataPathKind.Singleton, OperationType.Get) => new SingletonGetOperationHandler(document), - (ODataPathKind.Singleton, OperationType.Patch) => new SingletonPatchOperationHandler(document), + (ODataPathKind.Singleton, "get") => new SingletonGetOperationHandler(document), + (ODataPathKind.Singleton, "patch") => new SingletonPatchOperationHandler(document), // edm operation (Get|Post) - (ODataPathKind.Operation, OperationType.Get) => new EdmFunctionOperationHandler(document), - (ODataPathKind.Operation, OperationType.Post) => new EdmActionOperationHandler(document), + (ODataPathKind.Operation, "get") => new EdmFunctionOperationHandler(document), + (ODataPathKind.Operation, "post") => new EdmActionOperationHandler(document), // edm operation import (Get|Post) - (ODataPathKind.OperationImport, OperationType.Get) => new EdmFunctionImportOperationHandler(document), - (ODataPathKind.OperationImport, OperationType.Post) => new EdmActionImportOperationHandler(document), + (ODataPathKind.OperationImport, "get") => new EdmFunctionImportOperationHandler(document), + (ODataPathKind.OperationImport, "post") => new EdmActionImportOperationHandler(document), // navigation property (Get/Patch/Put/Post/Delete) - (ODataPathKind.NavigationProperty, OperationType.Get) => new NavigationPropertyGetOperationHandler(document), - (ODataPathKind.NavigationProperty, OperationType.Patch) => new NavigationPropertyPatchOperationHandler(document), - (ODataPathKind.NavigationProperty, OperationType.Put) => new NavigationPropertyPutOperationHandler(document), - (ODataPathKind.NavigationProperty, OperationType.Post) => new NavigationPropertyPostOperationHandler(document), - (ODataPathKind.NavigationProperty, OperationType.Delete) => new NavigationPropertyDeleteOperationHandler(document), + (ODataPathKind.NavigationProperty, "get") => new NavigationPropertyGetOperationHandler(document), + (ODataPathKind.NavigationProperty, "patch") => new NavigationPropertyPatchOperationHandler(document), + (ODataPathKind.NavigationProperty, "put") => new NavigationPropertyPutOperationHandler(document), + (ODataPathKind.NavigationProperty, "post") => new NavigationPropertyPostOperationHandler(document), + (ODataPathKind.NavigationProperty, "delete") => new NavigationPropertyDeleteOperationHandler(document), // navigation property ref (Get/Post/Put/Delete) - (ODataPathKind.Ref, OperationType.Get) => new RefGetOperationHandler(document), - (ODataPathKind.Ref, OperationType.Put) => new RefPutOperationHandler(document), - (ODataPathKind.Ref, OperationType.Post) => new RefPostOperationHandler(document), - (ODataPathKind.Ref, OperationType.Delete) => new RefDeleteOperationHandler(document), + (ODataPathKind.Ref, "get") => new RefGetOperationHandler(document), + (ODataPathKind.Ref, "put") => new RefPutOperationHandler(document), + (ODataPathKind.Ref, "post") => new RefPostOperationHandler(document), + (ODataPathKind.Ref, "delete") => new RefDeleteOperationHandler(document), // media entity operation (Get|Put|Delete) - (ODataPathKind.MediaEntity, OperationType.Get) => new MediaEntityGetOperationHandler(document), - (ODataPathKind.MediaEntity, OperationType.Put) => new MediaEntityPutOperationHandler(document), - (ODataPathKind.MediaEntity, OperationType.Delete) => new MediaEntityDeleteOperationHandler(document), + (ODataPathKind.MediaEntity, "get") => new MediaEntityGetOperationHandler(document), + (ODataPathKind.MediaEntity, "put") => new MediaEntityPutOperationHandler(document), + (ODataPathKind.MediaEntity, "delete") => new MediaEntityDeleteOperationHandler(document), // $metadata operation (Get) - (ODataPathKind.Metadata, OperationType.Get) => new MetadataGetOperationHandler(document), + (ODataPathKind.Metadata, "get") => new MetadataGetOperationHandler(document), // $count operation (Get) - (ODataPathKind.DollarCount, OperationType.Get) => new DollarCountGetOperationHandler(document), + (ODataPathKind.DollarCount, "get") => new DollarCountGetOperationHandler(document), // .../namespace.typename (cast, get) - (ODataPathKind.TypeCast, OperationType.Get) => new ODataTypeCastGetOperationHandler(document), + (ODataPathKind.TypeCast, "get") => new ODataTypeCastGetOperationHandler(document), // .../entity/propertyOfComplexType (Get/Patch/Put/Delete) - (ODataPathKind.ComplexProperty, OperationType.Get) => new ComplexPropertyGetOperationHandler(document), - (ODataPathKind.ComplexProperty, OperationType.Patch) => new ComplexPropertyPatchOperationHandler(document), - (ODataPathKind.ComplexProperty, OperationType.Put) => new ComplexPropertyPutOperationHandler(document), - (ODataPathKind.ComplexProperty, OperationType.Post) => new ComplexPropertyPostOperationHandler(document), + (ODataPathKind.ComplexProperty, "get") => new ComplexPropertyGetOperationHandler(document), + (ODataPathKind.ComplexProperty, "patch") => new ComplexPropertyPatchOperationHandler(document), + (ODataPathKind.ComplexProperty, "put") => new ComplexPropertyPutOperationHandler(document), + (ODataPathKind.ComplexProperty, "post") => new ComplexPropertyPostOperationHandler(document), (_, _) => null, }; diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/RefDeleteOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/RefDeleteOperationHandler.cs index 7cb172556..5211b8657 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/RefDeleteOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/RefDeleteOperationHandler.cs @@ -10,6 +10,7 @@ using Microsoft.OpenApi.OData.Generator; using Microsoft.OpenApi.OData.Vocabulary.Capabilities; using System.Linq; +using System.Net.Http; namespace Microsoft.OpenApi.OData.Operation { @@ -27,7 +28,7 @@ public RefDeleteOperationHandler(OpenApiDocument document) : base(document) } /// - public override OperationType OperationType => OperationType.Delete; + public override HttpMethod OperationType => HttpMethod.Delete; private DeleteRestrictionsType _deleteRestriction; /// diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/RefGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/RefGetOperationHandler.cs index 1dc242b5d..6f4138194 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/RefGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/RefGetOperationHandler.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; +using System.Net.Http; using System.Text.Json.Nodes; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; @@ -32,7 +33,7 @@ public RefGetOperationHandler(OpenApiDocument document) : base(document) } /// - public override OperationType OperationType => OperationType.Get; + public override HttpMethod OperationType => HttpMethod.Get; private ReadRestrictionsType _readRestriction; /// diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/RefPostOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/RefPostOperationHandler.cs index faa3b99d4..04c82e54b 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/RefPostOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/RefPostOperationHandler.cs @@ -4,6 +4,7 @@ // ------------------------------------------------------------ using System.Linq; +using System.Net.Http; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.OData.Common; @@ -27,7 +28,7 @@ public RefPostOperationHandler(OpenApiDocument document) : base(document) } /// - public override OperationType OperationType => OperationType.Post; + public override HttpMethod OperationType => HttpMethod.Post; private InsertRestrictionsType _insertRestriction; /// diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/RefPutOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/RefPutOperationHandler.cs index fb4d7b190..984be2386 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/RefPutOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/RefPutOperationHandler.cs @@ -4,6 +4,7 @@ // ------------------------------------------------------------ using System.Linq; +using System.Net.Http; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.OData.Common; @@ -27,7 +28,7 @@ public RefPutOperationHandler(OpenApiDocument document) : base(document) } /// - public override OperationType OperationType => OperationType.Patch; + public override HttpMethod OperationType => HttpMethod.Patch; private UpdateRestrictionsType _updateRestriction; /// diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonGetOperationHandler.cs index 9b8b55a92..76e9232c4 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonGetOperationHandler.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; +using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; @@ -32,7 +33,7 @@ public SingletonGetOperationHandler(OpenApiDocument document) : base(document) } /// - public override OperationType OperationType => OperationType.Get; + public override HttpMethod OperationType => HttpMethod.Get; private ReadRestrictionsType _readRestrictions; diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonPatchOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonPatchOperationHandler.cs index e8cb4b945..4342f8f64 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonPatchOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonPatchOperationHandler.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; +using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; @@ -32,7 +33,7 @@ public SingletonPatchOperationHandler(OpenApiDocument document) : base(document) } /// - public override OperationType OperationType => OperationType.Patch; + public override HttpMethod OperationType => HttpMethod.Patch; private UpdateRestrictionsType _updateRestrictions; diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/ComplexPropertyItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/ComplexPropertyItemHandler.cs index a3397eedb..f027d2f14 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/ComplexPropertyItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/ComplexPropertyItemHandler.cs @@ -3,6 +3,7 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; @@ -47,7 +48,7 @@ public void AddReadOperation(OpenApiPathItem item) if ((Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths && isReadable) || !Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths) { - AddOperation(item, OperationType.Get); + AddOperation(item, HttpMethod.Get); } } @@ -63,7 +64,7 @@ public void AddInsertOperation(OpenApiPathItem item) if ((Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths && isInsertable) || !Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths) { - AddOperation(item, OperationType.Post); + AddOperation(item, HttpMethod.Post); } } } @@ -80,16 +81,16 @@ public void AddUpdateOperation(OpenApiPathItem item) { if (updateRestrictions?.IsUpdateMethodPutAndPatch == true) { - AddOperation(item, OperationType.Put); - AddOperation(item, OperationType.Patch); + AddOperation(item, HttpMethod.Put); + AddOperation(item, HttpMethod.Patch); } else if (updateRestrictions?.IsUpdateMethodPut == true) { - AddOperation(item, OperationType.Put); + AddOperation(item, HttpMethod.Put); } else { - AddOperation(item, OperationType.Patch); + AddOperation(item, HttpMethod.Patch); } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/DollarCountPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/DollarCountPathItemHandler.cs index f1c124d1c..c68d044dd 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/DollarCountPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/DollarCountPathItemHandler.cs @@ -3,6 +3,7 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Net.Http; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Edm; @@ -27,7 +28,7 @@ public DollarCountPathItemHandler(OpenApiDocument document) : base(document) /// protected override void SetOperations(OpenApiPathItem item) { - AddOperation(item, OperationType.Get); + AddOperation(item, HttpMethod.Get); } /// protected override void SetBasicInfo(OpenApiPathItem pathItem) diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/EntityPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/EntityPathItemHandler.cs index 02aef7434..9b394158b 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/EntityPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/EntityPathItemHandler.cs @@ -3,6 +3,7 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; @@ -39,7 +40,7 @@ protected override void SetOperations(OpenApiPathItem item) (readRestrictions.ReadByKeyRestrictions != null && readRestrictions.ReadByKeyRestrictions.IsReadable)) { // If we don't have Read by key read restriction, we should check the set read restrction. - AddOperation(item, OperationType.Get); + AddOperation(item, HttpMethod.Get); } UpdateRestrictionsType updateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); @@ -50,16 +51,16 @@ protected override void SetOperations(OpenApiPathItem item) { if (updateRestrictions?.IsUpdateMethodPutAndPatch == true) { - AddOperation(item, OperationType.Put); - AddOperation(item, OperationType.Patch); + AddOperation(item, HttpMethod.Put); + AddOperation(item, HttpMethod.Patch); } else if (updateRestrictions?.IsUpdateMethodPut == true) { - AddOperation(item, OperationType.Put); + AddOperation(item, HttpMethod.Put); } else { - AddOperation(item, OperationType.Patch); + AddOperation(item, HttpMethod.Patch); } } @@ -69,7 +70,7 @@ protected override void SetOperations(OpenApiPathItem item) deleteRestrictions ??= entityDeleteRestrictions; if (deleteRestrictions?.IsDeletable ?? true) { - AddOperation(item, OperationType.Delete); + AddOperation(item, HttpMethod.Delete); } } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/EntitySetPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/EntitySetPathItemHandler.cs index 57d111362..0240a0fea 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/EntitySetPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/EntitySetPathItemHandler.cs @@ -3,6 +3,7 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; @@ -41,7 +42,7 @@ protected override void SetOperations(OpenApiPathItem item) readRestrictions ??= entityReadRestrictions; if (readRestrictions?.IsReadable ?? true) { - AddOperation(item, OperationType.Get); + AddOperation(item, HttpMethod.Get); } InsertRestrictionsType insertRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); @@ -50,7 +51,7 @@ protected override void SetOperations(OpenApiPathItem item) insertRestrictions ??= entityInsertRestrictions; if (insertRestrictions?.IsInsertable ?? true) { - AddOperation(item, OperationType.Post); + AddOperation(item, HttpMethod.Post); } } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/MediaEntityPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/MediaEntityPathItemHandler.cs index 48613a57c..48bf11f03 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/MediaEntityPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/MediaEntityPathItemHandler.cs @@ -3,6 +3,7 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Edm; @@ -48,7 +49,7 @@ protected override void SetOperations(OpenApiPathItem item) (readRestrictions.ReadByKeyRestrictions == null && readRestrictions.IsReadable) || (readRestrictions.ReadByKeyRestrictions != null && readRestrictions.ReadByKeyRestrictions.IsReadable)) { - AddOperation(item, OperationType.Get); + AddOperation(item, HttpMethod.Get); } UpdateRestrictionsType updateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); @@ -58,7 +59,7 @@ protected override void SetOperations(OpenApiPathItem item) updateRestrictions ??= navSourceUpdateRestrictions; if (updateRestrictions?.IsUpdatable ?? true) { - AddOperation(item, OperationType.Put); + AddOperation(item, HttpMethod.Put); } DeleteRestrictionsType deleteRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); @@ -68,7 +69,7 @@ protected override void SetOperations(OpenApiPathItem item) deleteRestrictions ??= navSourceDeleteRestrictions; if (deleteRestrictions?.IsDeletable ?? true) { - AddOperation(item, OperationType.Delete); + AddOperation(item, HttpMethod.Delete); } } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/MetadataPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/MetadataPathItemHandler.cs index 28d974e63..5862ad1c0 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/MetadataPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/MetadataPathItemHandler.cs @@ -3,6 +3,7 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Net.Http; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Edm; @@ -27,7 +28,7 @@ public MetadataPathItemHandler(OpenApiDocument document) : base(document) /// protected override void SetOperations(OpenApiPathItem item) { - AddOperation(item, OperationType.Get); + AddOperation(item, HttpMethod.Get); } /// protected override void SetBasicInfo(OpenApiPathItem pathItem) diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs index 890f24eef..21306c0d7 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs @@ -14,6 +14,7 @@ using Microsoft.OData.Edm.Vocabularies; using Microsoft.OpenApi.OData.Vocabulary.Capabilities; using System.Text.Json.Nodes; +using System.Net.Http; namespace Microsoft.OpenApi.OData.PathItem { @@ -126,7 +127,7 @@ protected override void SetOperations(OpenApiPathItem item) ((entityInsertRestrictions?.IsInsertable ?? true) && (navPropInsertRestrictions?.IsInsertable ?? true))) { - AddOperation(item, OperationType.Post); + AddOperation(item, HttpMethod.Post); } } } @@ -152,7 +153,7 @@ protected override void SetOperations(OpenApiPathItem item) { if (navPropInsertRestrictions?.Insertable ?? false) { - AddOperation(item, OperationType.Post); + AddOperation(item, HttpMethod.Post); } } } @@ -181,7 +182,7 @@ private void AddGetOperation(OpenApiPathItem item, NavigationPropertyRestriction bool isReadableDefault = navPropReadRestriction == null && entityReadRestriction == null; if (isReadableDefault) { - AddOperation(item, OperationType.Get); + AddOperation(item, HttpMethod.Get); return; } @@ -193,7 +194,7 @@ private void AddGetOperation(OpenApiPathItem item, NavigationPropertyRestriction if ((navPropReadRestriction?.ReadByKeyRestrictions?.IsReadable ?? true) && (entityReadRestriction?.IsReadable ?? true)) { - AddOperation(item, OperationType.Get); + AddOperation(item, HttpMethod.Get); } } else @@ -201,7 +202,7 @@ private void AddGetOperation(OpenApiPathItem item, NavigationPropertyRestriction if ((navPropReadRestriction?.IsReadable ?? true) && (entityReadRestriction?.IsReadable ?? true)) { - AddOperation(item, OperationType.Get); + AddOperation(item, HttpMethod.Get); } } } @@ -211,7 +212,7 @@ private void AddGetOperation(OpenApiPathItem item, NavigationPropertyRestriction if ((navPropReadRestriction?.IsReadable ?? true) && (entityReadRestriction?.IsReadable ?? true)) { - AddOperation(item, OperationType.Get); + AddOperation(item, HttpMethod.Get); } } } @@ -238,13 +239,13 @@ private void AddDeleteOperation(OpenApiPathItem item, NavigationPropertyRestrict if (NavigationProperty.ContainsTarget && isDeletable) { - AddOperation(item, OperationType.Delete); + AddOperation(item, HttpMethod.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); + AddOperation(item, HttpMethod.Delete); } return; @@ -256,16 +257,16 @@ private void AddUpdateOperation(OpenApiPathItem item, UpdateRestrictionsType upd { if (updateRestrictionsType?.IsUpdateMethodPutAndPatch == true) { - AddOperation(item, OperationType.Put); - AddOperation(item, OperationType.Patch); + AddOperation(item, HttpMethod.Put); + AddOperation(item, HttpMethod.Patch); } else if (updateRestrictionsType?.IsUpdateMethodPut == true) { - AddOperation(item, OperationType.Put); + AddOperation(item, HttpMethod.Put); } else { - AddOperation(item, OperationType.Patch); + AddOperation(item, HttpMethod.Patch); } } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/ODataTypeCastPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/ODataTypeCastPathItemHandler.cs index 13f1b406d..38e4e224e 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/ODataTypeCastPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/ODataTypeCastPathItemHandler.cs @@ -3,6 +3,7 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; @@ -29,7 +30,7 @@ public ODataTypeCastPathItemHandler(OpenApiDocument document) : base(document) /// protected override void SetOperations(OpenApiPathItem item) { - AddOperation(item, OperationType.Get); + AddOperation(item, HttpMethod.Get); } /// protected override void Initialize(ODataContext context, ODataPath path) diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/OperationImportPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/OperationImportPathItemHandler.cs index e26511d5e..2d3eab0a6 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/OperationImportPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/OperationImportPathItemHandler.cs @@ -3,6 +3,7 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; @@ -41,7 +42,7 @@ protected override void SetOperations(OpenApiPathItem item) // resource path of the action import prepended with a forward slash, and whose value is a Path // Item Object containing the keyword post with an Operation Object as value that describes // how to invoke the action import. - AddOperation(item, OperationType.Post); + AddOperation(item, HttpMethod.Post); } else { @@ -57,7 +58,7 @@ protected override void SetOperations(OpenApiPathItem item) readRestrictions ??= operationReadRestrictions; if (readRestrictions?.IsReadable ?? true) { - AddOperation(item, OperationType.Get); + AddOperation(item, HttpMethod.Get); } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/OperationPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/OperationPathItemHandler.cs index 775816da8..899271924 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/OperationPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/OperationPathItemHandler.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; +using System.Net.Http; using System.Text.Json.Nodes; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; @@ -42,13 +43,13 @@ protected override void SetOperations(OpenApiPathItem item) { // The Path Item Object for a bound action contains the keyword post, // The value of the operation keyword is an Operation Object that describes how to invoke the action. - AddOperation(item, OperationType.Post); + AddOperation(item, HttpMethod.Post); } else { // The Path Item Object for a bound function contains the keyword get, // The value of the operation keyword is an Operation Object that describes how to invoke the function. - AddOperation(item, OperationType.Get); + AddOperation(item, HttpMethod.Get); } } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/PathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/PathItemHandler.cs index e71b6d371..97e9c8805 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/PathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/PathItemHandler.cs @@ -10,6 +10,7 @@ using Microsoft.OpenApi.OData.Operation; using Microsoft.OpenApi.OData.Properties; using System; +using System.Net.Http; namespace Microsoft.OpenApi.OData.PathItem { @@ -111,7 +112,7 @@ protected virtual void SetExtensions(OpenApiPathItem item) /// /// The path item. /// The operation type. - protected virtual void AddOperation(OpenApiPathItem item, OperationType operationType) + protected virtual void AddOperation(OpenApiPathItem item, HttpMethod operationType) { string httpMethod = operationType.ToString(); if (!Path.SupportHttpMethod(httpMethod)) diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/RefPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/RefPathItemHandler.cs index 6b2450925..fffef6015 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/RefPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/RefPathItemHandler.cs @@ -11,6 +11,7 @@ using Microsoft.OpenApi.OData.Edm; using Microsoft.OData.Edm.Vocabularies; using Microsoft.OpenApi.OData.Vocabulary.Capabilities; +using System.Net.Http; namespace Microsoft.OpenApi.OData.PathItem { @@ -105,7 +106,7 @@ private void AddDeleteOperation(OpenApiPathItem item, NavigationPropertyRestrict deleteRestrictions ??= restriction?.DeleteRestrictions; if (deleteRestrictions?.IsDeletable ?? true) { - AddOperation(item, OperationType.Delete); + AddOperation(item, HttpMethod.Delete); } } @@ -116,7 +117,7 @@ private void AddReadOperation(OpenApiPathItem item, NavigationPropertyRestrictio readRestrictions ??= restriction?.ReadRestrictions; if (readRestrictions?.IsReadable ?? true) { - AddOperation(item, OperationType.Get); + AddOperation(item, HttpMethod.Get); } } @@ -127,7 +128,7 @@ private void AddInsertOperation(OpenApiPathItem item, NavigationPropertyRestrict insertRestrictions ??= restriction?.InsertRestrictions; if (insertRestrictions?.IsInsertable ?? true) { - AddOperation(item, OperationType.Post); + AddOperation(item, HttpMethod.Post); } } @@ -138,7 +139,7 @@ private void AddUpdateOperation(OpenApiPathItem item, NavigationPropertyRestrict updateRestrictions ??= restriction?.UpdateRestrictions; if (updateRestrictions?.IsUpdatable ?? true) { - AddOperation(item, OperationType.Put); + AddOperation(item, HttpMethod.Put); } } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/SingletonPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/SingletonPathItemHandler.cs index 5715c8cba..e288e1bac 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/SingletonPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/SingletonPathItemHandler.cs @@ -3,6 +3,7 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; @@ -42,7 +43,7 @@ protected override void SetOperations(OpenApiPathItem item) readRestrictions ??= singletonReadRestrictions; if (readRestrictions?.IsReadable ?? true) { - AddOperation(item, OperationType.Get); + AddOperation(item, HttpMethod.Get); } // Update a singleton @@ -52,7 +53,7 @@ protected override void SetOperations(OpenApiPathItem item) updateRestrictions ??= singletonUpdateRestrictions; if (updateRestrictions?.IsUpdatable ?? true) { - AddOperation(item, OperationType.Patch); + AddOperation(item, HttpMethod.Patch); } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/UpdateRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/UpdateRestrictionsType.cs index ff073e399..724d2ddc9 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/UpdateRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/UpdateRestrictionsType.cs @@ -16,7 +16,7 @@ namespace Microsoft.OpenApi.OData.Vocabulary.Capabilities /// Enumerates HTTP methods that can be used to update entities /// [Flags] - internal enum HttpMethod + internal enum HttpUpdateMethod { /// /// The HTTP PATCH Method @@ -48,13 +48,13 @@ 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 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; } + public HttpUpdateMethod? UpdateMethod { get; private set; } /// /// Gets the value indicating Members of collections can be updated via a PATCH request with a '/$filter(...)/$each' segment. @@ -128,24 +128,24 @@ public bool IsNonUpdatableNavigationProperty(string navigationPropertyPath) /// /// 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 - /// - /// This is not an official OASIS standard property. + public bool IsUpdateMethodPut => UpdateMethod.HasValue && UpdateMethod.Value == HttpUpdateMethod.PUT; + + /// + /// Tests whether the update method for the target has been explicitly specified as PATCH and PUT + /// + public bool IsUpdateMethodPutAndPatch => UpdateMethod.HasValue && + (UpdateMethod.Value & (HttpUpdateMethod.PUT | HttpUpdateMethod.PATCH)) == (HttpUpdateMethod.PUT | HttpUpdateMethod.PATCH); + + /// + /// Lists the media types acceptable for the request content + /// + /// This is not an official OASIS standard property. public IList RequestContentTypes { get; private set; } - /// - /// Lists the media types acceptable for the response content - /// - /// This is not an official OASIS standard property. + /// + /// Lists the media types acceptable for the response content + /// + /// This is not an official OASIS standard property. public IList ResponseContentTypes { get; private set; } /// @@ -165,8 +165,8 @@ public void Initialize(IEdmRecordExpression record) // DeltaUpdateSupported DeltaUpdateSupported = record.GetBoolean("DeltaUpdateSupported"); - // UpdateMethod - UpdateMethod = record.GetEnum("UpdateMethod"); + // UpdateMethod + UpdateMethod = record.GetEnum("UpdateMethod"); // FilterSegmentSupported FilterSegmentSupported = record.GetBoolean("FilterSegmentSupported"); @@ -175,9 +175,9 @@ public void Initialize(IEdmRecordExpression record) TypecastSegmentSupported = record.GetBoolean("TypecastSegmentSupported"); // NonUpdatableNavigationProperties - NonUpdatableNavigationProperties = record.GetCollectionPropertyPath("NonUpdatableNavigationProperties"); - - // MaxLevels + NonUpdatableNavigationProperties = record.GetCollectionPropertyPath("NonUpdatableNavigationProperties"); + + // MaxLevels MaxLevels = record.GetInteger("MaxLevels"); // Permissions @@ -203,48 +203,48 @@ public void Initialize(IEdmRecordExpression record) // ResponseContentTypes ResponseContentTypes = record.GetCollection("ResponseContentTypes"); - } - - /// - /// Merges properties of the specified object into this instance if they are null. - /// + } + + /// + /// Merges properties of the specified object into this instance if they are null. + /// /// The object containing properties to merge. - public void MergePropertiesIfNull(UpdateRestrictionsType source) - { - if (source == null) - return; - - Updatable ??= source.Updatable; - - Upsertable ??= source.Upsertable; - - DeltaUpdateSupported ??= source.DeltaUpdateSupported; - - UpdateMethod ??= source.UpdateMethod; - - FilterSegmentSupported ??= source.FilterSegmentSupported; - - TypecastSegmentSupported ??= source.TypecastSegmentSupported; - - NonUpdatableNavigationProperties ??= source.NonUpdatableNavigationProperties; - - MaxLevels ??= source.MaxLevels; - - Permissions ??= source.Permissions; - - QueryOptions ??= source.QueryOptions; - - CustomHeaders ??= source.CustomHeaders; - - CustomQueryOptions ??= source.CustomQueryOptions; - - Description ??= source.Description; - - LongDescription ??= source.LongDescription; - - RequestContentTypes ??= source.RequestContentTypes; - - ResponseContentTypes ??= source.ResponseContentTypes; + public void MergePropertiesIfNull(UpdateRestrictionsType source) + { + if (source == null) + return; + + Updatable ??= source.Updatable; + + Upsertable ??= source.Upsertable; + + DeltaUpdateSupported ??= source.DeltaUpdateSupported; + + UpdateMethod ??= source.UpdateMethod; + + FilterSegmentSupported ??= source.FilterSegmentSupported; + + TypecastSegmentSupported ??= source.TypecastSegmentSupported; + + NonUpdatableNavigationProperties ??= source.NonUpdatableNavigationProperties; + + MaxLevels ??= source.MaxLevels; + + Permissions ??= source.Permissions; + + QueryOptions ??= source.QueryOptions; + + CustomHeaders ??= source.CustomHeaders; + + CustomQueryOptions ??= source.CustomQueryOptions; + + Description ??= source.Description; + + LongDescription ??= source.LongDescription; + + RequestContentTypes ??= source.RequestContentTypes; + + ResponseContentTypes ??= source.ResponseContentTypes; } } } diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/EdmModelOpenApiExtensionsTest.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/EdmModelOpenApiExtensionsTest.cs index 9d22a50cd..15eddb242 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/EdmModelOpenApiExtensionsTest.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/EdmModelOpenApiExtensionsTest.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using Microsoft.OData.Edm; using Microsoft.OpenApi.Extensions; +using Microsoft.OpenApi.Writers; using Xunit; using Xunit.Abstractions; @@ -178,7 +179,8 @@ private static async Task WriteEdmModelAsOpenApi(IEdmModel model, OpenAp Assert.NotNull(document); // guard MemoryStream stream = new(); - await document.SerializeAsync(stream, settings.OpenApiSpecVersion, target); + var writerSettings = new OpenApiWriterSettings(); + await document.SerializeAsync(stream, settings.OpenApiSpecVersion, target, writerSettings); await stream.FlushAsync(); stream.Position = 0; return await new StreamReader(stream).ReadToEndAsync(); diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiDocumentGeneratorTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiDocumentGeneratorTests.cs index 251ef787b..cadd8ca89 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiDocumentGeneratorTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiDocumentGeneratorTests.cs @@ -42,7 +42,7 @@ public void CreateDocumentReturnsForEmptyModel() Assert.NotNull(document.Components); Assert.Null(document.ExternalDocs); - Assert.Null(document.SecurityRequirements); + Assert.Null(document.Security); } } } diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Microsoft.OpenAPI.OData.Reader.Tests.csproj b/test/Microsoft.OpenAPI.OData.Reader.Tests/Microsoft.OpenAPI.OData.Reader.Tests.csproj index a98f21559..d5b2ed876 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Microsoft.OpenAPI.OData.Reader.Tests.csproj +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Microsoft.OpenAPI.OData.Reader.Tests.csproj @@ -88,7 +88,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/OperationHandlerProviderTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/OperationHandlerProviderTests.cs index 2e3f3289f..c282de6db 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/OperationHandlerProviderTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Operation/OperationHandlerProviderTests.cs @@ -4,6 +4,7 @@ // ------------------------------------------------------------ using System; +using System.Net.Http; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Edm; using Xunit; @@ -13,40 +14,40 @@ namespace Microsoft.OpenApi.OData.Operation.Tests public class OperationHandlerProviderTests { [Theory] - [InlineData(ODataPathKind.EntitySet, OperationType.Get, typeof(EntitySetGetOperationHandler))] - [InlineData(ODataPathKind.EntitySet, OperationType.Post, typeof(EntitySetPostOperationHandler))] - [InlineData(ODataPathKind.Entity, OperationType.Get, typeof(EntityGetOperationHandler))] - [InlineData(ODataPathKind.Entity, OperationType.Patch, typeof(EntityPatchOperationHandler))] - [InlineData(ODataPathKind.Entity, OperationType.Delete, typeof(EntityDeleteOperationHandler))] - [InlineData(ODataPathKind.Singleton, OperationType.Get, typeof(SingletonGetOperationHandler))] - [InlineData(ODataPathKind.Singleton, OperationType.Patch, typeof(SingletonPatchOperationHandler))] - [InlineData(ODataPathKind.NavigationProperty, OperationType.Get, typeof(NavigationPropertyGetOperationHandler))] - [InlineData(ODataPathKind.NavigationProperty, OperationType.Post, typeof(NavigationPropertyPostOperationHandler))] - [InlineData(ODataPathKind.NavigationProperty, OperationType.Patch, typeof(NavigationPropertyPatchOperationHandler))] - [InlineData(ODataPathKind.NavigationProperty, OperationType.Delete, typeof(NavigationPropertyDeleteOperationHandler))] - [InlineData(ODataPathKind.Operation, OperationType.Get, typeof(EdmFunctionOperationHandler))] - [InlineData(ODataPathKind.Operation, OperationType.Post, typeof(EdmActionOperationHandler))] - [InlineData(ODataPathKind.OperationImport, OperationType.Get, typeof(EdmFunctionImportOperationHandler))] - [InlineData(ODataPathKind.OperationImport, OperationType.Post, typeof(EdmActionImportOperationHandler))] - [InlineData(ODataPathKind.Ref, OperationType.Post, typeof(RefPostOperationHandler))] - [InlineData(ODataPathKind.Ref, OperationType.Delete, typeof(RefDeleteOperationHandler))] - [InlineData(ODataPathKind.Ref, OperationType.Get, typeof(RefGetOperationHandler))] - [InlineData(ODataPathKind.Ref, OperationType.Put, typeof(RefPutOperationHandler))] - [InlineData(ODataPathKind.MediaEntity, OperationType.Get, typeof(MediaEntityGetOperationHandler))] - [InlineData(ODataPathKind.MediaEntity, OperationType.Put, typeof(MediaEntityPutOperationHandler))] - [InlineData(ODataPathKind.Metadata, OperationType.Get, typeof(MetadataGetOperationHandler))] - [InlineData(ODataPathKind.DollarCount, OperationType.Get, typeof(DollarCountGetOperationHandler))] - public void GetHandlerReturnsCorrectOperationHandlerType(ODataPathKind pathKind, OperationType operationType, Type handlerType) + [InlineData(ODataPathKind.EntitySet, "get", typeof(EntitySetGetOperationHandler))] + [InlineData(ODataPathKind.EntitySet, "post", typeof(EntitySetPostOperationHandler))] + [InlineData(ODataPathKind.Entity, "get", typeof(EntityGetOperationHandler))] + [InlineData(ODataPathKind.Entity, "patch", typeof(EntityPatchOperationHandler))] + [InlineData(ODataPathKind.Entity, "delete", typeof(EntityDeleteOperationHandler))] + [InlineData(ODataPathKind.Singleton, "get", typeof(SingletonGetOperationHandler))] + [InlineData(ODataPathKind.Singleton, "patch", typeof(SingletonPatchOperationHandler))] + [InlineData(ODataPathKind.NavigationProperty, "get", typeof(NavigationPropertyGetOperationHandler))] + [InlineData(ODataPathKind.NavigationProperty, "post", typeof(NavigationPropertyPostOperationHandler))] + [InlineData(ODataPathKind.NavigationProperty, "patch", typeof(NavigationPropertyPatchOperationHandler))] + [InlineData(ODataPathKind.NavigationProperty, "delete", typeof(NavigationPropertyDeleteOperationHandler))] + [InlineData(ODataPathKind.Operation, "get", typeof(EdmFunctionOperationHandler))] + [InlineData(ODataPathKind.Operation, "post", typeof(EdmActionOperationHandler))] + [InlineData(ODataPathKind.OperationImport, "get", typeof(EdmFunctionImportOperationHandler))] + [InlineData(ODataPathKind.OperationImport, "post", typeof(EdmActionImportOperationHandler))] + [InlineData(ODataPathKind.Ref, "post", typeof(RefPostOperationHandler))] + [InlineData(ODataPathKind.Ref, "delete", typeof(RefDeleteOperationHandler))] + [InlineData(ODataPathKind.Ref, "get", typeof(RefGetOperationHandler))] + [InlineData(ODataPathKind.Ref, "put", typeof(RefPutOperationHandler))] + [InlineData(ODataPathKind.MediaEntity, "get", typeof(MediaEntityGetOperationHandler))] + [InlineData(ODataPathKind.MediaEntity, "put", typeof(MediaEntityPutOperationHandler))] + [InlineData(ODataPathKind.Metadata, "get", typeof(MetadataGetOperationHandler))] + [InlineData(ODataPathKind.DollarCount, "get", typeof(DollarCountGetOperationHandler))] + public void GetHandlerReturnsCorrectOperationHandlerType(ODataPathKind pathKind, string operationType, Type handlerType) { // Arrange OpenApiDocument openApiDocument = new(); OperationHandlerProvider provider = new OperationHandlerProvider(); // Act - IOperationHandler hander = provider.GetHandler(pathKind, operationType, openApiDocument); + IOperationHandler handler = provider.GetHandler(pathKind, HttpMethod.Parse(operationType), openApiDocument); // Assert - Assert.Same(handlerType, hander.GetType()); + Assert.Same(handlerType, handler.GetType()); } } } diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/ComplexPropertyPathItemHandlerTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/ComplexPropertyPathItemHandlerTests.cs index 7b8f6447d..46c4ddfc3 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/ComplexPropertyPathItemHandlerTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/ComplexPropertyPathItemHandlerTests.cs @@ -4,6 +4,7 @@ // ------------------------------------------------------------ using System; +using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Interfaces; @@ -64,13 +65,13 @@ public void SetsDefaultOperations(bool useAnnotationToGeneratePath, bool annotat if (operationCount > 0) { - Assert.True(pathItem.Operations.ContainsKey(OperationType.Get)); - Assert.True(pathItem.Operations.ContainsKey(OperationType.Patch)); + Assert.True(pathItem.Operations.ContainsKey(HttpMethod.Get)); + Assert.True(pathItem.Operations.ContainsKey(HttpMethod.Patch)); } else { - Assert.False(pathItem.Operations.ContainsKey(OperationType.Get)); - Assert.False(pathItem.Operations.ContainsKey(OperationType.Patch)); + Assert.False(pathItem.Operations.ContainsKey(HttpMethod.Get)); + Assert.False(pathItem.Operations.ContainsKey(HttpMethod.Patch)); } } @@ -119,18 +120,18 @@ public void SetsUpdateOperationWithUpdateMethodUpdateRestrictions(bool useAnnota { if (annotationAvailable) { - Assert.True(pathItem.Operations.ContainsKey(OperationType.Put)); + Assert.True(pathItem.Operations.ContainsKey(HttpMethod.Put)); } else { - Assert.True(pathItem.Operations.ContainsKey(OperationType.Get)); - Assert.True(pathItem.Operations.ContainsKey(OperationType.Patch)); + Assert.True(pathItem.Operations.ContainsKey(HttpMethod.Get)); + Assert.True(pathItem.Operations.ContainsKey(HttpMethod.Patch)); } } else { - Assert.False(pathItem.Operations.ContainsKey(OperationType.Patch)); - Assert.False(pathItem.Operations.ContainsKey(OperationType.Put)); + Assert.False(pathItem.Operations.ContainsKey(HttpMethod.Patch)); + Assert.False(pathItem.Operations.ContainsKey(HttpMethod.Put)); } } @@ -175,11 +176,11 @@ public void SetsPostOnCollectionProperties(bool useAnnotationToGeneratePath, boo if (operationCount > 0) { - Assert.True(pathItem.Operations.ContainsKey(OperationType.Post)); + Assert.True(pathItem.Operations.ContainsKey(HttpMethod.Post)); } else { - Assert.False(pathItem.Operations.ContainsKey(OperationType.Post)); + Assert.False(pathItem.Operations.ContainsKey(HttpMethod.Post)); } } [Fact] @@ -256,15 +257,15 @@ public void CreatesComplexPropertyPathsBasedOnTargetPathAnnotations(string reada Assert.Equal(operationCount, pathItem.Operations.Count); if (operationCount == 1) { - Assert.True(pathItem.Operations.ContainsKey(OperationType.Patch)); - Assert.False(pathItem.Operations.ContainsKey(OperationType.Post)); - Assert.False(pathItem.Operations.ContainsKey(OperationType.Get)); + Assert.True(pathItem.Operations.ContainsKey(HttpMethod.Patch)); + Assert.False(pathItem.Operations.ContainsKey(HttpMethod.Post)); + Assert.False(pathItem.Operations.ContainsKey(HttpMethod.Get)); } else if (operationCount == 3) { - Assert.True(pathItem.Operations.ContainsKey(OperationType.Patch)); - Assert.True(pathItem.Operations.ContainsKey(OperationType.Post)); - Assert.True(pathItem.Operations.ContainsKey(OperationType.Get)); + Assert.True(pathItem.Operations.ContainsKey(HttpMethod.Patch)); + Assert.True(pathItem.Operations.ContainsKey(HttpMethod.Post)); + Assert.True(pathItem.Operations.ContainsKey(HttpMethod.Get)); } } } \ No newline at end of file diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/EntityPathItemHandlerTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/EntityPathItemHandlerTests.cs index 47a5a9d31..a78ccf990 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/EntityPathItemHandlerTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/EntityPathItemHandlerTests.cs @@ -5,6 +5,7 @@ using System; using System.Linq; +using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Interfaces; @@ -74,7 +75,7 @@ public void CreateEntityPathItemReturnsCorrectPathItem() Assert.NotNull(pathItem.Operations); Assert.NotEmpty(pathItem.Operations); Assert.Equal(3, pathItem.Operations.Count); - Assert.Equal(new OperationType[] { OperationType.Get, OperationType.Patch, OperationType.Delete }, + Assert.Equal(new HttpMethod[] { HttpMethod.Get, HttpMethod.Patch, HttpMethod.Delete }, pathItem.Operations.Select(o => o.Key)); } @@ -103,7 +104,7 @@ public void CreateEntityPathItemReturnsCorrectPathItemWithPathParameters(bool de Assert.NotNull(pathItem.Operations); Assert.NotEmpty(pathItem.Operations); Assert.Equal(3, pathItem.Operations.Count); - Assert.Equal(new OperationType[] { OperationType.Get, OperationType.Patch, OperationType.Delete }, + Assert.Equal(new HttpMethod[] { HttpMethod.Get, HttpMethod.Patch, HttpMethod.Delete }, pathItem.Operations.Select(o => o.Key)); if (declarePathParametersOnPathItem) @@ -138,15 +139,15 @@ public void CreateEntityPathItemReturnsCorrectPathItemWithReferences() Assert.NotNull(pathItem.Operations); Assert.NotEmpty(pathItem.Operations); Assert.Equal(3, pathItem.Operations.Count); - Assert.Equal(new OperationType[] { OperationType.Get, OperationType.Patch, OperationType.Delete }, + Assert.Equal(new HttpMethod[] { HttpMethod.Get, HttpMethod.Patch, HttpMethod.Delete }, pathItem.Operations.Select(o => o.Key)); Assert.NotEmpty(pathItem.Description); } [Theory] - [InlineData(true, new OperationType[] { OperationType.Get, OperationType.Patch, OperationType.Delete })] - [InlineData(false, new OperationType[] { OperationType.Patch, OperationType.Delete })] - public void CreateEntityPathItemWorksForReadByKeyRestrictionsCapablities(bool readable, OperationType[] expected) + [InlineData(true, new string[] { "get", "patch", "delete" })] + [InlineData(false, new string[] { "patch", "delete" })] + public void CreateEntityPathItemWorksForReadByKeyRestrictionsCapablities(bool readable, string[] expected) { // Arrange string annotation = $@" @@ -165,9 +166,9 @@ public void CreateEntityPathItemWorksForReadByKeyRestrictionsCapablities(bool re } [Theory] - [InlineData(true, new OperationType[] { OperationType.Get, OperationType.Patch, OperationType.Delete })] - [InlineData(false, new OperationType[] { OperationType.Patch, OperationType.Delete })] - public void CreateEntityPathItemWorksForReadRestrictionsCapablities(bool readable, OperationType[] expected) + [InlineData(true, new string[] { "get", "patch", "delete" })] + [InlineData(false, new string[] { "patch", "delete" })] + public void CreateEntityPathItemWorksForReadRestrictionsCapablities(bool readable, string[] expected) { // Arrange string annotation = $@" @@ -182,9 +183,9 @@ public void CreateEntityPathItemWorksForReadRestrictionsCapablities(bool readabl } [Theory] - [InlineData(true, new OperationType[] { OperationType.Get, OperationType.Patch, OperationType.Delete })] - [InlineData(false, new OperationType[] { OperationType.Get, OperationType.Delete })] - public void CreateEntityPathItemWorksForUpdateRestrictionsCapablities(bool updatable, OperationType[] expected) + [InlineData(true, new string[] { "get", "patch", "delete" })] + [InlineData(false, new string[] { "get", "delete" })] + public void CreateEntityPathItemWorksForUpdateRestrictionsCapablities(bool updatable, string[] expected) { // Arrange string annotation = $@" @@ -199,9 +200,9 @@ public void CreateEntityPathItemWorksForUpdateRestrictionsCapablities(bool updat } [Theory] - [InlineData(true, new OperationType[] { OperationType.Get, OperationType.Patch, OperationType.Delete })] - [InlineData(false, new OperationType[] { OperationType.Get, OperationType.Patch })] - public void CreateEntityPathItemWorksForDeleteRestrictionsCapablities(bool deletable, OperationType[] expected) + [InlineData(true, new string[] { "get", "patch", "delete" })] + [InlineData(false, new string[] { "get", "patch" })] + public void CreateEntityPathItemWorksForDeleteRestrictionsCapablities(bool deletable, string[] expected) { // Arrange string annotation = $@" @@ -216,9 +217,9 @@ public void CreateEntityPathItemWorksForDeleteRestrictionsCapablities(bool delet } [Theory] - [InlineData(false, new OperationType[] { OperationType.Get, OperationType.Patch, OperationType.Delete })] - [InlineData(true, new OperationType[] { OperationType.Get, OperationType.Put, OperationType.Delete })] - public void CreateEntityPathItemWorksForUpdateMethodRestrictionsCapabilities(bool updateMethod, OperationType[] expected) + [InlineData(false, new string[] { "get", "patch", "delete" })] + [InlineData(true, new string[] { "get", "put", "delete" })] + public void CreateEntityPathItemWorksForUpdateMethodRestrictionsCapabilities(bool updateMethod, string[] expected) { // Arrange string annotation = updateMethod ? $@" @@ -234,7 +235,7 @@ public void CreateEntityPathItemWorksForUpdateMethodRestrictionsCapabilities(boo VerifyPathItemOperations(annotation, expected); } - private void VerifyPathItemOperations(string annotation, OperationType[] expected) + private void VerifyPathItemOperations(string annotation, string[] expected) { // Arrange IEdmModel model = EntitySetPathItemHandlerTests.GetEdmModel(annotation); @@ -251,7 +252,7 @@ private void VerifyPathItemOperations(string annotation, OperationType[] expecte Assert.NotNull(pathItem.Operations); Assert.NotEmpty(pathItem.Operations); - Assert.Equal(expected, pathItem.Operations.Select(e => e.Key)); + Assert.Equal(expected, pathItem.Operations.Select(e => e.Key.ToString().ToLowerInvariant())); } [Fact] @@ -296,7 +297,7 @@ public MyEntityPathItemHandler(OpenApiDocument document) : base(document) { } - protected override void AddOperation(OpenApiPathItem item, OperationType operationType) + protected override void AddOperation(OpenApiPathItem item, HttpMethod operationType) { item.AddOperation(operationType, new OpenApiOperation()); } diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/EntitySetPathItemHandlerTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/EntitySetPathItemHandlerTests.cs index 290f53751..58afba883 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/EntitySetPathItemHandlerTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/EntitySetPathItemHandlerTests.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using System.Xml.Linq; using Microsoft.OData.Edm; using Microsoft.OData.Edm.Csdl; @@ -20,7 +21,7 @@ namespace Microsoft.OpenApi.OData.PathItem.Tests { public class EntitySetPathItemHandlerTests { - private EntitySetPathItemHandler _pathItemHandler = new MyEntitySetPathItemHandler(new()); + private readonly EntitySetPathItemHandler _pathItemHandler = new MyEntitySetPathItemHandler(new()); [Fact] public void CreatePathItemThrowsForNullContext() @@ -76,15 +77,15 @@ public void CreateEntitySetPathItemReturnsCorrectPathItem() Assert.NotNull(pathItem.Operations); Assert.NotEmpty(pathItem.Operations); Assert.Equal(2, pathItem.Operations.Count); - Assert.Equal(new OperationType[] { OperationType.Get, OperationType.Post }, + Assert.Equal([HttpMethod.Get, HttpMethod.Post], pathItem.Operations.Select(o => o.Key)); Assert.NotEmpty(pathItem.Description); } [Theory] - [InlineData(true, new OperationType[] { OperationType.Get, OperationType.Post })] - [InlineData(false, new OperationType[] { OperationType.Post })] - public void CreateEntitySetPathItemWorksForReadRestrictionsCapablities(bool readable, OperationType[] expected) + [InlineData(true, new [] { "get", "post" })] + [InlineData(false, new [] { "post" })] + public void CreateEntitySetPathItemWorksForReadRestrictionsCapabilities(bool readable, string[] expected) { // Arrange string annotation = $@" @@ -99,9 +100,9 @@ public void CreateEntitySetPathItemWorksForReadRestrictionsCapablities(bool read } [Theory] - [InlineData(true, new OperationType[] { OperationType.Get, OperationType.Post })] - [InlineData(false, new OperationType[] { OperationType.Get })] - public void CreateEntitySetPathItemWorksForInsertRestrictionsCapablities(bool insertable, OperationType[] expected) + [InlineData(true, new [] { "get", "post" })] + [InlineData(false, new [] { "get" })] + public void CreateEntitySetPathItemWorksForInsertRestrictionsCapablities(bool insertable, string[] expected) { // Arrange string annotation = $@" @@ -132,10 +133,10 @@ public void CreateEntitySetPathItemWorksForReadAndInsertRestrictionsCapablities( "; // Assert - VerifyPathItemOperations(annotation, new OperationType[] { }); + VerifyPathItemOperations(annotation, []); } - private void VerifyPathItemOperations(string annotation, OperationType[] expected) + private void VerifyPathItemOperations(string annotation, string[] expected) { // Arrange IEdmModel model = GetEdmModel(annotation); @@ -151,7 +152,7 @@ private void VerifyPathItemOperations(string annotation, OperationType[] expecte Assert.NotNull(pathItem); Assert.NotNull(pathItem.Operations); - Assert.Equal(expected, pathItem.Operations.Select(e => e.Key)); + Assert.Equal(expected, pathItem.Operations.Select(e => e.Key.ToString().ToLowerInvariant())); } [Fact] @@ -216,7 +217,7 @@ public static IEdmModel GetEdmModel(string annotation, string target = "\"NS.Def internal class MyEntitySetPathItemHandler(OpenApiDocument document) : EntitySetPathItemHandler(document) { - protected override void AddOperation(OpenApiPathItem item, OperationType operationType) + protected override void AddOperation(OpenApiPathItem item, HttpMethod operationType) { item.AddOperation(operationType, new OpenApiOperation()); } diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/MediaEntityPathItemHandlerTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/MediaEntityPathItemHandlerTests.cs index d7496a20b..75667e4fa 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/MediaEntityPathItemHandlerTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/MediaEntityPathItemHandlerTests.cs @@ -10,6 +10,7 @@ using Microsoft.OpenApi.OData.Properties; using System; using System.Linq; +using System.Net.Http; using System.Xml.Linq; using Xunit; @@ -90,17 +91,17 @@ public void CreateMediaEntityPathItemReturnsCorrectItem() Assert.NotEmpty(pathItem2.Operations); Assert.Equal(3, pathItem.Operations.Count); Assert.Equal(3, pathItem2.Operations.Count); - Assert.Equal(new OperationType[] { OperationType.Get, OperationType.Put, OperationType.Delete }, + Assert.Equal([HttpMethod.Get, HttpMethod.Put, HttpMethod.Delete], pathItem.Operations.Select(o => o.Key)); - Assert.Equal(new OperationType[] { OperationType.Get, OperationType.Put, OperationType.Delete }, + Assert.Equal([HttpMethod.Get, HttpMethod.Put, HttpMethod.Delete], pathItem2.Operations.Select(o => o.Key)); Assert.NotEmpty(pathItem.Description); } [Theory] - [InlineData(true, new OperationType[] { OperationType.Get, OperationType.Put, OperationType.Delete })] - [InlineData(false, new OperationType[] { OperationType.Put, OperationType.Delete })] - public void CreateMediaEntityPathItemWorksForReadByKeyRestrictionsCapabilities(bool readable, OperationType[] expected) + [InlineData(true, new string[] { "get", "put", "delete" })] + [InlineData(false, new string[] { "put", "delete" })] + public void CreateMediaEntityPathItemWorksForReadByKeyRestrictionsCapabilities(bool readable, string[] expected) { // Arrange string annotation = $@" @@ -120,9 +121,9 @@ public void CreateMediaEntityPathItemWorksForReadByKeyRestrictionsCapabilities(b } [Theory] - [InlineData(true, new OperationType[] { OperationType.Get, OperationType.Put, OperationType.Delete })] - [InlineData(false, new OperationType[] { OperationType.Get, OperationType.Delete })] - public void CreateMediaEntityPathItemWorksForUpdateRestrictionsCapabilities(bool updatable, OperationType[] expected) + [InlineData(true, new string[] { "get", "put", "delete" })] + [InlineData(false, new string[] { "get", "delete" })] + public void CreateMediaEntityPathItemWorksForUpdateRestrictionsCapabilities(bool updatable, string[] expected) { // Arrange string annotation = $@" @@ -138,9 +139,9 @@ public void CreateMediaEntityPathItemWorksForUpdateRestrictionsCapabilities(bool } [Theory] - [InlineData(true, new OperationType[] { OperationType.Get, OperationType.Put, OperationType.Delete })] - [InlineData(false, new OperationType[] { OperationType.Get, OperationType.Delete })] - public void CreateMediaEntityPathItemWorksForUpdateRestrictionsCapabilitiesWithTargetPathAnnotations(bool updatable, OperationType[] expected) + [InlineData(true, new string[] { "get", "put", "delete" })] + [InlineData(false, new string[] { "get", "delete" })] + public void CreateMediaEntityPathItemWorksForUpdateRestrictionsCapabilitiesWithTargetPathAnnotations(bool updatable, string[] expected) { string annotation = $@" @@ -164,9 +165,9 @@ public void CreateMediaEntityPathItemWorksForUpdateRestrictionsCapabilitiesWithT } [Theory] - [InlineData(true, new OperationType[] { OperationType.Get, OperationType.Put, OperationType.Delete })] - [InlineData(false, new OperationType[] { OperationType.Get, OperationType.Put })] - public void CreateMediaEntityPathItemWorksForDeleteRestrictionsCapabilities(bool deletable, OperationType[] expected) + [InlineData(true, new string[] { "get", "put", "delete" })] + [InlineData(false, new string[] { "get", "put" })] + public void CreateMediaEntityPathItemWorksForDeleteRestrictionsCapabilities(bool deletable, string[] expected) { // Arrange string annotation = $@" @@ -182,9 +183,9 @@ public void CreateMediaEntityPathItemWorksForDeleteRestrictionsCapabilities(bool } [Theory] - [InlineData(true, new OperationType[] { OperationType.Get, OperationType.Put, OperationType.Delete })] - [InlineData(false, new OperationType[] { OperationType.Get, OperationType.Put })] - public void CreateMediaEntityPathItemWorksForDeleteRestrictionsCapabilitiesWithTargetPathAnnotations(bool deletable, OperationType[] expected) + [InlineData(true, new string[] { "get", "put", "delete" })] + [InlineData(false, new string[] { "get", "put" })] + public void CreateMediaEntityPathItemWorksForDeleteRestrictionsCapabilitiesWithTargetPathAnnotations(bool deletable, string[] expected) { // Arrange string annotation = $@" @@ -209,7 +210,7 @@ public void CreateMediaEntityPathItemWorksForDeleteRestrictionsCapabilitiesWithT VerifyPathItemOperationsForStreamPropertySegment(annotation, expected, streamPropertyTargetPathAnnotation); } - private void VerifyPathItemOperationsForStreamPropertySegment(string annotation, OperationType[] expected, string targetPathAnnotations = "") + private void VerifyPathItemOperationsForStreamPropertySegment(string annotation, string[] expected, string targetPathAnnotations = "") { // Arrange @@ -232,10 +233,10 @@ private void VerifyPathItemOperationsForStreamPropertySegment(string annotation, Assert.NotNull(pathItem.Operations); Assert.NotEmpty(pathItem.Operations); - Assert.Equal(expected, pathItem.Operations.Select(e => e.Key)); + Assert.Equal(expected, pathItem.Operations.Select(e => e.Key.ToString().ToLowerInvariant())); } - private void VerifyPathItemOperationsForStreamContentSegment(string annotation, OperationType[] expected, string targetPathAnnotations = null) + private void VerifyPathItemOperationsForStreamContentSegment(string annotation, string[] expected, string targetPathAnnotations = null) { // Arrange IEdmModel model = GetEdmModel(annotation, targetPathAnnotations); @@ -268,8 +269,8 @@ private void VerifyPathItemOperationsForStreamContentSegment(string annotation, Assert.NotNull(pathItem2.Operations); Assert.NotEmpty(pathItem.Operations); Assert.NotEmpty(pathItem2.Operations); - Assert.Equal(expected, pathItem.Operations.Select(e => e.Key)); - Assert.Equal(expected, pathItem2.Operations.Select(e => e.Key)); + Assert.Equal(expected, pathItem.Operations.Select(e => e.Key.ToString().ToLowerInvariant())); + Assert.Equal(expected, pathItem2.Operations.Select(e => e.Key.ToString().ToLowerInvariant()));; } private IEdmModel GetEdmModel(string annotation, string targetPathAnnotation = "") @@ -315,7 +316,7 @@ private IEdmModel GetEdmModel(string annotation, string targetPathAnnotation = " internal class MyMediaEntityPathItemHandler(OpenApiDocument document) : MediaEntityPathItemHandler(document) { - protected override void AddOperation(OpenApiPathItem item, OperationType operationType) + protected override void AddOperation(OpenApiPathItem item, HttpMethod operationType) { item.AddOperation(operationType, new OpenApiOperation()); } diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/NavigationPropertyPathItemHandlerTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/NavigationPropertyPathItemHandlerTests.cs index f3a0aa86a..520f5d7c8 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/NavigationPropertyPathItemHandlerTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/NavigationPropertyPathItemHandlerTests.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using System.Xml.Linq; using Microsoft.OData.Edm; using Microsoft.OData.Edm.Csdl; @@ -59,11 +60,11 @@ 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, OperationType.Delete })] // Deletablity explicitly set via annotation - [InlineData(false, false, new OperationType[] { OperationType.Get})] - public void CreateCollectionNavigationPropertyPathItemReturnsCorrectPathItem(bool containment, bool keySegment, OperationType[] expected) + [InlineData(true, true, new string[] { "get", "patch", "delete" })] + [InlineData(true, false, new string[] { "get", "post" })] + [InlineData(false, true, new string[] { "get", "delete" })] // Deletablity explicitly set via annotation + [InlineData(false, false, new string[] { "get"})] + public void CreateCollectionNavigationPropertyPathItemReturnsCorrectPathItem(bool containment, bool keySegment, string[] expected) { string annotation = containment ? @@ -103,7 +104,7 @@ public void CreateCollectionNavigationPropertyPathItemReturnsCorrectPathItem(boo Assert.NotNull(pathItem.Operations); Assert.NotEmpty(pathItem.Operations); - Assert.Equal(expected, pathItem.Operations.Select(o => o.Key)); + Assert.Equal(expected, pathItem.Operations.Select(o => o.Key.ToString().ToLowerInvariant())); Assert.NotEmpty(pathItem.Description); } @@ -167,9 +168,9 @@ public void CreateNavigationPropertyPathItemReturnsCorrectPathItemWithPathParame } [Theory] - [InlineData(true, new OperationType[] { OperationType.Get, OperationType.Patch, OperationType.Delete })] - [InlineData(false, new OperationType[] { OperationType.Get })] - public void CreateSingleNavigationPropertyPathItemReturnsCorrectPathItem(bool containment, OperationType[] expected) + [InlineData(true, new string[] { "get", "patch", "delete" })] + [InlineData(false, new string[] { "get" })] + public void CreateSingleNavigationPropertyPathItemReturnsCorrectPathItem(bool containment, string[] expected) { // Arrange IEdmModel model = GetEdmModel(""); @@ -194,7 +195,7 @@ public void CreateSingleNavigationPropertyPathItemReturnsCorrectPathItem(bool co Assert.NotNull(pathItem.Operations); Assert.NotEmpty(pathItem.Operations); - Assert.Equal(expected, pathItem.Operations.Select(o => o.Key)); + Assert.Equal(expected, pathItem.Operations.Select(o => o.Key.ToString().ToLowerInvariant())); } public static IEnumerable CollectionNavigationPropertyData @@ -298,13 +299,13 @@ public void CreatePathItemForNavigationPropertyAndReadRestrictions(bool hasRestr if (hasRestrictions) { if (readable) - Assert.Contains(pathItem.Operations, o => o.Key == OperationType.Get); + Assert.Contains(pathItem.Operations, o => o.Key == HttpMethod.Get); else - Assert.DoesNotContain(pathItem.Operations, o => o.Key == OperationType.Get); + Assert.DoesNotContain(pathItem.Operations, o => o.Key == HttpMethod.Get); } else { - Assert.Contains(pathItem.Operations, o => o.Key == OperationType.Get); + Assert.Contains(pathItem.Operations, o => o.Key == HttpMethod.Get); } } @@ -349,18 +350,18 @@ public void CreatePathItemForNavigationPropertyAndInsertRestrictions(bool hasRes bool isContainment = path.Segments.OfType().Last().NavigationProperty.ContainsTarget; - OperationType[] expected; + HttpMethod[] expected; if (hasRestrictions) { expected = insertable - ? (new[] { OperationType.Get, OperationType.Post }) - : (new[] { OperationType.Get }); + ? (new[] { HttpMethod.Get, HttpMethod.Post }) + : (new[] { HttpMethod.Get }); } else { expected = isContainment - ? (new[] { OperationType.Get, OperationType.Post }) - : (new[] { OperationType.Get }); + ? (new[] { HttpMethod.Get, HttpMethod.Post }) + : (new[] { HttpMethod.Get }); } Assert.Equal(expected, pathItem.Operations.Select(o => o.Key)); @@ -410,27 +411,27 @@ public void CreatePathItemForNavigationPropertyAndUpdateRestrictions(bool hasRes bool isContainment = navigationProperty.ContainsTarget; bool isCollection = navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many; - OperationType[] expected; + HttpMethod[] expected; if (hasRestrictions) { if (isContainment) { expected = updatable - ? (new[] { OperationType.Get, OperationType.Patch, OperationType.Delete }) - : (new[] { OperationType.Get, OperationType.Delete }); + ? (new[] { HttpMethod.Get, HttpMethod.Patch, HttpMethod.Delete }) + : (new[] { HttpMethod.Get, HttpMethod.Delete }); } else { expected = updatable - ? (new[] { OperationType.Get, OperationType.Patch }) - : (new[] { OperationType.Get }); + ? (new[] { HttpMethod.Get, HttpMethod.Patch }) + : (new[] { HttpMethod.Get }); } } else { expected = isContainment - ? (new[] { OperationType.Get, OperationType.Patch, OperationType.Delete }) - : (new[] { OperationType.Get }); + ? (new[] { HttpMethod.Get, HttpMethod.Patch, HttpMethod.Delete }) + : (new[] { HttpMethod.Get }); } Assert.Equal(expected, pathItem.Operations.Select(o => o.Key)); @@ -480,29 +481,28 @@ public void CreatePathItemForNavigationPropertyAndUpdateMethodUpdateRestrictions var navigationProperty = path.Segments.OfType().Last().NavigationProperty; bool isContainment = navigationProperty.ContainsTarget; - bool isCollection = navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many; - OperationType[] expected; + HttpMethod[] expected; if (updateMethod) { if (isContainment) { expected = updatable - ? ([OperationType.Get, OperationType.Put, OperationType.Patch, OperationType.Delete]) - : ([OperationType.Get, OperationType.Delete]); + ? ([HttpMethod.Get, HttpMethod.Put, HttpMethod.Patch, HttpMethod.Delete]) + : ([HttpMethod.Get, HttpMethod.Delete]); } else { expected = updatable - ? ([OperationType.Get, OperationType.Put, OperationType.Patch,]) - : ([OperationType.Get]); + ? ([HttpMethod.Get, HttpMethod.Put, HttpMethod.Patch,]) + : ([HttpMethod.Get]); } } else { expected = isContainment - ? ([OperationType.Get, OperationType.Patch, OperationType.Delete]) - : ([OperationType.Get]); + ? ([HttpMethod.Get, HttpMethod.Patch, HttpMethod.Delete]) + : ([HttpMethod.Get]); } @@ -543,7 +543,7 @@ public void CreatePathItemForNavigationPropertyWithRestrictionAnnotationsDefined Assert.NotNull(pathItem); Assert.NotNull(pathItem.Operations); Assert.Single(pathItem.Operations); - Assert.Equal(OperationType.Get, pathItem.Operations.FirstOrDefault().Key); + Assert.Equal(HttpMethod.Get, pathItem.Operations.FirstOrDefault().Key); } [Fact] @@ -575,7 +575,7 @@ public void CreatePathItemForNavigationPropertyWithOutOfLineRestrictionAnnotatio Assert.NotNull(pathItem); Assert.NotNull(pathItem.Operations); Assert.Equal(2, pathItem.Operations.Count); - Assert.Equal(new[] { OperationType.Get, OperationType.Patch }, pathItem.Operations.Select(o => o.Key)); + Assert.Equal(new[] { HttpMethod.Get, HttpMethod.Patch }, pathItem.Operations.Select(o => o.Key)); } [Fact] diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/OperationImportPathItemHandlerTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/OperationImportPathItemHandlerTests.cs index 280885a34..99ed868c2 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/OperationImportPathItemHandlerTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/OperationImportPathItemHandlerTests.cs @@ -5,6 +5,7 @@ using System; using System.Linq; +using System.Net.Http; using System.Xml.Linq; using Microsoft.OData.Edm; using Microsoft.OData.Edm.Csdl; @@ -58,10 +59,10 @@ public void CreatePathItemThrowsForNonOperationImportPath() } [Theory] - [InlineData("GetNearestAirport", OperationType.Get)] - [InlineData("ResetDataSource", OperationType.Post)] + [InlineData("GetNearestAirport", "get")] + [InlineData("ResetDataSource", "post")] public void CreatePathItemForOperationImportReturnsCorrectPathItem(string operationImport, - OperationType operationType) + string operationType) { // Arrange IEdmModel model = EdmModelHelper.TripServiceModel; @@ -78,18 +79,18 @@ public void CreatePathItemForOperationImportReturnsCorrectPathItem(string operat Assert.NotNull(pathItem); Assert.NotNull(pathItem.Operations); var operationKeyValue = Assert.Single(pathItem.Operations); - Assert.Equal(operationType, operationKeyValue.Key); + Assert.Equal(HttpMethod.Parse(operationType), operationKeyValue.Key); Assert.NotNull(operationKeyValue.Value); Assert.NotEmpty(pathItem.Description); } [Theory] - [InlineData(true, "GetNearestCustomers", OperationType.Get)] + [InlineData(true, "GetNearestCustomers", "get")] [InlineData(false, "GetNearestCustomers", null)] - [InlineData(true, "ResetDataSource", OperationType.Post)] - [InlineData(false, "ResetDataSource", OperationType.Post)] + [InlineData(true, "ResetDataSource", "post")] + [InlineData(false, "ResetDataSource", "post")] public void CreatePathItemForOperationImportWithReadRestrictionsReturnsCorrectPathItem(bool readable, string operationImport, - OperationType? operationType) + string operationType) { // Arrange string annotation = $@" @@ -119,7 +120,7 @@ public void CreatePathItemForOperationImportWithReadRestrictionsReturnsCorrectPa else { var operationKeyValue = Assert.Single(pathItem.Operations); - Assert.Equal(operationType, operationKeyValue.Key); + Assert.Equal(HttpMethod.Parse(operationType), operationKeyValue.Key); Assert.NotNull(operationKeyValue.Value); } } @@ -189,7 +190,7 @@ public static IEdmModel GetEdmModel(string annotation) internal class MyOperationImportPathItemHandler(OpenApiDocument document) : OperationImportPathItemHandler(document) { - protected override void AddOperation(OpenApiPathItem item, OperationType operationType) + protected override void AddOperation(OpenApiPathItem item, HttpMethod operationType) { item.AddOperation(operationType, new OpenApiOperation()); } diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/OperationPathItemHandlerTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/OperationPathItemHandlerTests.cs index 3167d196f..51a76e9a7 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/OperationPathItemHandlerTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/OperationPathItemHandlerTests.cs @@ -5,6 +5,7 @@ using System; using System.Linq; +using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Interfaces; @@ -56,10 +57,10 @@ public void CreatePathItemThrowsForNonOperationPath() } [Theory] - [InlineData("GetFriendsTrips", "People", OperationType.Get)] - [InlineData("ShareTrip", "People", OperationType.Post)] + [InlineData("GetFriendsTrips", "People", "get")] + [InlineData("ShareTrip", "People", "post")] public void CreatePathItemForOperationReturnsCorrectPathItem(string operationName, string entitySet, - OperationType operationType) + string operationType) { // Arrange IEdmModel model = EdmModelHelper.TripServiceModel; @@ -80,7 +81,7 @@ public void CreatePathItemForOperationReturnsCorrectPathItem(string operationNam Assert.NotNull(pathItem); Assert.NotNull(pathItem.Operations); var operationKeyValue = Assert.Single(pathItem.Operations); - Assert.Equal(operationType, operationKeyValue.Key); + Assert.Equal(HttpMethod.Parse(operationType), operationKeyValue.Key); Assert.NotNull(operationKeyValue.Value); Assert.Equal(expectSummary, operationKeyValue.Value.Summary); diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/RefPathItemHandlerTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/RefPathItemHandlerTests.cs index 48baaf766..9679196a3 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/RefPathItemHandlerTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/RefPathItemHandlerTests.cs @@ -10,7 +10,6 @@ using Microsoft.OData.Edm; using Microsoft.OData.Edm.Csdl; using Microsoft.OData.Edm.Validation; -using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Edm; using Microsoft.OpenApi.OData.Properties; using Xunit; @@ -19,7 +18,7 @@ namespace Microsoft.OpenApi.OData.PathItem.Tests { public class RefPathItemHandlerTest { - private RefPathItemHandler _pathItemHandler = new RefPathItemHandler(new()); + private readonly RefPathItemHandler _pathItemHandler = new RefPathItemHandler(new()); [Fact] public void CreatePathItemThrowsForNullContext() @@ -57,10 +56,10 @@ public void CreatePathItemThrowsForNonNavigationPropertyPath() } [Theory] - [InlineData(true, new OperationType[] { OperationType.Delete}, true)] - [InlineData(true, new OperationType[] { OperationType.Get, OperationType.Post, OperationType.Delete })] - [InlineData(false, new OperationType[] { OperationType.Get, OperationType.Put, OperationType.Delete })] - public void CreateNavigationPropertyRefPathItemReturnsCorrectPathItem(bool collectionNav, OperationType[] expected, bool indexedColNav = false) + [InlineData(true, new string[] { "delete"}, true)] + [InlineData(true, new string[] { "get", "post", "delete" })] + [InlineData(false, new string[] { "get", "put", "delete" })] + public void CreateNavigationPropertyRefPathItemReturnsCorrectPathItem(bool collectionNav, string[] expected, bool indexedColNav = false) { // Arrange IEdmModel model = GetEdmModel(""); @@ -100,7 +99,7 @@ public void CreateNavigationPropertyRefPathItemReturnsCorrectPathItem(bool colle Assert.NotNull(pathItem.Operations); Assert.NotEmpty(pathItem.Operations); - Assert.Equal(expected, pathItem.Operations.Select(o => o.Key)); + Assert.Equal(expected, pathItem.Operations.Select(o => o.Key.ToString().ToLowerInvariant())); Assert.NotEmpty(pathItem.Description); } diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/SingletonPathItemHandlerTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/SingletonPathItemHandlerTests.cs index b94e63efc..731252517 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/SingletonPathItemHandlerTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/SingletonPathItemHandlerTests.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using System.Xml.Linq; using Microsoft.OData.Edm; using Microsoft.OData.Edm.Csdl; @@ -76,15 +77,15 @@ public void CreateSingletonPathItemReturnsCorrectPathItem() Assert.NotNull(pathItem.Operations); Assert.NotEmpty(pathItem.Operations); Assert.Equal(2, pathItem.Operations.Count); - Assert.Equal(new OperationType[] { OperationType.Get, OperationType.Patch }, + Assert.Equal([HttpMethod.Get, HttpMethod.Patch], pathItem.Operations.Select(o => o.Key)); Assert.NotEmpty(pathItem.Description); } [Theory] - [InlineData(true, new OperationType[] { OperationType.Get, OperationType.Patch })] - [InlineData(false, new OperationType[] { OperationType.Patch })] - public void CreateSingletonPathItemWorksForReadRestrictionsCapablities(bool readable, OperationType[] expected) + [InlineData(true, new string[] { "get", "patch" })] + [InlineData(false, new string[] { "patch" })] + public void CreateSingletonPathItemWorksForReadRestrictionsCapablities(bool readable, string[] expected) { // Arrange string annotation = $@" @@ -99,9 +100,9 @@ public void CreateSingletonPathItemWorksForReadRestrictionsCapablities(bool read } [Theory] - [InlineData(true, new OperationType[] { OperationType.Get, OperationType.Patch })] - [InlineData(false, new OperationType[] { OperationType.Get })] - public void CreateSingletonPathItemWorksForUpdateRestrictionsCapablities(bool updatable, OperationType[] expected) + [InlineData(true, new string[] { "get", "patch" })] + [InlineData(false, new string[] { "get" })] + public void CreateSingletonPathItemWorksForUpdateRestrictionsCapablities(bool updatable, string[] expected) { // Arrange string annotation = $@" @@ -115,7 +116,7 @@ public void CreateSingletonPathItemWorksForUpdateRestrictionsCapablities(bool up VerifyPathItemOperations(annotation, expected); } - private void VerifyPathItemOperations(string annotation, OperationType[] expected) + private void VerifyPathItemOperations(string annotation, string[] expected) { // Arrange IEdmModel model = GetEdmModel(annotation); @@ -132,7 +133,7 @@ private void VerifyPathItemOperations(string annotation, OperationType[] expecte Assert.NotNull(pathItem.Operations); Assert.NotEmpty(pathItem.Operations); - Assert.Equal(expected, pathItem.Operations.Select(e => e.Key)); + Assert.Equal(expected, pathItem.Operations.Select(e => e.Key.ToString().ToLowerInvariant())); } [Fact] @@ -195,7 +196,7 @@ public MySingletonPathItemHandler(OpenApiDocument document) : base(document) { } - protected override void AddOperation(OpenApiPathItem item, OperationType operationType) + protected override void AddOperation(OpenApiPathItem item, HttpMethod operationType) { item.AddOperation(operationType, new OpenApiOperation()); } From 93f46f09b2204e3f18ec19b68850ec7acd209e65 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 19 Mar 2025 15:16:04 -0400 Subject: [PATCH 02/24] feat: enables null reference types for the library Signed-off-by: Vincent Biret --- .editorconfig | 3 + .../Edm/EdmAnnotationExtensions.cs | 95 +++-- .../Edm/EdmModelExtensions.cs | 10 +- .../Edm/ODataKeySegment.cs | 2 +- .../Edm/ODataOperationSegment.cs | 17 +- .../Edm/ODataPathProvider.cs | 35 +- .../Edm/ODataSegment.cs | 4 +- .../Generator/OpenApiParameterGenerator.cs | 64 +-- .../Generator/OpenApiSchemaGenerator.cs | 2 +- .../Microsoft.OpenAPI.OData.Reader.csproj | 1 + .../Operation/EdmFunctionOperationHandler.cs | 5 +- .../Operation/EdmOperationOperationHandler.cs | 16 +- .../MediaEntityOperationalHandler.cs | 43 +- .../NavigationPropertyGetOperationHandler.cs | 39 +- .../NavigationPropertyOperationHandler.cs | 61 ++- .../ODataTypeCastGetOperationHandler.cs | 164 ++++---- .../Operation/OperationHandler.cs | 73 ++-- .../PublicAPI.Unshipped.txt | 383 +++++++++--------- .../Capabilities/DeleteRestrictionsType.cs | 2 +- .../Capabilities/InsertRestrictionsType.cs | 48 +-- .../Capabilities/ReadRestrictionsType.cs | 16 +- .../Capabilities/UpdateRestrictionsType.cs | 2 +- 22 files changed, 575 insertions(+), 510 deletions(-) diff --git a/.editorconfig b/.editorconfig index fc328cb5e..d650df54f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,3 +3,6 @@ # IDE0009: Member access should be qualified. dotnet_diagnostic.IDE0009.severity = none dotnet_diagnostic.CA2016.severity = warning + +[*.cs] +dotnet_public_api_analyzer.require_api_files = true \ No newline at end of file diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmAnnotationExtensions.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmAnnotationExtensions.cs index 97ed1cb64..97895481a 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmAnnotationExtensions.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmAnnotationExtensions.cs @@ -21,9 +21,9 @@ namespace Microsoft.OpenApi.OData.Edm /// internal static class EdmVocabularyAnnotationExtensions { - private static IDictionary> _cachedAnnotations; - private static IEdmModel _savedModel = null; // if diffenent model, the cache will be cleaned. - private static object _objectLock = new object(); + private static IDictionary>? _cachedAnnotations; + private static IEdmModel? _savedModel = null; // if different model, the cache will be cleaned. + private static readonly object _objectLock = new object(); /// /// Gets the boolean term value for the given . @@ -54,8 +54,7 @@ internal static class EdmVocabularyAnnotationExtensions // Note: Graph has a lot of annotations applied to the type, not to the navigation source. // Here's a work around to retrieve these annotations from type if we can't find it from navigation source. // It's the same reason for belows - IEdmNavigationSource navigationSource = target as IEdmNavigationSource; - if (navigationSource != null) + if (target is IEdmNavigationSource navigationSource) { IEdmEntityType entityType = navigationSource.EntityType; value = model.GetBoolean(entityType, term); @@ -87,7 +86,7 @@ internal static class EdmVocabularyAnnotationExtensions /// The Edm target. /// The Term qualified name. /// Null or the string value for this annotation. - public static string GetString(this IEdmModel model, IEdmVocabularyAnnotatable target, string qualifiedName) + public static string? GetString(this IEdmModel model, IEdmVocabularyAnnotatable target, string qualifiedName) { Utils.CheckArgumentNull(model, nameof(model)); Utils.CheckArgumentNull(target, nameof(target)); @@ -95,7 +94,7 @@ public static string GetString(this IEdmModel model, IEdmVocabularyAnnotatable t return GetOrAddCached(model, target, qualifiedName, () => { - string value = null; + string? value = null; IEdmTerm term = model.FindTerm(qualifiedName); if (term != null) { @@ -106,8 +105,7 @@ public static string GetString(this IEdmModel model, IEdmVocabularyAnnotatable t } else { - IEdmNavigationSource navigationSource = target as IEdmNavigationSource; - if (navigationSource != null) + if (target is IEdmNavigationSource navigationSource) { IEdmEntityType entityType = navigationSource.EntityType; value = model.GetString(entityType, term); @@ -127,8 +125,8 @@ public static string GetString(this IEdmModel model, IEdmVocabularyAnnotatable t /// The Edm model. /// The target element. /// Null or the record value (a complex type) for this annotation. - public static T GetRecord(this IEdmModel model, IEdmVocabularyAnnotatable target) - where T : IRecord, new() + public static T? GetRecord(this IEdmModel model, IEdmVocabularyAnnotatable target) + where T : class, IRecord, new() { string qualifiedName = Utils.GetTermQualifiedName(); return model.GetRecord(target, qualifiedName); @@ -142,8 +140,8 @@ public static T GetRecord(this IEdmModel model, IEdmVocabularyAnnotatable tar /// The Edm target. /// The Term qualified name. /// Null or the record value (a complex type) for this annotation. - public static T GetRecord(this IEdmModel model, IEdmVocabularyAnnotatable target, string qualifiedName) - where T : IRecord, new() + public static T? GetRecord(this IEdmModel model, IEdmVocabularyAnnotatable target, string qualifiedName) + where T : class, IRecord, new() { Utils.CheckArgumentNull(model, nameof(model)); Utils.CheckArgumentNull(target, nameof(target)); @@ -151,7 +149,7 @@ public static T GetRecord(this IEdmModel model, IEdmVocabularyAnnotatable tar return GetOrAddCached(model, target, qualifiedName, () => { - T value = default; + T? value = default; IEdmTerm term = model.FindTerm(qualifiedName); if (term != null) { @@ -162,8 +160,7 @@ public static T GetRecord(this IEdmModel model, IEdmVocabularyAnnotatable tar } else { - IEdmNavigationSource navigationSource = target as IEdmNavigationSource; - if (navigationSource != null) + if (target is IEdmNavigationSource navigationSource) { IEdmEntityType entityType = navigationSource.EntityType; value = model.GetRecord(entityType, term); @@ -183,8 +180,8 @@ public static T GetRecord(this IEdmModel model, IEdmVocabularyAnnotatable tar /// The string representation of the Edm target path. /// The Term qualified name. /// - public static T GetRecord(this IEdmModel model, string targetPath, string qualifiedName) - where T : IRecord, new() + public static T? GetRecord(this IEdmModel model, string targetPath, string qualifiedName) + where T : class, IRecord, new() { Utils.CheckArgumentNull(model, nameof(model)); Utils.CheckArgumentNull(targetPath, nameof(targetPath)); @@ -204,7 +201,7 @@ public static T GetRecord(this IEdmModel model, string targetPath, string qua /// The Edm target. /// The Term qualified name. /// Null or the collection of string value for this annotation. - public static IEnumerable GetCollection(this IEdmModel model, IEdmVocabularyAnnotatable target, string qualifiedName) + public static IEnumerable? GetCollection(this IEdmModel model, IEdmVocabularyAnnotatable target, string qualifiedName) { Utils.CheckArgumentNull(model, nameof(model)); Utils.CheckArgumentNull(target, nameof(target)); @@ -212,7 +209,7 @@ public static IEnumerable GetCollection(this IEdmModel model, IEdmVocabu return GetOrAddCached(model, target, qualifiedName, () => { - IEnumerable value = null; + IEnumerable? value = null; IEdmTerm term = model.FindTerm(qualifiedName); if (term != null) { @@ -223,8 +220,7 @@ public static IEnumerable GetCollection(this IEdmModel model, IEdmVocabu } else { - IEdmNavigationSource navigationSource = target as IEdmNavigationSource; - if (navigationSource != null) + if (target is IEdmNavigationSource navigationSource) { IEdmEntityType entityType = navigationSource.EntityType; value = model.GetCollection(entityType, term); @@ -244,7 +240,7 @@ public static IEnumerable GetCollection(this IEdmModel model, IEdmVocabu /// The Edm model. /// The Edm target. /// Null or the colllection of record value (a complex type) for this annotation. - public static IEnumerable GetCollection(this IEdmModel model, IEdmVocabularyAnnotatable target) + public static IEnumerable? GetCollection(this IEdmModel model, IEdmVocabularyAnnotatable target) where T : IRecord, new() { string qualifiedName = Utils.GetTermQualifiedName(); @@ -259,7 +255,7 @@ public static IEnumerable GetCollection(this IEdmModel model, IEdmVocabula /// The Edm target. /// The Term qualified name. /// Null or the colllection of record value (a complex type) for this annotation. - public static IEnumerable GetCollection(this IEdmModel model, IEdmVocabularyAnnotatable target, string qualifiedName) + public static IEnumerable? GetCollection(this IEdmModel model, IEdmVocabularyAnnotatable target, string qualifiedName) where T : IRecord, new() { Utils.CheckArgumentNull(model, nameof(model)); @@ -268,7 +264,7 @@ public static IEnumerable GetCollection(this IEdmModel model, IEdmVocabula return GetOrAddCached(model, target, qualifiedName, () => { - IEnumerable value = null; + IEnumerable? value = null; IEdmTerm term = model.FindTerm(qualifiedName); if (term != null) { @@ -279,8 +275,7 @@ public static IEnumerable GetCollection(this IEdmModel model, IEdmVocabula } else { - IEdmNavigationSource navigationSource = target as IEdmNavigationSource; - if (navigationSource != null) + if (target is IEdmNavigationSource navigationSource) { IEdmEntityType entityType = navigationSource.EntityType; value = model.GetCollection(entityType, term); @@ -299,7 +294,7 @@ public static IEnumerable GetCollection(this IEdmModel model, IEdmVocabula /// The Edm target. /// The link relation type for path operation. /// Null or the links record value (a complex type) for this annotation. - public static LinkType GetLinkRecord(this IEdmModel model, IEdmVocabularyAnnotatable target, string linkRel) + public static LinkType? GetLinkRecord(this IEdmModel model, IEdmVocabularyAnnotatable target, string linkRel) { Utils.CheckArgumentNull(model, nameof(model)); Utils.CheckArgumentNull(target, nameof(target)); @@ -314,7 +309,7 @@ public static LinkType GetLinkRecord(this IEdmModel model, IEdmVocabularyAnnotat /// The string representation of the Edm target path. /// The link relation type for path operation. /// Null or the links record value (a complex type) for this annotation. - public static LinkType GetLinkRecord(this IEdmModel model, string targetPath, string linkRel) + public static LinkType? GetLinkRecord(this IEdmModel model, string targetPath, string linkRel) { Utils.CheckArgumentNull(model, nameof(model)); Utils.CheckArgumentNull(targetPath, nameof(targetPath)); @@ -332,7 +327,7 @@ public static LinkType GetLinkRecord(this IEdmModel model, string targetPath, st /// The Edm model. /// The Edm target. /// The created object. - public static IEnumerable GetAuthorizations(this IEdmModel model, IEdmVocabularyAnnotatable target) + public static IEnumerable? GetAuthorizations(this IEdmModel model, IEdmVocabularyAnnotatable target) { Utils.CheckArgumentNull(model, nameof(model)); Utils.CheckArgumentNull(target, nameof(target)); @@ -342,7 +337,7 @@ public static IEnumerable GetAuthorizations(this IEdmModel model, IEdmTerm term = model.FindTerm(AuthorizationConstants.Authorizations); if (term != null) { - IEdmVocabularyAnnotation annotation = model.FindVocabularyAnnotations(target, term).FirstOrDefault(); + IEdmVocabularyAnnotation? annotation = model.FindVocabularyAnnotations(target, term).FirstOrDefault(); if (annotation != null && annotation.Value != null && annotation.Value.ExpressionKind == EdmExpressionKind.Collection) { IEdmCollectionExpression collection = (IEdmCollectionExpression)annotation.Value; @@ -364,7 +359,7 @@ public static IEnumerable GetAuthorizations(this IEdmModel model, }); } - public static string GetDescriptionAnnotation(this IEdmModel model, string targetPath) + public static string? GetDescriptionAnnotation(this IEdmModel model, string targetPath) { Utils.CheckArgumentNull(model, nameof(model)); Utils.CheckArgumentNull(targetPath, nameof(targetPath)); @@ -376,7 +371,7 @@ public static string GetDescriptionAnnotation(this IEdmModel model, string targe return model.GetDescriptionAnnotation(target); } - private static T GetOrAddCached(this IEdmModel model, IEdmVocabularyAnnotatable target, string qualifiedName, Func createFunc) + private static T? GetOrAddCached(this IEdmModel model, IEdmVocabularyAnnotatable target, string qualifiedName, Func createFunc) { if (model == null || target == null) { @@ -400,8 +395,8 @@ private static T GetOrAddCached(this IEdmModel model, IEdmVocabularyAnnotatab _cachedAnnotations = new Dictionary>(); } - object restriction; - if (_cachedAnnotations.TryGetValue(target, out IDictionary value)) + object? restriction; + if (_cachedAnnotations.TryGetValue(target, out var value)) { // Here means we visited target before and we are sure that the value is not null. if (value.TryGetValue(qualifiedName, out restriction)) @@ -409,9 +404,8 @@ private static T GetOrAddCached(this IEdmModel model, IEdmVocabularyAnnotatab T ret = (T)restriction; return ret; } - else + else if (createFunc() is T ret) { - T ret = createFunc(); value[qualifiedName] = ret; return ret; } @@ -420,9 +414,12 @@ private static T GetOrAddCached(this IEdmModel model, IEdmVocabularyAnnotatab // It's first time to query this target, create new dictionary and restriction. value = new Dictionary(); _cachedAnnotations[target] = value; - T newAnnotation = createFunc(); - value[qualifiedName] = newAnnotation; - return newAnnotation; + if (createFunc() is T newAnnotation) + { + value[qualifiedName] = newAnnotation; + return newAnnotation; + } + return default; } } @@ -432,7 +429,7 @@ private static T GetOrAddCached(this IEdmModel model, IEdmVocabularyAnnotatab Debug.Assert(target != null); Debug.Assert(term != null); - IEdmVocabularyAnnotation annotation = model.FindVocabularyAnnotations(target, term).FirstOrDefault(); + IEdmVocabularyAnnotation? annotation = model.FindVocabularyAnnotations(target, term).FirstOrDefault(); if (annotation != null && annotation.Value != null && annotation.Value.ExpressionKind == EdmExpressionKind.BooleanConstant) { IEdmBooleanConstantExpression boolConstant = (IEdmBooleanConstantExpression)annotation.Value; @@ -445,13 +442,13 @@ private static T GetOrAddCached(this IEdmModel model, IEdmVocabularyAnnotatab return null; } - private static string GetString(this IEdmModel model, IEdmVocabularyAnnotatable target, IEdmTerm term) + private static string? GetString(this IEdmModel model, IEdmVocabularyAnnotatable target, IEdmTerm term) { Debug.Assert(model != null); Debug.Assert(target != null); Debug.Assert(term != null); - IEdmVocabularyAnnotation annotation = model.FindVocabularyAnnotations(target, term).FirstOrDefault(); + IEdmVocabularyAnnotation? annotation = model.FindVocabularyAnnotations(target, term).FirstOrDefault(); if (annotation != null && annotation.Value != null && annotation.Value.ExpressionKind == EdmExpressionKind.StringConstant) { IEdmStringConstantExpression stringConstant = (IEdmStringConstantExpression)annotation.Value; @@ -461,13 +458,13 @@ private static string GetString(this IEdmModel model, IEdmVocabularyAnnotatable return null; } - private static IEnumerable GetCollection(this IEdmModel model, IEdmVocabularyAnnotatable target, IEdmTerm term) + private static IEnumerable? GetCollection(this IEdmModel model, IEdmVocabularyAnnotatable target, IEdmTerm term) { Debug.Assert(model != null); Debug.Assert(target != null); Debug.Assert(term != null); - IEdmVocabularyAnnotation annotation = model.FindVocabularyAnnotations(target, term).FirstOrDefault(); + IEdmVocabularyAnnotation? annotation = model.FindVocabularyAnnotations(target, term).FirstOrDefault(); if (annotation != null && annotation.Value != null && annotation.Value.ExpressionKind == EdmExpressionKind.Collection) { IEdmCollectionExpression collection = (IEdmCollectionExpression)annotation.Value; @@ -480,14 +477,14 @@ private static IEnumerable GetCollection(this IEdmModel model, IEdmVocab return null; } - private static T GetRecord(this IEdmModel model, IEdmVocabularyAnnotatable target, IEdmTerm term) + private static T? GetRecord(this IEdmModel model, IEdmVocabularyAnnotatable target, IEdmTerm term) where T : IRecord, new() { Debug.Assert(model != null); Debug.Assert(target != null); Debug.Assert(term != null); - IEdmVocabularyAnnotation annotation = model.FindVocabularyAnnotations(target, term).FirstOrDefault(); + IEdmVocabularyAnnotation? annotation = model.FindVocabularyAnnotations(target, term).FirstOrDefault(); if (annotation != null && annotation.Value != null && annotation.Value.ExpressionKind == EdmExpressionKind.Record) { IEdmRecordExpression recordExpression = (IEdmRecordExpression)annotation.Value; @@ -499,14 +496,14 @@ private static T GetRecord(this IEdmModel model, IEdmVocabularyAnnotatable ta return default; } - private static IEnumerable GetCollection(this IEdmModel model, IEdmVocabularyAnnotatable target, IEdmTerm term) + private static IEnumerable? GetCollection(this IEdmModel model, IEdmVocabularyAnnotatable target, IEdmTerm term) where T : IRecord, new() { Debug.Assert(model != null); Debug.Assert(target != null); Debug.Assert(term != null); - IEdmVocabularyAnnotation annotation = model.FindVocabularyAnnotations(target, term).FirstOrDefault(); + IEdmVocabularyAnnotation? annotation = model.FindVocabularyAnnotations(target, term).FirstOrDefault(); if (annotation != null && annotation.Value != null && annotation.Value.ExpressionKind == EdmExpressionKind.Collection) { IEdmCollectionExpression collection = (IEdmCollectionExpression)annotation.Value; diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs index 3ece9f1f6..e6e156a17 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs @@ -73,16 +73,16 @@ private static bool IsUrlEscapeFunction(this IEdmModel model, IEdmFunction funct /// /// The Edm model. /// The dictionary. - public static IDictionary> LoadAllNavigationSources(this IEdmModel model) + public static Dictionary> LoadAllNavigationSources(this IEdmModel model) { var navigationSourceDic = new Dictionary>(); if (model != null && model.EntityContainer != null) { Action>> action = (ns, dic) => { - if (!dic.TryGetValue(ns.EntityType, out IList value)) + if (!dic.TryGetValue(ns.EntityType, out var value)) { - value = new List(); + value = []; dic[ns.EntityType] = value; } @@ -96,9 +96,9 @@ public static IDictionary> LoadAllNa } // singleton - foreach (var singelton in model.EntityContainer.Singletons()) + foreach (var singleton in model.EntityContainer.Singletons()) { - action(singelton, navigationSourceDic); + action(singleton, navigationSourceDic); } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataKeySegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataKeySegment.cs index 3af32c2fa..ebef313d0 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataKeySegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataKeySegment.cs @@ -45,7 +45,7 @@ public ODataKeySegment(IEdmEntityType entityType, IDictionary ke /// /// Gets the key/template mappings. /// - public IDictionary KeyMappings { get; } + public IDictionary? KeyMappings { get; } /// public override IEdmEntityType EntityType { get; } diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataOperationSegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataOperationSegment.cs index 6ad4a2b5b..4da501dd6 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataOperationSegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataOperationSegment.cs @@ -77,12 +77,12 @@ public ODataOperationSegment(IEdmOperation operation, bool isEscapedFunction, IE /// /// Gets the parameter mappings. /// - public IDictionary ParameterMappings { get; } + public IDictionary? ParameterMappings { get; } /// /// Gets the operation. /// - public IEdmOperation Operation { get; } + public IEdmOperation? Operation { get; } /// /// Gets the is escaped function. @@ -93,19 +93,19 @@ public ODataOperationSegment(IEdmOperation operation, bool isEscapedFunction, IE public override ODataSegmentKind Kind => ODataSegmentKind.Operation; /// - public override string Identifier { get => Operation.Name; } + public override string? Identifier { get => Operation?.Name; } /// - public override IEdmEntityType EntityType => null; + public override IEdmEntityType? EntityType => null; /// public override string GetPathItemName(OpenApiConvertSettings settings, HashSet parameters) { Utils.CheckArgumentNull(settings, nameof(settings)); - if (Operation.IsFunction()) + if (Operation is IEdmFunction function) { - return FunctionName(Operation as IEdmFunction, settings, parameters); + return FunctionName(function, settings, parameters); } return OperationName(Operation, settings); @@ -115,9 +115,8 @@ internal IDictionary GetNameMapping(OpenApiConvertSettings setti { IDictionary parameterNamesMapping = new Dictionary(); - if (Operation.IsFunction()) + if (Operation is IEdmFunction function) { - IEdmFunction function = Operation as IEdmFunction; if (settings.EnableUriEscapeFunctionCall && IsEscapedFunction) { string parameterName = function.Parameters.Last().Name; @@ -192,7 +191,7 @@ private string FunctionName(IEdmFunction function, OpenApiConvertSettings settin /// public override IEnumerable GetAnnotables() { - return new IEdmVocabularyAnnotatable[] { Operation }; + return Operation is null ? [] : [Operation]; } } } \ No newline at end of file diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs index ca56a177f..5ac8315a6 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs @@ -19,17 +19,17 @@ namespace Microsoft.OpenApi.OData.Edm /// public class ODataPathProvider : IODataPathProvider { - private IDictionary> _allNavigationSources; + private Dictionary>? _allNavigationSources; - private IDictionary> _allNavigationSourcePaths = + private readonly IDictionary> _allNavigationSourcePaths = new Dictionary>(); - private IDictionary> _allNavigationPropertyPaths = + private readonly IDictionary> _allNavigationPropertyPaths = new Dictionary>(); - private IList _allOperationPaths = new List(); + private readonly List _allOperationPaths = []; - private IEdmModel _model; + private IEdmModel? _model; private readonly IDictionary> _dollarCountPaths = new Dictionary>(); @@ -52,7 +52,7 @@ public virtual IEnumerable GetPaths(IEdmModel model, OpenApiConvertSe { if (model == null || model.EntityContainer == null) { - return Enumerable.Empty(); + return []; } Initialize(model); @@ -734,7 +734,7 @@ private void CreateTypeCastPaths(ODataPath currentPath, OpenApiConvertSettings c if(!convertSettings.EnableODataTypeCast) return; - var annotedTypeNames = GetDerivedTypeConstaintTypeNames(annotable); + var annotedTypeNames = GetDerivedTypeConstraintTypeNames(annotable); if(!annotedTypeNames.Any() && convertSettings.RequireDerivedTypesConstraintForODataTypeCastSegments) return; // we don't want to generate any downcast path item if there is no type cast annotation. @@ -1099,11 +1099,11 @@ private bool HasUnsatisfiedDerivedTypeConstraint( OpenApiConvertSettings convertSettings) { return convertSettings.RequireDerivedTypesConstraintForBoundOperations && - !GetDerivedTypeConstaintTypeNames(annotatable) + !GetDerivedTypeConstraintTypeNames(annotatable) .Any(c => c.Equals(baseType.FullName(), StringComparison.OrdinalIgnoreCase)); } - private IEnumerable GetDerivedTypeConstaintTypeNames(IEdmVocabularyAnnotatable annotatable) => - _model.GetCollection(annotatable, "Org.OData.Validation.V1.DerivedTypeConstraint") ?? Enumerable.Empty(); + private IEnumerable GetDerivedTypeConstraintTypeNames(IEdmVocabularyAnnotatable annotatable) => + _model?.GetCollection(annotatable, "Org.OData.Validation.V1.DerivedTypeConstraint") ?? []; private void AppendBoundOperationOnDerivedNavigationPropertyPath( IEdmOperation edmOperation, @@ -1112,11 +1112,11 @@ private void AppendBoundOperationOnDerivedNavigationPropertyPath( OpenApiConvertSettings convertSettings) { if (!convertSettings.AppendBoundOperationsOnDerivedTypeCastSegments) return; - bool isEscapedFunction = _model.IsUrlEscapeFunction(edmOperation); + bool isEscapedFunction = _model?.IsUrlEscapeFunction(edmOperation) ?? false; foreach (var baseType in bindingEntityType.FindAllBaseTypes()) { - if (_allNavigationPropertyPaths.TryGetValue(baseType, out IList paths)) + if (_allNavigationPropertyPaths.TryGetValue(baseType, out var paths)) { foreach (var path in paths.Where(x => !_pathKindToSkipForNavigationProperties.Contains(x.Kind))) { @@ -1126,7 +1126,7 @@ private void AppendBoundOperationOnDerivedNavigationPropertyPath( continue; } - if (!EdmModelHelper.IsOperationAllowed(_model, edmOperation, npSegment.NavigationProperty, npSegment.NavigationProperty.ContainsTarget)) + if (_model is not null && !EdmModelHelper.IsOperationAllowed(_model, edmOperation, npSegment.NavigationProperty, npSegment.NavigationProperty.ContainsTarget)) { continue; } @@ -1173,7 +1173,7 @@ private void AppendBoundOperationOnDerivedNavigationPropertyPath( private void AppendBoundOperationOnOperationPath(IEdmOperation edmOperation, bool isCollection, IEdmEntityType bindingEntityType) { - bool isEscapedFunction = _model.IsUrlEscapeFunction(edmOperation); + bool isEscapedFunction = _model?.IsUrlEscapeFunction(edmOperation) ?? false; // only composable functions var paths = _allOperationPaths.Where(x => x.LastSegment is ODataOperationSegment operationSegment @@ -1187,7 +1187,7 @@ private void AppendBoundOperationOnOperationPath(IEdmOperation edmOperation, boo || operationSegment.Operation is not IEdmFunction edmFunction || !edmFunction.IsComposable || edmFunction.ReturnType == null || !edmFunction.ReturnType.Definition.Equals(bindingEntityType) || isCollection - || !EdmModelHelper.IsOperationAllowed(_model, edmOperation, operationSegment.Operation, true)) + || _model is not null && !EdmModelHelper.IsOperationAllowed(_model, edmOperation, operationSegment.Operation, true)) { continue; } @@ -1199,7 +1199,10 @@ private void AppendBoundOperationOnOperationPath(IEdmOperation edmOperation, boo } ODataPath newOperationPath = path.Clone(); - newOperationPath.Push(new ODataOperationSegment(edmOperation, isEscapedFunction, _model)); + if (_model is not null) + { + newOperationPath.Push(new ODataOperationSegment(edmOperation, isEscapedFunction, _model)); + } AppendPath(newOperationPath); } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataSegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataSegment.cs index 7a262d10b..515ea7385 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataSegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataSegment.cs @@ -105,7 +105,7 @@ public abstract class ODataSegment /// The path item name. public string GetPathItemName(OpenApiConvertSettings settings) { - return GetPathItemName(settings, new HashSet()); + return GetPathItemName(settings, []); } /// /// Provides a suffix for the operation id based on the operation path. @@ -113,7 +113,7 @@ public string GetPathItemName(OpenApiConvertSettings settings) /// Path to use to deduplicate. /// The settings. ///The suffix. - public string GetPathHash(OpenApiConvertSettings settings, ODataPath path = default) + public string GetPathHash(OpenApiConvertSettings settings, ODataPath? path = default) { var suffix = string.Join("/", path?.Segments.Select(x => x.Identifier).Distinct() ?? Enumerable.Empty()); return (GetPathItemName(settings) + suffix).GetHashSHA256().Substring(0, 4); diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiParameterGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiParameterGenerator.cs index dad145a3d..cfc0680c6 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiParameterGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiParameterGenerator.cs @@ -71,7 +71,7 @@ public static IList CreateParameters(this ODataContext contex /// The created list of . public static IList CreateParameters(this ODataContext context, IEdmFunction function, OpenApiDocument document, - IDictionary parameterNameMapping = null) + IDictionary? parameterNameMapping = null) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(function, nameof(function)); @@ -366,7 +366,7 @@ public static void AppendParameter(this IList parameters, IOp /// The Edm annotation target. /// The Open API document. /// The created or null. - public static IOpenApiParameter CreateTop(this ODataContext context, IEdmVocabularyAnnotatable target, OpenApiDocument document) + public static IOpenApiParameter? CreateTop(this ODataContext context, IEdmVocabularyAnnotatable target, OpenApiDocument document) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(target, nameof(target)); @@ -388,7 +388,7 @@ public static IOpenApiParameter CreateTop(this ODataContext context, IEdmVocabul /// The string representation of the Edm target path. /// The Open API document to use to build references. /// - public static IOpenApiParameter CreateTop(this ODataContext context, string targetPath, OpenApiDocument document) + public static IOpenApiParameter? CreateTop(this ODataContext context, string targetPath, OpenApiDocument document) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(targetPath, nameof(targetPath)); @@ -408,7 +408,7 @@ public static IOpenApiParameter CreateTop(this ODataContext context, string targ /// The Edm annotation target. /// The Open API document to use to build references. /// The created or null. - public static IOpenApiParameter CreateSkip(this ODataContext context, IEdmVocabularyAnnotatable target, OpenApiDocument document) + public static IOpenApiParameter? CreateSkip(this ODataContext context, IEdmVocabularyAnnotatable target, OpenApiDocument document) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(target, nameof(target)); @@ -430,7 +430,7 @@ public static IOpenApiParameter CreateSkip(this ODataContext context, IEdmVocabu /// The string representation of the Edm target path. /// The Open API document to use to build references. /// - public static IOpenApiParameter CreateSkip(this ODataContext context, string targetPath, OpenApiDocument document) + public static IOpenApiParameter? CreateSkip(this ODataContext context, string targetPath, OpenApiDocument document) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(targetPath, nameof(targetPath)); @@ -450,7 +450,7 @@ public static IOpenApiParameter CreateSkip(this ODataContext context, string tar /// The Edm annotation target. /// The Open API document to use to build references. /// The created or null. - public static IOpenApiParameter CreateSearch(this ODataContext context, IEdmVocabularyAnnotatable target, OpenApiDocument document) + public static IOpenApiParameter? CreateSearch(this ODataContext context, IEdmVocabularyAnnotatable target, OpenApiDocument document) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(target, nameof(target)); @@ -471,7 +471,7 @@ public static IOpenApiParameter CreateSearch(this ODataContext context, IEdmVoca /// The string representation of the Edm target path. /// The Open API document to use to build references. /// - public static IOpenApiParameter CreateSearch(this ODataContext context, string targetPath, OpenApiDocument document) + public static IOpenApiParameter? CreateSearch(this ODataContext context, string targetPath, OpenApiDocument document) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(targetPath, nameof(targetPath)); @@ -491,7 +491,7 @@ public static IOpenApiParameter CreateSearch(this ODataContext context, string t /// The Edm annotation target. /// The Open API document to use to build references. /// The created or null. - public static IOpenApiParameter CreateCount(this ODataContext context, IEdmVocabularyAnnotatable target, OpenApiDocument document) + public static IOpenApiParameter? CreateCount(this ODataContext context, IEdmVocabularyAnnotatable target, OpenApiDocument document) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(target, nameof(target)); @@ -513,7 +513,7 @@ public static IOpenApiParameter CreateCount(this ODataContext context, IEdmVocab /// The string representation of the Edm target path. /// The Open API document to use to build references. /// - public static IOpenApiParameter CreateCount(this ODataContext context, string targetPath, OpenApiDocument document) + public static IOpenApiParameter? CreateCount(this ODataContext context, string targetPath, OpenApiDocument document) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(targetPath, nameof(targetPath)); @@ -533,7 +533,7 @@ public static IOpenApiParameter CreateCount(this ODataContext context, string ta /// The Edm annotation target. /// The Open API document to use to build references. /// The created or null. - public static IOpenApiParameter CreateFilter(this ODataContext context, IEdmVocabularyAnnotatable target, OpenApiDocument document) + public static IOpenApiParameter? CreateFilter(this ODataContext context, IEdmVocabularyAnnotatable target, OpenApiDocument document) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(target, nameof(target)); @@ -555,7 +555,7 @@ public static IOpenApiParameter CreateFilter(this ODataContext context, IEdmVoca /// The string representation of the Edm target path. /// The Open API document to use to build references. /// - public static IOpenApiParameter CreateFilter(this ODataContext context, string targetPath, OpenApiDocument document) + public static IOpenApiParameter? CreateFilter(this ODataContext context, string targetPath, OpenApiDocument document) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(targetPath, nameof(targetPath)); @@ -567,7 +567,7 @@ public static IOpenApiParameter CreateFilter(this ODataContext context, string t return context.CreateFilter(target, document); } - public static OpenApiParameter CreateOrderBy(this ODataContext context, string targetPath, IEdmEntityType entityType) + public static OpenApiParameter? CreateOrderBy(this ODataContext context, string targetPath, IEdmEntityType entityType) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(targetPath, nameof(targetPath)); @@ -579,7 +579,7 @@ public static OpenApiParameter CreateOrderBy(this ODataContext context, string t return context.CreateOrderBy(target, entityType); } - public static OpenApiParameter CreateOrderBy(this ODataContext context, IEdmEntitySet entitySet) + public static OpenApiParameter? CreateOrderBy(this ODataContext context, IEdmEntitySet entitySet) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(entitySet, nameof(entitySet)); @@ -587,7 +587,7 @@ public static OpenApiParameter CreateOrderBy(this ODataContext context, IEdmEnti return context.CreateOrderBy(entitySet, entitySet.EntityType); } - public static OpenApiParameter CreateOrderBy(this ODataContext context, IEdmSingleton singleton) + public static OpenApiParameter? CreateOrderBy(this ODataContext context, IEdmSingleton singleton) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(singleton, nameof(singleton)); @@ -595,7 +595,7 @@ public static OpenApiParameter CreateOrderBy(this ODataContext context, IEdmSing return context.CreateOrderBy(singleton, singleton.EntityType); } - public static OpenApiParameter CreateOrderBy(this ODataContext context, IEdmNavigationProperty navigationProperty) + public static OpenApiParameter? CreateOrderBy(this ODataContext context, IEdmNavigationProperty navigationProperty) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(navigationProperty, nameof(navigationProperty)); @@ -610,12 +610,12 @@ public static OpenApiParameter CreateOrderBy(this ODataContext context, IEdmNavi /// The Edm annotation target. /// The Edm Entity type. /// The created or null. - public static OpenApiParameter CreateOrderBy(this ODataContext context, IEdmVocabularyAnnotatable target, IEdmEntityType entityType) + public static OpenApiParameter? CreateOrderBy(this ODataContext context, IEdmVocabularyAnnotatable target, IEdmEntityType entityType) {// patchwork to avoid breaking changes return context.CreateOrderBy(target, entityType as IEdmStructuredType); } - public static OpenApiParameter CreateOrderBy(this ODataContext context, string targetPath, IEdmStructuredType structuredType) + public static OpenApiParameter? CreateOrderBy(this ODataContext context, string targetPath, IEdmStructuredType structuredType) { IEdmTargetPath target = context.Model.GetTargetPath(targetPath); if (target == null) @@ -624,7 +624,7 @@ public static OpenApiParameter CreateOrderBy(this ODataContext context, string t return context.CreateOrderBy(target, structuredType); } - public static OpenApiParameter CreateOrderBy(this ODataContext context, IEdmVocabularyAnnotatable target, IEdmStructuredType structuredType) + public static OpenApiParameter? CreateOrderBy(this ODataContext context, IEdmVocabularyAnnotatable target, IEdmStructuredType structuredType) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(target, nameof(target)); @@ -684,7 +684,7 @@ public static OpenApiParameter CreateOrderBy(this ODataContext context, IEdmVoca }; } - public static OpenApiParameter CreateSelect(this ODataContext context, string targetPath, IEdmEntityType entityType) + public static OpenApiParameter? CreateSelect(this ODataContext context, string targetPath, IEdmEntityType entityType) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(targetPath, nameof(targetPath)); @@ -696,7 +696,7 @@ public static OpenApiParameter CreateSelect(this ODataContext context, string ta return context.CreateSelect(target, entityType); } - public static OpenApiParameter CreateSelect(this ODataContext context, IEdmEntitySet entitySet) + public static OpenApiParameter? CreateSelect(this ODataContext context, IEdmEntitySet entitySet) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(entitySet, nameof(entitySet)); @@ -704,7 +704,7 @@ public static OpenApiParameter CreateSelect(this ODataContext context, IEdmEntit return context.CreateSelect(entitySet, entitySet.EntityType); } - public static OpenApiParameter CreateSelect(this ODataContext context, IEdmSingleton singleton) + public static OpenApiParameter? CreateSelect(this ODataContext context, IEdmSingleton singleton) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(singleton, nameof(singleton)); @@ -712,7 +712,7 @@ public static OpenApiParameter CreateSelect(this ODataContext context, IEdmSingl return context.CreateSelect(singleton, singleton.EntityType); } - public static OpenApiParameter CreateSelect(this ODataContext context, IEdmNavigationProperty navigationProperty) + public static OpenApiParameter? CreateSelect(this ODataContext context, IEdmNavigationProperty navigationProperty) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(navigationProperty, nameof(navigationProperty)); @@ -727,12 +727,12 @@ public static OpenApiParameter CreateSelect(this ODataContext context, IEdmNavig /// The Edm target. /// The Edm entity type. /// The created or null. - public static OpenApiParameter CreateSelect(this ODataContext context, IEdmVocabularyAnnotatable target, IEdmEntityType entityType) + public static OpenApiParameter? CreateSelect(this ODataContext context, IEdmVocabularyAnnotatable target, IEdmEntityType entityType) { // patchwork to avoid breaking changes return context.CreateSelect(target, entityType as IEdmStructuredType); } - public static OpenApiParameter CreateSelect(this ODataContext context, string targetPath, IEdmStructuredType structuredType) + public static OpenApiParameter? CreateSelect(this ODataContext context, string targetPath, IEdmStructuredType structuredType) { IEdmTargetPath target = context.Model.GetTargetPath(targetPath); if (target == null) @@ -741,7 +741,7 @@ public static OpenApiParameter CreateSelect(this ODataContext context, string ta return context.CreateSelect(target, structuredType); } - public static OpenApiParameter CreateSelect(this ODataContext context, IEdmVocabularyAnnotatable target, IEdmStructuredType structuredType) + public static OpenApiParameter? CreateSelect(this ODataContext context, IEdmVocabularyAnnotatable target, IEdmStructuredType structuredType) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(target, nameof(target)); @@ -790,7 +790,7 @@ public static OpenApiParameter CreateSelect(this ODataContext context, IEdmVocab }; } - public static OpenApiParameter CreateExpand(this ODataContext context, string targetPath, IEdmEntityType entityType) + public static OpenApiParameter? CreateExpand(this ODataContext context, string targetPath, IEdmEntityType entityType) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(targetPath, nameof(targetPath)); @@ -802,7 +802,7 @@ public static OpenApiParameter CreateExpand(this ODataContext context, string ta return context.CreateExpand(target, entityType); } - public static OpenApiParameter CreateExpand(this ODataContext context, IEdmEntitySet entitySet) + public static OpenApiParameter? CreateExpand(this ODataContext context, IEdmEntitySet entitySet) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(entitySet, nameof(entitySet)); @@ -810,7 +810,7 @@ public static OpenApiParameter CreateExpand(this ODataContext context, IEdmEntit return context.CreateExpand(entitySet, entitySet.EntityType); } - public static OpenApiParameter CreateExpand(this ODataContext context, IEdmSingleton singleton) + public static OpenApiParameter? CreateExpand(this ODataContext context, IEdmSingleton singleton) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(singleton, nameof(singleton)); @@ -818,7 +818,7 @@ public static OpenApiParameter CreateExpand(this ODataContext context, IEdmSingl return context.CreateExpand(singleton, singleton.EntityType); } - public static OpenApiParameter CreateExpand(this ODataContext context, IEdmNavigationProperty navigationProperty) + public static OpenApiParameter? CreateExpand(this ODataContext context, IEdmNavigationProperty navigationProperty) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(navigationProperty, nameof(navigationProperty)); @@ -833,12 +833,12 @@ public static OpenApiParameter CreateExpand(this ODataContext context, IEdmNavig /// The edm entity path. /// The edm entity path. /// The created or null. - public static OpenApiParameter CreateExpand(this ODataContext context, IEdmVocabularyAnnotatable target, IEdmEntityType entityType) + public static OpenApiParameter? CreateExpand(this ODataContext context, IEdmVocabularyAnnotatable target, IEdmEntityType entityType) { // patchwork to avoid breaking changes return context.CreateExpand(target, entityType as IEdmStructuredType); } - public static OpenApiParameter CreateExpand(this ODataContext context, string targetPath, IEdmStructuredType structuredType) + public static OpenApiParameter? CreateExpand(this ODataContext context, string targetPath, IEdmStructuredType structuredType) { IEdmTargetPath target = context.Model.GetTargetPath(targetPath); if (target == null) @@ -847,7 +847,7 @@ public static OpenApiParameter CreateExpand(this ODataContext context, string ta return context.CreateExpand(target, structuredType); } - public static OpenApiParameter CreateExpand(this ODataContext context, IEdmVocabularyAnnotatable target, IEdmStructuredType structuredType) + public static OpenApiParameter? CreateExpand(this ODataContext context, IEdmVocabularyAnnotatable target, IEdmStructuredType structuredType) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(target, nameof(target)); diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs index 91648b010..7bad0fef5 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs @@ -700,7 +700,7 @@ EdmTypeKind.Primitive when edmTypeReference.IsInt16() || }; } - private static JsonNode CreateDefault(this IEdmStructuralProperty property) + private static JsonNode? CreateDefault(this IEdmStructuralProperty property) { if (property == null || property.DefaultValueString == 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 c394c3170..f07b7c5e8 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj +++ b/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj @@ -18,6 +18,7 @@ ..\..\bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml true + enable README.md diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionOperationHandler.cs index 802ccbbf4..e252492d7 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionOperationHandler.cs @@ -3,9 +3,11 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Collections.Generic; using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; @@ -32,7 +34,7 @@ public EdmFunctionOperationHandler(OpenApiDocument document):base(document) /// /// Gets the Edm Function. /// - public IEdmFunction Function => EdmOperation as IEdmFunction; + public IEdmFunction? Function => EdmOperation as IEdmFunction; /// protected override void SetBasicInfo(OpenApiOperation operation) @@ -54,6 +56,7 @@ protected override void SetBasicInfo(OpenApiOperation operation) /// protected override void SetExtensions(OpenApiOperation operation) { + operation.Extensions ??= new Dictionary(); operation.Extensions.Add(Constants.xMsDosOperationType, new OpenApiAny("function")); base.SetExtensions(operation); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationOperationHandler.cs index cfc186195..68e7d4149 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationOperationHandler.cs @@ -8,6 +8,7 @@ using System.Text.Json.Nodes; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.OData.Common; @@ -316,10 +317,14 @@ protected override void SetCustomLinkRelType() /// protected override void SetExternalDocs(OpenApiOperation operation) { - if (Context.Settings.ShowExternalDocs) + if (Context is { Settings.ShowExternalDocs: true }) { - var externalDocs = Context.Model.GetLinkRecord(TargetPath, CustomLinkRel) ?? - Context.Model.GetLinkRecord(EdmOperation, CustomLinkRel); + var externalDocs = (string.IsNullOrEmpty(TargetPath), string.IsNullOrEmpty(CustomLinkRel)) switch + { + (_, true) => null, + (false, false) => Context.Model.GetLinkRecord(TargetPath!, CustomLinkRel!), + (true, false) => Context.Model.GetLinkRecord(EdmOperation, CustomLinkRel!), + }; if (externalDocs != null) { @@ -335,14 +340,15 @@ protected override void SetExternalDocs(OpenApiOperation operation) // protected override void SetExtensions(OpenApiOperation operation) { - if (Context.Settings.EnablePagination && EdmOperation.ReturnType?.TypeKind() == EdmTypeKind.Collection) + if (Context is { Settings.EnablePagination: true } && EdmOperation.ReturnType?.TypeKind() == EdmTypeKind.Collection) { JsonObject extension = new JsonObject { { "nextLinkName", "@odata.nextLink"}, { "operationName", Context.Settings.PageableOperationName} }; - + + operation.Extensions ??= new Dictionary(); operation.Extensions.Add(Constants.xMsPageable, new OpenApiAny(extension)); } base.SetExtensions(operation); diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityOperationalHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityOperationalHandler.cs index 488046d6c..4a4fc6fa4 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityOperationalHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityOperationalHandler.cs @@ -203,35 +203,44 @@ protected IDictionary GetContentDescription() /// Gets the stream property and entity type declaring the stream property. /// /// The stream property and entity type declaring the stream property. - protected (IEdmEntityType entityType, IEdmProperty property) GetStreamElements() + protected (IEdmEntityType? entityType, IEdmProperty? property) GetStreamElements() { // Only ODataStreamPropertySegment is annotatable - if (!LastSegmentIsStreamPropertySegment && !LastSegmentIsStreamContentSegment) return (null, null); + if (!LastSegmentIsStreamPropertySegment && !LastSegmentIsStreamContentSegment || Path is null) return (null, null); // Retrieve the entity type of the segment before the stream property segment var entityType = LastSegmentIsStreamContentSegment - ? Path.Segments.ElementAtOrDefault(Path.Segments.Count - 3).EntityType - : Path.Segments.ElementAtOrDefault(Path.Segments.Count - 2).EntityType; + ? Path.Segments.ElementAtOrDefault(Path.Segments.Count - 3)?.EntityType + : Path.Segments.ElementAtOrDefault(Path.Segments.Count - 2)?.EntityType; + + if (entityType is null) return (null, null); // The stream property can either be a structural type or a navigation property type - ODataSegment lastSegmentProp = LastSegmentIsStreamContentSegment + var lastSegmentProp = LastSegmentIsStreamContentSegment ? Path.Segments.Reverse().Skip(1).FirstOrDefault() - : Path.Segments.LastOrDefault(c => c is ODataStreamPropertySegment); - IEdmProperty property = GetStructuralProperty(entityType, lastSegmentProp.Identifier); - if (property == null) + : Path.Segments.OfType().LastOrDefault(); + + if (lastSegmentProp?.Identifier is not string lastIdentifier) return (null, null); + + if (GetStructuralProperty(entityType, lastIdentifier) is IEdmProperty property) { - property = GetNavigationProperty(entityType, lastSegmentProp.Identifier); + return (entityType, property); } - return (entityType, property); + if (GetNavigationProperty(entityType, lastIdentifier) is IEdmProperty navigationProperty) + { + return (entityType, navigationProperty); + } + + return (null, null); } - private IEdmStructuralProperty GetStructuralProperty(IEdmEntityType entityType, string identifier) + private static IEdmStructuralProperty? GetStructuralProperty(IEdmEntityType entityType, string identifier) { return entityType.StructuralProperties().FirstOrDefault(x => x.Name.Equals(identifier)); } - private IEdmNavigationProperty GetNavigationProperty(IEdmEntityType entityType, string identifier) + private static IEdmNavigationProperty? GetNavigationProperty(IEdmEntityType entityType, string identifier) { return entityType.DeclaredNavigationProperties().FirstOrDefault(x => x.Name.Equals(identifier)); } @@ -239,10 +248,14 @@ private IEdmNavigationProperty GetNavigationProperty(IEdmEntityType entityType, /// protected override void SetExternalDocs(OpenApiOperation operation) { - if (Context.Settings.ShowExternalDocs && Property != null) + if (Context is { Settings.ShowExternalDocs: true } && Property != null) { - var externalDocs = Context.Model.GetLinkRecord(TargetPath, CustomLinkRel) ?? - Context.Model.GetLinkRecord(Property, CustomLinkRel); + var externalDocs = (string.IsNullOrEmpty(TargetPath), string.IsNullOrEmpty(CustomLinkRel)) switch + { + (_, true) => null, + (false, false) => Context.Model.GetLinkRecord(TargetPath!, CustomLinkRel!), + (_, false) => Context.Model.GetLinkRecord(Property, CustomLinkRel!), + }; if (externalDocs != null) { diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs index 0d01c013d..1c1f393af 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs @@ -9,6 +9,7 @@ using System.Text.Json.Nodes; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; @@ -37,7 +38,7 @@ public NavigationPropertyGetOperationHandler(OpenApiDocument document) : base(do /// public override HttpMethod OperationType => HttpMethod.Get; - private ReadRestrictionsType _readRestriction; + private ReadRestrictionsType? _readRestriction; /// protected override void Initialize(ODataContext context, ODataPath path) @@ -56,7 +57,7 @@ protected override void SetBasicInfo(OpenApiOperation operation) ?? Context.Model.GetDescriptionAnnotation(NavigationProperty); // OperationId - if (Context.Settings.EnableOperationId) + if (Context is { Settings.EnableOperationId: true }) { string prefix = "Get"; if (!LastSegmentIsKeySegment && NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) @@ -72,18 +73,16 @@ protected override void SetBasicInfo(OpenApiOperation operation) protected override void SetExtensions(OpenApiOperation operation) { - if (Context.Settings.EnablePagination) + if (Context is { Settings.EnablePagination: true } && !LastSegmentIsKeySegment && NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) { - if (!LastSegmentIsKeySegment && NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) + var extension = new JsonObject { - JsonObject extension = new JsonObject - { - { "nextLinkName", "@odata.nextLink"}, - { "operationName", Context.Settings.PageableOperationName} - }; + { "nextLinkName", "@odata.nextLink"}, + { "operationName", Context.Settings.PageableOperationName} + }; - operation.Extensions.Add(Constants.xMsPageable, new OpenApiAny(extension)); - } + operation.Extensions ??= new Dictionary(); + operation.Extensions.Add(Constants.xMsPageable, new OpenApiAny(extension)); } base.SetExtensions(operation); @@ -92,8 +91,8 @@ protected override void SetExtensions(OpenApiOperation operation) /// protected override void SetResponses(OpenApiOperation operation) { - IDictionary links = null; - if (Context.Settings.ShowLinks) + IDictionary? links = null; + if (Context is { Settings.ShowLinks: true }) { string operationId = GetOperationId(); @@ -114,7 +113,7 @@ protected override void SetResponses(OpenApiOperation operation) } else { - IOpenApiSchema schema = null; + IOpenApiSchema? schema = null; var entityType = NavigationProperty.ToEntityType(); if (Context.Settings.EnableDerivedTypesReferencesForResponses) @@ -157,10 +156,15 @@ protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); - OpenApiParameter selectParameter = Context.CreateSelect(TargetPath, NavigationProperty.ToEntityType()) + if (Context is null) + { + return; + } + + var selectParameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateSelect(TargetPath, NavigationProperty.ToEntityType())) ?? Context.CreateSelect(NavigationProperty); - OpenApiParameter expandParameter = Context.CreateExpand(TargetPath, NavigationProperty.ToEntityType()) + var expandParameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateExpand(TargetPath, NavigationProperty.ToEntityType())) ?? Context.CreateExpand(NavigationProperty); if (!LastSegmentIsKeySegment && NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) @@ -240,7 +244,8 @@ protected override void SetSecurity(OpenApiOperation operation) readBase = _readRestriction.ReadByKeyRestrictions; } - operation.Security = Context.CreateSecurityRequirements(readBase.Permissions, _document).ToList(); + if (readBase.Permissions is not null) + operation.Security = Context?.CreateSecurityRequirements(readBase.Permissions, _document).ToList(); } protected override void AppendCustomParameters(OpenApiOperation operation) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyOperationHandler.cs index 445dd4074..559ed86db 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyOperationHandler.cs @@ -34,17 +34,17 @@ protected NavigationPropertyOperationHandler(OpenApiDocument document):base(docu /// /// Gets the navigation property. /// - protected IEdmNavigationProperty NavigationProperty { get; private set; } + protected IEdmNavigationProperty? NavigationProperty { get; private set; } /// /// Gets the navigation source. /// - protected IEdmNavigationSource NavigationSource { get; private set; } + protected IEdmNavigationSource? NavigationSource { get; private set; } /// /// Gets the navigation restriction. /// - protected NavigationPropertyRestriction Restriction { get; private set; } + protected NavigationPropertyRestriction? Restriction { get; private set; } /// /// Gets a bool value indicating whether the last segment is a key segment. @@ -66,41 +66,37 @@ protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; - NavigationSource = navigationSourceSegment.NavigationSource; + ODataNavigationSourceSegment? navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; + NavigationSource = navigationSourceSegment?.NavigationSource; LastSegmentIsKeySegment = path.LastSegment is ODataKeySegment; LastSegmentIsRefSegment = path.LastSegment is ODataRefSegment; SecondLastSegmentIsKeySegment = Path.Segments.Reverse().Skip(1).Take(1).Single().Kind == ODataSegmentKind.Key; NavigationProperty = path.OfType().Last().NavigationProperty; - IEdmEntitySet entitySet = NavigationSource as IEdmEntitySet; - IEdmSingleton singleton = NavigationSource as IEdmSingleton; - - NavigationRestrictionsType navigation; - if (entitySet != null) - { - navigation = Context.Model.GetRecord(entitySet, CapabilitiesConstants.NavigationRestrictions); - } - else - { - navigation = Context.Model.GetRecord(singleton, CapabilitiesConstants.NavigationRestrictions); - } + var navigation = NavigationSource switch { + IEdmEntitySet entitySet => Context?.Model.GetRecord(entitySet, CapabilitiesConstants.NavigationRestrictions), + IEdmSingleton singleton => Context?.Model.GetRecord(singleton, CapabilitiesConstants.NavigationRestrictions), + _ => null + }; Restriction = navigation?.RestrictedProperties?.FirstOrDefault(r => r.NavigationProperty != null && r.NavigationProperty == Path.NavigationPropertyPath()) - ?? Context.Model.GetRecord(NavigationProperty, CapabilitiesConstants.NavigationRestrictions)?.RestrictedProperties?.FirstOrDefault(); + ?? Context?.Model.GetRecord(NavigationProperty, CapabilitiesConstants.NavigationRestrictions)?.RestrictedProperties?.FirstOrDefault(); } /// protected override void SetTags(OpenApiOperation operation) { - string name = EdmModelHelper.GenerateNavigationPropertyPathTagName(Path, Context); - Context.AddExtensionToTag(name, Constants.xMsTocType, new OpenApiAny("page"), () => new OpenApiTag() - { - Name = name - }); - operation.Tags ??= new HashSet(); - operation.Tags.Add(new OpenApiTagReference(name, _document)); + if (Context is not null && Path is not null) + { + string name = EdmModelHelper.GenerateNavigationPropertyPathTagName(Path, Context); + Context.AddExtensionToTag(name, Constants.xMsTocType, new OpenApiAny("page"), () => new OpenApiTag() + { + Name = name + }); + operation.Tags ??= new HashSet(); + operation.Tags.Add(new OpenApiTagReference(name, _document)); + } base.SetTags(operation); } @@ -143,12 +139,13 @@ protected override void SetExternalDocs(OpenApiOperation operation) /// /// The fully qualified restriction annotation term. /// The restriction annotation, or null if not available. - protected IRecord GetRestrictionAnnotation(string annotationTerm) + protected IRecord? GetRestrictionAnnotation(string annotationTerm) { + if (Context is null) return null; switch (annotationTerm) { case CapabilitiesConstants.ReadRestrictions: - var readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + var readRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); readRestrictions?.MergePropertiesIfNull(Restriction?.ReadRestrictions); readRestrictions ??= Restriction?.ReadRestrictions; @@ -158,7 +155,7 @@ protected IRecord GetRestrictionAnnotation(string annotationTerm) return readRestrictions; case CapabilitiesConstants.UpdateRestrictions: - var updateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); + var updateRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); updateRestrictions?.MergePropertiesIfNull(Restriction?.UpdateRestrictions); updateRestrictions ??= Restriction?.UpdateRestrictions; @@ -168,7 +165,7 @@ protected IRecord GetRestrictionAnnotation(string annotationTerm) return updateRestrictions; case CapabilitiesConstants.InsertRestrictions: - var insertRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); + var insertRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); insertRestrictions?.MergePropertiesIfNull(Restriction?.InsertRestrictions); insertRestrictions ??= Restriction?.InsertRestrictions; @@ -178,7 +175,7 @@ protected IRecord GetRestrictionAnnotation(string annotationTerm) return insertRestrictions; case CapabilitiesConstants.DeleteRestrictions: - var deleteRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); + var deleteRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); deleteRestrictions?.MergePropertiesIfNull(Restriction?.DeleteRestrictions); deleteRestrictions ??= Restriction?.DeleteRestrictions; @@ -193,7 +190,7 @@ protected IRecord GetRestrictionAnnotation(string annotationTerm) } } - protected IDictionary GetContent(IOpenApiSchema schema = null, IEnumerable mediaTypes = null) + protected Dictionary GetContent(IOpenApiSchema? schema = null, IEnumerable? mediaTypes = null) { schema ??= GetOpenApiSchema(); var content = new Dictionary(); @@ -215,7 +212,7 @@ protected IDictionary GetContent(IOpenApiSchema schema { Schema = schema }); - }; + } return content; } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/ODataTypeCastGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/ODataTypeCastGetOperationHandler.cs index 4b6555087..c6e804e1b 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/ODataTypeCastGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/ODataTypeCastGetOperationHandler.cs @@ -11,6 +11,7 @@ using Microsoft.OData.Edm; using Microsoft.OData.Edm.Vocabularies; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; @@ -42,7 +43,7 @@ public ODataTypeCastGetOperationHandler(OpenApiDocument document):base(document) /// Gets/sets the segment before cast. /// this segment could be "entity set", "Collection property", etc. /// - internal ODataSegment SecondLastSegment { get; set; } + internal ODataSegment? SecondLastSegment { get; set; } private bool isKeySegment; @@ -58,18 +59,18 @@ private bool IsSingleElement entitySet == null); } - private NavigationPropertyRestriction restriction; - private IEdmSingleton singleton; - private IEdmEntitySet entitySet; - private IEdmNavigationProperty navigationProperty; - private IEdmStructuredType parentStructuredType; - private IEdmSchemaElement ParentSchemaElement => parentStructuredType as IEdmSchemaElement; - private IEdmStructuredType targetStructuredType; - private IEdmSchemaElement TargetSchemaElement => targetStructuredType as IEdmSchemaElement; + private NavigationPropertyRestriction? restriction; + private IEdmSingleton? singleton; + private IEdmEntitySet? entitySet; + private IEdmNavigationProperty? navigationProperty; + private IEdmStructuredType? parentStructuredType; + private IEdmSchemaElement? ParentSchemaElement => parentStructuredType as IEdmSchemaElement; + private IEdmStructuredType? targetStructuredType; + private IEdmSchemaElement? TargetSchemaElement => targetStructuredType as IEdmSchemaElement; private const int SecondLastSegmentIndex = 2; private bool isIndexedCollValuedNavProp = false; - private IEdmNavigationSource navigationSource; - private IEdmVocabularyAnnotatable annotatable; + private IEdmNavigationSource? navigationSource; + private IEdmVocabularyAnnotatable? annotatable; /// protected override void Initialize(ODataContext context, ODataPath path) @@ -90,11 +91,13 @@ protected override void Initialize(ODataContext context, ODataPath path) // get the last second segment int count = path.Segments.Count; if(count >= SecondLastSegmentIndex) - SecondLastSegment = path.Segments.ElementAt(count - SecondLastSegmentIndex); + SecondLastSegment = path.Segments[count - SecondLastSegmentIndex]; - parentStructuredType = SecondLastSegment is ODataComplexPropertySegment complexSegment ? complexSegment.ComplexType : SecondLastSegment.EntityType; - ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; - navigationSource = navigationSourceSegment.NavigationSource; + parentStructuredType = SecondLastSegment is ODataComplexPropertySegment complexSegment ? complexSegment.ComplexType : SecondLastSegment?.EntityType; + if (path.FirstSegment is ODataNavigationSourceSegment navigationSourceSegment) + { + navigationSource = navigationSourceSegment.NavigationSource; + } if (SecondLastSegment is ODataNavigationPropertySegment navigationPropertySegment) { @@ -107,7 +110,7 @@ protected override void Initialize(ODataContext context, ODataPath path) else if (SecondLastSegment is ODataKeySegment) { isKeySegment = true; - var thirdLastSegment = path.Segments.ElementAt(count - SecondLastSegmentIndex - 1); + var thirdLastSegment = path.Segments[count - SecondLastSegmentIndex - 1]; if (thirdLastSegment is ODataNavigationPropertySegment navigationPropertySegment1) { isIndexedCollValuedNavProp = true; @@ -137,20 +140,21 @@ private void SetNavigationPropertyAndRestrictionFromNavigationSegment(ODataNavig { navigationProperty = navigationPropertySegment.NavigationProperty; annotatable = 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) + if(path.FirstSegment is ODataNavigationSourceSegment navigationSourceSegment && + Context is not null) { - NavigationRestrictionsType navigation = navigationSourceSegment.NavigationSource switch { + NavigationRestrictionsType? navigation = navigationSourceSegment.NavigationSource switch { IEdmEntitySet eSet => Context.Model.GetRecord(eSet, CapabilitiesConstants.NavigationRestrictions), IEdmSingleton single => Context.Model.GetRecord(single, CapabilitiesConstants.NavigationRestrictions), _ => null }; - if (navigation?.RestrictedProperties != null) + if (navigation?.RestrictedProperties != null && Path is not null) { + var navigationPropertyPath = string.Join("/", + Path.Segments.Where(s => !(s is ODataKeySegment || s is ODataNavigationSourceSegment + || s is ODataStreamContentSegment || s is ODataStreamPropertySegment)).Select(e => e.Identifier)); restriction = navigation.RestrictedProperties.FirstOrDefault(r => r.NavigationProperty != null && r.NavigationProperty == navigationPropertyPath); } } @@ -170,16 +174,16 @@ private void SetAnnotatableRestrictionFromNavigationSourceSegment(ODataNavigatio singleton = sTon; } - SetRestrictionFromAnnotatable(annotatable); + SetRestrictionFromAnnotatable(); } - private void SetRestrictionFromAnnotatable(IEdmVocabularyAnnotatable annotatable) + private void SetRestrictionFromAnnotatable() { - if (this.annotatable == null) + if (annotatable == null) return; - NavigationRestrictionsType navigation = Context.Model.GetRecord(annotatable, CapabilitiesConstants.NavigationRestrictions); + var navigation = Context?.Model.GetRecord(annotatable, CapabilitiesConstants.NavigationRestrictions); if (navigation?.RestrictedProperties != null) { restriction = navigation.RestrictedProperties.FirstOrDefault(r => r.NavigationProperty == null); @@ -189,7 +193,7 @@ private void SetRestrictionFromAnnotatable(IEdmVocabularyAnnotatable annotatable /// protected override void SetBasicInfo(OpenApiOperation operation) { - ReadRestrictionsType _readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + var _readRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); // Summary string placeHolder = IsSingleElement @@ -199,7 +203,9 @@ protected override void SetBasicInfo(OpenApiOperation operation) operation.Description = _readRestrictions?.LongDescription; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is { Settings.EnableOperationId: true } && + Path is not null && + TargetSchemaElement is not null) operation.OperationId = EdmModelHelper.GenerateODataTypeCastPathOperationIdPrefix(Path, Context) + $".As{Utils.UpperFirstChar(TargetSchemaElement.Name)}-{Path.GetPathHash(Context.Settings)}"; base.SetBasicInfo(operation); @@ -210,9 +216,9 @@ protected override void SetResponses(OpenApiOperation operation) { if (IsSingleElement) { - IOpenApiSchema schema = null; + IOpenApiSchema? schema = null; - if (Context.Settings.EnableDerivedTypesReferencesForResponses) + if (Context is { Settings.EnableDerivedTypesReferencesForResponses: true } && targetStructuredType is not null) { schema = EdmModelHelper.GetDerivedTypesReferenceSchema(targetStructuredType, Context.Model, _document); } @@ -229,7 +235,8 @@ protected override void SetResponses(OpenApiOperation operation) SetCollectionResponse(operation, TargetSchemaElement.FullName()); } - operation.AddErrorResponses(Context.Settings, _document, false); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, false); base.SetResponses(operation); } @@ -237,23 +244,26 @@ protected override void SetResponses(OpenApiOperation operation) /// protected override void SetTags(OpenApiOperation operation) { - string tagName = null; + if (Context is null) + return; + string? tagName = null; operation.Tags ??= new HashSet(); - if (SecondLastSegment is ODataNavigationPropertySegment || isIndexedCollValuedNavProp) + if ((SecondLastSegment is ODataNavigationPropertySegment || isIndexedCollValuedNavProp) && + Path is not null) { tagName = EdmModelHelper.GenerateNavigationPropertyPathTagName(Path, Context); } else if ((SecondLastSegment is ODataKeySegment && !isIndexedCollValuedNavProp) || (SecondLastSegment is ODataNavigationSourceSegment)) { - var singletonNavigationSource = navigationSource as IEdmSingleton; - - tagName = navigationSource is IEdmEntitySet entitySetNavigationSource - ? entitySetNavigationSource.Name + "." + entitySetNavigationSource.EntityType.Name - : singletonNavigationSource.Name + "." + singletonNavigationSource.EntityType.Name; + tagName = navigationSource switch { + IEdmEntitySet entitySetNavigationSource => entitySetNavigationSource.Name + "." + entitySetNavigationSource.EntityType.Name, + IEdmSingleton singletonNavigationSource => singletonNavigationSource.Name + "." + singletonNavigationSource.EntityType.Name, + _ => null + }; } - else if (SecondLastSegment is ODataComplexPropertySegment) + else if (SecondLastSegment is ODataComplexPropertySegment && Path is not null) { tagName = EdmModelHelper.GenerateComplexPropertyPathTagName(Path, Context); } @@ -277,14 +287,19 @@ protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); + if (Context is null) + return; + + operation.Parameters ??= []; + if(navigationProperty != null) { if (IsSingleElement) { - new OpenApiParameter[] { - Context.CreateSelect(TargetPath, navigationProperty.ToEntityType()) ?? Context.CreateSelect(navigationProperty), - Context.CreateExpand(TargetPath, navigationProperty.ToEntityType()) ?? Context.CreateExpand(navigationProperty), + new IOpenApiParameter?[] { + (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateSelect(TargetPath, navigationProperty.ToEntityType())) ?? Context.CreateSelect(navigationProperty), + (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateExpand(TargetPath, navigationProperty.ToEntityType())) ?? Context.CreateExpand(navigationProperty), } - .Where(x => x != null) + .OfType() .ToList() .ForEach(p => operation.Parameters.Add(p)); } @@ -292,12 +307,12 @@ protected override void SetParameters(OpenApiOperation operation) { GetParametersForAnnotableOfMany(navigationProperty) .Union( - new OpenApiParameter[] { - Context.CreateOrderBy(TargetPath, navigationProperty.ToEntityType()) ?? Context.CreateOrderBy(navigationProperty), - Context.CreateSelect(TargetPath, navigationProperty.ToEntityType()) ?? Context.CreateSelect(navigationProperty), - Context.CreateExpand(TargetPath, navigationProperty.ToEntityType()) ?? Context.CreateExpand(navigationProperty), - }) - .Where(x => x != null) + [ + (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateOrderBy(TargetPath, navigationProperty.ToEntityType())) ?? Context.CreateOrderBy(navigationProperty), + (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateSelect(TargetPath, navigationProperty.ToEntityType())) ?? Context.CreateSelect(navigationProperty), + (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateExpand(TargetPath, navigationProperty.ToEntityType())) ?? Context.CreateExpand(navigationProperty), + ]) + .OfType() .ToList() .ForEach(p => operation.Parameters.Add(p)); } @@ -306,11 +321,11 @@ protected override void SetParameters(OpenApiOperation operation) { if(IsSingleElement) { - new IOpenApiParameter[] { - Context.CreateSelect(TargetPath, entitySet.EntityType) ?? Context.CreateSelect(entitySet), - Context.CreateExpand(TargetPath, entitySet.EntityType) ?? Context.CreateExpand(entitySet), + new IOpenApiParameter?[] { + (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateSelect(TargetPath, entitySet.EntityType)) ?? Context.CreateSelect(entitySet), + (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateExpand(TargetPath, entitySet.EntityType)) ?? Context.CreateExpand(entitySet), } - .Where(x => x != null) + .OfType() .ToList() .ForEach(operation.Parameters.Add); } @@ -319,28 +334,30 @@ protected override void SetParameters(OpenApiOperation operation) GetParametersForAnnotableOfMany(entitySet) .Union( [ - Context.CreateOrderBy(TargetPath, entitySet.EntityType) ?? Context.CreateOrderBy(entitySet), - Context.CreateSelect(TargetPath, entitySet.EntityType) ?? Context.CreateSelect(entitySet), - Context.CreateExpand(TargetPath, entitySet.EntityType) ?? Context.CreateExpand(entitySet), + (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateOrderBy(TargetPath, entitySet.EntityType)) ?? Context.CreateOrderBy(entitySet), + (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateSelect(TargetPath, entitySet.EntityType)) ?? Context.CreateSelect(entitySet), + (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateExpand(TargetPath, entitySet.EntityType)) ?? Context.CreateExpand(entitySet), ]) - .Where(x => x != null) + .OfType() .ToList() .ForEach(p => operation.Parameters.Add(p)); } } else if(singleton != null) { - new OpenApiParameter[] { - Context.CreateSelect(TargetPath, singleton.EntityType) ?? Context.CreateSelect(singleton), - Context.CreateExpand(TargetPath, singleton.EntityType) ?? Context.CreateExpand(singleton), + new IOpenApiParameter?[] { + (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateSelect(TargetPath, singleton.EntityType)) ?? Context.CreateSelect(singleton), + (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateExpand(TargetPath, singleton.EntityType)) ?? Context.CreateExpand(singleton), } - .Where(x => x != null) + .OfType() .ToList() .ForEach(p => operation.Parameters.Add(p)); } } - private IEnumerable GetParametersForAnnotableOfMany(IEdmVocabularyAnnotatable annotable) + private IEnumerable GetParametersForAnnotableOfMany(IEdmVocabularyAnnotatable annotable) { + if (Context is null) + return []; // Need to verify that TopSupported or others should be applied to navigation source. // So, how about for the navigation property. return [ @@ -361,12 +378,12 @@ protected override void SetSecurity(OpenApiOperation operation) ReadRestrictionsBase readBase = restriction.ReadRestrictions; - operation.Security = Context.CreateSecurityRequirements(readBase.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(readBase.Permissions, _document).ToList(); } protected override void SetExtensions(OpenApiOperation operation) { - if (Context.Settings.EnablePagination && !IsSingleElement) + if (Context is { Settings.EnablePagination: true } && !IsSingleElement) { JsonObject extension = new() { @@ -374,6 +391,7 @@ protected override void SetExtensions(OpenApiOperation operation) { "operationName", Context.Settings.PageableOperationName} }; + operation.Extensions ??= new Dictionary(); operation.Extensions.Add(Constants.xMsPageable, new OpenApiAny(extension)); } @@ -385,10 +403,15 @@ protected override void AppendCustomParameters(OpenApiOperation operation) if (annotatable == null) return; - ReadRestrictionsType readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - var annotatableReadRestrictions = Context.Model.GetRecord(annotatable, CapabilitiesConstants.ReadRestrictions); - readRestrictions?.MergePropertiesIfNull(annotatableReadRestrictions); - readRestrictions ??= annotatableReadRestrictions; + if (Context is null) + return; + + var readRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + if (Context.Model.GetRecord(annotatable, CapabilitiesConstants.ReadRestrictions) is {} annotatableReadRestrictions) + { + readRestrictions?.MergePropertiesIfNull(annotatableReadRestrictions); + readRestrictions ??= annotatableReadRestrictions; + } if (readRestrictions == null) { @@ -408,7 +431,10 @@ protected override void AppendCustomParameters(OpenApiOperation operation) protected override void SetExternalDocs(OpenApiOperation operation) { - if (Context.Settings.ShowExternalDocs && Context.Model.GetLinkRecord(TargetPath, CustomLinkRel) is LinkType externalDocs) + if (Context is { Settings.ShowExternalDocs: true } && + !string.IsNullOrEmpty(CustomLinkRel) && + !string.IsNullOrEmpty(TargetPath) && + Context.Model.GetLinkRecord(TargetPath, CustomLinkRel) is LinkType externalDocs) { operation.ExternalDocs = new OpenApiExternalDocs() { diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandler.cs index 4f27692c6..ea345dbe0 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandler.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Net.Http; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.MicrosoftExtensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; @@ -37,17 +38,17 @@ protected OperationHandler(OpenApiDocument document) /// public abstract HttpMethod OperationType { get; } - protected IDictionary> ParameterMappings; + protected IDictionary>? ParameterMappings; /// /// The path parameters in the path /// - protected IList PathParameters; + protected IList? PathParameters; /// /// The string representation of the Edm target path for annotations. /// - protected string TargetPath; + protected string? TargetPath; /// public virtual OpenApiOperation CreateOperation(ODataContext context, ODataPath path) @@ -96,38 +97,43 @@ will be used in the Responses when creating Links. private void SetDeprecation(OpenApiOperation operation) { - if (operation != null && Context.Settings.EnableDeprecationInformation) + if (operation is null || + Context is null || + !Context.Settings.EnableDeprecationInformation || + Path is null) { - var deprecationInfo = Path.SelectMany(x => x.GetAnnotables()) - .SelectMany(x => Context.GetDeprecationInformations(x)) - .Where(x => x != null) - .OrderByDescending(x => x.Date) - .ThenByDescending(x => x.RemovalDate) - .FirstOrDefault(); - - if (deprecationInfo != null) - { - operation.Deprecated = true; - var deprecationDetails = deprecationInfo.GetOpenApiExtension(); - operation.Extensions.Add(OpenApiDeprecationExtension.Name, deprecationDetails); - } + return; + } + var deprecationInfo = Path.SelectMany(x => x.GetAnnotables()) + .SelectMany(x => Context.GetDeprecationInformations(x)) + .Where(x => x != null) + .OrderByDescending(x => x.Date) + .ThenByDescending(x => x.RemovalDate) + .FirstOrDefault(); + + if (deprecationInfo != null) + { + operation.Deprecated = true; + var deprecationDetails = deprecationInfo.GetOpenApiExtension(); + operation.Extensions ??= new Dictionary(); + operation.Extensions.Add(OpenApiDeprecationExtension.Name, deprecationDetails); } } /// /// Gets the OData context. /// - protected ODataContext Context { get; private set; } + protected ODataContext? Context { get; private set; } /// /// Gets the OData path. /// - protected ODataPath Path { get; private set; } + protected ODataPath? Path { get; private set; } /// /// Gets the custom link relation type for path based on operation type /// - protected string CustomLinkRel { get; set; } + protected string? CustomLinkRel { get; set; } /// /// Initialize the handler. @@ -175,12 +181,16 @@ protected virtual void SetRequestBody(OpenApiOperation operation) /// The . protected virtual void SetParameters(OpenApiOperation operation) { - PathParameters = Path.CreatePathParameters(Context, _document); - if (!Context.Settings.DeclarePathParametersOnPathItem) + if (Context is not null && Path is not null) { - foreach (var parameter in PathParameters) + PathParameters = Path.CreatePathParameters(Context, _document); + if (!Context.Settings.DeclarePathParametersOnPathItem) { - operation.Parameters.AppendParameter(parameter); + operation.Parameters ??= []; + foreach (var parameter in PathParameters) + { + operation.Parameters.AppendParameter(parameter); + } } } @@ -239,7 +249,7 @@ protected static void AppendCustomParameters(OpenApiOperation operation, IList protected virtual void SetCustomLinkRelType() { - if (Context.Settings.CustomHttpMethodLinkRelMapping != null) + if (Context?.Settings.CustomHttpMethodLinkRelMapping is not null && + Path is not null) { LinkRelKey? key = OperationType.ToString().ToLowerInvariant() switch { @@ -300,9 +312,8 @@ protected virtual void SetCustomLinkRelType() _ => null, }; - if (key != null) + if (key != null && key.HasValue && Context.Settings.CustomHttpMethodLinkRelMapping.TryGetValue(key.Value, out var linkRelValue)) { - Context.Settings.CustomHttpMethodLinkRelMapping.TryGetValue((LinkRelKey)key, out string linkRelValue); CustomLinkRel = linkRelValue; } } @@ -316,7 +327,7 @@ internal void SetCollectionResponse(OpenApiOperation operation, string targetEle operation.Responses = new OpenApiResponses { { - Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, + (Context?.Settings.UseSuccessStatusCodeRange ?? false) ? Constants.StatusCodeClass2XX : Constants.StatusCode200, new OpenApiResponseReference($"{targetElementFullName}{Constants.CollectionSchemaSuffix}", _document) } }; @@ -330,7 +341,7 @@ internal void SetSingleResponse(OpenApiOperation operation, IOpenApiSchema schem operation.Responses = new OpenApiResponses { { - Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, + (Context?.Settings.UseSuccessStatusCodeRange ?? false) ? Constants.StatusCodeClass2XX : Constants.StatusCode200, new OpenApiResponse { Description = "Entity result.", diff --git a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt index 96bcd04af..8271bde4a 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt +++ b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt @@ -1,120 +1,67 @@ -abstract Microsoft.OpenApi.OData.Edm.ODataSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, System.Collections.Generic.HashSet parameters) -> string -abstract Microsoft.OpenApi.OData.Edm.ODataSegment.Identifier.get -> string +#nullable enable +abstract Microsoft.OpenApi.OData.Edm.ODataSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! +abstract Microsoft.OpenApi.OData.Edm.ODataSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! +abstract Microsoft.OpenApi.OData.Edm.ODataSegment.Identifier.get -> string! abstract Microsoft.OpenApi.OData.Edm.ODataSegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -abstract Microsoft.OpenApi.OData.Edm.ODataSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable Microsoft.OpenApi.OData.Common.Utils Microsoft.OpenApi.OData.Edm.EdmModelExtensions Microsoft.OpenApi.OData.Edm.EdmTypeExtensions -Microsoft.OpenApi.OData.Edm.ODataKeySegment.IsAlternateKey.get -> bool -Microsoft.OpenApi.OData.Edm.ODataKeySegment.IsAlternateKey.set -> void -Microsoft.OpenApi.OData.Edm.ODataOperationSegment.ODataOperationSegment(Microsoft.OData.Edm.IEdmOperation operation) -> void -Microsoft.OpenApi.OData.Edm.ODataOperationSegment.ODataOperationSegment(Microsoft.OData.Edm.IEdmOperation operation, bool isEscapedFunction) -> void -Microsoft.OpenApi.OData.Edm.ODataOperationSegment.ODataOperationSegment(Microsoft.OData.Edm.IEdmOperation operation, bool isEscapedFunction, Microsoft.OData.Edm.IEdmModel model) -> void -Microsoft.OpenApi.OData.Edm.ODataOperationSegment.ODataOperationSegment(Microsoft.OData.Edm.IEdmOperation operation, Microsoft.OData.Edm.IEdmModel model) -> void -Microsoft.OpenApi.OData.Edm.ODataOperationSegment.ODataOperationSegment(Microsoft.OData.Edm.IEdmOperation operation, System.Collections.Generic.IDictionary parameterMappings) -> void -Microsoft.OpenApi.OData.Edm.ODataPath.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings) -> string -Microsoft.OpenApi.OData.Edm.ODataSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings) -> string -Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.ODataTypeCastSegment(Microsoft.OData.Edm.IEdmStructuredType structuredType, Microsoft.OData.Edm.IEdmModel model) -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.AddAlternateKeyPaths.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.AddAlternateKeyPaths.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.AddEnumFlagsExtension.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.AddEnumFlagsExtension.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.AppendBoundOperationsOnDerivedTypeCastSegments.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.AppendBoundOperationsOnDerivedTypeCastSegments.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.ComposableFunctionsExpansionDepth.get -> int -Microsoft.OpenApi.OData.OpenApiConvertSettings.ComposableFunctionsExpansionDepth.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.CustomHttpMethodLinkRelMapping.get -> System.Collections.Generic.Dictionary -Microsoft.OpenApi.OData.OpenApiConvertSettings.CustomHttpMethodLinkRelMapping.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableAliasForOperationSegments.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableAliasForOperationSegments.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableAliasForTypeCastSegments.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableAliasForTypeCastSegments.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableCount.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableCount.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableODataAnnotationReferencesForResponses.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableODataAnnotationReferencesForResponses.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableTypeDisambiguationForDefaultValueOfOdataTypeProperty.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableTypeDisambiguationForDefaultValueOfOdataTypeProperty.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.CustomXMLAttributesMapping.get -> System.Collections.Generic.Dictionary -Microsoft.OpenApi.OData.OpenApiConvertSettings.CustomXMLAttributesMapping.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.GenerateDerivedTypesProperties.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.GenerateDerivedTypesProperties.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.IncludeAssemblyInfo.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.IncludeAssemblyInfo.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.NamespacePrefixToStripForInMethodPaths.get -> string -Microsoft.OpenApi.OData.OpenApiConvertSettings.NamespacePrefixToStripForInMethodPaths.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.SemVerVersion.get -> string -Microsoft.OpenApi.OData.OpenApiConvertSettings.SemVerVersion.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.ShowExternalDocs.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.ShowExternalDocs.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.UseStringArrayForQueryOptionsSchema.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.UseStringArrayForQueryOptionsSchema.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.UseSuccessStatusCodeRange.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.UseSuccessStatusCodeRange.set -> void -Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey -Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.Action = 6 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey -Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.Create = 2 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey -Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.Delete = 4 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey -Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.Function = 5 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey -Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.List = 1 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey -Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.ReadByKey = 0 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey -Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.Update = 3 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey -override Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, System.Collections.Generic.HashSet parameters) -> string -override Microsoft.OpenApi.OData.Edm.ODataMetadataSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, System.Collections.Generic.HashSet parameters) -> string -override Microsoft.OpenApi.OData.Edm.ODataNavigationPropertySegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, System.Collections.Generic.HashSet parameters) -> string -override Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, System.Collections.Generic.HashSet parameters) -> string -override Microsoft.OpenApi.OData.Edm.ODataOperationSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, System.Collections.Generic.HashSet parameters) -> string -override Microsoft.OpenApi.OData.Edm.ODataRefSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, System.Collections.Generic.HashSet parameters) -> string -override Microsoft.OpenApi.OData.Edm.ODataStreamContentSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, System.Collections.Generic.HashSet parameters) -> string -override Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, System.Collections.Generic.HashSet parameters) -> string -override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, System.Collections.Generic.HashSet parameters) -> string -static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.OperationTargetsMultiplePaths(this Microsoft.OData.Edm.IEdmModel model, Microsoft.OData.Edm.IEdmOperation operation) -> bool -static Microsoft.OpenApi.OData.Edm.EdmTypeExtensions.ShouldPathParameterBeQuoted(this Microsoft.OData.Edm.IEdmType edmType, Microsoft.OpenApi.OData.OpenApiConvertSettings settings) -> bool Microsoft.OpenApi.OData.Edm.IODataPathProvider -Microsoft.OpenApi.OData.Edm.IODataPathProvider.CanFilter(Microsoft.OData.Edm.IEdmElement element) -> bool -Microsoft.OpenApi.OData.Edm.IODataPathProvider.GetPaths(Microsoft.OData.Edm.IEdmModel model, Microsoft.OpenApi.OData.OpenApiConvertSettings settings) -> System.Collections.Generic.IEnumerable +Microsoft.OpenApi.OData.Edm.IODataPathProvider.CanFilter(Microsoft.OData.Edm.IEdmElement! element) -> bool +Microsoft.OpenApi.OData.Edm.IODataPathProvider.GetPaths(Microsoft.OData.Edm.IEdmModel! model, Microsoft.OpenApi.OData.OpenApiConvertSettings! settings) -> System.Collections.Generic.IEnumerable! +Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment +Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.ComplexType.get -> Microsoft.OData.Edm.IEdmComplexType! +Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.ODataComplexPropertySegment(Microsoft.OData.Edm.IEdmStructuralProperty! property) -> void +Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.Property.get -> Microsoft.OData.Edm.IEdmStructuralProperty! Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment.ODataDollarCountSegment() -> void Microsoft.OpenApi.OData.Edm.ODataKeySegment -Microsoft.OpenApi.OData.Edm.ODataKeySegment.KeyMappings.get -> System.Collections.Generic.IDictionary -Microsoft.OpenApi.OData.Edm.ODataKeySegment.ODataKeySegment(Microsoft.OData.Edm.IEdmEntityType entityType) -> void -Microsoft.OpenApi.OData.Edm.ODataKeySegment.ODataKeySegment(Microsoft.OData.Edm.IEdmEntityType entityType, System.Collections.Generic.IDictionary keyMappings) -> void +Microsoft.OpenApi.OData.Edm.ODataKeySegment.IsAlternateKey.get -> bool +Microsoft.OpenApi.OData.Edm.ODataKeySegment.IsAlternateKey.set -> void +Microsoft.OpenApi.OData.Edm.ODataKeySegment.KeyMappings.get -> System.Collections.Generic.IDictionary? +Microsoft.OpenApi.OData.Edm.ODataKeySegment.ODataKeySegment(Microsoft.OData.Edm.IEdmEntityType! entityType) -> void +Microsoft.OpenApi.OData.Edm.ODataKeySegment.ODataKeySegment(Microsoft.OData.Edm.IEdmEntityType! entityType, System.Collections.Generic.IDictionary! keyMappings) -> void Microsoft.OpenApi.OData.Edm.ODataMetadataSegment Microsoft.OpenApi.OData.Edm.ODataMetadataSegment.ODataMetadataSegment() -> void Microsoft.OpenApi.OData.Edm.ODataNavigationPropertySegment -Microsoft.OpenApi.OData.Edm.ODataNavigationPropertySegment.NavigationProperty.get -> Microsoft.OData.Edm.IEdmNavigationProperty -Microsoft.OpenApi.OData.Edm.ODataNavigationPropertySegment.ODataNavigationPropertySegment(Microsoft.OData.Edm.IEdmNavigationProperty navigationProperty) -> void +Microsoft.OpenApi.OData.Edm.ODataNavigationPropertySegment.NavigationProperty.get -> Microsoft.OData.Edm.IEdmNavigationProperty! +Microsoft.OpenApi.OData.Edm.ODataNavigationPropertySegment.ODataNavigationPropertySegment(Microsoft.OData.Edm.IEdmNavigationProperty! navigationProperty) -> void Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment -Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.NavigationSource.get -> Microsoft.OData.Edm.IEdmNavigationSource -Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.ODataNavigationSourceSegment(Microsoft.OData.Edm.IEdmNavigationSource navigationSource) -> void +Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.NavigationSource.get -> Microsoft.OData.Edm.IEdmNavigationSource! +Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.ODataNavigationSourceSegment(Microsoft.OData.Edm.IEdmNavigationSource! navigationSource) -> void Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment -Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.ODataOperationImportSegment(Microsoft.OData.Edm.IEdmOperationImport operationImport) -> void -Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.ODataOperationImportSegment(Microsoft.OData.Edm.IEdmOperationImport operationImport, System.Collections.Generic.IDictionary parameterMappings) -> void -Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.OperationImport.get -> Microsoft.OData.Edm.IEdmOperationImport -Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.ParameterMappings.get -> System.Collections.Generic.IDictionary +Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.ODataOperationImportSegment(Microsoft.OData.Edm.IEdmOperationImport! operationImport) -> void +Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.ODataOperationImportSegment(Microsoft.OData.Edm.IEdmOperationImport! operationImport, System.Collections.Generic.IDictionary! parameterMappings) -> void +Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.OperationImport.get -> Microsoft.OData.Edm.IEdmOperationImport! +Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.ParameterMappings.get -> System.Collections.Generic.IDictionary! Microsoft.OpenApi.OData.Edm.ODataOperationSegment Microsoft.OpenApi.OData.Edm.ODataOperationSegment.IsEscapedFunction.get -> bool -Microsoft.OpenApi.OData.Edm.ODataOperationSegment.Operation.get -> Microsoft.OData.Edm.IEdmOperation -Microsoft.OpenApi.OData.Edm.ODataOperationSegment.ParameterMappings.get -> System.Collections.Generic.IDictionary +Microsoft.OpenApi.OData.Edm.ODataOperationSegment.ODataOperationSegment(Microsoft.OData.Edm.IEdmOperation! operation) -> void +Microsoft.OpenApi.OData.Edm.ODataOperationSegment.ODataOperationSegment(Microsoft.OData.Edm.IEdmOperation! operation, bool isEscapedFunction) -> void +Microsoft.OpenApi.OData.Edm.ODataOperationSegment.ODataOperationSegment(Microsoft.OData.Edm.IEdmOperation! operation, bool isEscapedFunction, Microsoft.OData.Edm.IEdmModel! model) -> void +Microsoft.OpenApi.OData.Edm.ODataOperationSegment.ODataOperationSegment(Microsoft.OData.Edm.IEdmOperation! operation, Microsoft.OData.Edm.IEdmModel! model) -> void +Microsoft.OpenApi.OData.Edm.ODataOperationSegment.ODataOperationSegment(Microsoft.OData.Edm.IEdmOperation! operation, System.Collections.Generic.IDictionary! parameterMappings) -> void +Microsoft.OpenApi.OData.Edm.ODataOperationSegment.Operation.get -> Microsoft.OData.Edm.IEdmOperation? +Microsoft.OpenApi.OData.Edm.ODataOperationSegment.ParameterMappings.get -> System.Collections.Generic.IDictionary? Microsoft.OpenApi.OData.Edm.ODataPath -Microsoft.OpenApi.OData.Edm.ODataPath.Clone() -> Microsoft.OpenApi.OData.Edm.ODataPath -Microsoft.OpenApi.OData.Edm.ODataPath.GetPathHash(Microsoft.OpenApi.OData.OpenApiConvertSettings settings) -> string -Microsoft.OpenApi.OData.Edm.ODataPath.CompareTo(Microsoft.OpenApi.OData.Edm.ODataPath other) -> int +Microsoft.OpenApi.OData.Edm.ODataPath.Clone() -> Microsoft.OpenApi.OData.Edm.ODataPath! +Microsoft.OpenApi.OData.Edm.ODataPath.CompareTo(Microsoft.OpenApi.OData.Edm.ODataPath! other) -> int Microsoft.OpenApi.OData.Edm.ODataPath.Count.get -> int -Microsoft.OpenApi.OData.Edm.ODataPath.FirstSegment.get -> Microsoft.OpenApi.OData.Edm.ODataSegment +Microsoft.OpenApi.OData.Edm.ODataPath.FirstSegment.get -> Microsoft.OpenApi.OData.Edm.ODataSegment! Microsoft.OpenApi.OData.Edm.ODataPath.GetCount(bool keySegmentAsDepth) -> int -Microsoft.OpenApi.OData.Edm.ODataPath.GetEnumerator() -> System.Collections.Generic.IEnumerator -Microsoft.OpenApi.OData.Edm.ODataPath.GetPathItemName() -> string -Microsoft.OpenApi.OData.Edm.ODataPath.HttpMethods.get -> System.Collections.Generic.ISet -Microsoft.OpenApi.OData.Edm.ODataPath.LastSegment.get -> Microsoft.OpenApi.OData.Edm.ODataSegment -Microsoft.OpenApi.OData.Edm.ODataPath.ODataPath(params Microsoft.OpenApi.OData.Edm.ODataSegment[] segments) -> void -Microsoft.OpenApi.OData.Edm.ODataPath.ODataPath(System.Collections.Generic.IEnumerable segments) -> void -Microsoft.OpenApi.OData.Edm.ODataPath.PathTemplate.get -> string +Microsoft.OpenApi.OData.Edm.ODataPath.GetEnumerator() -> System.Collections.Generic.IEnumerator! +Microsoft.OpenApi.OData.Edm.ODataPath.GetPathHash(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings) -> string! +Microsoft.OpenApi.OData.Edm.ODataPath.GetPathItemName() -> string! +Microsoft.OpenApi.OData.Edm.ODataPath.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings) -> string! +Microsoft.OpenApi.OData.Edm.ODataPath.HttpMethods.get -> System.Collections.Generic.ISet! +Microsoft.OpenApi.OData.Edm.ODataPath.LastSegment.get -> Microsoft.OpenApi.OData.Edm.ODataSegment! +Microsoft.OpenApi.OData.Edm.ODataPath.ODataPath(params Microsoft.OpenApi.OData.Edm.ODataSegment![]! segments) -> void +Microsoft.OpenApi.OData.Edm.ODataPath.ODataPath(System.Collections.Generic.IEnumerable! segments) -> void +Microsoft.OpenApi.OData.Edm.ODataPath.PathTemplate.get -> string! Microsoft.OpenApi.OData.Edm.ODataPath.PathTemplate.set -> void -Microsoft.OpenApi.OData.Edm.ODataPath.Segments.get -> System.Collections.Generic.IList +Microsoft.OpenApi.OData.Edm.ODataPath.Segments.get -> System.Collections.Generic.IList! Microsoft.OpenApi.OData.Edm.ODataPathKind +Microsoft.OpenApi.OData.Edm.ODataPathKind.ComplexProperty = 11 -> Microsoft.OpenApi.OData.Edm.ODataPathKind Microsoft.OpenApi.OData.Edm.ODataPathKind.DollarCount = 9 -> Microsoft.OpenApi.OData.Edm.ODataPathKind Microsoft.OpenApi.OData.Edm.ODataPathKind.Entity = 1 -> Microsoft.OpenApi.OData.Edm.ODataPathKind Microsoft.OpenApi.OData.Edm.ODataPathKind.EntitySet = 0 -> Microsoft.OpenApi.OData.Edm.ODataPathKind @@ -126,15 +73,16 @@ Microsoft.OpenApi.OData.Edm.ODataPathKind.OperationImport = 4 -> Microsoft.OpenA Microsoft.OpenApi.OData.Edm.ODataPathKind.Ref = 6 -> Microsoft.OpenApi.OData.Edm.ODataPathKind Microsoft.OpenApi.OData.Edm.ODataPathKind.Singleton = 2 -> Microsoft.OpenApi.OData.Edm.ODataPathKind Microsoft.OpenApi.OData.Edm.ODataPathKind.TypeCast = 10 -> Microsoft.OpenApi.OData.Edm.ODataPathKind -Microsoft.OpenApi.OData.Edm.ODataPathKind.ComplexProperty = 11 -> Microsoft.OpenApi.OData.Edm.ODataPathKind Microsoft.OpenApi.OData.Edm.ODataPathKind.Unknown = 12 -> Microsoft.OpenApi.OData.Edm.ODataPathKind Microsoft.OpenApi.OData.Edm.ODataPathProvider Microsoft.OpenApi.OData.Edm.ODataPathProvider.ODataPathProvider() -> void Microsoft.OpenApi.OData.Edm.ODataRefSegment Microsoft.OpenApi.OData.Edm.ODataSegment -Microsoft.OpenApi.OData.Edm.ODataSegment.GetPathHash(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, Microsoft.OpenApi.OData.Edm.ODataPath path = null) -> string +Microsoft.OpenApi.OData.Edm.ODataSegment.GetPathHash(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, Microsoft.OpenApi.OData.Edm.ODataPath? path = null) -> string! +Microsoft.OpenApi.OData.Edm.ODataSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings) -> string! Microsoft.OpenApi.OData.Edm.ODataSegment.ODataSegment() -> void Microsoft.OpenApi.OData.Edm.ODataSegmentKind +Microsoft.OpenApi.OData.Edm.ODataSegmentKind.ComplexProperty = 11 -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind Microsoft.OpenApi.OData.Edm.ODataSegmentKind.DollarCount = 10 -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind Microsoft.OpenApi.OData.Edm.ODataSegmentKind.Key = 5 -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind Microsoft.OpenApi.OData.Edm.ODataSegmentKind.Metadata = 0 -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind @@ -146,41 +94,66 @@ Microsoft.OpenApi.OData.Edm.ODataSegmentKind.Ref = 7 -> Microsoft.OpenApi.OData. Microsoft.OpenApi.OData.Edm.ODataSegmentKind.StreamContent = 8 -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind Microsoft.OpenApi.OData.Edm.ODataSegmentKind.StreamProperty = 9 -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind Microsoft.OpenApi.OData.Edm.ODataSegmentKind.TypeCast = 6 -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -Microsoft.OpenApi.OData.Edm.ODataSegmentKind.ComplexProperty = 11 -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind Microsoft.OpenApi.OData.Edm.ODataStreamContentSegment Microsoft.OpenApi.OData.Edm.ODataStreamContentSegment.ODataStreamContentSegment() -> void Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment -Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.ODataStreamPropertySegment(string streamPropertyName) -> void +Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.ODataStreamPropertySegment(string! streamPropertyName) -> void Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment -Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment -Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.ODataComplexPropertySegment(Microsoft.OData.Edm.IEdmStructuralProperty property) -> void -Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.Property.get -> Microsoft.OData.Edm.IEdmStructuralProperty -override Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType -override Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.Identifier.get -> string -Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.ComplexType.get -> Microsoft.OData.Edm.IEdmComplexType -override Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.GetAnnotables() -> System.Collections.Generic.IEnumerable +Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.ODataTypeCastSegment(Microsoft.OData.Edm.IEdmStructuredType! structuredType, Microsoft.OData.Edm.IEdmModel! model) -> void +Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.StructuredType.get -> Microsoft.OData.Edm.IEdmStructuredType! Microsoft.OpenApi.OData.EdmModelOpenApiExtensions Microsoft.OpenApi.OData.Extensions.IODataRoutePathPrefixProvider -Microsoft.OpenApi.OData.Extensions.IODataRoutePathPrefixProvider.Parameters.get -> System.Collections.Generic.IEnumerable -Microsoft.OpenApi.OData.Extensions.IODataRoutePathPrefixProvider.PathPrefix.get -> string +Microsoft.OpenApi.OData.Extensions.IODataRoutePathPrefixProvider.Parameters.get -> System.Collections.Generic.IEnumerable! +Microsoft.OpenApi.OData.Extensions.IODataRoutePathPrefixProvider.PathPrefix.get -> string! Microsoft.OpenApi.OData.Extensions.ODataRoutePathPrefixProvider Microsoft.OpenApi.OData.Extensions.ODataRoutePathPrefixProvider.ODataRoutePathPrefixProvider() -> void -Microsoft.OpenApi.OData.Extensions.ODataRoutePathPrefixProvider.Parameters.get -> System.Collections.Generic.IEnumerable +Microsoft.OpenApi.OData.Extensions.ODataRoutePathPrefixProvider.Parameters.get -> System.Collections.Generic.IEnumerable! Microsoft.OpenApi.OData.Extensions.ODataRoutePathPrefixProvider.Parameters.set -> void -Microsoft.OpenApi.OData.Extensions.ODataRoutePathPrefixProvider.PathPrefix.get -> string +Microsoft.OpenApi.OData.Extensions.ODataRoutePathPrefixProvider.PathPrefix.get -> string! Microsoft.OpenApi.OData.Extensions.ODataRoutePathPrefixProvider.PathPrefix.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings +Microsoft.OpenApi.OData.OpenApiConvertSettings.AddAlternateKeyPaths.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.AddAlternateKeyPaths.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.AddEnumDescriptionExtension.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.AddEnumDescriptionExtension.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.AddEnumFlagsExtension.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.AddEnumFlagsExtension.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.AddSingleQuotesForStringParameters.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.AddSingleQuotesForStringParameters.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.AppendBoundOperationsOnDerivedTypeCastSegments.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.AppendBoundOperationsOnDerivedTypeCastSegments.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.ComposableFunctionsExpansionDepth.get -> int +Microsoft.OpenApi.OData.OpenApiConvertSettings.ComposableFunctionsExpansionDepth.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.CustomHttpMethodLinkRelMapping.get -> System.Collections.Generic.Dictionary! +Microsoft.OpenApi.OData.OpenApiConvertSettings.CustomHttpMethodLinkRelMapping.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.CustomXMLAttributesMapping.get -> System.Collections.Generic.Dictionary! +Microsoft.OpenApi.OData.OpenApiConvertSettings.CustomXMLAttributesMapping.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.DeclarePathParametersOnPathItem.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.DeclarePathParametersOnPathItem.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableAliasForOperationSegments.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableAliasForOperationSegments.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableAliasForTypeCastSegments.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableAliasForTypeCastSegments.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableCount.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableCount.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDeprecationInformation.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDeprecationInformation.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDerivedTypesReferencesForRequestBody.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDerivedTypesReferencesForRequestBody.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDerivedTypesReferencesForResponses.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDerivedTypesReferencesForResponses.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDiscriminatorValue.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDiscriminatorValue.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDollarCountPath.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDollarCountPath.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableKeyAsSegment.get -> bool? Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableKeyAsSegment.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableNavigationPropertyPath.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableNavigationPropertyPath.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableODataAnnotationReferencesForResponses.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableODataAnnotationReferencesForResponses.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableODataTypeCast.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableODataTypeCast.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableOperationId.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableOperationId.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableOperationImportPath.get -> bool @@ -189,37 +162,49 @@ Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableOperationPath.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableOperationPath.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.EnablePagination.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.EnablePagination.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableTypeDisambiguationForDefaultValueOfOdataTypeProperty.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableTypeDisambiguationForDefaultValueOfOdataTypeProperty.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableUnqualifiedCall.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableUnqualifiedCall.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableUriEscapeFunctionCall.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableUriEscapeFunctionCall.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.ErrorResponsesAsDefault.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.ErrorResponsesAsDefault.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.GenerateDerivedTypesProperties.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.GenerateDerivedTypesProperties.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.IEEE754Compatible.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.IEEE754Compatible.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.IncludeAssemblyInfo.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.IncludeAssemblyInfo.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.InnerErrorComplexTypeName.get -> string! +Microsoft.OpenApi.OData.OpenApiConvertSettings.InnerErrorComplexTypeName.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.NamespacePrefixToStripForInMethodPaths.get -> string! +Microsoft.OpenApi.OData.OpenApiConvertSettings.NamespacePrefixToStripForInMethodPaths.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.OpenApiConvertSettings() -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.OpenApiSpecVersion.get -> Microsoft.OpenApi.OpenApiSpecVersion Microsoft.OpenApi.OData.OpenApiConvertSettings.OpenApiSpecVersion.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.PageableOperationName.get -> string +Microsoft.OpenApi.OData.OpenApiConvertSettings.PageableOperationName.get -> string! Microsoft.OpenApi.OData.OpenApiConvertSettings.PageableOperationName.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.PathPrefix.get -> string +Microsoft.OpenApi.OData.OpenApiConvertSettings.PathPrefix.get -> string! Microsoft.OpenApi.OData.OpenApiConvertSettings.PathPrefix.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.PathProvider.get -> Microsoft.OpenApi.OData.Edm.IODataPathProvider +Microsoft.OpenApi.OData.OpenApiConvertSettings.PathProvider.get -> Microsoft.OpenApi.OData.Edm.IODataPathProvider! Microsoft.OpenApi.OData.OpenApiConvertSettings.PathProvider.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDollarCountPath.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDollarCountPath.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.AddSingleQuotesForStringParameters.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.AddSingleQuotesForStringParameters.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableODataTypeCast.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableODataTypeCast.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.RequireDerivedTypesConstraintForODataTypeCastSegments.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.RequireDerivedTypesConstraintForODataTypeCastSegments.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.PrefixEntityTypeNameBeforeKey.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.PrefixEntityTypeNameBeforeKey.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.RequireDerivedTypesConstraintForBoundOperations.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.RequireDerivedTypesConstraintForBoundOperations.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.RoutePathPrefixProvider.get -> Microsoft.OpenApi.OData.Extensions.IODataRoutePathPrefixProvider +Microsoft.OpenApi.OData.OpenApiConvertSettings.RequireDerivedTypesConstraintForODataTypeCastSegments.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.RequireDerivedTypesConstraintForODataTypeCastSegments.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.RoutePathPrefixProvider.get -> Microsoft.OpenApi.OData.Extensions.IODataRoutePathPrefixProvider! Microsoft.OpenApi.OData.OpenApiConvertSettings.RoutePathPrefixProvider.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.ServiceRoot.get -> System.Uri +Microsoft.OpenApi.OData.OpenApiConvertSettings.SemVerVersion.get -> string! +Microsoft.OpenApi.OData.OpenApiConvertSettings.SemVerVersion.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.ServiceRoot.get -> System.Uri! Microsoft.OpenApi.OData.OpenApiConvertSettings.ServiceRoot.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.ShowExternalDocs.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.ShowExternalDocs.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.ShowLinks.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.ShowLinks.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.ShowMsDosGroupPath.get -> bool @@ -232,82 +217,98 @@ Microsoft.OpenApi.OData.OpenApiConvertSettings.TagDepth.get -> int Microsoft.OpenApi.OData.OpenApiConvertSettings.TagDepth.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.TopExample.get -> int Microsoft.OpenApi.OData.OpenApiConvertSettings.TopExample.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.UseStringArrayForQueryOptionsSchema.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.UseStringArrayForQueryOptionsSchema.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.UseSuccessStatusCodeRange.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.UseSuccessStatusCodeRange.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.VerifyEdmModel.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.VerifyEdmModel.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDeprecationInformation.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDeprecationInformation.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.AddEnumDescriptionExtension.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.AddEnumDescriptionExtension.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.ErrorResponsesAsDefault.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.ErrorResponsesAsDefault.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.InnerErrorComplexTypeName.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.InnerErrorComplexTypeName.get -> string -Microsoft.OpenApi.OData.OpenApiConvertSettings.DeclarePathParametersOnPathItem.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.DeclarePathParametersOnPathItem.set -> void -override Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, System.Collections.Generic.HashSet parameters) -> string -override Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment.Identifier.get -> string -override Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType +Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey +Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.Action = 6 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey +Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.Create = 2 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey +Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.Delete = 4 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey +Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.Function = 5 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey +Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.List = 1 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey +Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.ReadByKey = 0 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey +Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.Update = 3 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey +override Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType! +override Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! +override Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! +override Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.Identifier.get -> string! +override Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind +override Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType! +override Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! +override Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! +override Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment.Identifier.get -> string! override Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable -override Microsoft.OpenApi.OData.Edm.ODataKeySegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType -override Microsoft.OpenApi.OData.Edm.ODataKeySegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, System.Collections.Generic.HashSet parameters) -> string -override Microsoft.OpenApi.OData.Edm.ODataKeySegment.Identifier.get -> string +override Microsoft.OpenApi.OData.Edm.ODataKeySegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType! +override Microsoft.OpenApi.OData.Edm.ODataKeySegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! +override Microsoft.OpenApi.OData.Edm.ODataKeySegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! +override Microsoft.OpenApi.OData.Edm.ODataKeySegment.Identifier.get -> string! override Microsoft.OpenApi.OData.Edm.ODataKeySegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataKeySegment.GetAnnotables() -> System.Collections.Generic.IEnumerable -override Microsoft.OpenApi.OData.Edm.ODataMetadataSegment.Identifier.get -> string -override Microsoft.OpenApi.OData.Edm.ODataMetadataSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType +override Microsoft.OpenApi.OData.Edm.ODataMetadataSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType! +override Microsoft.OpenApi.OData.Edm.ODataMetadataSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! +override Microsoft.OpenApi.OData.Edm.ODataMetadataSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! +override Microsoft.OpenApi.OData.Edm.ODataMetadataSegment.Identifier.get -> string! override Microsoft.OpenApi.OData.Edm.ODataMetadataSegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataMetadataSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable -override Microsoft.OpenApi.OData.Edm.ODataNavigationPropertySegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType -override Microsoft.OpenApi.OData.Edm.ODataNavigationPropertySegment.Identifier.get -> string +override Microsoft.OpenApi.OData.Edm.ODataNavigationPropertySegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType! +override Microsoft.OpenApi.OData.Edm.ODataNavigationPropertySegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! +override Microsoft.OpenApi.OData.Edm.ODataNavigationPropertySegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! +override Microsoft.OpenApi.OData.Edm.ODataNavigationPropertySegment.Identifier.get -> string! override Microsoft.OpenApi.OData.Edm.ODataNavigationPropertySegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataNavigationPropertySegment.GetAnnotables() -> System.Collections.Generic.IEnumerable -override Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType -override Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, System.Collections.Generic.HashSet parameters) -> string -override Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.Identifier.get -> string +override Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType! +override Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! +override Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! +override Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.Identifier.get -> string! override Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable -override Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.Identifier.get -> string -override Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType +override Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType! +override Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! +override Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! +override Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.Identifier.get -> string! override Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable -override Microsoft.OpenApi.OData.Edm.ODataOperationSegment.Identifier.get -> string -override Microsoft.OpenApi.OData.Edm.ODataOperationSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType +override Microsoft.OpenApi.OData.Edm.ODataOperationSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType? +override Microsoft.OpenApi.OData.Edm.ODataOperationSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! +override Microsoft.OpenApi.OData.Edm.ODataOperationSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! +override Microsoft.OpenApi.OData.Edm.ODataOperationSegment.Identifier.get -> string? override Microsoft.OpenApi.OData.Edm.ODataOperationSegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataOperationSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable -override Microsoft.OpenApi.OData.Edm.ODataPath.ToString() -> string -override Microsoft.OpenApi.OData.Edm.ODataRefSegment.Identifier.get -> string -override Microsoft.OpenApi.OData.Edm.ODataRefSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType +override Microsoft.OpenApi.OData.Edm.ODataPath.ToString() -> string! +override Microsoft.OpenApi.OData.Edm.ODataRefSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType! +override Microsoft.OpenApi.OData.Edm.ODataRefSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! +override Microsoft.OpenApi.OData.Edm.ODataRefSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! +override Microsoft.OpenApi.OData.Edm.ODataRefSegment.Identifier.get -> string! override Microsoft.OpenApi.OData.Edm.ODataRefSegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataRefSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable -override Microsoft.OpenApi.OData.Edm.ODataStreamContentSegment.Identifier.get -> string -override Microsoft.OpenApi.OData.Edm.ODataStreamContentSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType +override Microsoft.OpenApi.OData.Edm.ODataStreamContentSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType! +override Microsoft.OpenApi.OData.Edm.ODataStreamContentSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! +override Microsoft.OpenApi.OData.Edm.ODataStreamContentSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! +override Microsoft.OpenApi.OData.Edm.ODataStreamContentSegment.Identifier.get -> string! override Microsoft.OpenApi.OData.Edm.ODataStreamContentSegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataStreamContentSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable -override Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.Identifier.get -> string -override Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType +override Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType! +override Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! +override Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! +override Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.Identifier.get -> string! override Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.GetAnnotables() -> System.Collections.Generic.IEnumerable -Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.StructuredType.get -> Microsoft.OData.Edm.IEdmStructuredType -override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.Identifier.get -> string -override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType +override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType! +override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! +override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! +override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.Identifier.get -> string! override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable -static Microsoft.OpenApi.OData.Common.Utils.GetTermQualifiedName() -> string -static Microsoft.OpenApi.OData.Common.Utils.GetUniqueName(string input, System.Collections.Generic.HashSet set) -> string -static Microsoft.OpenApi.OData.Common.Utils.UpperFirstChar(string input) -> string -static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.FindAllBaseTypes(this Microsoft.OData.Edm.IEdmEntityType entityType) -> System.Collections.Generic.IEnumerable -static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.FindAllBaseTypes(this Microsoft.OData.Edm.IEdmComplexType complexType) -> System.Collections.Generic.IEnumerable -static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.GetAllElements(this Microsoft.OData.Edm.IEdmModel model) -> System.Collections.Generic.IEnumerable -static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.IsOperationImportOverload(this Microsoft.OData.Edm.IEdmModel model, Microsoft.OData.Edm.IEdmOperationImport operationImport) -> bool -static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.IsOperationOverload(this Microsoft.OData.Edm.IEdmModel model, Microsoft.OData.Edm.IEdmOperation operation) -> bool -static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.IsUrlEscapeFunction(this Microsoft.OData.Edm.IEdmModel model, Microsoft.OData.Edm.IEdmOperation operation) -> bool -static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.LoadAllNavigationSources(this Microsoft.OData.Edm.IEdmModel model) -> System.Collections.Generic.IDictionary> -static Microsoft.OpenApi.OData.Edm.ODataRefSegment.Instance -> Microsoft.OpenApi.OData.Edm.ODataRefSegment -static Microsoft.OpenApi.OData.EdmModelOpenApiExtensions.ConvertToOpenApi(this Microsoft.OData.Edm.IEdmModel model) -> Microsoft.OpenApi.Models.OpenApiDocument -static Microsoft.OpenApi.OData.EdmModelOpenApiExtensions.ConvertToOpenApi(this Microsoft.OData.Edm.IEdmModel model, Microsoft.OpenApi.OData.OpenApiConvertSettings settings) -> Microsoft.OpenApi.Models.OpenApiDocument +static Microsoft.OpenApi.OData.Common.Utils.GetTermQualifiedName() -> string! +static Microsoft.OpenApi.OData.Common.Utils.GetUniqueName(string! input, System.Collections.Generic.HashSet! set) -> string! +static Microsoft.OpenApi.OData.Common.Utils.UpperFirstChar(string! input) -> string! +static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.FindAllBaseTypes(this Microsoft.OData.Edm.IEdmComplexType! complexType) -> System.Collections.Generic.IEnumerable! +static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.FindAllBaseTypes(this Microsoft.OData.Edm.IEdmEntityType! entityType) -> System.Collections.Generic.IEnumerable! +static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.GetAllElements(this Microsoft.OData.Edm.IEdmModel! model) -> System.Collections.Generic.IEnumerable! +static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.IsOperationImportOverload(this Microsoft.OData.Edm.IEdmModel! model, Microsoft.OData.Edm.IEdmOperationImport! operationImport) -> bool +static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.IsOperationOverload(this Microsoft.OData.Edm.IEdmModel! model, Microsoft.OData.Edm.IEdmOperation! operation) -> bool +static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.IsUrlEscapeFunction(this Microsoft.OData.Edm.IEdmModel! model, Microsoft.OData.Edm.IEdmOperation! operation) -> bool +static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.LoadAllNavigationSources(this Microsoft.OData.Edm.IEdmModel! model) -> System.Collections.Generic.Dictionary!>! +static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.OperationTargetsMultiplePaths(this Microsoft.OData.Edm.IEdmModel! model, Microsoft.OData.Edm.IEdmOperation! operation) -> bool +static Microsoft.OpenApi.OData.Edm.EdmTypeExtensions.ShouldPathParameterBeQuoted(this Microsoft.OData.Edm.IEdmType! edmType, Microsoft.OpenApi.OData.OpenApiConvertSettings! settings) -> bool +static Microsoft.OpenApi.OData.Edm.ODataRefSegment.Instance -> Microsoft.OpenApi.OData.Edm.ODataRefSegment! +static Microsoft.OpenApi.OData.EdmModelOpenApiExtensions.ConvertToOpenApi(this Microsoft.OData.Edm.IEdmModel! model) -> Microsoft.OpenApi.Models.OpenApiDocument! +static Microsoft.OpenApi.OData.EdmModelOpenApiExtensions.ConvertToOpenApi(this Microsoft.OData.Edm.IEdmModel! model, Microsoft.OpenApi.OData.OpenApiConvertSettings! settings) -> Microsoft.OpenApi.Models.OpenApiDocument! virtual Microsoft.OpenApi.OData.Edm.ODataPath.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataPathKind -virtual Microsoft.OpenApi.OData.Edm.ODataPathProvider.CanFilter(Microsoft.OData.Edm.IEdmElement element) -> bool -virtual Microsoft.OpenApi.OData.Edm.ODataPathProvider.GetPaths(Microsoft.OData.Edm.IEdmModel model, Microsoft.OpenApi.OData.OpenApiConvertSettings settings) -> System.Collections.Generic.IEnumerable -virtual Microsoft.OpenApi.OData.Edm.ODataPathProvider.Initialize(Microsoft.OData.Edm.IEdmModel model) -> void -virtual Microsoft.OpenApi.OData.Edm.ODataSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType +virtual Microsoft.OpenApi.OData.Edm.ODataPathProvider.CanFilter(Microsoft.OData.Edm.IEdmElement! element) -> bool +virtual Microsoft.OpenApi.OData.Edm.ODataPathProvider.GetPaths(Microsoft.OData.Edm.IEdmModel! model, Microsoft.OpenApi.OData.OpenApiConvertSettings! settings) -> System.Collections.Generic.IEnumerable! +virtual Microsoft.OpenApi.OData.Edm.ODataPathProvider.Initialize(Microsoft.OData.Edm.IEdmModel! model) -> void +virtual Microsoft.OpenApi.OData.Edm.ODataSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType! diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/DeleteRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/DeleteRestrictionsType.cs index 9171681dd..e772d8297 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/DeleteRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/DeleteRestrictionsType.cs @@ -128,7 +128,7 @@ public void Initialize(IEdmRecordExpression record) /// Merges properties of the specified object into this instance if they are null. /// /// The object containing properties to merge. - public void MergePropertiesIfNull(DeleteRestrictionsType source) + public void MergePropertiesIfNull(DeleteRestrictionsType? source) { if (source == null) return; diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/InsertRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/InsertRestrictionsType.cs index 8652f7a72..7b1258a0e 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/InsertRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/InsertRestrictionsType.cs @@ -25,12 +25,12 @@ internal class InsertRestrictionsType : IRecord /// /// Gets the structural properties cannot be specified on insert. /// - public IList NonInsertableProperties { get; private set; } + public IList? NonInsertableProperties { get; private set; } /// /// Gets the navigation properties which do not allow deep inserts. /// - public IList NonInsertableNavigationProperties { get; private set; } + public IList? NonInsertableNavigationProperties { get; private set; } /// /// Gets the maximum number of navigation properties that can be traversed. @@ -45,50 +45,50 @@ internal class InsertRestrictionsType : IRecord /// /// Gets the required scopes to perform the insert. /// - public IList Permissions { get; private set; } + public IList? Permissions { get; private set; } /// /// Gets the Support for query options with insert requests. /// - public ModificationQueryOptionsType QueryOptions { get; private set; } + public ModificationQueryOptionsType? QueryOptions { get; private set; } /// /// Gets the Supported or required custom headers. /// - public IList CustomHeaders { get; private set; } + public IList? CustomHeaders { get; private set; } /// /// Gets the Supported or required custom query options. /// - public IList CustomQueryOptions { get; private set; } + public IList? CustomQueryOptions { get; private set; } /// /// Gets A brief description of the request. /// - public string Description { get; private set; } + public string? Description { get; private set; } /// /// Gets A lengthy description of the request. /// - public string LongDescription { get; private set; } + public string? LongDescription { get; private set; } /// /// Test the target supports insert. /// /// True/false. - public bool IsInsertable => Insertable == null || Insertable.Value == true; + public bool IsInsertable => Insertable == null || Insertable.Value; /// /// Lists the media types acceptable for the request content /// /// This is not an official OASIS standard property. - public IList RequestContentTypes { get; private set; } + public IList? RequestContentTypes { get; private set; } /// /// Lists the media types acceptable for the response content /// /// This is not an official OASIS standard property. - public IList ResponseContentTypes { get; private set; } + public IList? ResponseContentTypes { get; private set; } /// /// Test the input navigation property do not allow deep insert. @@ -111,47 +111,47 @@ public void Initialize(IEdmRecordExpression record) Utils.CheckArgumentNull(record, nameof(record)); // Insertable - Insertable = record.GetBoolean("Insertable"); + Insertable = record.GetBoolean(nameof(Insertable)); // NonInsertableNavigationProperties - NonInsertableNavigationProperties = record.GetCollectionPropertyPath("NonInsertableNavigationProperties"); + NonInsertableNavigationProperties = record.GetCollectionPropertyPath(nameof(NonInsertableNavigationProperties)); // MaxLevels - MaxLevels = record.GetInteger("MaxLevels"); + MaxLevels = record.GetInteger(nameof(MaxLevels)); // TypecastSegmentSupported - TypecastSegmentSupported = record.GetBoolean("TypecastSegmentSupported"); + TypecastSegmentSupported = record.GetBoolean(nameof(TypecastSegmentSupported)); // Permissions - Permissions = record.GetCollection("Permissions"); + Permissions = record.GetCollection(nameof(Permissions)); // QueryOptions - QueryOptions = record.GetRecord("QueryOptions"); + QueryOptions = record.GetRecord(nameof(QueryOptions)); // CustomHeaders - CustomHeaders = record.GetCollection("CustomHeaders"); + CustomHeaders = record.GetCollection(nameof(CustomHeaders)); // CustomHeaders - CustomQueryOptions = record.GetCollection("CustomQueryOptions"); + CustomQueryOptions = record.GetCollection(nameof(CustomQueryOptions)); // Description - Description = record.GetString("Description"); + Description = record.GetString(nameof(Description)); // LongDescription - LongDescription = record.GetString("LongDescription"); + LongDescription = record.GetString(nameof(LongDescription)); // RequestContentTypes - RequestContentTypes = record.GetCollection("RequestContentTypes"); + RequestContentTypes = record.GetCollection(nameof(RequestContentTypes)); // ResponseContentTypes - ResponseContentTypes = record.GetCollection("ResponseContentTypes"); + ResponseContentTypes = record.GetCollection(nameof(ResponseContentTypes)); } /// /// Merges properties of the specified object into this instance if they are null. /// /// The object containing properties to merge. - public void MergePropertiesIfNull(InsertRestrictionsType source) + public void MergePropertiesIfNull(InsertRestrictionsType? source) { if (source == null) return; diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ReadRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ReadRestrictionsType.cs index 7061b4b56..7b2d84487 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ReadRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ReadRestrictionsType.cs @@ -23,27 +23,27 @@ internal abstract class ReadRestrictionsBase : IRecord /// /// Gets the List of required scopes to invoke an action or function /// - public IList Permissions { get; private set; } + public IList? Permissions { get; private set; } /// /// Gets the Supported or required custom headers. /// - public IList CustomHeaders { get; private set; } + public IList? CustomHeaders { get; private set; } /// /// Gets the Supported or required custom query options. /// - public IList CustomQueryOptions { get; private set; } + public IList? CustomQueryOptions { get; private set; } /// /// Gets A brief description of the request. /// - public string Description { get; private set; } + public string? Description { get; private set; } /// /// Gets A lengthy description of the request. /// - public string LongDescription { get; private set; } + public string? LongDescription { get; private set; } /// /// Test the target supports read. @@ -83,7 +83,7 @@ public virtual void Initialize(IEdmRecordExpression record) /// Merges properties of the specified object into this instance if they are null. /// /// The object containing properties to merge. - public void MergePropertiesIfNull(ReadRestrictionsBase source) + public void MergePropertiesIfNull(ReadRestrictionsBase? source) { if (source == null) return; @@ -120,7 +120,7 @@ internal class ReadRestrictionsType : ReadRestrictionsBase /// /// Gets the Restrictions for retrieving an entity by key /// - public ReadByKeyRestrictions ReadByKeyRestrictions { get; set; } + public ReadByKeyRestrictions? ReadByKeyRestrictions { get; set; } /// /// Init the . @@ -139,7 +139,7 @@ public override void Initialize(IEdmRecordExpression record) /// Merges properties of the specified object into this instance if they are null. /// /// The object containing properties to merge. - public void MergePropertiesIfNull(ReadRestrictionsType source) + public void MergePropertiesIfNull(ReadRestrictionsType? source) { base.MergePropertiesIfNull(source); diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/UpdateRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/UpdateRestrictionsType.cs index 724d2ddc9..7cbd6a460 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/UpdateRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/UpdateRestrictionsType.cs @@ -209,7 +209,7 @@ public void Initialize(IEdmRecordExpression record) /// Merges properties of the specified object into this instance if they are null. /// /// The object containing properties to merge. - public void MergePropertiesIfNull(UpdateRestrictionsType source) + public void MergePropertiesIfNull(UpdateRestrictionsType? source) { if (source == null) return; From 255a84b496308ac92f0bbc01a25cb8db8b057372 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 24 Mar 2025 10:28:02 -0400 Subject: [PATCH 03/24] chore: additional NRT fixes Signed-off-by: Vincent Biret --- .../Generator/OpenApiParameterGenerator.cs | 3 +- .../NavigationPropertyGetOperationHandler.cs | 108 +++++++++--------- 2 files changed, 52 insertions(+), 59 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiParameterGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiParameterGenerator.cs index cfc0680c6..fba493831 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiParameterGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiParameterGenerator.cs @@ -689,8 +689,7 @@ public static void AppendParameter(this IList parameters, IOp Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(targetPath, nameof(targetPath)); - IEdmTargetPath target = context.Model.GetTargetPath(targetPath); - if (target == null) + if (context.Model.GetTargetPath(targetPath) is not {} target) return null; return context.CreateSelect(target, entityType); diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs index 1c1f393af..f06add9cb 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.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 System.Net.Http; @@ -161,73 +162,66 @@ protected override void SetParameters(OpenApiOperation operation) return; } - var selectParameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateSelect(TargetPath, NavigationProperty.ToEntityType())) - ?? Context.CreateSelect(NavigationProperty); - - var expandParameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateExpand(TargetPath, NavigationProperty.ToEntityType())) - ?? Context.CreateExpand(NavigationProperty); - - if (!LastSegmentIsKeySegment && NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) + var (selectParameter, expandParameter) = (string.IsNullOrEmpty(TargetPath), NavigationProperty) switch + { + (false, not null) when NavigationProperty.ToEntityType() is {} entityType => + (Context.CreateSelect(TargetPath!, entityType) ?? Context.CreateSelect(NavigationProperty), + Context.CreateExpand(TargetPath!, entityType) ?? Context.CreateExpand(NavigationProperty)), + (true, not null) => (Context.CreateSelect(NavigationProperty), Context.CreateExpand(NavigationProperty)), + _ => (null, null), + }; + + var parametersToAdd = new List(); + if (!LastSegmentIsKeySegment && NavigationProperty?.TargetMultiplicity() == EdmMultiplicity.Many) { // Need to verify that TopSupported or others should be applied to navigation source. // So, how about for the navigation property. - var parameter = Context.CreateTop(TargetPath, _document) ?? Context.CreateTop(NavigationProperty, _document); - if (parameter != null) - { - operation.Parameters.Add(parameter); - } - - parameter = Context.CreateSkip(TargetPath, _document) ?? Context.CreateSkip(NavigationProperty, _document); - if (parameter != null) - { - operation.Parameters.Add(parameter); - } - - parameter = Context.CreateSearch(TargetPath, _document) ?? Context.CreateSearch(NavigationProperty, _document); - if (parameter != null) - { - operation.Parameters.Add(parameter); - } - - parameter = Context.CreateFilter(TargetPath, _document) ?? Context.CreateFilter(NavigationProperty, _document); - if (parameter != null) - { - operation.Parameters.Add(parameter); - } - - parameter = Context.CreateCount(TargetPath, _document) ?? Context.CreateCount(NavigationProperty, _document); - if (parameter != null) + AddParameterIfExists(parametersToAdd, Context.CreateTop, Context.CreateTop); + AddParameterIfExists(parametersToAdd, Context.CreateSkip, Context.CreateSkip); + AddParameterIfExists(parametersToAdd, Context.CreateSearch, Context.CreateSearch); + AddParameterIfExists(parametersToAdd, Context.CreateFilter, Context.CreateFilter); + AddParameterIfExists(parametersToAdd, Context.CreateCount, Context.CreateCount); + + var orderByParameter = (string.IsNullOrEmpty(TargetPath), NavigationProperty) switch + { + (false, not null) when NavigationProperty.ToEntityType() is {} entityType => + Context.CreateOrderBy(TargetPath!, entityType), + (true, not null) => Context.CreateOrderBy(NavigationProperty), + _ => null, + }; + if (orderByParameter != null) { - operation.Parameters.Add(parameter); + parametersToAdd.Add(orderByParameter); } + } - parameter = Context.CreateOrderBy(TargetPath, NavigationProperty.ToEntityType()) ?? Context.CreateOrderBy(NavigationProperty); - if (parameter != null) - { - operation.Parameters.Add(parameter); - } + if (selectParameter != null) + { + parametersToAdd.Add(selectParameter); + } - if (selectParameter != null) - { - operation.Parameters.Add(selectParameter); - } + if (expandParameter != null) + { + parametersToAdd.Add(expandParameter); + } - if (expandParameter != null) - { - operation.Parameters.Add(expandParameter); - } + if (parametersToAdd.Count > 0) + { + if (operation.Parameters is null) operation.Parameters = parametersToAdd; + else parametersToAdd.ForEach(p => operation.Parameters.Add(p)); } - else + } + private void AddParameterIfExists(List parameters, + Func createParameterFromPath, + Func createParameterFromProperty) + { + if (!string.IsNullOrEmpty(TargetPath) && createParameterFromPath(TargetPath, _document) is {} parameterFromPath) { - if (selectParameter != null) - { - operation.Parameters.Add(selectParameter); - } - - if (expandParameter != null) - { - operation.Parameters.Add(expandParameter); - } + parameters.Add(parameterFromPath); + } + else if (NavigationProperty is not null && createParameterFromProperty(NavigationProperty, _document) is {} parameterFromProperty) + { + parameters.Add(parameterFromProperty); } } From 0868da21a534e0d6355e21c5fb485954f6fe1d47 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 24 Mar 2025 10:46:39 -0400 Subject: [PATCH 04/24] chore: additional NRT fixes batch Signed-off-by: Vincent Biret --- .../Generator/OpenApiLinkGenerator.cs | 2 +- .../Operation/EntityDeleteOperationHandler.cs | 20 ++++++------ .../MediaEntityDeleteOperationHandler.cs | 22 +++++++------ ...avigationPropertyDeleteOperationHandler.cs | 11 ++++--- .../NavigationPropertyGetOperationHandler.cs | 15 ++++----- .../NavigationPropertyPostOperationHandler.cs | 31 ++++++++----------- ...avigationPropertyUpdateOperationHandler.cs | 19 ++++++------ 7 files changed, 60 insertions(+), 60 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiLinkGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiLinkGenerator.cs index 5fb7804ea..ea8969dca 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiLinkGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiLinkGenerator.cs @@ -31,7 +31,7 @@ internal static class OpenApiLinkGenerator /// The created dictionary of object. public static IDictionary CreateLinks(this ODataContext context, IEdmEntityType entityType, string entityName, string entityKind, ODataPath path, - IList parameters = null, string navPropOperationId = null) + IList? parameters = null, string? navPropOperationId = null) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(entityType, nameof(entityType)); diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityDeleteOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityDeleteOperationHandler.cs index 8b2091f05..c037c74de 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityDeleteOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityDeleteOperationHandler.cs @@ -32,13 +32,15 @@ public EntityDeleteOperationHandler(OpenApiDocument document) : base(document) /// public override HttpMethod OperationType => HttpMethod.Delete; - private DeleteRestrictionsType _deleteRestrictions; + private DeleteRestrictionsType? _deleteRestrictions; protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - _deleteRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); + if (Context is null) return; + if (!string.IsNullOrEmpty(TargetPath)) + _deleteRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); var entityDeleteRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.DeleteRestrictions); _deleteRestrictions?.MergePropertiesIfNull(entityDeleteRestrictions); _deleteRestrictions ??= entityDeleteRestrictions; @@ -48,11 +50,10 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetBasicInfo(OpenApiOperation operation) { IEdmEntityType entityType = EntitySet.EntityType; - ODataKeySegment keySegment = Path.LastSegment as ODataKeySegment; // Description string placeHolder = $"Delete entity from {EntitySet.Name}"; - if (keySegment.IsAlternateKey) + if (Path is {LastSegment: ODataKeySegment {IsAlternateKey: true} keySegment}) { placeHolder = $"{placeHolder} by {keySegment.Identifier}"; } @@ -60,13 +61,13 @@ protected override void SetBasicInfo(OpenApiOperation operation) operation.Description = _deleteRestrictions?.LongDescription; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is { Settings.EnableOperationId: true}) { string typeName = entityType.Name; string operationName =$"Delete{Utils.UpperFirstChar(typeName)}"; - if (keySegment.IsAlternateKey) + if (Path is {LastSegment: ODataKeySegment {IsAlternateKey: true} keySegment2}) { - string alternateKeyName = string.Join("", keySegment.Identifier.Split(',').Select(static x => Utils.UpperFirstChar(x))); + string alternateKeyName = string.Join("", keySegment2.Identifier.Split(',').Select(static x => Utils.UpperFirstChar(x))); operationName = $"{operationName}By{alternateKeyName}"; } operation.OperationId = $"{EntitySet.Name}.{typeName}.{operationName}"; @@ -78,6 +79,7 @@ protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); + operation.Parameters ??= []; operation.Parameters.Add(new OpenApiParameter { Name = "If-Match", @@ -94,7 +96,7 @@ protected override void SetParameters(OpenApiOperation operation) protected override void SetResponses(OpenApiOperation operation) { // Response for Delete methods should be 204 No Content - OpenApiConvertSettings settings = Context.Settings.Clone(); + OpenApiConvertSettings settings = Context?.Settings.Clone() ?? new(); settings.UseSuccessStatusCodeRange = false; operation.AddErrorResponses(settings, _document, true); @@ -108,7 +110,7 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_deleteRestrictions.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_deleteRestrictions.Permissions, _document).ToList() ?? []; } protected override void AppendCustomParameters(OpenApiOperation operation) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityDeleteOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityDeleteOperationHandler.cs index af94ff02c..ba40a0a2f 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityDeleteOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityDeleteOperationHandler.cs @@ -22,7 +22,7 @@ public MediaEntityDeleteOperationHandler(OpenApiDocument document) : base(docume /// public override HttpMethod OperationType => HttpMethod.Delete; - private DeleteRestrictionsType _deleteRestrictions; + private DeleteRestrictionsType? _deleteRestrictions; protected override void Initialize(ODataContext context, ODataPath path) { @@ -30,17 +30,18 @@ protected override void Initialize(ODataContext context, ODataPath path) if (Property != null) { - _deleteRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); + if (!string.IsNullOrEmpty(TargetPath)) + _deleteRestrictions = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); if (Property is IEdmNavigationProperty) { - var navigationDeleteRestrictions = Context.Model.GetRecord(Property, CapabilitiesConstants.NavigationRestrictions)? + var navigationDeleteRestrictions = Context?.Model.GetRecord(Property, CapabilitiesConstants.NavigationRestrictions)? .RestrictedProperties?.FirstOrDefault()?.DeleteRestrictions; _deleteRestrictions?.MergePropertiesIfNull(navigationDeleteRestrictions); _deleteRestrictions ??= navigationDeleteRestrictions; } else { - var propertyDeleteRestrictions = Context.Model.GetRecord(Property, CapabilitiesConstants.DeleteRestrictions); + var propertyDeleteRestrictions = Context?.Model.GetRecord(Property, CapabilitiesConstants.DeleteRestrictions); _deleteRestrictions?.MergePropertiesIfNull(propertyDeleteRestrictions); _deleteRestrictions ??= propertyDeleteRestrictions; } @@ -51,19 +52,19 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetBasicInfo(OpenApiOperation operation) { // Summary - string placeholderValue = LastSegmentIsStreamPropertySegment ? Path.LastSegment.Identifier : "media content"; + string placeholderValue = LastSegmentIsStreamPropertySegment && Path is not null ? Path.LastSegment.Identifier : "media content"; operation.Summary = _deleteRestrictions?.Description; operation.Summary ??= IsNavigationPropertyPath ? $"Delete {placeholderValue} for the navigation property {NavigationProperty.Name} in {NavigationSourceSegment.NavigationSource.Name}" : $"Delete {placeholderValue} for {NavigationSourceSegment.EntityType.Name} in {NavigationSourceSegment.Identifier}"; // Description - operation.Description = _deleteRestrictions?.LongDescription ?? Context.Model.GetDescriptionAnnotation(Property); + operation.Description = _deleteRestrictions?.LongDescription ?? Context?.Model.GetDescriptionAnnotation(Property); // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true}) { - string identifier = LastSegmentIsStreamPropertySegment ? Path.LastSegment.Identifier : "Content"; + string identifier = LastSegmentIsStreamPropertySegment && Path is not null ? Path.LastSegment.Identifier : "Content"; operation.OperationId = GetOperationId("Delete", identifier); } @@ -75,6 +76,7 @@ protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); + operation.Parameters ??= []; operation.Parameters.Add(new OpenApiParameter { Name = "If-Match", @@ -91,7 +93,7 @@ protected override void SetParameters(OpenApiOperation operation) protected override void SetResponses(OpenApiOperation operation) { // Response for Delete methods should be 204 No Content - OpenApiConvertSettings settings = Context.Settings.Clone(); + OpenApiConvertSettings settings = Context?.Settings.Clone() ?? new(); settings.UseSuccessStatusCodeRange = false; operation.AddErrorResponses(settings, _document, true); @@ -105,7 +107,7 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_deleteRestrictions.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_deleteRestrictions.Permissions, _document).ToList() ?? []; } /// diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyDeleteOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyDeleteOperationHandler.cs index 2bedd562a..3fa154048 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyDeleteOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyDeleteOperationHandler.cs @@ -31,7 +31,7 @@ public NavigationPropertyDeleteOperationHandler(OpenApiDocument document):base(d /// public override HttpMethod OperationType => HttpMethod.Delete; - private DeleteRestrictionsType _deleteRestriction; + private DeleteRestrictionsType? _deleteRestriction; /// protected override void Initialize(ODataContext context, ODataPath path) @@ -44,12 +44,12 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetBasicInfo(OpenApiOperation operation) { // Summary and Description - string placeHolder = "Delete navigation property " + NavigationProperty.Name + " for " + NavigationSource.Name; + string placeHolder = "Delete navigation property " + NavigationProperty?.Name + " for " + NavigationSource?.Name; operation.Summary = _deleteRestriction?.Description ?? placeHolder; operation.Description = _deleteRestriction?.LongDescription; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is { Settings.EnableOperationId: true}) { string prefix = "Delete"; operation.OperationId = GetOperationId(prefix); @@ -63,6 +63,7 @@ protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); + operation.Parameters ??= []; operation.Parameters.Add(new OpenApiParameter { Name = "If-Match", @@ -83,14 +84,14 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_deleteRestriction.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_deleteRestriction.Permissions, _document).ToList() ?? []; } /// protected override void SetResponses(OpenApiOperation operation) { // Response for Delete methods should be 204 No Content - OpenApiConvertSettings settings = Context.Settings.Clone(); + OpenApiConvertSettings settings = Context?.Settings.Clone() ?? new(); settings.UseSuccessStatusCodeRange = false; operation.AddErrorResponses(settings, _document, true); diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs index f06add9cb..ab9e9f9f5 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs @@ -52,10 +52,10 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetBasicInfo(OpenApiOperation operation) { // Summary and Description - string placeHolder = "Get " + NavigationProperty.Name + " from " + NavigationSource.Name; + string placeHolder = "Get " + NavigationProperty?.Name + " from " + NavigationSource?.Name; operation.Summary = (LastSegmentIsKeySegment ? _readRestriction?.ReadByKeyRestrictions?.Description : _readRestriction?.Description) ?? placeHolder; operation.Description = (LastSegmentIsKeySegment ? _readRestriction?.ReadByKeyRestrictions?.LongDescription : _readRestriction?.LongDescription) - ?? Context.Model.GetDescriptionAnnotation(NavigationProperty); + ?? Context?.Model.GetDescriptionAnnotation(NavigationProperty); // OperationId if (Context is { Settings.EnableOperationId: true }) @@ -93,7 +93,7 @@ protected override void SetExtensions(OpenApiOperation operation) protected override void SetResponses(OpenApiOperation operation) { IDictionary? links = null; - if (Context is { Settings.ShowLinks: true }) + if (Context is { Settings.ShowLinks: true } && NavigationProperty is not null && Path is not null) { string operationId = GetOperationId(); @@ -107,7 +107,7 @@ protected override void SetResponses(OpenApiOperation operation) operation.Responses = new OpenApiResponses { { - Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, + Context?.Settings.UseSuccessStatusCodeRange ?? false ? Constants.StatusCodeClass2XX : Constants.StatusCode200, new OpenApiResponseReference($"{NavigationProperty.ToEntityType().FullName()}{Constants.CollectionSchemaSuffix}", _document) } }; @@ -117,7 +117,7 @@ protected override void SetResponses(OpenApiOperation operation) IOpenApiSchema? schema = null; var entityType = NavigationProperty.ToEntityType(); - if (Context.Settings.EnableDerivedTypesReferencesForResponses) + if (Context is { Settings.EnableDerivedTypesReferencesForResponses: true }) { schema = EdmModelHelper.GetDerivedTypesReferenceSchema(entityType, Context.Model, _document); } @@ -127,7 +127,7 @@ protected override void SetResponses(OpenApiOperation operation) operation.Responses = new OpenApiResponses { { - Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, + Context?.Settings.UseSuccessStatusCodeRange ?? false ? Constants.StatusCodeClass2XX : Constants.StatusCode200, new OpenApiResponse { Description = "Retrieved navigation property", @@ -147,7 +147,8 @@ protected override void SetResponses(OpenApiOperation operation) }; } - operation.AddErrorResponses(Context.Settings, _document, false); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, false); base.SetResponses(operation); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPostOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPostOperationHandler.cs index 065fcfe44..de3e656bb 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPostOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPostOperationHandler.cs @@ -32,7 +32,7 @@ public NavigationPropertyPostOperationHandler(OpenApiDocument document):base(doc /// public override HttpMethod OperationType => HttpMethod.Post; - private InsertRestrictionsType _insertRestriction; + private InsertRestrictionsType? _insertRestriction; /// protected override void Initialize(ODataContext context, ODataPath path) @@ -45,12 +45,12 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetBasicInfo(OpenApiOperation operation) { // Summary and Description - string placeHolder = "Create new navigation property to " + NavigationProperty.Name + " for " + NavigationSource.Name; + string placeHolder = "Create new navigation property to " + NavigationProperty?.Name + " for " + NavigationSource?.Name; operation.Summary = _insertRestriction?.Description ?? placeHolder; operation.Description = _insertRestriction?.LongDescription; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true}) { string prefix = "Create"; operation.OperationId = GetOperationId(prefix); @@ -62,12 +62,9 @@ protected override void SetBasicInfo(OpenApiOperation operation) /// protected override void SetRequestBody(OpenApiOperation operation) { - OpenApiSchema schema = null; - - if (Context.Settings.EnableDerivedTypesReferencesForRequestBody) - { - schema = EdmModelHelper.GetDerivedTypesReferenceSchema(NavigationProperty.ToEntityType(), Context.Model, _document); - } + var schema = Context is {Settings.EnableDerivedTypesReferencesForRequestBody: true} ? + EdmModelHelper.GetDerivedTypesReferenceSchema(NavigationProperty.ToEntityType(), Context.Model, _document) : + null; operation.RequestBody = new OpenApiRequestBody { @@ -82,17 +79,14 @@ protected override void SetRequestBody(OpenApiOperation operation) /// protected override void SetResponses(OpenApiOperation operation) { - OpenApiSchema schema = null; - - if (Context.Settings.EnableDerivedTypesReferencesForResponses) - { - schema = EdmModelHelper.GetDerivedTypesReferenceSchema(NavigationProperty.ToEntityType(), Context.Model, _document); - } + var schema = Context is {Settings.EnableDerivedTypesReferencesForResponses: true} ? + EdmModelHelper.GetDerivedTypesReferenceSchema(NavigationProperty.ToEntityType(), Context.Model, _document) : + null; operation.Responses = new OpenApiResponses { { - Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode201, + Context?.Settings.UseSuccessStatusCodeRange ?? false ? Constants.StatusCodeClass2XX : Constants.StatusCode201, new OpenApiResponse { Description = "Created navigation property.", @@ -100,7 +94,8 @@ protected override void SetResponses(OpenApiOperation operation) } } }; - operation.AddErrorResponses(Context.Settings, _document, false); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, false); base.SetResponses(operation); } @@ -112,7 +107,7 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_insertRestriction.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_insertRestriction.Permissions ?? [], _document).ToList() ?? []; } protected override void AppendCustomParameters(OpenApiOperation operation) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyUpdateOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyUpdateOperationHandler.cs index 3549480a6..98b7479d6 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyUpdateOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyUpdateOperationHandler.cs @@ -30,7 +30,7 @@ protected NavigationPropertyUpdateOperationHandler(OpenApiDocument document):bas { } - private UpdateRestrictionsType _updateRestriction; + private UpdateRestrictionsType? _updateRestriction; /// protected override void Initialize(ODataContext context, ODataPath path) @@ -43,12 +43,12 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetBasicInfo(OpenApiOperation operation) { // Summary and Description - string placeHolder = "Update the navigation property " + NavigationProperty.Name + " in " + NavigationSource.Name; + string placeHolder = "Update the navigation property " + NavigationProperty?.Name + " in " + NavigationSource?.Name; operation.Summary = _updateRestriction?.Description ?? placeHolder; operation.Description = _updateRestriction?.LongDescription; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true}) { string prefix = OperationType == HttpMethod.Patch ? "Update" : "Set"; operation.OperationId = GetOperationId(prefix); @@ -60,11 +60,9 @@ protected override void SetBasicInfo(OpenApiOperation operation) /// protected override void SetRequestBody(OpenApiOperation operation) { - OpenApiSchema schema = null; - if (Context.Settings.EnableDerivedTypesReferencesForRequestBody) - { - schema = EdmModelHelper.GetDerivedTypesReferenceSchema(NavigationProperty.ToEntityType(), Context.Model, _document); - } + var schema = Context is { Settings.EnableDerivedTypesReferencesForRequestBody: true } ? + EdmModelHelper.GetDerivedTypesReferenceSchema(NavigationProperty.ToEntityType(), Context.Model, _document) : + null; operation.RequestBody = new OpenApiRequestBody { @@ -79,7 +77,8 @@ protected override void SetRequestBody(OpenApiOperation operation) /// protected override void SetResponses(OpenApiOperation operation) { - operation.AddErrorResponses(Context.Settings, _document, true, GetOpenApiSchema()); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, true, GetOpenApiSchema()); base.SetResponses(operation); } @@ -90,7 +89,7 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_updateRestriction.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_updateRestriction.Permissions, _document).ToList() ?? []; } protected override void AppendCustomParameters(OpenApiOperation operation) From c8154127360001c3ef9d6ed0e93d31aa4c875e8b Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 24 Mar 2025 15:22:38 -0400 Subject: [PATCH 05/24] chore: another batch of NRT fixes Signed-off-by: Vincent Biret --- .../Common/EdmModelHelper.cs | 130 ++++++++++-------- .../Edm/EdmAnnotationExtensions.cs | 1 + .../Generator/OpenApiLinkGenerator.cs | 6 +- .../NavigationPropertyOperationHandler.cs | 52 ++++--- 4 files changed, 111 insertions(+), 78 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Common/EdmModelHelper.cs b/src/Microsoft.OpenApi.OData.Reader/Common/EdmModelHelper.cs index b3cdf8ed4..6a8490386 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Common/EdmModelHelper.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Common/EdmModelHelper.cs @@ -23,7 +23,7 @@ internal static class EdmModelHelper /// Adds the derived types references together with their base type reference in the OneOf property of an OpenAPI schema. /// /// The OpenAPI schema with the list of derived types references and their base type references set in the OneOf property. - internal static OpenApiSchema GetDerivedTypesReferenceSchema(IEdmStructuredType structuredType, IEdmModel edmModel, OpenApiDocument document) + internal static OpenApiSchema? GetDerivedTypesReferenceSchema(IEdmStructuredType structuredType, IEdmModel edmModel, OpenApiDocument document) { Utils.CheckArgumentNull(structuredType, nameof(structuredType)); Utils.CheckArgumentNull(edmModel, nameof(edmModel)); @@ -38,7 +38,7 @@ internal static OpenApiSchema GetDerivedTypesReferenceSchema(IEdmStructuredType OpenApiSchema schema = new() { - OneOf = new List() + OneOf = [] }; var baseTypeSchema = new OpenApiSchemaReference(schemaElement.FullName(), document); @@ -48,7 +48,7 @@ internal static OpenApiSchema GetDerivedTypesReferenceSchema(IEdmStructuredType { var derivedTypeSchema = new OpenApiSchemaReference(derivedType.FullName(), document); schema.OneOf.Add(derivedTypeSchema); - }; + } return schema; } @@ -82,7 +82,7 @@ internal static bool NavigationRestrictionsAllowsNavigability( /// The OData context. /// Optional: Identifier indicating whether it is a collection-valued non-indexed or single-valued navigation property. /// The operation id generated from the given navigation property path. - internal static string GenerateNavigationPropertyPathOperationId(ODataPath path, ODataContext context, string prefix = null) + internal static string? GenerateNavigationPropertyPathOperationId(ODataPath path, ODataContext context, string? prefix = null) { IList items = RetrieveNavigationPropertyPathsOperationIdSegments(path, context); @@ -110,24 +110,22 @@ internal static string GenerateNavigationPropertyPathOperationId(ODataPath path, /// The OData context. /// Optional: Identifier indicating whether it is a collection-valued or single-valued complex property. /// The operation id generated from the given complex property path. - internal static string GenerateComplexPropertyPathOperationId(ODataPath path, ODataContext context, string prefix = null) + internal static string? GenerateComplexPropertyPathOperationId(ODataPath path, ODataContext context, string? prefix = null) { IList items = RetrieveNavigationPropertyPathsOperationIdSegments(path, context); if (!items.Any()) return null; - ODataComplexPropertySegment lastSegment = path.Segments.Skip(1).OfType()?.Last(); - Utils.CheckArgumentNull(lastSegment, nameof(lastSegment)); - - if (!string.IsNullOrEmpty(prefix)) - { - items.Add(prefix + Utils.UpperFirstChar(lastSegment?.Identifier)); - } - else - { - items.Add(Utils.UpperFirstChar(lastSegment?.Identifier)); - } + if (path.Segments.Skip(1).OfType()?.Last()?.Identifier is string lastSegmentIdentifier) + if (!string.IsNullOrEmpty(prefix)) + { + items.Add(prefix + Utils.UpperFirstChar(lastSegmentIdentifier)); + } + else + { + items.Add(Utils.UpperFirstChar(lastSegmentIdentifier)); + } return GenerateNavigationPropertyPathOperationId(items); } @@ -137,7 +135,7 @@ internal static string GenerateComplexPropertyPathOperationId(ODataPath path, OD /// /// The list of string values. /// The generated navigation property operation id. - private static string GenerateNavigationPropertyPathOperationId(IList items) + private static string? GenerateNavigationPropertyPathOperationId(IList items) { if (!items.Any()) return null; @@ -155,10 +153,10 @@ internal static IList RetrieveNavigationPropertyPathsOperationIdSegments { Utils.CheckArgumentNull(path, nameof(path)); - IEdmNavigationSource navigationSource = (path.FirstSegment as ODataNavigationSourceSegment)?.NavigationSource; - Utils.CheckArgumentNull(navigationSource, nameof(navigationSource)); + if (path.FirstSegment is not ODataNavigationSourceSegment {NavigationSource: IEdmNavigationSource navigationSource}) + throw new InvalidOperationException("The first segment of the path is not a navigation source segment."); - IList items = new List + var items = new List { navigationSource.Name }; @@ -174,7 +172,7 @@ s is ODataOperationSegment || s is ODataKeySegment); Utils.CheckArgumentNull(segments, nameof(segments)); - string previousTypeCastSegmentId = null; + string? previousTypeCastSegmentId = null; string pathHash = string.Empty; foreach (var segment in segments) @@ -185,15 +183,18 @@ s is ODataOperationSegment || } else if (segment is ODataTypeCastSegment typeCastSegment && path.Kind != ODataPathKind.TypeCast // ex: ~/NavSource/NavProp/TypeCast - && !(path.Kind == ODataPathKind.DollarCount && path.Segments.ElementAt(path.Segments.Count - 2)?.Kind == ODataSegmentKind.TypeCast)) // ex: ~/NavSource/NavProp/TypeCast/$count + && !(path.Kind == ODataPathKind.DollarCount && path.Segments[path.Segments.Count - 2]?.Kind == ODataSegmentKind.TypeCast)) // ex: ~/NavSource/NavProp/TypeCast/$count { // Only the last OData type cast segment identifier is added to the operation id - items.Remove(previousTypeCastSegmentId); - IEdmSchemaElement schemaElement = typeCastSegment.StructuredType as IEdmSchemaElement; - previousTypeCastSegmentId = "As" + Utils.UpperFirstChar(schemaElement.Name); - items.Add(previousTypeCastSegmentId); + if (!string.IsNullOrEmpty(previousTypeCastSegmentId)) + items.Remove(previousTypeCastSegmentId); + if (typeCastSegment.StructuredType is IEdmSchemaElement schemaElement) + { + previousTypeCastSegmentId = "As" + Utils.UpperFirstChar(schemaElement.Name); + items.Add(previousTypeCastSegmentId); + } } - else if (segment is ODataOperationSegment operationSegment) + else if (segment is ODataOperationSegment operationSegment && !string.IsNullOrEmpty(operationSegment.Identifier)) { // Navigation property generated via composable function if (operationSegment.Operation is IEdmFunction function && context.Model.IsOperationOverload(function)) @@ -239,19 +240,20 @@ internal static string GenerateNavigationPropertyPathTagName(ODataPath path, ODa Utils.CheckArgumentNull(path, nameof(path)); Utils.CheckArgumentNull(context, nameof(context)); - IEdmNavigationSource navigationSource = (path.FirstSegment as ODataNavigationSourceSegment)?.NavigationSource; + if (path.FirstSegment is not ODataNavigationSourceSegment {NavigationSource: IEdmNavigationSource navigationSource }) + throw new InvalidOperationException("The first segment of the path is not a navigation source segment."); - IList items = new List + var items = new List { navigationSource.Name }; - IEdmNavigationProperty navigationProperty = path.OfType()?.Last()?.NavigationProperty; - Utils.CheckArgumentNull(navigationProperty, nameof(navigationProperty)); + if (path.OfType()?.Last()?.NavigationProperty is not IEdmNavigationProperty navigationProperty) + throw new InvalidOperationException("The last segment of the path is not a navigation property segment."); - foreach (var segment in path.Segments.Skip(1).OfType()) + foreach (var segment in path.Segments.Skip(1).OfType().Select(static x => x.NavigationProperty)) { - if (segment.NavigationProperty == navigationProperty) + if (segment == navigationProperty) { items.Add(navigationProperty.ToEntityType().Name); break; @@ -260,12 +262,12 @@ internal static string GenerateNavigationPropertyPathTagName(ODataPath path, ODa { if (items.Count >= context.Settings.TagDepth - 1) { - items.Add(segment.NavigationProperty.ToEntityType().Name); + items.Add(segment.ToEntityType().Name); break; } else { - items.Add(segment.NavigationProperty.Name); + items.Add(segment.Name); } } } @@ -284,12 +286,12 @@ internal static string GenerateComplexPropertyPathTagName(ODataPath path, ODataC Utils.CheckArgumentNull(path, nameof(path)); Utils.CheckArgumentNull(context, nameof(context)); - ODataComplexPropertySegment complexSegment = path.Segments.OfType()?.Last(); - Utils.CheckArgumentNull(complexSegment, nameof(complexSegment)); + if (path.Segments.OfType()?.Last() is not ODataComplexPropertySegment complexSegment) + throw new InvalidOperationException("The last segment of the path is not a complex property segment."); // Get the segment before the last complex type segment int complexSegmentIndex = path.Segments.IndexOf(complexSegment); - ODataSegment preComplexSegment = path.Segments.ElementAt(complexSegmentIndex - 1); + ODataSegment preComplexSegment = path.Segments[complexSegmentIndex - 1]; int preComplexSegmentIndex = path.Segments.IndexOf(preComplexSegment); while (preComplexSegment is ODataTypeCastSegment) @@ -297,10 +299,10 @@ internal static string GenerateComplexPropertyPathTagName(ODataPath path, ODataC // Skip this segment, // Tag names don't include OData type cast segment identifiers preComplexSegmentIndex--; - preComplexSegment = path.Segments.ElementAt(preComplexSegmentIndex); + preComplexSegment = path.Segments[preComplexSegmentIndex]; } - string tagName = null; + string? tagName = null; if (preComplexSegment is ODataNavigationSourceSegment sourceSegment) { @@ -312,7 +314,7 @@ internal static string GenerateComplexPropertyPathTagName(ODataPath path, ODataC } else if (preComplexSegment is ODataKeySegment) { - var prevKeySegment = path.Segments.ElementAt(preComplexSegmentIndex - 1); + var prevKeySegment = path.Segments[preComplexSegmentIndex - 1]; if (prevKeySegment is ODataNavigationPropertySegment) { tagName = GenerateNavigationPropertyPathTagName(path, context); @@ -323,7 +325,7 @@ internal static string GenerateComplexPropertyPathTagName(ODataPath path, ODataC } } - List tagNameItems = tagName?.Split('.').ToList(); + List tagNameItems = tagName?.Split('.').ToList() ?? []; if (tagNameItems.Count < context.Settings.TagDepth) { @@ -340,41 +342,41 @@ internal static string GenerateComplexPropertyPathTagName(ODataPath path, ODataC /// The OData context. /// Optional: Whether to include the List or Get prefix to the generated operation id. /// The operation id prefix generated from the OData type cast path. - internal static string GenerateODataTypeCastPathOperationIdPrefix(ODataPath path, ODataContext context, bool includeListOrGetPrefix = true) + internal static string? GenerateODataTypeCastPathOperationIdPrefix(ODataPath path, ODataContext context, bool includeListOrGetPrefix = true) { // Get the segment before the last OData type cast segment - ODataTypeCastSegment typeCastSegment = path.Segments.OfType()?.Last(); - Utils.CheckArgumentNull(typeCastSegment, nameof(typeCastSegment)); + if (path.Segments.OfType()?.Last() is not ODataTypeCastSegment typeCastSegment) + throw new InvalidOperationException("The last segment of the path is not a type cast segment."); int typeCastSegmentIndex = path.Segments.IndexOf(typeCastSegment); // The segment 1 place before the last OData type cast segment - ODataSegment secondLastSegment = path.Segments.ElementAt(typeCastSegmentIndex - 1); + ODataSegment secondLastSegment = path.Segments[typeCastSegmentIndex - 1]; bool isIndexedCollValuedNavProp = false; if (secondLastSegment is ODataKeySegment) { // The segment 2 places before the last OData type cast segment - ODataSegment thirdLastSegment = path.Segments.ElementAt(typeCastSegmentIndex - 2); + ODataSegment thirdLastSegment = path.Segments[typeCastSegmentIndex - 2]; if (thirdLastSegment is ODataNavigationPropertySegment) { isIndexedCollValuedNavProp = true; } } - ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; - IEdmSingleton singleton = navigationSourceSegment?.NavigationSource as IEdmSingleton; - IEdmEntitySet entitySet = navigationSourceSegment?.NavigationSource as IEdmEntitySet; + ODataNavigationSourceSegment? navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; + IEdmSingleton? singleton = navigationSourceSegment?.NavigationSource as IEdmSingleton; + IEdmEntitySet? entitySet = navigationSourceSegment?.NavigationSource as IEdmEntitySet; - string operationId = null; + string? operationId = null; if (secondLastSegment is ODataComplexPropertySegment complexSegment) { - string listOrGet = includeListOrGetPrefix ? (complexSegment.Property.Type.IsCollection() ? "List" : "Get") : null; + string? listOrGet = includeListOrGetPrefix ? (complexSegment.Property.Type.IsCollection() ? "List" : "Get") : null; operationId = GenerateComplexPropertyPathOperationId(path, context, listOrGet); } else if (secondLastSegment is ODataNavigationPropertySegment navPropSegment) { - string prefix = null; + string? prefix = null; if (includeListOrGetPrefix) { prefix = navPropSegment?.NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many ? "List" : "Get"; @@ -391,22 +393,34 @@ internal static string GenerateODataTypeCastPathOperationIdPrefix(ODataPath path else { string entityTypeName = keySegment.EntityType.Name; - string getPrefix = includeListOrGetPrefix ? "Get" : null; + string? getPrefix = includeListOrGetPrefix ? "Get" : null; string operationName = $"{getPrefix}{Utils.UpperFirstChar(entityTypeName)}"; if (keySegment.IsAlternateKey) { string alternateKeyName = string.Join("", keySegment.Identifier.Split(',').Select(static x => Utils.UpperFirstChar(x))); operationName = $"{operationName}By{alternateKeyName}"; } - operationId = (entitySet != null) ? entitySet.Name : singleton.Name; + if (entitySet != null) + { + operationId = entitySet.Name; + } + else if (singleton != null) + { + operationId = singleton.Name; + } operationId += $".{entityTypeName}.{operationName}"; } } else if (secondLastSegment is ODataNavigationSourceSegment) { - operationId = (entitySet != null) - ? entitySet.Name + "." + entitySet.EntityType.Name + $".{(includeListOrGetPrefix ? "List" : null)}" + Utils.UpperFirstChar(entitySet.EntityType.Name) - : singleton.Name + "." + singleton.EntityType.Name + $".{(includeListOrGetPrefix ? "Get" : null)}" + Utils.UpperFirstChar(singleton.EntityType.Name); + if (entitySet != null) + { + operationId = entitySet.Name + "." + entitySet.EntityType.Name + $".{(includeListOrGetPrefix ? "List" : null)}" + Utils.UpperFirstChar(entitySet.EntityType.Name); + } + else if (singleton != null) + { + operationId = singleton.Name + "." + singleton.EntityType.Name + $".{(includeListOrGetPrefix ? "Get" : null)}" + Utils.UpperFirstChar(singleton.EntityType.Name); + } } return operationId; diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmAnnotationExtensions.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmAnnotationExtensions.cs index 97895481a..3046e3d03 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmAnnotationExtensions.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmAnnotationExtensions.cs @@ -298,6 +298,7 @@ internal static class EdmVocabularyAnnotationExtensions { Utils.CheckArgumentNull(model, nameof(model)); Utils.CheckArgumentNull(target, nameof(target)); + Utils.CheckArgumentNull(linkRel, nameof(linkRel)); return model.GetCollection(target, CoreConstants.Links)?.FirstOrDefault(x => x.Rel == linkRel); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiLinkGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiLinkGenerator.cs index ea8969dca..63d42da11 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiLinkGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiLinkGenerator.cs @@ -10,6 +10,7 @@ using Microsoft.OpenApi.OData.Edm; using System.Linq; using Microsoft.OpenApi.Models.Interfaces; +using System; namespace Microsoft.OpenApi.OData.Generator { @@ -47,7 +48,8 @@ public static IDictionary CreateLinks(this ODataContext co foreach (var parameter in parameters) { if (!string.IsNullOrEmpty(parameter.Description) && - parameter.Description.ToLower().Contains("key")) + parameter.Description.Contains("key", StringComparison.OrdinalIgnoreCase) && + !string.IsNullOrEmpty(parameter.Name)) { pathKeyNames.Add(parameter.Name); } @@ -68,7 +70,7 @@ public static IDictionary CreateLinks(this ODataContext co switch (entityKind) { - case "Navigation": // just for contained navigations + case "Navigation" when !string.IsNullOrEmpty(navPropOperationId): // just for contained navigations operationPrefix = navPropOperationId; break; default: // EntitySet, Entity, Singleton diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyOperationHandler.cs index 559ed86db..625480f59 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyOperationHandler.cs @@ -5,6 +5,7 @@ using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; @@ -71,7 +72,7 @@ protected override void Initialize(ODataContext context, ODataPath path) LastSegmentIsKeySegment = path.LastSegment is ODataKeySegment; LastSegmentIsRefSegment = path.LastSegment is ODataRefSegment; - SecondLastSegmentIsKeySegment = Path.Segments.Reverse().Skip(1).Take(1).Single().Kind == ODataSegmentKind.Key; + SecondLastSegmentIsKeySegment = Path?.Segments.Reverse().Skip(1).Take(1).Single().Kind == ODataSegmentKind.Key; NavigationProperty = path.OfType().Last().NavigationProperty; var navigation = NavigationSource switch { @@ -80,7 +81,9 @@ protected override void Initialize(ODataContext context, ODataPath path) _ => null }; - Restriction = navigation?.RestrictedProperties?.FirstOrDefault(r => r.NavigationProperty != null && r.NavigationProperty == Path.NavigationPropertyPath()) + var navPropertyPath = Path?.NavigationPropertyPath(); + + Restriction = navigation?.RestrictedProperties?.FirstOrDefault(r => r.NavigationProperty != null && r.NavigationProperty == navPropertyPath) ?? Context?.Model.GetRecord(NavigationProperty, CapabilitiesConstants.NavigationRestrictions)?.RestrictedProperties?.FirstOrDefault(); } @@ -104,12 +107,13 @@ protected override void SetTags(OpenApiOperation operation) /// protected override void SetExtensions(OpenApiOperation operation) { + operation.Extensions ??= new Dictionary(); operation.Extensions.Add(Constants.xMsDosOperationType, new OpenApiAny("operation")); base.SetExtensions(operation); } - internal string GetOperationId(string prefix = null) + internal string GetOperationId(string? prefix = null) { return EdmModelHelper.GenerateNavigationPropertyPathOperationId(Path, Context, prefix); } @@ -117,10 +121,10 @@ internal string GetOperationId(string prefix = null) /// protected override void SetExternalDocs(OpenApiOperation operation) { - if (Context.Settings.ShowExternalDocs) + if (Context is {Settings.ShowExternalDocs: true} && !string.IsNullOrEmpty(CustomLinkRel)) { - var externalDocs = Context.Model.GetLinkRecord(TargetPath, CustomLinkRel) ?? - Context.Model.GetLinkRecord(NavigationProperty, CustomLinkRel); + var externalDocs = (string.IsNullOrEmpty(TargetPath) ? null : Context.Model.GetLinkRecord(TargetPath, CustomLinkRel)) ?? + (NavigationProperty is null ? null : Context.Model.GetLinkRecord(NavigationProperty, CustomLinkRel)); if (externalDocs != null) { @@ -149,9 +153,12 @@ protected override void SetExternalDocs(OpenApiOperation operation) readRestrictions?.MergePropertiesIfNull(Restriction?.ReadRestrictions); readRestrictions ??= Restriction?.ReadRestrictions; - var navPropReadRestrictions = Context.Model.GetRecord(NavigationProperty, CapabilitiesConstants.ReadRestrictions); - readRestrictions?.MergePropertiesIfNull(navPropReadRestrictions); - readRestrictions ??= navPropReadRestrictions; + if (NavigationProperty is not null) + { + var navPropReadRestrictions = Context.Model.GetRecord(NavigationProperty, CapabilitiesConstants.ReadRestrictions); + readRestrictions?.MergePropertiesIfNull(navPropReadRestrictions); + readRestrictions ??= navPropReadRestrictions; + } return readRestrictions; case CapabilitiesConstants.UpdateRestrictions: @@ -159,9 +166,12 @@ protected override void SetExternalDocs(OpenApiOperation operation) updateRestrictions?.MergePropertiesIfNull(Restriction?.UpdateRestrictions); updateRestrictions ??= Restriction?.UpdateRestrictions; - var navPropUpdateRestrictions = Context.Model.GetRecord(NavigationProperty, CapabilitiesConstants.UpdateRestrictions); - updateRestrictions?.MergePropertiesIfNull(navPropUpdateRestrictions); - updateRestrictions ??= navPropUpdateRestrictions; + if (NavigationProperty is not null) + { + var navPropUpdateRestrictions = Context.Model.GetRecord(NavigationProperty, CapabilitiesConstants.UpdateRestrictions); + updateRestrictions?.MergePropertiesIfNull(navPropUpdateRestrictions); + updateRestrictions ??= navPropUpdateRestrictions; + } return updateRestrictions; case CapabilitiesConstants.InsertRestrictions: @@ -169,9 +179,12 @@ protected override void SetExternalDocs(OpenApiOperation operation) insertRestrictions?.MergePropertiesIfNull(Restriction?.InsertRestrictions); insertRestrictions ??= Restriction?.InsertRestrictions; - var navPropInsertRestrictions = Context.Model.GetRecord(NavigationProperty, CapabilitiesConstants.InsertRestrictions); - insertRestrictions?.MergePropertiesIfNull(navPropInsertRestrictions); - insertRestrictions ??= navPropInsertRestrictions; + if (NavigationProperty is not null) + { + var navPropInsertRestrictions = Context.Model.GetRecord(NavigationProperty, CapabilitiesConstants.InsertRestrictions); + insertRestrictions?.MergePropertiesIfNull(navPropInsertRestrictions); + insertRestrictions ??= navPropInsertRestrictions; + } return insertRestrictions; case CapabilitiesConstants.DeleteRestrictions: @@ -179,9 +192,12 @@ protected override void SetExternalDocs(OpenApiOperation operation) deleteRestrictions?.MergePropertiesIfNull(Restriction?.DeleteRestrictions); deleteRestrictions ??= Restriction?.DeleteRestrictions; - var navPropDeleteRestrictions = Context.Model.GetRecord(NavigationProperty, CapabilitiesConstants.DeleteRestrictions); - deleteRestrictions?.MergePropertiesIfNull(navPropDeleteRestrictions); - deleteRestrictions ??= navPropDeleteRestrictions; + if (NavigationProperty is not null) + { + var navPropDeleteRestrictions = Context.Model.GetRecord(NavigationProperty, CapabilitiesConstants.DeleteRestrictions); + deleteRestrictions?.MergePropertiesIfNull(navPropDeleteRestrictions); + deleteRestrictions ??= navPropDeleteRestrictions; + } return deleteRestrictions; default: From 176ff3156c80ab8ffa63f133989deed798e5515d Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Mon, 24 Mar 2025 15:28:43 -0400 Subject: [PATCH 06/24] chore: another batch of NRT fixes Signed-off-by: Vincent Biret --- src/Microsoft.OpenApi.OData.Reader/Edm/ODataPath.cs | 12 ++++++------ .../Operation/NavigationPropertyOperationHandler.cs | 8 ++++++-- .../Operation/ODataTypeCastGetOperationHandler.cs | 6 ++---- .../PublicAPI.Unshipped.txt | 8 ++++---- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPath.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPath.cs index e3a28619c..bdb2e8ad2 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPath.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPath.cs @@ -20,7 +20,7 @@ namespace Microsoft.OpenApi.OData.Edm public class ODataPath : IEnumerable, IComparable { private ODataPathKind? _pathKind; - private string _defaultPathItemName; + private string? _defaultPathItemName; /// /// Initializes a new instance of class. @@ -54,7 +54,7 @@ public ODataPath(params ODataSegment[] segments) /// Gets/Sets the path template for this path. /// If it is set, it will be used to generate the path item. /// - public string PathTemplate { get; set; } + public string? PathTemplate { get; set; } /// /// Gets the segments. @@ -80,12 +80,12 @@ public virtual ODataPathKind Kind /// /// Gets the first segment in the path. Returns null if the path is empty. /// - public ODataSegment FirstSegment => Segments.Count == 0 ? null : Segments[0]; + public ODataSegment? FirstSegment => Segments is null || Segments.Count == 0 ? null : Segments[0]; /// /// Get the last segment in the path. Returns null if the path is empty. /// - public ODataSegment LastSegment => Segments.Count == 0 ? null : this.Segments[Segments.Count - 1]; + public ODataSegment? LastSegment => Segments is null || Segments.Count == 0 ? null : this.Segments[Segments.Count - 1]; /// /// Get the number of segments in this path. @@ -365,7 +365,7 @@ private ODataPathKind CalcPathType() /// /// The settings. ///The suffix. - public string GetPathHash(OpenApiConvertSettings settings) => - LastSegment.GetPathHash(settings, this); + public string? GetPathHash(OpenApiConvertSettings settings) => + LastSegment?.GetPathHash(settings, this); } } \ No newline at end of file diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyOperationHandler.cs index 625480f59..d55a0ec2c 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyOperationHandler.cs @@ -113,8 +113,12 @@ protected override void SetExtensions(OpenApiOperation operation) base.SetExtensions(operation); } - internal string GetOperationId(string? prefix = null) - { + internal string? GetOperationId(string? prefix = null) + { + if (Context is null || Path is null) + { + return null; + } return EdmModelHelper.GenerateNavigationPropertyPathOperationId(Path, Context, prefix); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/ODataTypeCastGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/ODataTypeCastGetOperationHandler.cs index c6e804e1b..bff2cf5f0 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/ODataTypeCastGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/ODataTypeCastGetOperationHandler.cs @@ -371,14 +371,12 @@ protected override void SetParameters(OpenApiOperation operation) protected override void SetSecurity(OpenApiOperation operation) { - if (restriction == null || restriction.ReadRestrictions == null) + if (restriction is not {ReadRestrictions.Permissions: not null}) { return; } - ReadRestrictionsBase readBase = restriction.ReadRestrictions; - - operation.Security = Context?.CreateSecurityRequirements(readBase.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(restriction.ReadRestrictions.Permissions, _document).ToList(); } protected override void SetExtensions(OpenApiOperation operation) diff --git a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt index 8271bde4a..d1362972b 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt +++ b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt @@ -47,17 +47,17 @@ Microsoft.OpenApi.OData.Edm.ODataPath Microsoft.OpenApi.OData.Edm.ODataPath.Clone() -> Microsoft.OpenApi.OData.Edm.ODataPath! Microsoft.OpenApi.OData.Edm.ODataPath.CompareTo(Microsoft.OpenApi.OData.Edm.ODataPath! other) -> int Microsoft.OpenApi.OData.Edm.ODataPath.Count.get -> int -Microsoft.OpenApi.OData.Edm.ODataPath.FirstSegment.get -> Microsoft.OpenApi.OData.Edm.ODataSegment! +Microsoft.OpenApi.OData.Edm.ODataPath.FirstSegment.get -> Microsoft.OpenApi.OData.Edm.ODataSegment? Microsoft.OpenApi.OData.Edm.ODataPath.GetCount(bool keySegmentAsDepth) -> int Microsoft.OpenApi.OData.Edm.ODataPath.GetEnumerator() -> System.Collections.Generic.IEnumerator! -Microsoft.OpenApi.OData.Edm.ODataPath.GetPathHash(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings) -> string! +Microsoft.OpenApi.OData.Edm.ODataPath.GetPathHash(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings) -> string? Microsoft.OpenApi.OData.Edm.ODataPath.GetPathItemName() -> string! Microsoft.OpenApi.OData.Edm.ODataPath.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings) -> string! Microsoft.OpenApi.OData.Edm.ODataPath.HttpMethods.get -> System.Collections.Generic.ISet! -Microsoft.OpenApi.OData.Edm.ODataPath.LastSegment.get -> Microsoft.OpenApi.OData.Edm.ODataSegment! +Microsoft.OpenApi.OData.Edm.ODataPath.LastSegment.get -> Microsoft.OpenApi.OData.Edm.ODataSegment? Microsoft.OpenApi.OData.Edm.ODataPath.ODataPath(params Microsoft.OpenApi.OData.Edm.ODataSegment![]! segments) -> void Microsoft.OpenApi.OData.Edm.ODataPath.ODataPath(System.Collections.Generic.IEnumerable! segments) -> void -Microsoft.OpenApi.OData.Edm.ODataPath.PathTemplate.get -> string! +Microsoft.OpenApi.OData.Edm.ODataPath.PathTemplate.get -> string? Microsoft.OpenApi.OData.Edm.ODataPath.PathTemplate.set -> void Microsoft.OpenApi.OData.Edm.ODataPath.Segments.get -> System.Collections.Generic.IList! Microsoft.OpenApi.OData.Edm.ODataPathKind From a755dd8f191194ad1fbd0c1aaf46f44f72e4fb33 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 25 Mar 2025 10:25:01 -0400 Subject: [PATCH 07/24] chore: additional NRT fixes batch Signed-off-by: Vincent Biret --- .../Edm/ODataPath.cs | 5 +- .../Generator/OpenApiParameterGenerator.cs | 15 +++--- .../DollarCountGetOperationHandler.cs | 9 ++-- .../Operation/EntitySetGetOperationHandler.cs | 51 +++++++++++-------- .../MediaEntityGetOperationHandler.cs | 34 +++++++------ .../MediaEntityOperationalHandler.cs | 47 +++++++++-------- .../Operation/MetadataGetOperationHandler.cs | 5 +- .../NavigationPropertyGetOperationHandler.cs | 2 +- 8 files changed, 91 insertions(+), 77 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPath.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPath.cs index bdb2e8ad2..85073fba3 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPath.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPath.cs @@ -204,10 +204,7 @@ internal bool SupportHttpMethod(string method) /// The whole path object. internal ODataPath Push(ODataSegment segment) { - if (Segments == null) - { - Segments = new List(); - } + Segments ??= []; _pathKind = null; _defaultPathItemName = null; diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiParameterGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiParameterGenerator.cs index fba493831..f3ad4900f 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiParameterGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiParameterGenerator.cs @@ -456,8 +456,7 @@ public static void AppendParameter(this IList parameters, IOp Utils.CheckArgumentNull(target, nameof(target)); Utils.CheckArgumentNull(document, nameof(document)); - SearchRestrictionsType search = context.Model.GetRecord(target, CapabilitiesConstants.SearchRestrictions); - if (search == null || search.IsSearchable) + if (context.Model.GetRecord(target, CapabilitiesConstants.SearchRestrictions) is not {} search || search.IsSearchable) { return new OpenApiParameterReference("search", document); } @@ -497,8 +496,7 @@ public static void AppendParameter(this IList parameters, IOp Utils.CheckArgumentNull(target, nameof(target)); Utils.CheckArgumentNull(document, nameof(document)); - CountRestrictionsType count = context.Model.GetRecord(target, CapabilitiesConstants.CountRestrictions); - if (count == null || count.IsCountable) + if (context.Model.GetRecord(target, CapabilitiesConstants.CountRestrictions) is not {} count || count.IsCountable) { return new OpenApiParameterReference("count", document); } @@ -539,8 +537,7 @@ public static void AppendParameter(this IList parameters, IOp Utils.CheckArgumentNull(target, nameof(target)); Utils.CheckArgumentNull(document, nameof(document)); - FilterRestrictionsType filter = context.Model.GetRecord(target, CapabilitiesConstants.FilterRestrictions); - if (filter == null || filter.IsFilterable) + if (context.Model.GetRecord(target, CapabilitiesConstants.FilterRestrictions) is not {} filter || filter.IsFilterable) { return new OpenApiParameterReference("filter", document); } @@ -630,7 +627,7 @@ public static void AppendParameter(this IList parameters, IOp Utils.CheckArgumentNull(target, nameof(target)); Utils.CheckArgumentNull(structuredType, nameof(structuredType)); - SortRestrictionsType sort = context.Model.GetRecord(target, CapabilitiesConstants.SortRestrictions); + var sort = context.Model.GetRecord(target, CapabilitiesConstants.SortRestrictions); if (sort != null && !sort.IsSortable) { return null; @@ -746,7 +743,7 @@ public static void AppendParameter(this IList parameters, IOp Utils.CheckArgumentNull(target, nameof(target)); Utils.CheckArgumentNull(structuredType, nameof(structuredType)); - NavigationRestrictionsType navigation = context.Model.GetRecord(target, CapabilitiesConstants.NavigationRestrictions); + var navigation = context.Model.GetRecord(target, CapabilitiesConstants.NavigationRestrictions); if (navigation != null && !navigation.IsNavigable) { return null; @@ -852,7 +849,7 @@ public static void AppendParameter(this IList parameters, IOp Utils.CheckArgumentNull(target, nameof(target)); Utils.CheckArgumentNull(structuredType, nameof(structuredType)); - ExpandRestrictionsType expand = context.Model.GetRecord(target, CapabilitiesConstants.ExpandRestrictions); + var expand = context.Model.GetRecord(target, CapabilitiesConstants.ExpandRestrictions); if (expand != null && !expand.IsExpandable) { return null; diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/DollarCountGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/DollarCountGetOperationHandler.cs index 0f7620d63..1779329cc 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/DollarCountGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/DollarCountGetOperationHandler.cs @@ -187,17 +187,20 @@ protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); - IOpenApiParameter parameter; - parameter = Context.CreateSearch(TargetPath, _document) ?? (annotatables.Count == 0 ? null : annotatables.Select(x => Context.CreateSearch(x, _document)).FirstOrDefault(static x => x is not null)); + var parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context?.CreateSearch(TargetPath, _document)) ?? + (annotatables.Count == 0 ? null : annotatables.Select(x => Context?.CreateSearch(x, _document)).FirstOrDefault(static x => x is not null)); if (parameter != null) { + operation.Parameters ??= []; operation.Parameters.Add(parameter); } - parameter = Context.CreateFilter(TargetPath, _document) ?? (annotatables.Count == 0 ? null : annotatables.Select(x => Context.CreateFilter(x, _document)).FirstOrDefault(static x => x is not null)); + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context?.CreateFilter(TargetPath, _document)) ?? + (annotatables.Count == 0 ? null : annotatables.Select(x => Context?.CreateFilter(x, _document)).FirstOrDefault(static x => x is not null)); if (parameter != null) { + operation.Parameters ??= []; operation.Parameters.Add(parameter); } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetGetOperationHandler.cs index 9dba9d979..d79848c1e 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetGetOperationHandler.cs @@ -3,11 +3,14 @@ // 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 System.Net.Http; using System.Text.Json.Nodes; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.OData.Common; @@ -36,16 +39,20 @@ public EntitySetGetOperationHandler(OpenApiDocument document) : base(document) /// public override HttpMethod OperationType => HttpMethod.Get; - private ReadRestrictionsType _readRestrictions; + private ReadRestrictionsType? _readRestrictions; protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - _readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - var entityReadRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.ReadRestrictions); - _readRestrictions?.MergePropertiesIfNull(entityReadRestrictions); - _readRestrictions ??= entityReadRestrictions; + if (!string.IsNullOrEmpty(TargetPath)) + _readRestrictions = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + if (Context is not null) + { + var entityReadRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.ReadRestrictions); + _readRestrictions?.MergePropertiesIfNull(entityReadRestrictions); + _readRestrictions ??= entityReadRestrictions; + } } /// @@ -54,10 +61,10 @@ protected override void SetBasicInfo(OpenApiOperation operation) // Summary and Descriptions string placeHolder = "Get entities from " + EntitySet.Name; operation.Summary = _readRestrictions?.Description ?? placeHolder; - operation.Description = _readRestrictions?.LongDescription ?? Context.Model.GetDescriptionAnnotation(EntitySet); + operation.Description = _readRestrictions?.LongDescription ?? Context?.Model.GetDescriptionAnnotation(EntitySet); // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true}) { string typeName = EntitySet.EntityType.Name; operation.OperationId = EntitySet.Name + "." + typeName + ".List" + Utils.UpperFirstChar(typeName); @@ -66,13 +73,14 @@ protected override void SetBasicInfo(OpenApiOperation operation) protected override void SetExtensions(OpenApiOperation operation) { - if (Context.Settings.EnablePagination) + if (Context is {Settings.EnablePagination: true}) { - JsonObject extension = new JsonObject + var extension = new JsonObject { { "nextLinkName", "@odata.nextLink"}, { "operationName", Context.Settings.PageableOperationName} }; + operation.Extensions ??= new Dictionary(); operation.Extensions.Add(Constants.xMsPageable, new OpenApiAny(extension)); base.SetExtensions(operation); @@ -83,41 +91,43 @@ protected override void SetExtensions(OpenApiOperation operation) protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); + if (Context is null) return; // The parameters array contains Parameter Objects for all system query options allowed for this collection, // and it does not list system query options not allowed for this collection, see terms // Capabilities.TopSupported, Capabilities.SkipSupported, Capabilities.SearchRestrictions, // Capabilities.FilterRestrictions, and Capabilities.CountRestrictions // $top - var parameter = Context.CreateTop(TargetPath, _document) ?? Context.CreateTop(EntitySet, _document); + operation.Parameters ??= []; + var parameter = (TargetPath is null ? null : Context.CreateTop(TargetPath, _document)) ?? Context.CreateTop(EntitySet, _document); if (parameter != null) { operation.Parameters.Add(parameter); } // $skip - parameter = Context.CreateSkip(TargetPath, _document) ?? Context.CreateSkip(EntitySet, _document); + parameter = (TargetPath is null ? null : Context.CreateSkip(TargetPath, _document)) ?? Context.CreateSkip(EntitySet, _document); if (parameter != null) { operation.Parameters.Add(parameter); } // $search - parameter = Context.CreateSearch(TargetPath, _document) ?? Context.CreateSearch(EntitySet, _document); + parameter = (TargetPath is null ? null : Context.CreateSearch(TargetPath, _document)) ?? Context.CreateSearch(EntitySet, _document); if (parameter != null) { operation.Parameters.Add(parameter); } // $filter - parameter = Context.CreateFilter(TargetPath, _document) ?? Context.CreateFilter(EntitySet, _document); + parameter = (TargetPath is null ? null : Context.CreateFilter(TargetPath, _document)) ?? Context.CreateFilter(EntitySet, _document); if (parameter != null) { operation.Parameters.Add(parameter); } // $count - parameter = Context.CreateCount(TargetPath, _document) ?? Context.CreateCount(EntitySet, _document); + parameter = (TargetPath is null ? null : Context.CreateCount(TargetPath, _document)) ?? Context.CreateCount(EntitySet, _document); if (parameter != null) { operation.Parameters.Add(parameter); @@ -128,21 +138,21 @@ protected override void SetParameters(OpenApiOperation operation) // of just providing a comma-separated list of properties can be expressed via an array-valued // parameter with an enum constraint // $order - parameter = Context.CreateOrderBy(TargetPath, EntitySet.EntityType) ?? Context.CreateOrderBy(EntitySet); + parameter = (TargetPath is null ? null : Context.CreateOrderBy(TargetPath, EntitySet.EntityType)) ?? Context.CreateOrderBy(EntitySet); if (parameter != null) { operation.Parameters.Add(parameter); } // $select - parameter = Context.CreateSelect(TargetPath, EntitySet.EntityType) ?? Context.CreateSelect(EntitySet); + parameter = (TargetPath is null ? null : Context.CreateSelect(TargetPath, EntitySet.EntityType)) ?? Context.CreateSelect(EntitySet); if (parameter != null) { operation.Parameters.Add(parameter); } // $expand - parameter = Context.CreateExpand(TargetPath, EntitySet.EntityType) ?? Context.CreateExpand(EntitySet); + parameter = (TargetPath is null ? null : Context.CreateExpand(TargetPath, EntitySet.EntityType)) ?? Context.CreateExpand(EntitySet); if (parameter != null) { operation.Parameters.Add(parameter); @@ -155,12 +165,13 @@ protected override void SetResponses(OpenApiOperation operation) operation.Responses = new OpenApiResponses { { - Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, + Context?.Settings.UseSuccessStatusCodeRange ?? false ? Constants.StatusCodeClass2XX : Constants.StatusCode200, new OpenApiResponseReference($"{EntitySet.EntityType.FullName()}{Constants.CollectionSchemaSuffix}", _document) } }; - operation.AddErrorResponses(Context.Settings, _document, false); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, false); base.SetResponses(operation); } @@ -172,7 +183,7 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_readRestrictions.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_readRestrictions.Permissions, _document).ToList(); } protected override void AppendCustomParameters(OpenApiOperation operation) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityGetOperationHandler.cs index 1f6a695b7..43da96434 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityGetOperationHandler.cs @@ -30,7 +30,7 @@ public MediaEntityGetOperationHandler(OpenApiDocument document) : base(document) } /// public override HttpMethod OperationType => HttpMethod.Get; - private ReadRestrictionsType _readRestrictions = null; + private ReadRestrictionsType? _readRestrictions = null; protected override void Initialize(ODataContext context, ODataPath path) { @@ -38,17 +38,18 @@ protected override void Initialize(ODataContext context, ODataPath path) if (Property != null) { - _readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + if (!string.IsNullOrEmpty(TargetPath)) + _readRestrictions = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); if (Property is IEdmNavigationProperty) { - var navigationReadRestrictions = Context.Model.GetRecord(Property, CapabilitiesConstants.NavigationRestrictions)? + var navigationReadRestrictions = Context?.Model.GetRecord(Property, CapabilitiesConstants.NavigationRestrictions)? .RestrictedProperties?.FirstOrDefault()?.ReadRestrictions; _readRestrictions?.MergePropertiesIfNull(navigationReadRestrictions); _readRestrictions ??= navigationReadRestrictions; } else { - var propertyReadRestrictions = Context.Model.GetRecord(Property, CapabilitiesConstants.ReadRestrictions); + var propertyReadRestrictions = Context?.Model.GetRecord(Property, CapabilitiesConstants.ReadRestrictions); _readRestrictions?.MergePropertiesIfNull(propertyReadRestrictions); _readRestrictions ??= propertyReadRestrictions; } @@ -59,34 +60,35 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetBasicInfo(OpenApiOperation operation) { // Summary - string placeholderValue = LastSegmentIsStreamPropertySegment ? Path.LastSegment.Identifier : "media content"; + var placeholderValue = LastSegmentIsStreamPropertySegment ? Path?.LastSegment?.Identifier : "media content"; operation.Summary = _readRestrictions?.Description; operation.Summary ??= IsNavigationPropertyPath ? $"Get {placeholderValue} for the navigation property {NavigationProperty.Name} from {NavigationSourceSegment.NavigationSource.Name}" : $"Get {placeholderValue} for {NavigationSourceSegment.EntityType.Name} from {NavigationSourceSegment.Identifier}"; // Description - string description; + string? description; if (Property is IEdmNavigationProperty) { description = LastSegmentIsKeySegment ? _readRestrictions?.ReadByKeyRestrictions?.LongDescription : _readRestrictions?.LongDescription - ?? Context.Model.GetDescriptionAnnotation(Property); + ?? Context?.Model.GetDescriptionAnnotation(Property); } else { // Structural property - description = _readRestrictions?.LongDescription ?? Context.Model.GetDescriptionAnnotation(Property); + description = _readRestrictions?.LongDescription ?? Context?.Model.GetDescriptionAnnotation(Property); } - operation.Description = description; + if (!string.IsNullOrEmpty(description)) + operation.Description = description; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true} && + (LastSegmentIsStreamPropertySegment ? Path?.LastSegment?.Identifier : "Content") is string identifier) { - string identifier = LastSegmentIsStreamPropertySegment ? Path.LastSegment.Identifier : "Content"; operation.OperationId = GetOperationId("Get", identifier); } } @@ -97,7 +99,7 @@ protected override void SetResponses(OpenApiOperation operation) operation.Responses = new OpenApiResponses { { - Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, + Context?.Settings.UseSuccessStatusCodeRange ?? false ? Constants.StatusCodeClass2XX : Constants.StatusCode200, new OpenApiResponse { Description = "Retrieved media content", @@ -105,7 +107,8 @@ protected override void SetResponses(OpenApiOperation operation) } } }; - operation.AddErrorResponses(Context.Settings, _document, false); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, false); base.SetResponses(operation); } @@ -114,8 +117,7 @@ protected override void SetResponses(OpenApiOperation operation) protected override void SetSecurity(OpenApiOperation operation) { IEdmVocabularyAnnotatable annotatableNavigationSource = (IEdmVocabularyAnnotatable)NavigationSourceSegment.NavigationSource; - ReadRestrictionsType read = Context.Model.GetRecord(annotatableNavigationSource, CapabilitiesConstants.ReadRestrictions); - if (read == null) + if (Context?.Model.GetRecord(annotatableNavigationSource, CapabilitiesConstants.ReadRestrictions) is not {} read) { return; } @@ -126,7 +128,7 @@ protected override void SetSecurity(OpenApiOperation operation) readBase = read.ReadByKeyRestrictions; } - if (readBase == null && readBase.Permissions == null) + if (readBase == null || readBase.Permissions == null) { return; } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityOperationalHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityOperationalHandler.cs index 4a4fc6fa4..cc954648c 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityOperationalHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityOperationalHandler.cs @@ -10,6 +10,7 @@ using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; using Microsoft.OpenApi.OData.Vocabulary.Core; +using System; using System.Collections.Generic; using System.Linq; @@ -31,7 +32,7 @@ protected MediaEntityOperationalHandler(OpenApiDocument document) : base(documen /// /// Gets/Sets the NavigationSource segment /// - protected ODataNavigationSourceSegment NavigationSourceSegment { get; private set; } + protected ODataNavigationSourceSegment? NavigationSourceSegment { get; private set; } /// /// Gets/Sets flag indicating whether path is navigation property path @@ -50,12 +51,12 @@ protected MediaEntityOperationalHandler(OpenApiDocument document) : base(documen /// /// Gets the media entity property. /// - protected IEdmProperty Property { get; private set; } + protected IEdmProperty? Property { get; private set; } /// /// Gets the navigation property. /// - protected IEdmNavigationProperty NavigationProperty { get; private set; } + protected IEdmNavigationProperty? NavigationProperty { get; private set; } /// protected override void Initialize(ODataContext context, ODataPath path) @@ -64,12 +65,13 @@ protected override void Initialize(ODataContext context, ODataPath path) NavigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; // Check whether path is a navigation property path - IsNavigationPropertyPath = Path.Segments.Contains( - Path.Segments.FirstOrDefault(segment => segment is ODataNavigationPropertySegment)); + IsNavigationPropertyPath = Path is not null && + Path.Segments.OfType().FirstOrDefault() is {} firstPropSegment && + Path.Segments.Contains(firstPropSegment); - LastSegmentIsStreamPropertySegment = Path.LastSegment.Kind == ODataSegmentKind.StreamProperty; + LastSegmentIsStreamPropertySegment = Path?.LastSegment?.Kind == ODataSegmentKind.StreamProperty; - LastSegmentIsStreamContentSegment = Path.LastSegment.Kind == ODataSegmentKind.StreamContent; + LastSegmentIsStreamContentSegment = Path?.LastSegment?.Kind == ODataSegmentKind.StreamContent; LastSegmentIsKeySegment = path.LastSegment is ODataKeySegment; @@ -87,12 +89,12 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetTags(OpenApiOperation operation) { - string tagIdentifier = IsNavigationPropertyPath + string tagIdentifier = IsNavigationPropertyPath && Path is not null && Context is not null ? EdmModelHelper.GenerateNavigationPropertyPathTagName(Path, Context) - : NavigationSourceSegment.Identifier + "." + NavigationSourceSegment.EntityType.Name; + : NavigationSourceSegment?.Identifier + "." + NavigationSourceSegment?.EntityType.Name; - Context.AddExtensionToTag(tagIdentifier, Constants.xMsTocType, new OpenApiAny("page"), () => new OpenApiTag() + Context?.AddExtensionToTag(tagIdentifier, Constants.xMsTocType, new OpenApiAny("page"), () => new OpenApiTag() { Name = tagIdentifier }); @@ -118,17 +120,19 @@ protected string GetOperationId(string prefix, string identifier) Utils.CheckArgumentNullOrEmpty(prefix, nameof(prefix)); Utils.CheckArgumentNullOrEmpty(identifier, nameof(identifier)); - var items = new List + var items = NavigationSourceSegment is null ? [] : new List { NavigationSourceSegment.Identifier }; + if (Path is null) throw new InvalidOperationException("Path is null."); + ODataSegment lastSegment = Path.Segments.Last(c => c is ODataStreamContentSegment || c is ODataStreamPropertySegment); foreach (ODataSegment segment in Path.Segments.Skip(1)) { if (segment == lastSegment) { - if (!IsNavigationPropertyPath) + if (!IsNavigationPropertyPath && NavigationSourceSegment is not null) { string typeName = NavigationSourceSegment.EntityType.Name; items.Add(typeName); @@ -138,8 +142,11 @@ protected string GetOperationId(string prefix, string identifier) { // Remove the last navigation property segment for navigation property paths, // as this will be included within the prefixed name of the operation id - items.Remove(NavigationProperty.Name); - items.Add(prefix + Utils.UpperFirstChar(NavigationProperty.Name) + Utils.UpperFirstChar(identifier)); + if (NavigationProperty is not null) + { + items.Remove(NavigationProperty.Name); + items.Add(prefix + Utils.UpperFirstChar(NavigationProperty.Name) + Utils.UpperFirstChar(identifier)); + } } break; } @@ -152,7 +159,7 @@ protected string GetOperationId(string prefix, string identifier) } } - return $"{string.Join(".", items)}-{Path.GetPathHash(Context.Settings)}"; + return $"{string.Join(".", items)}-{Path.GetPathHash(Context?.Settings ?? new())}"; } /// @@ -163,12 +170,6 @@ protected IDictionary GetContentDescription() { // Fetch the respective AcceptableMediaTypes (_, var property) = GetStreamElements(); - IEnumerable mediaTypes = null; - if (property != null) - { - mediaTypes = Context.Model.GetCollection(property, - CoreConstants.AcceptableMediaTypes); - } OpenApiSchema schema = new() { @@ -177,7 +178,9 @@ protected IDictionary GetContentDescription() }; var content = new Dictionary(); - if (mediaTypes != null) + if (property is not null && + Context?.Model.GetCollection(property, + CoreConstants.AcceptableMediaTypes) is {} mediaTypes) { foreach (string item in mediaTypes) { diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/MetadataGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/MetadataGetOperationHandler.cs index 4ec24a1ee..9b453baf8 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/MetadataGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/MetadataGetOperationHandler.cs @@ -60,7 +60,7 @@ protected override void SetResponses(OpenApiOperation operation) operation.Responses = new OpenApiResponses { { - Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, + Context?.Settings.UseSuccessStatusCodeRange ?? false ? Constants.StatusCodeClass2XX : Constants.StatusCode200, new OpenApiResponse { Description = "Retrieved metadata document", @@ -77,7 +77,8 @@ protected override void SetResponses(OpenApiOperation operation) } } }; - operation.AddErrorResponses(Context.Settings, _document, false); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, false); base.SetResponses(operation); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs index ab9e9f9f5..49a271198 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs @@ -95,7 +95,7 @@ protected override void SetResponses(OpenApiOperation operation) IDictionary? links = null; if (Context is { Settings.ShowLinks: true } && NavigationProperty is not null && Path is not null) { - string operationId = GetOperationId(); + var operationId = GetOperationId(); links = Context.CreateLinks(entityType: NavigationProperty.ToEntityType(), entityName: NavigationProperty.Name, entityKind: NavigationProperty.PropertyKind.ToString(), path: Path, parameters: PathParameters, From 6827d889de3b24800ad761c13ead18f11a54bff3 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 25 Mar 2025 10:58:40 -0400 Subject: [PATCH 08/24] chore: another batch of NRT fixes Signed-off-by: Vincent Biret --- .../Common/EdmModelHelper.cs | 4 +- .../Edm/ODataPath.cs | 6 +- .../Edm/ODataPathProvider.cs | 76 ++++++++++--------- .../Operation/EdmFunctionOperationHandler.cs | 4 +- .../EntitySetPostOperationHandler.cs | 40 +++++----- .../MediaEntityGetOperationHandler.cs | 4 +- .../MediaEntityPutOperationHandler.cs | 33 ++++---- .../PublicAPI.Unshipped.txt | 2 +- 8 files changed, 88 insertions(+), 81 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Common/EdmModelHelper.cs b/src/Microsoft.OpenApi.OData.Reader/Common/EdmModelHelper.cs index 6a8490386..7c057ab11 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Common/EdmModelHelper.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Common/EdmModelHelper.cs @@ -60,8 +60,8 @@ internal static class EdmModelHelper /// The . /// true, if navigability is allowed, otherwise false. internal static bool NavigationRestrictionsAllowsNavigability( - NavigationRestrictionsType restrictionType, - NavigationPropertyRestriction restrictionProperty) + NavigationRestrictionsType? restrictionType, + NavigationPropertyRestriction? restrictionProperty) { // Verify using individual navigation restriction first if (restrictionProperty?.Navigability != null && restrictionProperty.Navigability.Value == NavigationType.None) diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPath.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPath.cs index 85073fba3..856a5c893 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPath.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPath.cs @@ -287,7 +287,7 @@ public override string ToString() return PathTemplate; } - return "/" + String.Join("/", Segments.Select(e => e.Kind)); + return "/" + string.Join("/", Segments.Select(e => e.Kind)); } /// @@ -295,9 +295,9 @@ public override string ToString() /// /// The compare to ODataPath. /// true/false - public int CompareTo(ODataPath other) + public int CompareTo(ODataPath? other) { - return GetPathItemName().CompareTo(other.GetPathItemName()); + return GetPathItemName().CompareTo(other?.GetPathItemName()); } private ODataPathKind CalcPathType() diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs index 5ac8315a6..896f36068 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs @@ -142,9 +142,9 @@ private void AppendPath(ODataPath path) case ODataPathKind.MediaEntity: if (path.FirstSegment is ODataNavigationSourceSegment navigationSourceSegment) { - if(!_allNavigationSourcePaths.TryGetValue(navigationSourceSegment.EntityType, out IList nsList)) + if(!_allNavigationSourcePaths.TryGetValue(navigationSourceSegment.EntityType, out var nsList)) { - nsList = new List(); + nsList = []; _allNavigationSourcePaths[navigationSourceSegment.EntityType] = nsList; } @@ -157,9 +157,9 @@ private void AppendPath(ODataPath path) } else { - if (!_dollarCountPaths.TryGetValue(navigationSourceSegment.EntityType, out IList dollarPathList)) + if (!_dollarCountPaths.TryGetValue(navigationSourceSegment.EntityType, out var dollarPathList)) { - dollarPathList = new List(); + dollarPathList = []; _dollarCountPaths[navigationSourceSegment.EntityType] = dollarPathList; } dollarPathList.Add(path); @@ -174,9 +174,9 @@ private void AppendPath(ODataPath path) case ODataPathKind.Ref: ODataNavigationPropertySegment navigationPropertySegment = path.OfType().Last(); - if (!_allNavigationPropertyPaths.TryGetValue(navigationPropertySegment.EntityType, out IList npList)) + if (!_allNavigationPropertyPaths.TryGetValue(navigationPropertySegment.EntityType, out var npList)) { - npList = new List(); + npList = []; _allNavigationPropertyPaths[navigationPropertySegment.EntityType] = npList; } @@ -190,7 +190,7 @@ private void AppendPath(ODataPath path) foreach (var kvp in _dollarCountPaths) { if (kvp.Value.FirstOrDefault(p => DollarCountAndOperationPathsSimilar(p, path)) is ODataPath dollarCountPath && - _allNavigationSourcePaths.TryGetValue(kvp.Key, out IList dollarPathList)) + _allNavigationSourcePaths.TryGetValue(kvp.Key, out var dollarPathList)) { dollarPathList.Remove(dollarCountPath); break; @@ -208,9 +208,9 @@ private void AppendPath(ODataPath path) bool DollarCountAndOperationPathsSimilar(ODataPath path1, ODataPath path2) { if ((path1.Kind == ODataPathKind.DollarCount && - path2.Kind == ODataPathKind.Operation && path2.LastSegment.Identifier.Equals(Constants.CountSegmentIdentifier, StringComparison.OrdinalIgnoreCase)) || + path2.Kind == ODataPathKind.Operation && Constants.CountSegmentIdentifier.Equals(path2.LastSegment?.Identifier, StringComparison.OrdinalIgnoreCase)) || (path2.Kind == ODataPathKind.DollarCount && - path1.Kind == ODataPathKind.Operation && path1.LastSegment.Identifier.Equals(Constants.CountSegmentIdentifier, StringComparison.OrdinalIgnoreCase))) + path1.Kind == ODataPathKind.Operation && Constants.CountSegmentIdentifier.Equals(path1.LastSegment?.Identifier, StringComparison.OrdinalIgnoreCase))) { return GetModifiedPathItemName(path1)?.Equals(GetModifiedPathItemName(path2), StringComparison.OrdinalIgnoreCase) ?? false; } @@ -218,9 +218,9 @@ bool DollarCountAndOperationPathsSimilar(ODataPath path1, ODataPath path2) return false; } - string GetModifiedPathItemName(ODataPath path) + string? GetModifiedPathItemName(ODataPath path) { - if (!path.Any()) return null; + if (path.Count == 0) return null; IEnumerable modifiedSegments = path.Take(path.Count - 1); ODataPath modifiedPath = new(modifiedSegments); @@ -242,14 +242,15 @@ private void RetrieveNavigationSourcePaths(IEdmNavigationSource navigationSource ODataPath path = new(new ODataNavigationSourceSegment(navigationSource)); AppendPath(path.Clone()); - IEdmEntitySet entitySet = navigationSource as IEdmEntitySet; IEdmEntityType entityType = navigationSource.EntityType; - CountRestrictionsType count = null; + CountRestrictionsType? count = null; bool? indexableByKey = false; + var entitySetIsNull = true; // for entity set, create a path with key and a $count path - if (entitySet != null) + if (navigationSource is IEdmEntitySet entitySet && _model is not null) { + entitySetIsNull = false; string targetPath = path.GetTargetPath(_model); count = _model.GetRecord(targetPath, CapabilitiesConstants.CountRestrictions) ?? _model.GetRecord(entitySet, CapabilitiesConstants.CountRestrictions); @@ -291,13 +292,13 @@ private void RetrieveNavigationSourcePaths(IEdmNavigationSource navigationSource } } - if (entitySet != null && (indexableByKey ?? true)) + if (!entitySetIsNull && (indexableByKey ?? true)) { path.Pop(); // end of entity } path.Pop(); // end of navigation source. - Debug.Assert(path.Any() == false); + Debug.Assert(path.Count == 0); } /// @@ -312,7 +313,7 @@ private void RetrieveComplexPropertyPaths(IEdmEntityType entityType, ODataPath c Utils.CheckArgumentNull(currentPath, nameof(currentPath)); Utils.CheckArgumentNull(convertSettings, nameof(convertSettings)); - if (!convertSettings.EnableNavigationPropertyPath) return; + if (!convertSettings.EnableNavigationPropertyPath || _model is null) return; foreach (IEdmStructuralProperty sp in entityType.StructuralProperties() .Where(x => x.Type.IsComplex() || @@ -327,9 +328,9 @@ private void RetrieveComplexPropertyPaths(IEdmEntityType entityType, ODataPath c } AppendPath(currentPath.Clone()); - if (sp.Type.IsCollection()) + if (sp.Type.IsCollection() && sp.Type.Definition.AsElementType() is IEdmComplexType elemType) { - CreateTypeCastPaths(currentPath, convertSettings, sp.Type.Definition.AsElementType() as IEdmComplexType, sp, true); + CreateTypeCastPaths(currentPath, convertSettings, elemType, sp, true); var isCountable = _model.GetRecord(targetPath, CapabilitiesConstants.CountRestrictions)?.IsCountable ?? _model.GetRecord(sp, CapabilitiesConstants.CountRestrictions)?.IsCountable ?? true; @@ -373,7 +374,7 @@ private bool RetrieveComplexTypeNavigationPropertyPaths(IEdmComplexType complexT .Distinct() .Where(CanFilter); - if (!navigationProperties.Any()) return false; + if (!navigationProperties.Any() || _model is null) return false; foreach (var np in navigationProperties) { @@ -434,14 +435,14 @@ private bool ShouldCreateComplexPropertyPaths(IEdmStructuralProperty complexProp if (!convertSettings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths) return true; - bool isReadable = _model.GetRecord(targetPath, CapabilitiesConstants.ReadRestrictions)?.Readable - ?? _model.GetRecord(complexProperty, CapabilitiesConstants.ReadRestrictions)?.Readable + bool isReadable = _model?.GetRecord(targetPath, CapabilitiesConstants.ReadRestrictions)?.Readable + ?? _model?.GetRecord(complexProperty, CapabilitiesConstants.ReadRestrictions)?.Readable ?? false; - bool isUpdatable = _model.GetRecord(targetPath, CapabilitiesConstants.UpdateRestrictions)?.Updatable - ??_model.GetRecord(complexProperty, CapabilitiesConstants.UpdateRestrictions)?.Updatable + bool isUpdatable = _model?.GetRecord(targetPath, CapabilitiesConstants.UpdateRestrictions)?.Updatable + ??_model?.GetRecord(complexProperty, CapabilitiesConstants.UpdateRestrictions)?.Updatable ?? false; - bool isInsertable = _model.GetRecord(targetPath, CapabilitiesConstants.InsertRestrictions)?.Insertable - ?? _model.GetRecord(complexProperty, CapabilitiesConstants.InsertRestrictions)?.Insertable + bool isInsertable = _model?.GetRecord(targetPath, CapabilitiesConstants.InsertRestrictions)?.Insertable + ?? _model?.GetRecord(complexProperty, CapabilitiesConstants.InsertRestrictions)?.Insertable ?? false; return isReadable || isUpdatable || isInsertable; @@ -494,10 +495,10 @@ private void RetrieveMediaEntityStreamPaths(IEdmEntityType entityType, ODataPath /// A stack that holds the visited navigation properties in the . private void RetrieveNavigationPropertyPaths( IEdmNavigationProperty navigationProperty, - CountRestrictionsType count, + CountRestrictionsType? count, ODataPath currentPath, OpenApiConvertSettings convertSettings, - Stack visitedNavigationProperties = null) + Stack? visitedNavigationProperties = null) { Utils.CheckArgumentNull(navigationProperty, nameof(navigationProperty)); Utils.CheckArgumentNull(currentPath, nameof(currentPath)); @@ -519,17 +520,17 @@ private void RetrieveNavigationPropertyPaths( // Get the annotatable navigation source for this navigation property. IEdmVocabularyAnnotatable annotatableNavigationSource = (currentPath.FirstSegment as ODataNavigationSourceSegment)?.NavigationSource as IEdmVocabularyAnnotatable; - NavigationRestrictionsType navSourceRestrictionType = null; - NavigationRestrictionsType navPropRestrictionType = null; + NavigationRestrictionsType? navSourceRestrictionType = null; + NavigationRestrictionsType? navPropRestrictionType = null; // Get the NavigationRestrictions referenced by this navigation property: Can be defined in the navigation source or in-lined in the navigation property. - if (annotatableNavigationSource != null) + if (annotatableNavigationSource != null && _model is not null) { navSourceRestrictionType = _model.GetRecord(annotatableNavigationSource, CapabilitiesConstants.NavigationRestrictions); navPropRestrictionType = _model.GetRecord(navigationProperty, CapabilitiesConstants.NavigationRestrictions); } - NavigationPropertyRestriction restriction = navSourceRestrictionType?.RestrictedProperties? + NavigationPropertyRestriction? restriction = navSourceRestrictionType?.RestrictedProperties? .FirstOrDefault(r => r.NavigationProperty == currentPath.NavigationPropertyPath(navigationProperty.Name)) ?? navPropRestrictionType?.RestrictedProperties?.FirstOrDefault(); @@ -1162,10 +1163,13 @@ private void AppendBoundOperationOnDerivedNavigationPropertyPath( continue; } - ODataPath newPath = path.Clone(); - newPath.Push(new ODataTypeCastSegment(bindingEntityType, _model)); - newPath.Push(new ODataOperationSegment(edmOperation, isEscapedFunction, _model)); - AppendPath(newPath); + if (_model is not null) + { + ODataPath newPath = path.Clone(); + newPath.Push(new ODataTypeCastSegment(bindingEntityType, _model)); + newPath.Push(new ODataOperationSegment(edmOperation, isEscapedFunction, _model)); + AppendPath(newPath); + } } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionOperationHandler.cs index e252492d7..b291a33ad 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionOperationHandler.cs @@ -41,8 +41,8 @@ protected override void SetBasicInfo(OpenApiOperation operation) { base.SetBasicInfo(operation); - ReadRestrictionsType readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - ReadRestrictionsType operationReadRestrictions = Context.Model.GetRecord(EdmOperation, CapabilitiesConstants.ReadRestrictions); + var readRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + var operationReadRestrictions = Context?.Model.GetRecord(EdmOperation, CapabilitiesConstants.ReadRestrictions); readRestrictions?.MergePropertiesIfNull(operationReadRestrictions); readRestrictions ??= operationReadRestrictions; diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetPostOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetPostOperationHandler.cs index 046ba8380..4364e7a23 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetPostOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetPostOperationHandler.cs @@ -36,16 +36,20 @@ public EntitySetPostOperationHandler(OpenApiDocument document) : base(document) /// public override HttpMethod OperationType => HttpMethod.Post; - private InsertRestrictionsType _insertRestrictions; + private InsertRestrictionsType? _insertRestrictions; protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - _insertRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); - var entityInsertRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.InsertRestrictions); - _insertRestrictions?.MergePropertiesIfNull(entityInsertRestrictions); - _insertRestrictions ??= entityInsertRestrictions; + if (!string.IsNullOrEmpty(TargetPath)) + _insertRestrictions = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); + if (Context is not null) + { + var entityInsertRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.InsertRestrictions); + _insertRestrictions?.MergePropertiesIfNull(entityInsertRestrictions); + _insertRestrictions ??= entityInsertRestrictions; + } } /// @@ -57,7 +61,7 @@ protected override void SetBasicInfo(OpenApiOperation operation) operation.Description = _insertRestrictions?.LongDescription; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true}) { string typeName = EntitySet.EntityType.Name; operation.OperationId = EntitySet.Name + "." + typeName + ".Create" + Utils.UpperFirstChar(typeName); @@ -85,7 +89,7 @@ protected override void SetResponses(OpenApiOperation operation) operation.Responses = new OpenApiResponses { { - Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode201, + Context?.Settings.UseSuccessStatusCodeRange ?? false ? Constants.StatusCodeClass2XX : Constants.StatusCode201, new OpenApiResponse { Description = "Created entity", @@ -94,7 +98,8 @@ protected override void SetResponses(OpenApiOperation operation) } }; - operation.AddErrorResponses(Context.Settings, _document, false); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, false); base.SetResponses(operation); } @@ -106,7 +111,7 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_insertRestrictions.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_insertRestrictions.Permissions, _document).ToList(); } protected override void AppendCustomParameters(OpenApiOperation operation) @@ -131,17 +136,15 @@ protected override void AppendCustomParameters(OpenApiOperation operation) /// Get the entity content description. /// /// The entity content description. - private IDictionary GetContentDescription() + private IDictionary GetContentDescription() { var schema = GetEntitySchema(); - var content = new Dictionary(); + var content = new Dictionary(); if (EntitySet.EntityType.HasStream) { - IEnumerable mediaTypes = Context.Model.GetCollection(EntitySet.EntityType, - CoreConstants.AcceptableMediaTypes); - - if (mediaTypes != null) + if (Context?.Model.GetCollection(EntitySet.EntityType, + CoreConstants.AcceptableMediaTypes) is {} mediaTypes) { foreach (string item in mediaTypes) { @@ -164,8 +167,7 @@ private IDictionary GetContentDescription() else { // Add the annotated request content media types - IEnumerable mediaTypes = _insertRestrictions?.RequestContentTypes; - if (mediaTypes != null) + if (_insertRestrictions?.RequestContentTypes is {} mediaTypes) { foreach (string mediaType in mediaTypes) { @@ -192,9 +194,9 @@ private IDictionary GetContentDescription() /// Get the entity schema. /// /// The entity schema. - private IOpenApiSchema GetEntitySchema() + private IOpenApiSchema? GetEntitySchema() { - return Context.Settings.EnableDerivedTypesReferencesForRequestBody ? + return Context?.Settings.EnableDerivedTypesReferencesForRequestBody ?? false ? EdmModelHelper.GetDerivedTypesReferenceSchema(EntitySet.EntityType, Context.Model, _document) : new OpenApiSchemaReference(EntitySet.EntityType.FullName(), _document); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityGetOperationHandler.cs index 43da96434..f6b86d60c 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityGetOperationHandler.cs @@ -63,8 +63,8 @@ protected override void SetBasicInfo(OpenApiOperation operation) var placeholderValue = LastSegmentIsStreamPropertySegment ? Path?.LastSegment?.Identifier : "media content"; operation.Summary = _readRestrictions?.Description; operation.Summary ??= IsNavigationPropertyPath - ? $"Get {placeholderValue} for the navigation property {NavigationProperty.Name} from {NavigationSourceSegment.NavigationSource.Name}" - : $"Get {placeholderValue} for {NavigationSourceSegment.EntityType.Name} from {NavigationSourceSegment.Identifier}"; + ? $"Get {placeholderValue} for the navigation property {NavigationProperty?.Name} from {NavigationSourceSegment?.NavigationSource.Name}" + : $"Get {placeholderValue} for {NavigationSourceSegment?.EntityType.Name} from {NavigationSourceSegment?.Identifier}"; // Description string? description; diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityPutOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityPutOperationHandler.cs index 0fde994a4..66db24322 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityPutOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityPutOperationHandler.cs @@ -33,7 +33,7 @@ public MediaEntityPutOperationHandler(OpenApiDocument document):base(document) /// public override HttpMethod OperationType => HttpMethod.Put; - private UpdateRestrictionsType _updateRestrictions = null; + private UpdateRestrictionsType? _updateRestrictions = null; protected override void Initialize(ODataContext context, ODataPath path) { @@ -41,17 +41,18 @@ protected override void Initialize(ODataContext context, ODataPath path) if (Property != null) { - _updateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); + if (!string.IsNullOrEmpty(TargetPath)) + _updateRestrictions = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); if (Property is IEdmNavigationProperty) { - var navigationUpdateRestrictions = Context.Model.GetRecord(Property, CapabilitiesConstants.NavigationRestrictions)? + var navigationUpdateRestrictions = Context?.Model.GetRecord(Property, CapabilitiesConstants.NavigationRestrictions)? .RestrictedProperties?.FirstOrDefault()?.UpdateRestrictions; _updateRestrictions?.MergePropertiesIfNull(navigationUpdateRestrictions); _updateRestrictions ??= navigationUpdateRestrictions; } else { - var propertyUpdateRestrictions = Context.Model.GetRecord(Property, CapabilitiesConstants.UpdateRestrictions); + var propertyUpdateRestrictions = Context?.Model.GetRecord(Property, CapabilitiesConstants.UpdateRestrictions); _updateRestrictions?.MergePropertiesIfNull(propertyUpdateRestrictions); _updateRestrictions ??= propertyUpdateRestrictions; } @@ -62,19 +63,19 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetBasicInfo(OpenApiOperation operation) { // Summary - string placeholderValue = LastSegmentIsStreamPropertySegment ? Path.LastSegment.Identifier : "media content"; + var placeholderValue = LastSegmentIsStreamPropertySegment ? Path?.LastSegment?.Identifier : "media content"; operation.Summary = _updateRestrictions?.Description; operation.Summary ??= IsNavigationPropertyPath - ? $"Update {placeholderValue} for the navigation property {NavigationProperty.Name} in {NavigationSourceSegment.NavigationSource.Name}" - : $"Update {placeholderValue} for {NavigationSourceSegment.EntityType.Name} in {NavigationSourceSegment.Identifier}"; + ? $"Update {placeholderValue} for the navigation property {NavigationProperty?.Name} in {NavigationSourceSegment?.NavigationSource.Name}" + : $"Update {placeholderValue} for {NavigationSourceSegment?.EntityType.Name} in {NavigationSourceSegment?.Identifier}"; // Description - operation.Description = _updateRestrictions?.LongDescription ?? Context.Model.GetDescriptionAnnotation(Property); + operation.Description = _updateRestrictions?.LongDescription ?? Context?.Model.GetDescriptionAnnotation(Property); // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true}) { - string identifier = LastSegmentIsStreamPropertySegment ? Path.LastSegment.Identifier : "Content"; + var identifier = LastSegmentIsStreamPropertySegment && Path?.LastSegment?.Identifier is string lastIdentifier ? lastIdentifier : "Content"; operation.OperationId = GetOperationId("Update", identifier); } } @@ -95,18 +96,18 @@ protected override void SetRequestBody(OpenApiOperation operation) /// protected override void SetResponses(OpenApiOperation operation) { - if (LastSegmentIsStreamPropertySegment && Path.LastSegment.Identifier.Equals(Constants.Content, StringComparison.OrdinalIgnoreCase)) + if (LastSegmentIsStreamPropertySegment && Constants.Content.Equals(Path?.LastSegment?.Identifier, StringComparison.OrdinalIgnoreCase)) { // Get the entity type declaring this stream property. (var entityType, _) = GetStreamElements(); var schema = new OpenApiSchemaReference(entityType.FullName(), _document); - operation.AddErrorResponses(Context.Settings, _document, addNoContent: true, schema: schema); + operation.AddErrorResponses(Context?.Settings ?? new(), _document, addNoContent: true, schema: schema); } else { - operation.AddErrorResponses(Context.Settings, _document, true); + operation.AddErrorResponses(Context?.Settings ?? new(), _document, true); } base.SetResponses(operation); @@ -115,9 +116,9 @@ protected override void SetResponses(OpenApiOperation operation) /// protected override void SetSecurity(OpenApiOperation operation) { - IEdmVocabularyAnnotatable annotatableNavigationSource = (IEdmVocabularyAnnotatable)NavigationSourceSegment.NavigationSource; - UpdateRestrictionsType update = Context.Model.GetRecord(annotatableNavigationSource, CapabilitiesConstants.UpdateRestrictions); - if (update == null || update.Permissions == null) + if (NavigationSourceSegment?.NavigationSource is not IEdmVocabularyAnnotatable annotatableNavigationSource || + Context?.Model.GetRecord(annotatableNavigationSource, CapabilitiesConstants.UpdateRestrictions) is not {} update || + update.Permissions == null) { return; } diff --git a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt index d1362972b..9c2e9cb2b 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt +++ b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt @@ -45,7 +45,7 @@ Microsoft.OpenApi.OData.Edm.ODataOperationSegment.Operation.get -> Microsoft.ODa Microsoft.OpenApi.OData.Edm.ODataOperationSegment.ParameterMappings.get -> System.Collections.Generic.IDictionary? Microsoft.OpenApi.OData.Edm.ODataPath Microsoft.OpenApi.OData.Edm.ODataPath.Clone() -> Microsoft.OpenApi.OData.Edm.ODataPath! -Microsoft.OpenApi.OData.Edm.ODataPath.CompareTo(Microsoft.OpenApi.OData.Edm.ODataPath! other) -> int +Microsoft.OpenApi.OData.Edm.ODataPath.CompareTo(Microsoft.OpenApi.OData.Edm.ODataPath? other) -> int Microsoft.OpenApi.OData.Edm.ODataPath.Count.get -> int Microsoft.OpenApi.OData.Edm.ODataPath.FirstSegment.get -> Microsoft.OpenApi.OData.Edm.ODataSegment? Microsoft.OpenApi.OData.Edm.ODataPath.GetCount(bool keySegmentAsDepth) -> int From 4ab5808d189002e1a5f8c3aa8395ddd0a0e73b30 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 25 Mar 2025 16:25:21 -0400 Subject: [PATCH 09/24] chore: additional NRT fixes Signed-off-by: Vincent Biret --- .../Edm/ODataOperationSegment.cs | 12 ++- .../Edm/ODataSegment.cs | 8 +- .../Operation/EdmOperationOperationHandler.cs | 79 +++++++++++-------- .../Operation/EntitySetOperationHandler.cs | 19 ++--- .../Operation/EntityUpdateOperationHandler.cs | 43 +++++----- .../MediaEntityDeleteOperationHandler.cs | 8 +- .../MediaEntityGetOperationHandler.cs | 4 +- .../Operation/MetadataGetOperationHandler.cs | 2 +- .../PublicAPI.Unshipped.txt | 10 +-- 9 files changed, 100 insertions(+), 85 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataOperationSegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataOperationSegment.cs index 4da501dd6..fabee69ce 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataOperationSegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataOperationSegment.cs @@ -72,7 +72,7 @@ public ODataOperationSegment(IEdmOperation operation, bool isEscapedFunction, IE _model = model ?? throw Error.ArgumentNull(nameof(model)); } - private readonly IEdmModel _model; + private readonly IEdmModel? _model; /// /// Gets the parameter mappings. @@ -99,7 +99,7 @@ public ODataOperationSegment(IEdmOperation operation, bool isEscapedFunction, IE public override IEdmEntityType? EntityType => null; /// - public override string GetPathItemName(OpenApiConvertSettings settings, HashSet parameters) + public override string? GetPathItemName(OpenApiConvertSettings settings, HashSet parameters) { Utils.CheckArgumentNull(settings, nameof(settings)); @@ -108,7 +108,7 @@ public override string GetPathItemName(OpenApiConvertSettings settings, HashSet< return FunctionName(function, settings, parameters); } - return OperationName(Operation, settings); + return Operation is null ? null : OperationName(Operation, settings); } internal IDictionary GetNameMapping(OpenApiConvertSettings settings, HashSet parameters) @@ -155,8 +155,6 @@ private string FunctionName(IEdmFunction function, OpenApiConvertSettings settin { if (settings.EnableUriEscapeFunctionCall && IsEscapedFunction) { - // Debug.Assert(function.Parameters.Count == 2); It should be verify at Edm model. - // Debug.Assert(function.IsBound == true); string parameterName = function.Parameters.Last().Name; string uniqueName = Utils.GetUniqueName(parameterName, parameters); if (function.IsComposable) @@ -171,7 +169,7 @@ private string FunctionName(IEdmFunction function, OpenApiConvertSettings settin StringBuilder functionName = new(); functionName.Append(OperationName(function, settings)); - functionName.Append("("); + functionName.Append('('); int skip = function.IsBound ? 1 : 0; functionName.Append(string.Join(",", function.Parameters.Skip(skip).Select(p => @@ -183,7 +181,7 @@ private string FunctionName(IEdmFunction function, OpenApiConvertSettings settin : p.Name + $"={quote}{{{uniqueName}}}{quote}"; }))); - functionName.Append(")"); + functionName.Append(')'); return functionName.ToString(); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataSegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataSegment.cs index 515ea7385..b9eeb31a4 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataSegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataSegment.cs @@ -86,7 +86,7 @@ public abstract class ODataSegment /// /// Gets the entity type of current segment. /// - public virtual IEdmEntityType EntityType => throw new NotImplementedException(); + public virtual IEdmEntityType? EntityType => throw new NotImplementedException(); /// /// Gets the kind of this segment. @@ -96,14 +96,14 @@ public abstract class ODataSegment /// /// Gets the identifier of this segment. /// - public abstract string Identifier { get; } + public abstract string? Identifier { get; } /// /// Gets the path item name for this segment. /// /// The settings. /// The path item name. - public string GetPathItemName(OpenApiConvertSettings settings) + public string? GetPathItemName(OpenApiConvertSettings settings) { return GetPathItemName(settings, []); } @@ -125,7 +125,7 @@ public string GetPathHash(OpenApiConvertSettings settings, ODataPath? path = def /// The settings. /// The existing parameters. /// The path item name. - public abstract string GetPathItemName(OpenApiConvertSettings settings, HashSet parameters); + public abstract string? GetPathItemName(OpenApiConvertSettings settings, HashSet parameters); /// /// Returns the list of this segment refers to. diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationOperationHandler.cs index 68e7d4149..bcc644713 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationOperationHandler.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 System.Text.Json.Nodes; @@ -32,22 +33,22 @@ protected EdmOperationOperationHandler(OpenApiDocument document) : base(document { } - private OperationRestrictionsType _operationRestriction; + private OperationRestrictionsType? _operationRestriction; /// /// Gets the navigation source. /// - protected IEdmNavigationSource NavigationSource { get; private set; } + protected IEdmNavigationSource? NavigationSource { get; private set; } /// /// Gets the Edm operation. /// - protected IEdmOperation EdmOperation { get; private set; } + protected IEdmOperation? EdmOperation { get; private set; } /// /// Gets the OData operation segment. /// - protected ODataOperationSegment OperationSegment { get; private set; } + protected ODataOperationSegment? OperationSegment { get; private set; } /// /// Gets a value indicating whether the path has type cast segment or not. @@ -60,31 +61,38 @@ protected override void Initialize(ODataContext context, ODataPath path) base.Initialize(context, path); // It's bound operation, the first segment must be the navigaiton source. - ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; - NavigationSource = navigationSourceSegment.NavigationSource; + if (path.FirstSegment is ODataNavigationSourceSegment navigationSourceSegment) + NavigationSource = navigationSourceSegment.NavigationSource; - OperationSegment = path.LastSegment as ODataOperationSegment; - EdmOperation = OperationSegment.Operation; + if (path.LastSegment is ODataOperationSegment opSegment) + { + OperationSegment = opSegment; + EdmOperation = opSegment.Operation; + } HasTypeCast = path.Segments.Any(s => s is ODataTypeCastSegment); - _operationRestriction = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.OperationRestrictions); - var operationRestrictions = Context.Model.GetRecord(EdmOperation, CapabilitiesConstants.OperationRestrictions); - _operationRestriction?.MergePropertiesIfNull(operationRestrictions); - _operationRestriction ??= operationRestrictions; + if (!string.IsNullOrEmpty(TargetPath)) + _operationRestriction = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.OperationRestrictions); + if (Context is not null && EdmOperation is not null && + Context.Model.GetRecord(EdmOperation, CapabilitiesConstants.OperationRestrictions) is { } operationRestrictions) + { + _operationRestriction?.MergePropertiesIfNull(operationRestrictions); + _operationRestriction ??= operationRestrictions; + } } /// protected override void SetBasicInfo(OpenApiOperation operation) { // Summary - operation.Summary = "Invoke " + (EdmOperation.IsAction() ? "action " : "function ") + EdmOperation.Name; + operation.Summary = "Invoke " + (EdmOperation?.IsAction() ?? false ? "action " : "function ") + EdmOperation?.Name; // Description - operation.Description = Context.Model.GetDescriptionAnnotation(TargetPath) ?? Context.Model.GetDescriptionAnnotation(EdmOperation); + operation.Description = (string.IsNullOrEmpty(TargetPath) ? null :Context?.Model.GetDescriptionAnnotation(TargetPath)) ?? Context?.Model.GetDescriptionAnnotation(EdmOperation); // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true} && Path is not null) { // When the key segment is available, // its EntityType name will be used @@ -97,7 +105,7 @@ protected override void SetBasicInfo(OpenApiOperation operation) { if (segment is ODataKeySegment keySegment) { - if (!keySegment.IsAlternateKey) + if (!keySegment.IsAlternateKey && segment is {EntityType: not null}) { identifiers.Add(segment.EntityType.Name); continue; @@ -113,7 +121,7 @@ protected override void SetBasicInfo(OpenApiOperation operation) identifiers.Add(keySegment.Identifier); } } - else if (segment is ODataOperationSegment opSegment) + else if (segment is ODataOperationSegment {Identifier: not null} opSegment) { if (opSegment.Operation is IEdmFunction function && Context.Model.IsOperationOverload(function)) { @@ -123,9 +131,9 @@ protected override void SetBasicInfo(OpenApiOperation operation) : (pathHash + opSegment.GetPathHash(Context.Settings)).GetHashSHA256()[..4]; } - identifiers.Add(segment.Identifier); + identifiers.Add(opSegment.Identifier); } - else + else if (!string.IsNullOrEmpty(segment.Identifier)) { identifiers.Add(segment.Identifier); } @@ -154,11 +162,12 @@ protected override void SetTags(OpenApiOperation operation) { Name = tagName, }; + tag.Extensions ??= new Dictionary(); tag.Extensions.Add(Constants.xMsTocType, new OpenApiAny("container")); operation.Tags ??= new HashSet(); operation.Tags.Add(new OpenApiTagReference(tag.Name, _document)); - Context.AppendTag(tag); + Context?.AppendTag(tag); base.SetTags(operation); } @@ -169,12 +178,13 @@ protected override void SetTags(OpenApiOperation operation) /// The generated tag name. /// The number of segments to skip. private void GenerateTagName(out string tagName, int skip = 1) - { + { + if (Path is null) throw new InvalidOperationException("Path is null."); var targetSegment = Path.Segments.Reverse().Skip(skip).FirstOrDefault(); switch (targetSegment) { - case ODataNavigationPropertySegment: + case ODataNavigationPropertySegment when Context is not null: tagName = EdmModelHelper.GenerateNavigationPropertyPathTagName(Path, Context); break; case ODataOperationImportSegment: @@ -184,7 +194,7 @@ private void GenerateTagName(out string tagName, int skip = 1) GenerateTagName(out tagName, skip); break; default: - tagName = NavigationSource.Name + "." + NavigationSource.EntityType.Name; + tagName = NavigationSource?.Name + "." + NavigationSource?.EntityType.Name; if (EdmOperation.IsAction()) { tagName += ".Actions"; @@ -202,9 +212,8 @@ protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); - if (EdmOperation.IsFunction()) + if (EdmOperation.IsFunction() && EdmOperation is IEdmFunction function) { - IEdmFunction function = (IEdmFunction)EdmOperation; AppendSystemQueryOptions(function, operation); } } @@ -212,7 +221,8 @@ protected override void SetParameters(OpenApiOperation operation) /// protected override void SetResponses(OpenApiOperation operation) { - operation.Responses = Context.CreateResponses(EdmOperation, _document); + if (EdmOperation is not null && Context is not null) + operation.Responses = Context.CreateResponses(EdmOperation, _document); base.SetResponses(operation); } @@ -224,7 +234,7 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_operationRestriction.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_operationRestriction.Permissions, _document).ToList(); } /// @@ -248,8 +258,9 @@ protected override void AppendCustomParameters(OpenApiOperation operation) private void AppendSystemQueryOptions(IEdmFunction function, OpenApiOperation operation) { - if (function.ReturnType.IsCollection()) + if (function.ReturnType.IsCollection() && Context is not null) { + operation.Parameters ??= []; // $top if (Context.CreateTop(function, _document) is {} topParameter) { @@ -306,10 +317,10 @@ private void AppendSystemQueryOptions(IEdmFunction function, OpenApiOperation op /// protected override void SetCustomLinkRelType() { - if (Context.Settings.CustomHttpMethodLinkRelMapping != null && EdmOperation != null) + if (Context is {Settings.CustomHttpMethodLinkRelMapping: not null} && EdmOperation != null) { LinkRelKey key = EdmOperation.IsAction() ? LinkRelKey.Action : LinkRelKey.Function; - Context.Settings.CustomHttpMethodLinkRelMapping.TryGetValue(key, out string linkRelValue); + Context.Settings.CustomHttpMethodLinkRelMapping.TryGetValue(key, out var linkRelValue); CustomLinkRel = linkRelValue; } } @@ -321,9 +332,9 @@ protected override void SetExternalDocs(OpenApiOperation operation) { var externalDocs = (string.IsNullOrEmpty(TargetPath), string.IsNullOrEmpty(CustomLinkRel)) switch { - (_, true) => null, (false, false) => Context.Model.GetLinkRecord(TargetPath!, CustomLinkRel!), - (true, false) => Context.Model.GetLinkRecord(EdmOperation, CustomLinkRel!), + (true, false) when EdmOperation is not null => Context.Model.GetLinkRecord(EdmOperation, CustomLinkRel!), + (_, _) => null, }; if (externalDocs != null) @@ -340,9 +351,9 @@ protected override void SetExternalDocs(OpenApiOperation operation) // protected override void SetExtensions(OpenApiOperation operation) { - if (Context is { Settings.EnablePagination: true } && EdmOperation.ReturnType?.TypeKind() == EdmTypeKind.Collection) + if (Context is { Settings.EnablePagination: true } && EdmOperation?.ReturnType?.TypeKind() == EdmTypeKind.Collection) { - JsonObject extension = new JsonObject + var extension = new JsonObject { { "nextLinkName", "@odata.nextLink"}, { "operationName", Context.Settings.PageableOperationName} diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetOperationHandler.cs index 4719ddee7..e3a79902c 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetOperationHandler.cs @@ -5,6 +5,7 @@ using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.OData.Common; @@ -30,7 +31,7 @@ protected EntitySetOperationHandler(OpenApiDocument document) : base(document) /// /// Gets/sets the . /// - protected IEdmEntitySet EntitySet { get; private set; } + protected IEdmEntitySet? EntitySet { get; private set; } /// protected override void Initialize(ODataContext context, ODataPath path) @@ -38,19 +39,18 @@ protected override void Initialize(ODataContext context, ODataPath path) base.Initialize(context, path); // get the entity set. - ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; - - EntitySet = navigationSourceSegment.NavigationSource as IEdmEntitySet; + if (path.FirstSegment is ODataNavigationSourceSegment {NavigationSource: IEdmEntitySet navigationSource}) + EntitySet = navigationSource; } /// protected override void SetTags(OpenApiOperation operation) { - var tagName = EntitySet.Name + "." + EntitySet.EntityType.Name; + var tagName = EntitySet?.Name + "." + EntitySet?.EntityType.Name; operation.Tags ??= new HashSet(); operation.Tags.Add(new OpenApiTagReference(tagName, _document)); - Context.AddExtensionToTag(tagName, Constants.xMsTocType, new OpenApiAny("page"), () => new OpenApiTag() + Context?.AddExtensionToTag(tagName, Constants.xMsTocType, new OpenApiAny("page"), () => new OpenApiTag() { Name = tagName }); @@ -61,6 +61,7 @@ protected override void SetTags(OpenApiOperation operation) /// protected override void SetExtensions(OpenApiOperation operation) { + operation.Extensions ??= new Dictionary(); operation.Extensions.Add(Constants.xMsDosOperationType, new OpenApiAny("operation")); base.SetExtensions(operation); @@ -69,10 +70,10 @@ protected override void SetExtensions(OpenApiOperation operation) /// protected override void SetExternalDocs(OpenApiOperation operation) { - if (Context.Settings.ShowExternalDocs) + if (Context is {Settings.ShowExternalDocs: true} && CustomLinkRel is not null) { - var externalDocs = Context.Model.GetLinkRecord(TargetPath, CustomLinkRel) ?? - Context.Model.GetLinkRecord(EntitySet, CustomLinkRel); + var externalDocs = (string.IsNullOrEmpty(TargetPath) ? null : Context.Model.GetLinkRecord(TargetPath, CustomLinkRel)) ?? + (EntitySet is null ? null : Context.Model.GetLinkRecord(EntitySet, CustomLinkRel)); if (externalDocs != null) { diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityUpdateOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityUpdateOperationHandler.cs index a34d6d9f2..81be9e2bd 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityUpdateOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityUpdateOperationHandler.cs @@ -30,27 +30,30 @@ protected EntityUpdateOperationHandler(OpenApiDocument document):base(document) { } - private UpdateRestrictionsType _updateRestrictions; + private UpdateRestrictionsType? _updateRestrictions; protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - _updateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); - var entityUpdateRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.UpdateRestrictions); - _updateRestrictions?.MergePropertiesIfNull(entityUpdateRestrictions); - _updateRestrictions ??= entityUpdateRestrictions; + if (!string.IsNullOrEmpty(TargetPath)) + _updateRestrictions = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); + if (Context is not null && EntitySet is not null) + { + var entityUpdateRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.UpdateRestrictions); + _updateRestrictions?.MergePropertiesIfNull(entityUpdateRestrictions); + _updateRestrictions ??= entityUpdateRestrictions; + } } /// protected override void SetBasicInfo(OpenApiOperation operation) { - IEdmEntityType entityType = EntitySet.EntityType; - ODataKeySegment keySegment = Path.LastSegment as ODataKeySegment; + var keySegment = Path?.LastSegment as ODataKeySegment; // Summary and Description - string placeHolder = "Update entity in " + EntitySet.Name; - if (keySegment.IsAlternateKey) + string placeHolder = "Update entity in " + EntitySet?.Name; + if (keySegment is {IsAlternateKey: true}) { placeHolder = $"{placeHolder} by {keySegment.Identifier}"; } @@ -58,12 +61,12 @@ protected override void SetBasicInfo(OpenApiOperation operation) operation.Description = _updateRestrictions?.LongDescription; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true} && EntitySet?.EntityType is {} entityType) { string typeName = entityType.Name; string prefix = OperationType == HttpMethod.Patch ? "Update" : "Set"; string operationName = $"{prefix}{ Utils.UpperFirstChar(typeName)}"; - if (keySegment.IsAlternateKey) + if (keySegment is {IsAlternateKey: true}) { string alternateKeyName = string.Join("", keySegment.Identifier.Split(',').Select(static x => Utils.UpperFirstChar(x))); operationName = $"{operationName}By{alternateKeyName}"; @@ -89,10 +92,9 @@ protected IDictionary GetContent() { var schema = GetOpenApiSchema(); var content = new Dictionary(); - IEnumerable mediaTypes = _updateRestrictions?.RequestContentTypes; // Add the annotated request content media types - if (mediaTypes != null) + if (_updateRestrictions?.RequestContentTypes is {} mediaTypes) { foreach (string mediaType in mediaTypes) { @@ -109,7 +111,7 @@ protected IDictionary GetContent() { Schema = schema }); - }; + } return content; } @@ -117,7 +119,8 @@ protected IDictionary GetContent() /// protected override void SetResponses(OpenApiOperation operation) { - operation.AddErrorResponses(Context.Settings, _document, true, GetOpenApiSchema()); + if (GetOpenApiSchema() is {} schema) + operation.AddErrorResponses(Context?.Settings ?? new(), _document, true, schema); base.SetResponses(operation); } @@ -128,7 +131,7 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_updateRestrictions.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_updateRestrictions.Permissions, _document).ToList(); } protected override void AppendCustomParameters(OpenApiOperation operation) @@ -149,11 +152,13 @@ protected override void AppendCustomParameters(OpenApiOperation operation) } } - private IOpenApiSchema GetOpenApiSchema() + private IOpenApiSchema? GetOpenApiSchema() { - if (Context.Settings.EnableDerivedTypesReferencesForRequestBody) + if (EntitySet is null) return null; + if (Context is {Settings.EnableDerivedTypesReferencesForRequestBody: true} && + EdmModelHelper.GetDerivedTypesReferenceSchema(EntitySet.EntityType, Context.Model, _document) is {} schema) { - return EdmModelHelper.GetDerivedTypesReferenceSchema(EntitySet.EntityType, Context.Model, _document); + return schema; } return new OpenApiSchemaReference(EntitySet.EntityType.FullName(), _document); diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityDeleteOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityDeleteOperationHandler.cs index ba40a0a2f..bacd851e2 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityDeleteOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityDeleteOperationHandler.cs @@ -52,11 +52,11 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetBasicInfo(OpenApiOperation operation) { // Summary - string placeholderValue = LastSegmentIsStreamPropertySegment && Path is not null ? Path.LastSegment.Identifier : "media content"; + string placeholderValue = LastSegmentIsStreamPropertySegment && Path is {LastSegment.Identifier: not null} ? Path.LastSegment.Identifier : "media content"; operation.Summary = _deleteRestrictions?.Description; operation.Summary ??= IsNavigationPropertyPath - ? $"Delete {placeholderValue} for the navigation property {NavigationProperty.Name} in {NavigationSourceSegment.NavigationSource.Name}" - : $"Delete {placeholderValue} for {NavigationSourceSegment.EntityType.Name} in {NavigationSourceSegment.Identifier}"; + ? $"Delete {placeholderValue} for the navigation property {NavigationProperty?.Name} in {NavigationSourceSegment?.NavigationSource.Name}" + : $"Delete {placeholderValue} for {NavigationSourceSegment?.EntityType.Name} in {NavigationSourceSegment?.Identifier}"; // Description operation.Description = _deleteRestrictions?.LongDescription ?? Context?.Model.GetDescriptionAnnotation(Property); @@ -64,7 +64,7 @@ protected override void SetBasicInfo(OpenApiOperation operation) // OperationId if (Context is {Settings.EnableOperationId: true}) { - string identifier = LastSegmentIsStreamPropertySegment && Path is not null ? Path.LastSegment.Identifier : "Content"; + string identifier = LastSegmentIsStreamPropertySegment && Path is {LastSegment.Identifier: not null} ? Path.LastSegment.Identifier : "Content"; operation.OperationId = GetOperationId("Delete", identifier); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityGetOperationHandler.cs index f6b86d60c..e44471ed4 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityGetOperationHandler.cs @@ -116,8 +116,8 @@ protected override void SetResponses(OpenApiOperation operation) /// protected override void SetSecurity(OpenApiOperation operation) { - IEdmVocabularyAnnotatable annotatableNavigationSource = (IEdmVocabularyAnnotatable)NavigationSourceSegment.NavigationSource; - if (Context?.Model.GetRecord(annotatableNavigationSource, CapabilitiesConstants.ReadRestrictions) is not {} read) + if (NavigationSourceSegment?.NavigationSource is not IEdmVocabularyAnnotatable annotatableNavigationSource || + Context?.Model.GetRecord(annotatableNavigationSource, CapabilitiesConstants.ReadRestrictions) is not {} read) { return; } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/MetadataGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/MetadataGetOperationHandler.cs index 9b453baf8..f3114b698 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/MetadataGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/MetadataGetOperationHandler.cs @@ -33,7 +33,7 @@ protected override void SetBasicInfo(OpenApiOperation operation) operation.Summary = $"Get OData metadata (CSDL) document"; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true}) { string routePrefix = Context.Settings.PathPrefix ?? ""; if (Context.Settings.PathPrefix != null) diff --git a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt index 9c2e9cb2b..2f2f4074f 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt +++ b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt @@ -1,7 +1,7 @@ #nullable enable abstract Microsoft.OpenApi.OData.Edm.ODataSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! -abstract Microsoft.OpenApi.OData.Edm.ODataSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! -abstract Microsoft.OpenApi.OData.Edm.ODataSegment.Identifier.get -> string! +abstract Microsoft.OpenApi.OData.Edm.ODataSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string? +abstract Microsoft.OpenApi.OData.Edm.ODataSegment.Identifier.get -> string? abstract Microsoft.OpenApi.OData.Edm.ODataSegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind Microsoft.OpenApi.OData.Common.Utils Microsoft.OpenApi.OData.Edm.EdmModelExtensions @@ -79,7 +79,7 @@ Microsoft.OpenApi.OData.Edm.ODataPathProvider.ODataPathProvider() -> void Microsoft.OpenApi.OData.Edm.ODataRefSegment Microsoft.OpenApi.OData.Edm.ODataSegment Microsoft.OpenApi.OData.Edm.ODataSegment.GetPathHash(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, Microsoft.OpenApi.OData.Edm.ODataPath? path = null) -> string! -Microsoft.OpenApi.OData.Edm.ODataSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings) -> string! +Microsoft.OpenApi.OData.Edm.ODataSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings) -> string? Microsoft.OpenApi.OData.Edm.ODataSegment.ODataSegment() -> void Microsoft.OpenApi.OData.Edm.ODataSegmentKind Microsoft.OpenApi.OData.Edm.ODataSegmentKind.ComplexProperty = 11 -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind @@ -268,7 +268,7 @@ override Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.Identifier.get override Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind override Microsoft.OpenApi.OData.Edm.ODataOperationSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType? override Microsoft.OpenApi.OData.Edm.ODataOperationSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! -override Microsoft.OpenApi.OData.Edm.ODataOperationSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! +override Microsoft.OpenApi.OData.Edm.ODataOperationSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string? override Microsoft.OpenApi.OData.Edm.ODataOperationSegment.Identifier.get -> string? override Microsoft.OpenApi.OData.Edm.ODataOperationSegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind override Microsoft.OpenApi.OData.Edm.ODataPath.ToString() -> string! @@ -311,4 +311,4 @@ virtual Microsoft.OpenApi.OData.Edm.ODataPath.Kind.get -> Microsoft.OpenApi.ODat virtual Microsoft.OpenApi.OData.Edm.ODataPathProvider.CanFilter(Microsoft.OData.Edm.IEdmElement! element) -> bool virtual Microsoft.OpenApi.OData.Edm.ODataPathProvider.GetPaths(Microsoft.OData.Edm.IEdmModel! model, Microsoft.OpenApi.OData.OpenApiConvertSettings! settings) -> System.Collections.Generic.IEnumerable! virtual Microsoft.OpenApi.OData.Edm.ODataPathProvider.Initialize(Microsoft.OData.Edm.IEdmModel! model) -> void -virtual Microsoft.OpenApi.OData.Edm.ODataSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType! +virtual Microsoft.OpenApi.OData.Edm.ODataSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType? From 61875366d890d092a3f33e49c5b1611bce38b362 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 26 Mar 2025 10:49:43 -0400 Subject: [PATCH 10/24] chore: additional NRT fixes Signed-off-by: Vincent Biret --- .../PathItem/MediaEntityPathItemHandler.cs | 11 +- .../NavigationPropertyPathItemHandler.cs | 124 +++++++++++------- 2 files changed, 77 insertions(+), 58 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/MediaEntityPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/MediaEntityPathItemHandler.cs index 48bf11f03..0abd02072 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/MediaEntityPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/MediaEntityPathItemHandler.cs @@ -79,13 +79,10 @@ protected override void Initialize(ODataContext context, ODataPath path) base.Initialize(context, path); // The first segment could be an entity set segment or a singleton segment. - ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; - - EntitySet = navigationSourceSegment.NavigationSource as IEdmEntitySet; - if (EntitySet == null) - { - Singleton = navigationSourceSegment.NavigationSource as IEdmSingleton; - } + if (path.FirstSegment is ODataNavigationSourceSegment {NavigationSource: IEdmEntitySet entitySet}) + EntitySet = entitySet; + if (path.FirstSegment is ODataNavigationSourceSegment {NavigationSource: IEdmSingleton singleton}) + Singleton = singleton; } /// protected override void SetBasicInfo(OpenApiPathItem pathItem) diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs index 21306c0d7..751190923 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs @@ -15,6 +15,7 @@ using Microsoft.OpenApi.OData.Vocabulary.Capabilities; using System.Text.Json.Nodes; using System.Net.Http; +using Microsoft.OpenApi.Interfaces; namespace Microsoft.OpenApi.OData.PathItem { @@ -37,12 +38,12 @@ public NavigationPropertyPathItemHandler(OpenApiDocument document) : base(docume /// /// Gets the navigation property. /// - public IEdmNavigationProperty NavigationProperty { get; private set; } + public IEdmNavigationProperty? NavigationProperty { get; private set; } /// /// Gets the navigation source. /// - public IEdmNavigationSource NavigationSource { get; private set; } + public IEdmNavigationSource? NavigationSource { get; private set; } /// /// Gets a bool value indicating whether the last segment is a key segment. @@ -57,26 +58,28 @@ public NavigationPropertyPathItemHandler(OpenApiDocument document) : base(docume /// /// The entity type targeted by the /// - private IEdmEntityType _navPropEntityType; + private IEdmEntityType? _navPropEntityType; /// protected override void SetOperations(OpenApiPathItem item) { - IEdmEntitySet entitySet = NavigationSource as IEdmEntitySet; - IEdmVocabularyAnnotatable target = entitySet; - target ??= NavigationSource as IEdmSingleton; - - NavigationRestrictionsType targetPathRestrictionType = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.NavigationRestrictions); - NavigationRestrictionsType navSourceRestrictionType = Context.Model.GetRecord(target, CapabilitiesConstants.NavigationRestrictions); - NavigationRestrictionsType navPropRestrictionType = Context.Model.GetRecord(NavigationProperty, CapabilitiesConstants.NavigationRestrictions); + IEdmVocabularyAnnotatable? target = NavigationSource switch { + IEdmEntitySet es => es, + IEdmSingleton singleton => singleton, + _ => null + }; + + var targetPathRestrictionType = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.NavigationRestrictions); + var navSourceRestrictionType = target is null ? null : Context.Model.GetRecord(target, CapabilitiesConstants.NavigationRestrictions); + var navPropRestrictionType = NavigationProperty is null ? null : Context.Model.GetRecord(NavigationProperty, CapabilitiesConstants.NavigationRestrictions); - NavigationPropertyRestriction restriction = targetPathRestrictionType?.RestrictedProperties?.FirstOrDefault() + var restriction = targetPathRestrictionType?.RestrictedProperties?.FirstOrDefault() ?? navSourceRestrictionType?.RestrictedProperties?.FirstOrDefault(r => r.NavigationProperty == Path.NavigationPropertyPath()) ?? navPropRestrictionType?.RestrictedProperties?.FirstOrDefault(); // Check whether the navigation property should be part of the path - if (EdmModelHelper.NavigationRestrictionsAllowsNavigability(navSourceRestrictionType, restriction) == false || - EdmModelHelper.NavigationRestrictionsAllowsNavigability(navPropRestrictionType, restriction) == false) + if (!EdmModelHelper.NavigationRestrictionsAllowsNavigability(navSourceRestrictionType, restriction) || + !EdmModelHelper.NavigationRestrictionsAllowsNavigability(navPropRestrictionType, restriction)) { return; } @@ -84,28 +87,34 @@ protected override void SetOperations(OpenApiPathItem item) AddGetOperation(item, restriction); // Update restrictions - UpdateRestrictionsType navPropUpdateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); + var navPropUpdateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); navPropUpdateRestrictions?.MergePropertiesIfNull(restriction?.UpdateRestrictions); navPropUpdateRestrictions ??= restriction?.UpdateRestrictions; - UpdateRestrictionsType updateRestrictions = Context.Model.GetRecord(NavigationProperty); - navPropUpdateRestrictions?.MergePropertiesIfNull(updateRestrictions); - navPropUpdateRestrictions ??= updateRestrictions; + if (NavigationProperty is not null) + { + var updateRestrictions = Context.Model.GetRecord(NavigationProperty); + navPropUpdateRestrictions?.MergePropertiesIfNull(updateRestrictions); + navPropUpdateRestrictions ??= updateRestrictions; + } // Insert restrictions - InsertRestrictionsType navPropInsertRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); + var navPropInsertRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); navPropInsertRestrictions?.MergePropertiesIfNull(restriction?.InsertRestrictions); navPropInsertRestrictions ??= restriction?.InsertRestrictions; - InsertRestrictionsType insertRestrictions = Context.Model.GetRecord(NavigationProperty); - navPropInsertRestrictions?.MergePropertiesIfNull(insertRestrictions); - navPropInsertRestrictions ??= insertRestrictions; + if (NavigationProperty is not null) + { + var insertRestrictions = Context.Model.GetRecord(NavigationProperty); + navPropInsertRestrictions?.MergePropertiesIfNull(insertRestrictions); + navPropInsertRestrictions ??= insertRestrictions; + } // Entity insert restrictions - UpdateRestrictionsType entityUpdateRestrictions = Context.Model.GetRecord(_navPropEntityType); + var entityUpdateRestrictions = Context.Model.GetRecord(_navPropEntityType); // containment: (Post - Collection | Patch/Put - Single) - if (NavigationProperty.ContainsTarget) + if (NavigationProperty?.ContainsTarget ?? false) { - UpdateRestrictionsType updateRestrictionType = navPropUpdateRestrictions ?? entityUpdateRestrictions; + var updateRestrictionType = navPropUpdateRestrictions ?? entityUpdateRestrictions; if (NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) { if (LastSegmentIsKeySegment) @@ -120,7 +129,7 @@ protected override void SetOperations(OpenApiPathItem item) } else { - InsertRestrictionsType entityInsertRestrictions = Context.Model.GetRecord(_navPropEntityType); + var entityInsertRestrictions = Context.Model.GetRecord(_navPropEntityType); bool isInsertableDefault = navPropInsertRestrictions == null && entityInsertRestrictions == null; if (isInsertableDefault || @@ -169,16 +178,20 @@ protected override void SetOperations(OpenApiPathItem item) AddDeleteOperation(item, restriction); } - private void AddGetOperation(OpenApiPathItem item, NavigationPropertyRestriction restriction) + private void AddGetOperation(OpenApiPathItem item, NavigationPropertyRestriction? restriction) { - ReadRestrictionsType navPropReadRestriction = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + var navPropReadRestriction = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); navPropReadRestriction?.MergePropertiesIfNull(restriction?.ReadRestrictions); navPropReadRestriction ??= restriction?.ReadRestrictions; - ReadRestrictionsType readRestrictions = Context.Model.GetRecord(NavigationProperty); - navPropReadRestriction?.MergePropertiesIfNull(readRestrictions); - navPropReadRestriction ??= readRestrictions; - ReadRestrictionsType entityReadRestriction = Context.Model.GetRecord(_navPropEntityType); + if (NavigationProperty is not null) + { + var readRestrictions = Context.Model.GetRecord(NavigationProperty); + navPropReadRestriction?.MergePropertiesIfNull(readRestrictions); + navPropReadRestriction ??= readRestrictions; + } + + var entityReadRestriction = _navPropEntityType is null ? null : Context.Model.GetRecord(_navPropEntityType); bool isReadableDefault = navPropReadRestriction == null && entityReadRestriction == null; if (isReadableDefault) { @@ -208,7 +221,7 @@ private void AddGetOperation(OpenApiPathItem item, NavigationPropertyRestriction } else { - Debug.Assert(LastSegmentIsKeySegment == false); + Debug.Assert(!LastSegmentIsKeySegment); if ((navPropReadRestriction?.IsReadable ?? true) && (entityReadRestriction?.IsReadable ?? true)) { @@ -217,27 +230,30 @@ private void AddGetOperation(OpenApiPathItem item, NavigationPropertyRestriction } } - private void AddDeleteOperation(OpenApiPathItem item, NavigationPropertyRestriction restriction) + private void AddDeleteOperation(OpenApiPathItem item, NavigationPropertyRestriction? restriction) { Debug.Assert(!LastSegmentIsRefSegment); - DeleteRestrictionsType navPropDeleteRestriction = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); + var navPropDeleteRestriction = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); navPropDeleteRestriction?.MergePropertiesIfNull(restriction?.DeleteRestrictions); navPropDeleteRestriction ??= restriction?.DeleteRestrictions; - DeleteRestrictionsType insertRestrictions = Context.Model.GetRecord(NavigationProperty); - navPropDeleteRestriction?.MergePropertiesIfNull(insertRestrictions); - navPropDeleteRestriction ??= insertRestrictions; + if (NavigationProperty is not null) + { + var insertRestrictions = Context.Model.GetRecord(NavigationProperty); + navPropDeleteRestriction?.MergePropertiesIfNull(insertRestrictions); + navPropDeleteRestriction ??= insertRestrictions; + } if (!(NavigationProperty.TargetMultiplicity() != EdmMultiplicity.Many || LastSegmentIsKeySegment)) return; - DeleteRestrictionsType entityDeleteRestriction = Context.Model.GetRecord(_navPropEntityType); + var entityDeleteRestriction = _navPropEntityType is null ? null : Context.Model.GetRecord(_navPropEntityType); bool isDeletable = (navPropDeleteRestriction == null && entityDeleteRestriction == null) || ((entityDeleteRestriction?.IsDeletable ?? true) && (navPropDeleteRestriction?.IsDeletable ?? true)); - if (NavigationProperty.ContainsTarget && isDeletable) + if ((NavigationProperty?.ContainsTarget ?? false) && isDeletable) { AddOperation(item, HttpMethod.Delete); } @@ -251,7 +267,7 @@ private void AddDeleteOperation(OpenApiPathItem item, NavigationPropertyRestrict return; } - private void AddUpdateOperation(OpenApiPathItem item, UpdateRestrictionsType updateRestrictionsType) + private void AddUpdateOperation(OpenApiPathItem item, UpdateRestrictionsType? updateRestrictionsType) { if (updateRestrictionsType?.IsUpdatable ?? true) { @@ -277,11 +293,11 @@ protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; - NavigationSource = navigationSourceSegment.NavigationSource; + if (path.FirstSegment is ODataNavigationSourceSegment {NavigationSource: {} source}) + NavigationSource = source; - LastSegmentIsKeySegment = path.LastSegment.Kind == ODataSegmentKind.Key; - LastSegmentIsRefSegment = path.LastSegment.Kind == ODataSegmentKind.Ref; + LastSegmentIsKeySegment = path.LastSegment?.Kind == ODataSegmentKind.Key; + LastSegmentIsRefSegment = path.LastSegment?.Kind == ODataSegmentKind.Ref; NavigationProperty = path.OfType().Last().NavigationProperty; _navPropEntityType = NavigationProperty.ToEntityType(); } @@ -309,11 +325,12 @@ protected override void SetExtensions(OpenApiPathItem item) continue; } - if (path.LastSegment is not ODataNavigationPropertySegment npSegment) - { - npSegment = path.Segments[path.Count - 2] as ODataNavigationPropertySegment; - } - if (NavigationProperty != npSegment.NavigationProperty) + var npSegment = path.LastSegment is ODataNavigationPropertySegment npS ? + npS : + path.Segments[path.Count - 2] is ODataNavigationPropertySegment npSegmentFallback ? + npSegmentFallback : + null; + if (NavigationProperty != npSegment?.NavigationProperty) { continue; } @@ -331,17 +348,22 @@ protected override void SetExtensions(OpenApiPathItem item) array.Add(p.GetPathItemName(settings)); } + item.Extensions ??= new Dictionary(); item.Extensions.Add(Constants.xMsDosGroupPath, new OpenApiAny(array)); } base.SetExtensions(item); - item.Extensions.AddCustomAttributesToExtensions(Context, NavigationProperty); + if (NavigationProperty is not null) + { + item.Extensions ??= new Dictionary(); + item.Extensions.AddCustomAttributesToExtensions(Context, NavigationProperty); + } } /// protected override void SetBasicInfo(OpenApiPathItem pathItem) { base.SetBasicInfo(pathItem); - pathItem.Description = $"Provides operations to manage the {NavigationProperty.Name} property of the {NavigationProperty.DeclaringType.FullTypeName()} entity."; + pathItem.Description = $"Provides operations to manage the {NavigationProperty?.Name} property of the {NavigationProperty?.DeclaringType.FullTypeName()} entity."; } } } From 44f1e2a6c299630393366f8a739ecb3219f899b9 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 26 Mar 2025 12:34:55 -0400 Subject: [PATCH 11/24] chore: additional NRT fixes Signed-off-by: Vincent Biret --- .../Edm/EdmOperationProvider.cs | 15 ++-- .../Edm/ODataOperationImportSegment.cs | 12 +-- .../Edm/ODataPath.cs | 25 +++--- .../EdmFunctionImportOperationHandler.cs | 14 +++- .../Operation/EntityDeleteOperationHandler.cs | 15 ++-- .../Operation/EntityGetOperationHandler.cs | 79 ++++++++++--------- .../Operation/EntitySetGetOperationHandler.cs | 10 +-- .../EntitySetPostOperationHandler.cs | 9 ++- .../Operation/IOperationHandlerProvider.cs | 2 +- .../Operation/OperationHandlerProvider.cs | 2 +- .../Operation/RefDeleteOperationHandler.cs | 15 ++-- .../PathItem/ComplexPropertyItemHandler.cs | 44 +++++++---- .../PublicAPI.Unshipped.txt | 4 +- 13 files changed, 137 insertions(+), 109 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmOperationProvider.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmOperationProvider.cs index fd928476a..d62a24c24 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmOperationProvider.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmOperationProvider.cs @@ -13,7 +13,7 @@ namespace Microsoft.OpenApi.OData.Edm { internal class EdmOperationProvider { - private Lazy>> _boundEdmOperations; + private readonly Lazy>> _boundEdmOperations; /// /// Gets the Edm model. @@ -31,7 +31,7 @@ public EdmOperationProvider(IEdmModel model) Model = model; _boundEdmOperations = new Lazy>>( - () => LoadEdmOperations(), isThreadSafe: false); + LoadEdmOperations, isThreadSafe: false); } public IDictionary> Operations => _boundEdmOperations.Value; @@ -42,20 +42,19 @@ public EdmOperationProvider(IEdmModel model) /// The binding entity type. /// The collection or not. /// The found Edm operations. - public IEnumerable FindOperations(IEdmEntityType entityType, bool collection) + public IEnumerable? FindOperations(IEdmEntityType entityType, bool collection) { Utils.CheckArgumentNull(entityType, nameof(entityType)); string fullTypeName = collection ? "Collection(" + entityType.FullName() + ")" : entityType.FullName(); - IList edmOperations; - _boundEdmOperations.Value.TryGetValue(fullTypeName, out edmOperations); + if (!_boundEdmOperations.Value.TryGetValue(fullTypeName, out var edmOperations)) return null; foreach (IEdmEntityType derived in Model.FindAllDerivedTypes(entityType).OfType()) { string subFullTypeName = collection ? "Collection(" + derived.FullName() + ")" : derived.FullName(); - if (_boundEdmOperations.Value.TryGetValue(subFullTypeName, out IList edmSubOperations)) + if (_boundEdmOperations.Value.TryGetValue(subFullTypeName, out var edmSubOperations)) { foreach(var edmOperation in edmSubOperations) { @@ -77,9 +76,9 @@ private IDictionary> LoadEdmOperations() string bindingTypeName = bindingParameter.Type.FullName(); - if (!edmOperationDict.TryGetValue(bindingTypeName, out IList value)) + if (!edmOperationDict.TryGetValue(bindingTypeName, out var value)) { - value = new List(); + value = []; edmOperationDict[bindingTypeName] = value; } value.Add(edmOperation); diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataOperationImportSegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataOperationImportSegment.cs index 4a8ebd51f..ee2b70df0 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataOperationImportSegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataOperationImportSegment.cs @@ -41,7 +41,7 @@ public ODataOperationImportSegment(IEdmOperationImport operationImport, IDiction /// /// Gets the parameter mappings. /// - public IDictionary ParameterMappings { get; } + public IDictionary? ParameterMappings { get; } /// /// Gets the operation import. @@ -49,7 +49,7 @@ public ODataOperationImportSegment(IEdmOperationImport operationImport, IDiction public IEdmOperationImport OperationImport { get; } /// - public override IEdmEntityType EntityType => null; + public override IEdmEntityType? EntityType => null; /// public override ODataSegmentKind Kind => ODataSegmentKind.OperationImport; @@ -60,7 +60,7 @@ public ODataOperationImportSegment(IEdmOperationImport operationImport, IDiction /// public override IEnumerable GetAnnotables() { - return new IEdmVocabularyAnnotatable[] { OperationImport }; + return [OperationImport]; } /// @@ -68,15 +68,15 @@ public override string GetPathItemName(OpenApiConvertSettings settings, HashSet< { Utils.CheckArgumentNull(settings, nameof(settings)); - if (OperationImport.IsFunctionImport()) + if (OperationImport.IsFunctionImport() && OperationImport is IEdmFunctionImport edmFunctionImport) { - return FunctionImportName(OperationImport as IEdmFunctionImport, settings, parameters); + return FunctionImportName(edmFunctionImport, settings, parameters); } return OperationImport.Name; } - private string FunctionImportName(IEdmFunctionImport functionImport, OpenApiConvertSettings settings, HashSet parameters) + private static string FunctionImportName(IEdmFunctionImport functionImport, OpenApiConvertSettings settings, HashSet parameters) { StringBuilder functionName = new StringBuilder(functionImport.Name); functionName.Append("("); diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPath.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPath.cs index 856a5c893..5ae52b2fa 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPath.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPath.cs @@ -150,35 +150,34 @@ public string GetPathItemName(OpenApiConvertSettings settings) if (!string.IsNullOrWhiteSpace(settings.PathPrefix)) { - sb.Append("/"); + sb.Append('/'); sb.Append(settings.PathPrefix); } foreach (var segment in Segments) { - string pathItemName = segment.GetPathItemName(settings, parameters); + var pathItemName = segment.GetPathItemName(settings, parameters); if (segment is ODataKeySegment keySegment && (settings.EnableKeyAsSegment == null || !settings.EnableKeyAsSegment.Value || keySegment.IsAlternateKey)) { - sb.Append("("); + sb.Append('('); sb.Append(pathItemName); - sb.Append(")"); + sb.Append(')'); } else // other segments { - if (segment.Kind == ODataSegmentKind.Operation) + if (segment.Kind == ODataSegmentKind.Operation && + segment is ODataOperationSegment operation && + operation.IsEscapedFunction && + settings.EnableUriEscapeFunctionCall) { - ODataOperationSegment operation = (ODataOperationSegment)segment; - if (operation.IsEscapedFunction && settings.EnableUriEscapeFunctionCall) - { - sb.Append(":/"); - sb.Append(pathItemName); - continue; - } + sb.Append(":/"); + sb.Append(pathItemName); + continue; } - sb.Append("/"); + sb.Append('/'); sb.Append(pathItemName); } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionImportOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionImportOperationHandler.cs index 50ec9a9f5..a49b34ca2 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionImportOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionImportOperationHandler.cs @@ -3,9 +3,11 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Collections.Generic; using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Generator; @@ -38,18 +40,21 @@ protected override void SetParameters(OpenApiOperation operation) return; } - if (OperationImportSegment.ParameterMappings != null) + if (OperationImportSegment.ParameterMappings != null && + Context?.CreateParameters(functionImport.Function, _document, OperationImportSegment.ParameterMappings) is {} functionParamMappings) { - foreach (var param in Context.CreateParameters(functionImport.Function, _document, OperationImportSegment.ParameterMappings)) + operation.Parameters ??= []; + foreach (var param in functionParamMappings) { operation.Parameters.AppendParameter(param); } } - else + else if (Context?.CreateParameters(functionImport, _document) is {} functionParams) { + operation.Parameters ??= []; //The parameters array contains a Parameter Object for each parameter of the function overload, // and it contains specific Parameter Objects for the allowed system query options. - foreach (var param in Context.CreateParameters(functionImport, _document)) + foreach (var param in functionParams) { operation.Parameters.AppendParameter(param); } @@ -59,6 +64,7 @@ protected override void SetParameters(OpenApiOperation operation) /// protected override void SetExtensions(OpenApiOperation operation) { + operation.Extensions ??= new Dictionary(); operation.Extensions.Add(Constants.xMsDosOperationType, new OpenApiAny("functionImport")); base.SetExtensions(operation); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityDeleteOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityDeleteOperationHandler.cs index c037c74de..16f8f7f3b 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityDeleteOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityDeleteOperationHandler.cs @@ -41,18 +41,19 @@ protected override void Initialize(ODataContext context, ODataPath path) if (Context is null) return; if (!string.IsNullOrEmpty(TargetPath)) _deleteRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); - var entityDeleteRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.DeleteRestrictions); - _deleteRestrictions?.MergePropertiesIfNull(entityDeleteRestrictions); - _deleteRestrictions ??= entityDeleteRestrictions; + if (EntitySet is not null) + { + var entityDeleteRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.DeleteRestrictions); + _deleteRestrictions?.MergePropertiesIfNull(entityDeleteRestrictions); + _deleteRestrictions ??= entityDeleteRestrictions; + } } /// protected override void SetBasicInfo(OpenApiOperation operation) { - IEdmEntityType entityType = EntitySet.EntityType; - // Description - string placeHolder = $"Delete entity from {EntitySet.Name}"; + string placeHolder = $"Delete entity from {EntitySet?.Name}"; if (Path is {LastSegment: ODataKeySegment {IsAlternateKey: true} keySegment}) { placeHolder = $"{placeHolder} by {keySegment.Identifier}"; @@ -61,7 +62,7 @@ protected override void SetBasicInfo(OpenApiOperation operation) operation.Description = _deleteRestrictions?.LongDescription; // OperationId - if (Context is { Settings.EnableOperationId: true}) + if (Context is { Settings.EnableOperationId: true} && EntitySet?.EntityType is IEdmEntityType entityType) { string typeName = entityType.Name; string operationName =$"Delete{Utils.UpperFirstChar(typeName)}"; diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityGetOperationHandler.cs index 224c38333..b02d38abf 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityGetOperationHandler.cs @@ -35,39 +35,43 @@ public EntityGetOperationHandler(OpenApiDocument document) : base(document) /// public override HttpMethod OperationType => HttpMethod.Get; - private ReadRestrictionsType _readRestrictions; + private ReadRestrictionsType? _readRestrictions; protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - _readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - var entityReadRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.ReadRestrictions); - _readRestrictions?.MergePropertiesIfNull(entityReadRestrictions); - _readRestrictions ??= entityReadRestrictions; + if (!string.IsNullOrEmpty(TargetPath)) + _readRestrictions = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + if (Context is not null && EntitySet is not null) + { + var entityReadRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.ReadRestrictions); + _readRestrictions?.MergePropertiesIfNull(entityReadRestrictions); + _readRestrictions ??= entityReadRestrictions; + } } /// protected override void SetBasicInfo(OpenApiOperation operation) { - IEdmEntityType entityType = EntitySet.EntityType; - ODataKeySegment keySegment = Path.LastSegment as ODataKeySegment; + var keySegment = Path?.LastSegment as ODataKeySegment; // Description - string placeHolder = "Get entity from " + EntitySet.Name + " by key"; - if (keySegment.IsAlternateKey) + string placeHolder = "Get entity from " + EntitySet?.Name + " by key"; + if (keySegment?.IsAlternateKey ?? false) { placeHolder = $"{placeHolder} ({keySegment.Identifier})"; } operation.Summary = _readRestrictions?.ReadByKeyRestrictions?.Description ?? placeHolder; - operation.Description = _readRestrictions?.ReadByKeyRestrictions?.LongDescription ?? Context.Model.GetDescriptionAnnotation(entityType); + operation.Description = _readRestrictions?.ReadByKeyRestrictions?.LongDescription ?? + (EntitySet is null ? null : Context?.Model.GetDescriptionAnnotation(EntitySet.EntityType)); // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true} && EntitySet?.EntityType.Name is string entityTypeName) { - string typeName = entityType.Name; + string typeName = entityTypeName; string operationName = $"Get{Utils.UpperFirstChar(typeName)}"; - if (keySegment.IsAlternateKey) + if (keySegment?.IsAlternateKey ?? false) { string alternateKeyName = string.Join("", keySegment.Identifier.Split(',').Select(static x => Utils.UpperFirstChar(x))); operationName = $"{operationName}By{alternateKeyName}"; @@ -81,47 +85,49 @@ protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); + if (Context is null || EntitySet is null) return; + // $select - OpenApiParameter parameter = Context.CreateSelect(EntitySet); - if (parameter != null) + if (Context.CreateSelect(EntitySet) is {} sParameter) { - operation.Parameters.Add(parameter); + operation.Parameters ??= []; + operation.Parameters.Add(sParameter); } // $expand - parameter = Context.CreateExpand(EntitySet); - if (parameter != null) + if (Context.CreateExpand(EntitySet) is {} eParameter) { - operation.Parameters.Add(parameter); + operation.Parameters ??= []; + operation.Parameters.Add(eParameter); } } /// protected override void SetResponses(OpenApiOperation operation) { - IOpenApiSchema schema = null; - IDictionary links = null; + IOpenApiSchema? schema = null; + IDictionary? links = null; - if (Context.Settings.EnableDerivedTypesReferencesForResponses) + if (EntitySet is not null) { - schema = EdmModelHelper.GetDerivedTypesReferenceSchema(EntitySet.EntityType, Context.Model, _document); - } + if (Context is {Settings.EnableDerivedTypesReferencesForResponses: true}) + { + schema = EdmModelHelper.GetDerivedTypesReferenceSchema(EntitySet.EntityType, Context.Model, _document); + } - if (Context.Settings.ShowLinks) - { - links = Context.CreateLinks(entityType: EntitySet.EntityType, entityName: EntitySet.Name, - entityKind: EntitySet.ContainerElementKind.ToString(), path: Path, parameters: PathParameters); - } + if (Context is {Settings.ShowLinks: true} && Path is not null) + { + links = Context.CreateLinks(entityType: EntitySet.EntityType, entityName: EntitySet.Name, + entityKind: EntitySet.ContainerElementKind.ToString(), path: Path, parameters: PathParameters); + } - if (schema == null) - { - schema = new OpenApiSchemaReference(EntitySet.EntityType.FullName(), _document); + schema ??= new OpenApiSchemaReference(EntitySet.EntityType.FullName(), _document); } operation.Responses = new OpenApiResponses { { - Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, + Context?.Settings.UseSuccessStatusCodeRange ?? false ? Constants.StatusCodeClass2XX : Constants.StatusCode200, new OpenApiResponse { Description = "Retrieved entity", @@ -139,7 +145,8 @@ protected override void SetResponses(OpenApiOperation operation) } } }; - operation.AddErrorResponses(Context.Settings, _document, false); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, false); base.SetResponses(operation); } @@ -157,12 +164,12 @@ protected override void SetSecurity(OpenApiOperation operation) readBase = _readRestrictions.ReadByKeyRestrictions; } - if (readBase == null && readBase.Permissions == null) + if (readBase == null || readBase.Permissions == null) { return; } - operation.Security = Context.CreateSecurityRequirements(readBase.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(readBase.Permissions, _document).ToList(); } protected override void AppendCustomParameters(OpenApiOperation operation) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetGetOperationHandler.cs index d79848c1e..e4b36f8ef 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetGetOperationHandler.cs @@ -47,7 +47,7 @@ protected override void Initialize(ODataContext context, ODataPath path) if (!string.IsNullOrEmpty(TargetPath)) _readRestrictions = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - if (Context is not null) + if (Context is not null && EntitySet is not null) { var entityReadRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.ReadRestrictions); _readRestrictions?.MergePropertiesIfNull(entityReadRestrictions); @@ -59,12 +59,12 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetBasicInfo(OpenApiOperation operation) { // Summary and Descriptions - string placeHolder = "Get entities from " + EntitySet.Name; + string placeHolder = "Get entities from " + EntitySet?.Name; operation.Summary = _readRestrictions?.Description ?? placeHolder; operation.Description = _readRestrictions?.LongDescription ?? Context?.Model.GetDescriptionAnnotation(EntitySet); // OperationId - if (Context is {Settings.EnableOperationId: true}) + if (Context is {Settings.EnableOperationId: true} && EntitySet is not null) { string typeName = EntitySet.EntityType.Name; operation.OperationId = EntitySet.Name + "." + typeName + ".List" + Utils.UpperFirstChar(typeName); @@ -91,7 +91,7 @@ protected override void SetExtensions(OpenApiOperation operation) protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); - if (Context is null) return; + if (Context is null || EntitySet is null) return; // The parameters array contains Parameter Objects for all system query options allowed for this collection, // and it does not list system query options not allowed for this collection, see terms @@ -166,7 +166,7 @@ protected override void SetResponses(OpenApiOperation operation) { { Context?.Settings.UseSuccessStatusCodeRange ?? false ? Constants.StatusCodeClass2XX : Constants.StatusCode200, - new OpenApiResponseReference($"{EntitySet.EntityType.FullName()}{Constants.CollectionSchemaSuffix}", _document) + new OpenApiResponseReference($"{EntitySet?.EntityType.FullName()}{Constants.CollectionSchemaSuffix}", _document) } }; diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetPostOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetPostOperationHandler.cs index 4364e7a23..cb81cacee 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetPostOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetPostOperationHandler.cs @@ -44,7 +44,7 @@ protected override void Initialize(ODataContext context, ODataPath path) if (!string.IsNullOrEmpty(TargetPath)) _insertRestrictions = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); - if (Context is not null) + if (Context is not null && EntitySet is not null) { var entityInsertRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.InsertRestrictions); _insertRestrictions?.MergePropertiesIfNull(entityInsertRestrictions); @@ -56,12 +56,12 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetBasicInfo(OpenApiOperation operation) { // Summary and Description - string placeHolder = "Add new entity to " + EntitySet.Name; + string placeHolder = "Add new entity to " + EntitySet?.Name; operation.Summary = _insertRestrictions?.Description ?? placeHolder; operation.Description = _insertRestrictions?.LongDescription; // OperationId - if (Context is {Settings.EnableOperationId: true}) + if (Context is {Settings.EnableOperationId: true} && EntitySet is not null) { string typeName = EntitySet.EntityType.Name; operation.OperationId = EntitySet.Name + "." + typeName + ".Create" + Utils.UpperFirstChar(typeName); @@ -141,7 +141,7 @@ protected override void AppendCustomParameters(OpenApiOperation operation) var schema = GetEntitySchema(); var content = new Dictionary(); - if (EntitySet.EntityType.HasStream) + if (EntitySet is {EntityType.HasStream: true}) { if (Context?.Model.GetCollection(EntitySet.EntityType, CoreConstants.AcceptableMediaTypes) is {} mediaTypes) @@ -196,6 +196,7 @@ protected override void AppendCustomParameters(OpenApiOperation operation) /// The entity schema. private IOpenApiSchema? GetEntitySchema() { + if (EntitySet is null) return null; return Context?.Settings.EnableDerivedTypesReferencesForRequestBody ?? false ? EdmModelHelper.GetDerivedTypesReferenceSchema(EntitySet.EntityType, Context.Model, _document) : new OpenApiSchemaReference(EntitySet.EntityType.FullName(), _document); diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/IOperationHandlerProvider.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/IOperationHandlerProvider.cs index be07c065f..4d812c1c7 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/IOperationHandlerProvider.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/IOperationHandlerProvider.cs @@ -21,6 +21,6 @@ internal interface IOperationHandlerProvider /// The operation type. /// The Open API document to use to lookup references. /// The corresponding . - IOperationHandler GetHandler(ODataPathKind pathKind, HttpMethod operationType, OpenApiDocument document); + IOperationHandler? GetHandler(ODataPathKind pathKind, HttpMethod operationType, OpenApiDocument document); } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandlerProvider.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandlerProvider.cs index 9f65fedf8..ebb420d37 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandlerProvider.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandlerProvider.cs @@ -16,7 +16,7 @@ namespace Microsoft.OpenApi.OData.Operation internal class OperationHandlerProvider : IOperationHandlerProvider { /// - public IOperationHandler GetHandler(ODataPathKind pathKind, HttpMethod operationType, OpenApiDocument document) + public IOperationHandler? GetHandler(ODataPathKind pathKind, HttpMethod operationType, OpenApiDocument document) { return (pathKind, operationType.ToString().ToLowerInvariant()) switch { diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/RefDeleteOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/RefDeleteOperationHandler.cs index 5211b8657..f0f544400 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/RefDeleteOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/RefDeleteOperationHandler.cs @@ -29,7 +29,7 @@ public RefDeleteOperationHandler(OpenApiDocument document) : base(document) } /// public override HttpMethod OperationType => HttpMethod.Delete; - private DeleteRestrictionsType _deleteRestriction; + private DeleteRestrictionsType? _deleteRestriction; /// protected override void Initialize(ODataContext context, ODataPath path) @@ -42,15 +42,15 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetBasicInfo(OpenApiOperation operation) { // Summary and Description - string placeHolder = "Delete ref of navigation property " + NavigationProperty.Name + " for " + NavigationSource.Name; + string placeHolder = "Delete ref of navigation property " + NavigationProperty?.Name + " for " + NavigationSource?.Name; operation.Summary = _deleteRestriction?.Description ?? placeHolder; operation.Description = _deleteRestriction?.LongDescription; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true}) { string prefix = "DeleteRef"; - var segments = GetOperationId().Split('.').ToList(); + var segments = GetOperationId()?.Split('.').ToList() ?? []; if (SecondLastSegmentIsKeySegment) { @@ -73,6 +73,7 @@ protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); + operation.Parameters ??= []; operation.Parameters.Add(new OpenApiParameter { Name = "If-Match", @@ -86,7 +87,7 @@ protected override void SetParameters(OpenApiOperation operation) // for collection, we should have @id in query if (NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many && - Path.Segments.Reverse().Skip(1).First() is ODataNavigationPropertySegment) + Path?.Segments.Reverse().Skip(1).First() is ODataNavigationPropertySegment) { operation.Parameters.Add(new OpenApiParameter { @@ -110,14 +111,14 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_deleteRestriction.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_deleteRestriction.Permissions, _document).ToList(); } /// protected override void SetResponses(OpenApiOperation operation) { // Response for Delete methods should be 204 No Content - OpenApiConvertSettings settings = Context.Settings.Clone(); + var settings = Context?.Settings.Clone() ?? new(); settings.UseSuccessStatusCodeRange = false; operation.AddErrorResponses(settings, _document, true); diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/ComplexPropertyItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/ComplexPropertyItemHandler.cs index f027d2f14..db185db72 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/ComplexPropertyItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/ComplexPropertyItemHandler.cs @@ -3,8 +3,10 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Collections.Generic; using System.Net.Http; using Microsoft.OData.Edm; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; @@ -28,7 +30,7 @@ public ComplexPropertyItemHandler(OpenApiDocument document) : base(document) /// /// Gets the complex property /// - protected IEdmStructuralProperty ComplexProperty { get; private set; } + protected IEdmStructuralProperty? ComplexProperty { get; private set; } /// protected override void SetOperations(OpenApiPathItem item) @@ -40,10 +42,13 @@ protected override void SetOperations(OpenApiPathItem item) public void AddReadOperation(OpenApiPathItem item) { - ReadRestrictionsType readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - ReadRestrictionsType complexTypeReadRestrictions = Context.Model.GetRecord(ComplexProperty, CapabilitiesConstants.ReadRestrictions); - readRestrictions?.MergePropertiesIfNull(complexTypeReadRestrictions); - readRestrictions ??= complexTypeReadRestrictions; + var readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + if (ComplexProperty is not null) + { + var complexTypeReadRestrictions = Context.Model.GetRecord(ComplexProperty, CapabilitiesConstants.ReadRestrictions); + readRestrictions?.MergePropertiesIfNull(complexTypeReadRestrictions); + readRestrictions ??= complexTypeReadRestrictions; + } bool isReadable = readRestrictions?.Readable ?? false; if ((Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths && isReadable) || !Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths) @@ -56,10 +61,13 @@ public void AddInsertOperation(OpenApiPathItem item) { if (Path.LastSegment is ODataComplexPropertySegment segment && segment.Property.Type.IsCollection()) { - InsertRestrictionsType insertRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); - InsertRestrictionsType entityInsertRestrictions = Context.Model.GetRecord(ComplexProperty, CapabilitiesConstants.InsertRestrictions); - insertRestrictions?.MergePropertiesIfNull(entityInsertRestrictions); - insertRestrictions ??= entityInsertRestrictions; + var insertRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); + if (ComplexProperty is not null) + { + var entityInsertRestrictions = Context.Model.GetRecord(ComplexProperty, CapabilitiesConstants.InsertRestrictions); + insertRestrictions?.MergePropertiesIfNull(entityInsertRestrictions); + insertRestrictions ??= entityInsertRestrictions; + } bool isInsertable = insertRestrictions?.Insertable ?? false; if ((Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths && isInsertable) || !Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths) @@ -71,10 +79,13 @@ public void AddInsertOperation(OpenApiPathItem item) public void AddUpdateOperation(OpenApiPathItem item) { - UpdateRestrictionsType updateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); - UpdateRestrictionsType complexTypeUpdateRestrictions = Context.Model.GetRecord(ComplexProperty, CapabilitiesConstants.UpdateRestrictions); - updateRestrictions?.MergePropertiesIfNull(complexTypeUpdateRestrictions); - updateRestrictions ??= complexTypeUpdateRestrictions; + var updateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); + if (ComplexProperty is not null) + { + var complexTypeUpdateRestrictions = Context.Model.GetRecord(ComplexProperty, CapabilitiesConstants.UpdateRestrictions); + updateRestrictions?.MergePropertiesIfNull(complexTypeUpdateRestrictions); + updateRestrictions ??= complexTypeUpdateRestrictions; + } bool isUpdatable = updateRestrictions?.Updatable ?? false; if ((Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths && isUpdatable) || !Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths) @@ -101,13 +112,16 @@ protected override void Initialize(ODataContext context, ODataPath path) base.Initialize(context, path); // The last segment should be the complex property segment. - ODataComplexPropertySegment navigationSourceSegment = path.LastSegment as ODataComplexPropertySegment; - ComplexProperty = navigationSourceSegment.Property; + if (path.LastSegment is ODataComplexPropertySegment {Property: {} property}) + ComplexProperty = property; } /// protected override void SetExtensions(OpenApiPathItem item) { + if (ComplexProperty is null) return; + + item.Extensions ??= new Dictionary(); item.Extensions.AddCustomAttributesToExtensions(Context, ComplexProperty); } } \ No newline at end of file diff --git a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt index 2f2f4074f..acd486f25 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt +++ b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt @@ -33,7 +33,7 @@ Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.ODataOperationImportSegment(Microsoft.OData.Edm.IEdmOperationImport! operationImport) -> void Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.ODataOperationImportSegment(Microsoft.OData.Edm.IEdmOperationImport! operationImport, System.Collections.Generic.IDictionary! parameterMappings) -> void Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.OperationImport.get -> Microsoft.OData.Edm.IEdmOperationImport! -Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.ParameterMappings.get -> System.Collections.Generic.IDictionary! +Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.ParameterMappings.get -> System.Collections.Generic.IDictionary? Microsoft.OpenApi.OData.Edm.ODataOperationSegment Microsoft.OpenApi.OData.Edm.ODataOperationSegment.IsEscapedFunction.get -> bool Microsoft.OpenApi.OData.Edm.ODataOperationSegment.ODataOperationSegment(Microsoft.OData.Edm.IEdmOperation! operation) -> void @@ -261,7 +261,7 @@ override Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.GetAnnotables( override Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! override Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.Identifier.get -> string! override Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType! +override Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType? override Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! override Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! override Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.Identifier.get -> string! From 0de5fb19ff6ce44d3ed1e8d3096f89c57c4198b7 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 26 Mar 2025 13:31:26 -0400 Subject: [PATCH 12/24] chore: additional NRT fixes Signed-off-by: Vincent Biret --- .../Common/Utils.cs | 6 +- .../Generator/OpenApiSchemaGenerator.cs | 38 ++++++----- .../ComplexPropertyPostOperationHandler.cs | 18 +++-- .../ComplexPropertyUpdateOperationHandler.cs | 15 +++-- .../DollarCountGetOperationHandler.cs | 45 +++++++------ .../EdmOperationImportOperationHandler.cs | 66 +++++++++++-------- .../PathItem/EntityPathItemHandler.cs | 47 ++++++++----- .../PathItem/EntitySetPathItemHandler.cs | 42 +++++++----- .../PathItem/MediaEntityPathItemHandler.cs | 24 +++---- .../OperationImportPathItemHandler.cs | 23 ++++--- .../PathItem/PathItemHandler.cs | 23 ++++--- 11 files changed, 207 insertions(+), 140 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Common/Utils.cs b/src/Microsoft.OpenApi.OData.Reader/Common/Utils.cs index d5db7aa58..7438e6e84 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Common/Utils.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Common/Utils.cs @@ -212,10 +212,10 @@ private static Dictionary GetCustomXMLAttributesValueMapping(IEd internal static bool IsBaseTypeReferencedAsTypeInModel( this IEdmModel model, IEdmStructuredType baseType, - IEnumerable structuredTypes = null, - IEnumerable actions = null) + IEnumerable? structuredTypes = null, + IEnumerable? actions = null) { - string baseTypeName = baseType?.FullTypeName(); + string baseTypeName = baseType.FullTypeName(); bool isBaseTypeEntity = Constants.EntityName.Equals(baseTypeName?.Split('.').Last(), StringComparison.OrdinalIgnoreCase); if (!string.IsNullOrEmpty(baseTypeName) && !isBaseTypeEntity) diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs index 7bad0fef5..1cb0941da 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs @@ -106,6 +106,7 @@ public static void AddSchemasToDocument(this ODataContext context, OpenApiDocume }; document.AddComponent(Constants.BaseCollectionPaginationCountResponse, responseSchema); + responseSchema.Properties ??= new Dictionary(); if (context.Settings.EnableCount) responseSchema.Properties.Add(ODataConstants.OdataCount); if (context.Settings.EnablePagination) @@ -210,7 +211,7 @@ internal static IEnumerable GetAllCollectionEntityTypes(this private static OpenApiSchema CreateCollectionSchema(ODataContext context, IEdmStructuredType structuredType, OpenApiDocument document) { - IOpenApiSchema schema = null; + IOpenApiSchema? schema = null; var entityType = structuredType as IEdmEntityType; if (context.Settings.EnableDerivedTypesReferencesForResponses && entityType != null) @@ -315,6 +316,7 @@ public static OpenApiSchema CreateEnumTypeSchema(this ODataContext context, IEdm { IsFlags = true, }; + schema.Extensions ??= new Dictionary(); schema.Extensions.Add(OpenApiEnumFlagsExtension.Name, enumFlagsExtension); } @@ -334,12 +336,15 @@ public static OpenApiSchema CreateEnumTypeSchema(this ODataContext context, IEdm AddEnumDescription(member, extension, context); } - if(extension?.ValuesDescriptions.Any() ?? false) + if(extension is {ValuesDescriptions.Count:> 0}) + { + schema.Extensions ??= new Dictionary(); schema.Extensions.Add(OpenApiEnumValuesDescriptionExtension.Name, extension); + } schema.Title = enumType.Name; return schema; } - private static void AddEnumDescription(IEdmEnumMember member, OpenApiEnumValuesDescriptionExtension target, ODataContext context) + private static void AddEnumDescription(IEdmEnumMember member, OpenApiEnumValuesDescriptionExtension? target, ODataContext context) { if (target == null) return; @@ -485,12 +490,12 @@ internal static IOpenApiSchema CreateSchemaTypeSchema(this ODataContext context, private static OpenApiSchema CreateStructuredTypeSchema(this ODataContext context, IEdmStructuredType structuredType, bool processBase, bool processExample, OpenApiDocument document, - IEnumerable derivedTypes = null) + IEnumerable? derivedTypes = null) { Debug.Assert(context != null); Debug.Assert(structuredType != null); - JsonNode example = null; + JsonNode? example = null; if (context.Settings.ShowSchemaExamples) { example = CreateStructuredTypePropertiesExample(context, structuredType, document); @@ -504,8 +509,8 @@ private static OpenApiSchema CreateStructuredTypeSchema(this ODataContext contex if (processBase && structuredType.BaseType != null) { // The x-ms-discriminator-value extension is added to structured types which are derived types. - Dictionary extension = null; - if (context.Settings.EnableDiscriminatorValue && !derivedTypes.Any()) + Dictionary? extension = null; + if (context.Settings.EnableDiscriminatorValue && (derivedTypes is null || !derivedTypes.Any())) { extension = new Dictionary { @@ -537,11 +542,13 @@ private static OpenApiSchema CreateStructuredTypeSchema(this ODataContext contex else { // The discriminator object is added to structured types which have derived types. - OpenApiDiscriminator discriminator = null; - if (context.Settings.EnableDiscriminatorValue && derivedTypes.Any()) + OpenApiDiscriminator? discriminator = null; + if (context.Settings.EnableDiscriminatorValue && derivedTypes is not null && derivedTypes.Any()) { Dictionary mapping = derivedTypes - .ToDictionary(x => $"#{x.FullTypeName()}", x => new OpenApiSchemaReference(x.FullTypeName(), document).Reference.ReferenceV3); + .Select(x => ($"#{x.FullTypeName()}", new OpenApiSchemaReference(x.FullTypeName(), document).Reference.ReferenceV3)) + .Where(x => x.Item2 != null) + .ToDictionary(x => x.Item1, x => x.Item2!); discriminator = new OpenApiDiscriminator { @@ -571,13 +578,13 @@ private static OpenApiSchema CreateStructuredTypeSchema(this ODataContext contex if (context.Settings.EnableDiscriminatorValue) { - JsonNode defaultValue = null; + JsonNode? defaultValue = null; bool isBaseTypeEntity = Constants.EntityName.Equals(structuredType.BaseType?.FullTypeName().Split('.').Last(), StringComparison.OrdinalIgnoreCase); bool isBaseTypeAbstractNonEntity = (structuredType.BaseType?.IsAbstract ?? false) && !isBaseTypeEntity; if (!context.Settings.EnableTypeDisambiguationForDefaultValueOfOdataTypeProperty || isBaseTypeAbstractNonEntity || - context.Model.IsBaseTypeReferencedAsTypeInModel(structuredType.BaseType)) + structuredType.BaseType is not null && context.Model.IsBaseTypeReferencedAsTypeInModel(structuredType.BaseType)) { defaultValue = "#" + structuredType.FullTypeName(); } @@ -591,6 +598,7 @@ private static OpenApiSchema CreateStructuredTypeSchema(this ODataContext contex throw new InvalidOperationException( $"Property {Constants.OdataType} is already present in schema {structuredType.FullTypeName()}; verify CSDL."); } + schema.Required ??= new HashSet(); schema.Required.Add(Constants.OdataType); } @@ -629,7 +637,7 @@ internal static JsonObject CreateStructuredTypePropertiesExample(ODataContext co if (propertyType.TypeKind() == EdmTypeKind.Primitive && item is JsonValue jsonValue && - jsonValue.TryGetValue(out string stringAny) && + jsonValue.TryGetValue(out var stringAny) && structuredType is IEdmEntityType entityType && entityType.Key().Any(k => StringComparer.Ordinal.Equals(k.Name, property.Name))) { @@ -642,7 +650,7 @@ structuredType is IEdmEntityType entityType && return example; } - private static JsonNode GetTypeNameForPrimitive(ODataContext context, IEdmTypeReference edmTypeReference, OpenApiDocument document) + private static JsonNode? GetTypeNameForPrimitive(ODataContext context, IEdmTypeReference edmTypeReference, OpenApiDocument document) { IEdmPrimitiveType primitiveType = edmTypeReference.AsPrimitive().PrimitiveDefinition(); IOpenApiSchema schema = context.CreateSchema(primitiveType, document); @@ -685,7 +693,7 @@ EdmTypeKind.Primitive when edmTypeReference.IsInt16() || edmTypeReference.IsInt64() || edmTypeReference.IsFloating() || edmTypeReference.IsDouble() => 0, - EdmTypeKind.Primitive => GetTypeNameForPrimitive(context, edmTypeReference, document), + EdmTypeKind.Primitive when GetTypeNameForPrimitive(context, edmTypeReference, document) is JsonNode primitiveType => primitiveType, EdmTypeKind.Entity or EdmTypeKind.Complex => new JsonObject() { diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPostOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPostOperationHandler.cs index a6734b032..6afcd91bb 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPostOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPostOperationHandler.cs @@ -36,21 +36,25 @@ protected override void Initialize(ODataContext context, ODataPath path) throw new InvalidOperationException("OData conventions do not support POSTing to a complex property that is not a collection."); } - _insertRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); - var complexPropertyInsertRestrictions = Context.Model.GetRecord(ComplexPropertySegment.Property, CapabilitiesConstants.InsertRestrictions); + if (!string.IsNullOrEmpty(TargetPath)) + { + _insertRestrictions = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); + } + + var complexPropertyInsertRestrictions = Context?.Model.GetRecord(ComplexPropertySegment.Property, CapabilitiesConstants.InsertRestrictions); _insertRestrictions?.MergePropertiesIfNull(complexPropertyInsertRestrictions); _insertRestrictions ??= complexPropertyInsertRestrictions; } /// public override HttpMethod OperationType => HttpMethod.Post; - private InsertRestrictionsType _insertRestrictions; + private InsertRestrictionsType? _insertRestrictions; /// protected override void SetBasicInfo(OpenApiOperation operation) { // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true} && Path is not null) { operation.OperationId = EdmModelHelper.GenerateComplexPropertyPathOperationId(Path, Context, "Set"); } @@ -68,6 +72,7 @@ protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); + operation.Parameters ??= []; operation.Parameters.Add(new OpenApiParameter { Name = "If-Match", @@ -102,7 +107,8 @@ protected override void SetRequestBody(OpenApiOperation operation) /// protected override void SetResponses(OpenApiOperation operation) { - operation.AddErrorResponses(Context.Settings, _document, true, GetOpenApiSchema()); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, true, GetOpenApiSchema()); base.SetResponses(operation); } @@ -113,7 +119,7 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_insertRestrictions.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_insertRestrictions.Permissions, _document).ToList(); } protected override void AppendCustomParameters(OpenApiOperation operation) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyUpdateOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyUpdateOperationHandler.cs index 1ac6ce8da..27de2675c 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyUpdateOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyUpdateOperationHandler.cs @@ -28,14 +28,16 @@ protected ComplexPropertyUpdateOperationHandler(OpenApiDocument document) : base } - private UpdateRestrictionsType _updateRestrictions; + private UpdateRestrictionsType? _updateRestrictions; protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - _updateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); - var complexPropertyUpdateRestrictions = Context.Model.GetRecord(ComplexPropertySegment.Property, CapabilitiesConstants.UpdateRestrictions); + if (!string.IsNullOrEmpty(TargetPath)) + _updateRestrictions = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); + + var complexPropertyUpdateRestrictions = Context?.Model.GetRecord(ComplexPropertySegment.Property, CapabilitiesConstants.UpdateRestrictions); _updateRestrictions?.MergePropertiesIfNull(complexPropertyUpdateRestrictions); _updateRestrictions ??= complexPropertyUpdateRestrictions; } @@ -49,7 +51,7 @@ protected override void SetBasicInfo(OpenApiOperation operation) operation.Description = _updateRestrictions?.LongDescription; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true} && Path is not null) { string prefix = OperationType == HttpMethod.Patch ? "Update" : "Set"; operation.OperationId = EdmModelHelper.GenerateComplexPropertyPathOperationId(Path, Context, prefix); @@ -80,7 +82,8 @@ protected override void SetRequestBody(OpenApiOperation operation) /// protected override void SetResponses(OpenApiOperation operation) { - operation.AddErrorResponses(Context.Settings, _document, true, GetOpenApiSchema()); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, true, GetOpenApiSchema()); base.SetResponses(operation); } protected override void SetSecurity(OpenApiOperation operation) @@ -90,7 +93,7 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_updateRestrictions.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_updateRestrictions.Permissions, _document).ToList(); } protected override void AppendCustomParameters(OpenApiOperation operation) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/DollarCountGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/DollarCountGetOperationHandler.cs index 1779329cc..96b6e773d 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/DollarCountGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/DollarCountGetOperationHandler.cs @@ -11,7 +11,6 @@ using Microsoft.OData.Edm.Vocabularies; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; -using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; @@ -40,8 +39,8 @@ public DollarCountGetOperationHandler(OpenApiDocument document) : base(document) /// Gets/sets the segment before $count. /// this segment could be "entity set", "Collection property", "Composable function whose return is collection",etc. /// - internal ODataSegment SecondLastSegment { get; set; } - private ODataSegment firstSegment; + internal ODataSegment? SecondLastSegment { get; set; } + private ODataSegment? firstSegment; private int pathCount; private const int SecondLastSegmentIndex = 2; private readonly List annotatables = []; @@ -61,19 +60,19 @@ protected override void Initialize(ODataContext context, ODataPath path) AddODataSegmentToAnnotables(SecondLastSegment, path.Segments.Count > SecondLastSegmentIndex ? path.Segments.SkipLast(SecondLastSegmentIndex).ToArray() : []); } - private void AddODataSegmentToAnnotables(ODataSegment oDataSegment, ODataSegment[] oDataSegments) + private void AddODataSegmentToAnnotables(ODataSegment? oDataSegment, ODataSegment[] oDataSegments) { - if (oDataSegment is ODataNavigationSourceSegment sourceSegment) + if (oDataSegment is ODataNavigationSourceSegment {NavigationSource: IEdmEntitySet sourceSet}) { - annotatables.Add(sourceSegment.NavigationSource as IEdmEntitySet); + annotatables.Add(sourceSet); } else if (oDataSegment is ODataNavigationPropertySegment navigationPropertySegment) { annotatables.Add(navigationPropertySegment.NavigationProperty); } - else if (oDataSegment is ODataTypeCastSegment odataTypeCastSegment) + else if (oDataSegment is ODataTypeCastSegment {StructuredType: IEdmVocabularyAnnotatable annotable}) { - annotatables.Add(odataTypeCastSegment.StructuredType as IEdmVocabularyAnnotatable); + annotatables.Add(annotable); if (annotatables.Count == 1 && oDataSegments.Length > 0) {// we want to look at the parent navigation property or entity set AddODataSegmentToAnnotables(oDataSegments[oDataSegments.Length - 1], oDataSegments.SkipLast(1).ToArray()); @@ -84,7 +83,7 @@ private void AddODataSegmentToAnnotables(ODataSegment oDataSegment, ODataSegment /// protected override void SetTags(OpenApiOperation operation) { - string tagName = null; + string? tagName = null; operation.Tags ??= new HashSet(); if (SecondLastSegment is ODataNavigationSourceSegment sourceSegment) @@ -95,7 +94,7 @@ protected override void SetTags(OpenApiOperation operation) { tagName = TagNameFromNavigationPropertySegment(); } - else if (SecondLastSegment is ODataTypeCastSegment) + else if (SecondLastSegment is ODataTypeCastSegment && Path is not null) { ODataSegment lastThirdSegment = Path.Segments[pathCount - 3]; if (lastThirdSegment is ODataNavigationSourceSegment sourceSegment2) @@ -107,12 +106,12 @@ protected override void SetTags(OpenApiOperation operation) tagName = TagNameFromNavigationPropertySegment(); } } - else if (SecondLastSegment is ODataComplexPropertySegment) + else if (SecondLastSegment is ODataComplexPropertySegment && Path is not null && Context is not null) { tagName = EdmModelHelper.GenerateComplexPropertyPathTagName(Path, Context); } - if (tagName != null) + if (tagName != null && Context is not null) { Context.AddExtensionToTag(tagName, Constants.xMsTocType, new OpenApiAny("page"), () => new OpenApiTag() { @@ -127,9 +126,9 @@ string TagNameFromNavigationSourceSegment(ODataNavigationSourceSegment sourceSeg return $"{sourceSegment.NavigationSource.Name}.{sourceSegment.NavigationSource.EntityType.Name}"; } - string TagNameFromNavigationPropertySegment() + string? TagNameFromNavigationPropertySegment() { - return EdmModelHelper.GenerateNavigationPropertyPathTagName(Path, Context); + return Path is null || Context is null ? null : EdmModelHelper.GenerateNavigationPropertyPathTagName(Path, Context); } base.SetTags(operation); @@ -142,9 +141,9 @@ protected override void SetBasicInfo(OpenApiOperation operation) operation.Summary = $"Get the number of the resource"; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true} && Path is not null) { - if (SecondLastSegment is ODataNavigationSourceSegment) + if (SecondLastSegment is ODataNavigationSourceSegment && firstSegment is not null) { operation.OperationId = $"{firstSegment.Identifier}.GetCount-{Path.GetPathHash(Context.Settings)}"; } @@ -153,9 +152,8 @@ protected override void SetBasicInfo(OpenApiOperation operation) var navPropOpId = string.Join(".", EdmModelHelper.RetrieveNavigationPropertyPathsOperationIdSegments(Path, Context)); operation.OperationId = $"{navPropOpId}.GetCount-{Path.GetPathHash(Context.Settings)}"; } - else if (SecondLastSegment is ODataTypeCastSegment odataTypeCastSegment) + else if (SecondLastSegment is ODataTypeCastSegment { StructuredType: IEdmNamedElement targetStructuredType}) { - IEdmNamedElement targetStructuredType = odataTypeCastSegment.StructuredType as IEdmNamedElement; operation.OperationId = $"{EdmModelHelper.GenerateODataTypeCastPathOperationIdPrefix(Path, Context, false)}.GetCount.As{Utils.UpperFirstChar(targetStructuredType.Name)}-{Path.GetPathHash(Context.Settings)}"; } else if (SecondLastSegment is ODataComplexPropertySegment) @@ -173,11 +171,12 @@ protected override void SetResponses(OpenApiOperation operation) operation.Responses = new OpenApiResponses { { - Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, + Context?.Settings.UseSuccessStatusCodeRange ?? false ? Constants.StatusCodeClass2XX : Constants.StatusCode200, new OpenApiResponseReference(Constants.DollarCountSchemaName, _document) } }; - operation.AddErrorResponses(Context.Settings, _document, false); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, false); base.SetResponses(operation); } @@ -207,10 +206,10 @@ protected override void SetParameters(OpenApiOperation operation) protected override void AppendCustomParameters(OpenApiOperation operation) { - ReadRestrictionsType readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - if (annotatables.Count > 0) + var readRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + if (annotatables.Count > 0 && Context is not null) { - ReadRestrictionsType annotatableReadRestrictions = annotatables.Select(x => Context.Model.GetRecord(x, CapabilitiesConstants.ReadRestrictions)).FirstOrDefault(static x => x is not null); + var annotatableReadRestrictions = annotatables.Select(x => Context.Model.GetRecord(x, CapabilitiesConstants.ReadRestrictions)).FirstOrDefault(static x => x is not null); readRestrictions?.MergePropertiesIfNull(annotatableReadRestrictions); readRestrictions ??= annotatableReadRestrictions; } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationImportOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationImportOperationHandler.cs index d158e0654..b537b0b62 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationImportOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationImportOperationHandler.cs @@ -8,6 +8,7 @@ using System.Linq; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.OData.Common; @@ -31,17 +32,17 @@ protected EdmOperationImportOperationHandler(OpenApiDocument document):base(docu { } - private OperationRestrictionsType _operationRestriction; + private OperationRestrictionsType? _operationRestriction; /// /// Gets the . /// - protected IEdmOperationImport EdmOperationImport { get; private set; } + protected IEdmOperationImport? EdmOperationImport { get; private set; } /// /// Gets the . /// - protected ODataOperationImportSegment OperationImportSegment { get; private set; } + protected ODataOperationImportSegment? OperationImportSegment { get; private set; } /// protected override void Initialize(ODataContext context, ODataPath path) @@ -49,29 +50,34 @@ protected override void Initialize(ODataContext context, ODataPath path) base.Initialize(context, path); OperationImportSegment = path.LastSegment as ODataOperationImportSegment; - EdmOperationImport = OperationImportSegment.OperationImport; + EdmOperationImport = OperationImportSegment?.OperationImport; - _operationRestriction = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.OperationRestrictions); - var operationRestrictions = Context.Model.GetRecord(EdmOperationImport, CapabilitiesConstants.OperationRestrictions); - - if (_operationRestriction == null) - { - _operationRestriction = operationRestrictions; - } - else + _operationRestriction = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.OperationRestrictions); + + + if (EdmOperationImport is not null && Context?.Model.GetRecord(EdmOperationImport, CapabilitiesConstants.OperationRestrictions) is {} operationRestrictions) { - _operationRestriction.MergePropertiesIfNull(operationRestrictions); + if (_operationRestriction == null) + { + _operationRestriction = operationRestrictions; + } + else + { + _operationRestriction.MergePropertiesIfNull(operationRestrictions); + } } } /// protected override void SetBasicInfo(OpenApiOperation operation) { - operation.Summary = "Invoke " + (EdmOperationImport.IsActionImport() ? "actionImport " : "functionImport ") + EdmOperationImport.Name; + operation.Summary = "Invoke " + (EdmOperationImport.IsActionImport() ? "actionImport " : "functionImport ") + EdmOperationImport?.Name; - operation.Description = Context.Model.GetDescriptionAnnotation(TargetPath) ?? Context.Model.GetDescriptionAnnotation(EdmOperationImport); + if (Context is not null) + operation.Description = (string.IsNullOrEmpty(TargetPath) ? null : Context.Model.GetDescriptionAnnotation(TargetPath)) ?? + Context.Model.GetDescriptionAnnotation(EdmOperationImport); - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true} && EdmOperationImport is not null ) { if (EdmOperationImport.IsActionImport()) { @@ -81,7 +87,7 @@ protected override void SetBasicInfo(OpenApiOperation operation) { if (Context.Model.IsOperationImportOverload(EdmOperationImport)) { - operation.OperationId = "FunctionImport." + EdmOperationImport.Name + "-" + Path.LastSegment.GetPathHash(Context.Settings); + operation.OperationId = "FunctionImport." + EdmOperationImport.Name + "-" + Path?.LastSegment?.GetPathHash(Context.Settings); } else { @@ -100,7 +106,9 @@ protected override void SetResponses(OpenApiOperation operation) // describing the structure of the success response by referencing an appropriate schema // in the global schemas. In addition, it contains a default name/value pair for // the OData error response referencing the global responses. - operation.Responses = Context.CreateResponses(EdmOperationImport, _document); + + if (Context is not null && EdmOperationImport is not null) + operation.Responses = Context.CreateResponses(EdmOperationImport, _document); base.SetResponses(operation); } @@ -113,7 +121,7 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_operationRestriction.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_operationRestriction.Permissions, _document).ToList(); } /// @@ -138,12 +146,16 @@ protected override void AppendCustomParameters(OpenApiOperation operation) /// protected override void SetTags(OpenApiOperation operation) { - var tag = CreateTag(EdmOperationImport); - tag.Extensions.Add(Constants.xMsTocType, new OpenApiAny("container")); - Context.AppendTag(tag); + if (EdmOperationImport is not null) + { + var tag = CreateTag(EdmOperationImport); + tag.Extensions ??= new Dictionary(); + tag.Extensions.Add(Constants.xMsTocType, new OpenApiAny("container")); + Context?.AppendTag(tag); - operation.Tags ??= new HashSet(); - operation.Tags.Add(new OpenApiTagReference(tag.Name, _document)); + operation.Tags ??= new HashSet(); + operation.Tags.Add(new OpenApiTagReference(tag.Name!, _document)); + } base.SetTags(operation); } @@ -172,10 +184,10 @@ internal static string PathAsString(IEnumerable path) /// protected override void SetExternalDocs(OpenApiOperation operation) { - if (Context.Settings.ShowExternalDocs) + if (Context is {Settings.ShowExternalDocs: true} && CustomLinkRel is not null) { - var externalDocs = Context.Model.GetLinkRecord(TargetPath, CustomLinkRel) ?? - Context.Model.GetLinkRecord(EdmOperationImport, CustomLinkRel); + var externalDocs = (string.IsNullOrEmpty(TargetPath) ? null : Context.Model.GetLinkRecord(TargetPath, CustomLinkRel)) ?? + (EdmOperationImport is null ? null : Context.Model.GetLinkRecord(EdmOperationImport, CustomLinkRel)); if (externalDocs != null) { diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/EntityPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/EntityPathItemHandler.cs index 9b394158b..22f91287a 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/EntityPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/EntityPathItemHandler.cs @@ -3,8 +3,10 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Collections.Generic; using System.Net.Http; using Microsoft.OData.Edm; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; @@ -31,10 +33,14 @@ public EntityPathItemHandler(OpenApiDocument document) : base(document) /// protected override void SetOperations(OpenApiPathItem item) { - ReadRestrictionsType readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - ReadRestrictionsType entityReadRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.ReadRestrictions); - readRestrictions?.MergePropertiesIfNull(entityReadRestrictions); - readRestrictions ??= entityReadRestrictions; + var readRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + + if (Context is not null && EntitySet is not null) + { + var entityReadRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.ReadRestrictions); + readRestrictions?.MergePropertiesIfNull(entityReadRestrictions); + readRestrictions ??= entityReadRestrictions; + } if (readRestrictions == null || (readRestrictions.ReadByKeyRestrictions == null && readRestrictions.IsReadable) || (readRestrictions.ReadByKeyRestrictions != null && readRestrictions.ReadByKeyRestrictions.IsReadable)) @@ -43,10 +49,14 @@ protected override void SetOperations(OpenApiPathItem item) AddOperation(item, HttpMethod.Get); } - UpdateRestrictionsType updateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); - UpdateRestrictionsType entityUpdateRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.UpdateRestrictions); - updateRestrictions?.MergePropertiesIfNull(entityUpdateRestrictions); - updateRestrictions ??= entityUpdateRestrictions; + var updateRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); + + if (Context is not null && EntitySet is not null) + { + var entityUpdateRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.UpdateRestrictions); + updateRestrictions?.MergePropertiesIfNull(entityUpdateRestrictions); + updateRestrictions ??= entityUpdateRestrictions; + } if (updateRestrictions?.IsUpdatable ?? true) { if (updateRestrictions?.IsUpdateMethodPutAndPatch == true) @@ -64,10 +74,14 @@ protected override void SetOperations(OpenApiPathItem item) } } - DeleteRestrictionsType deleteRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); - DeleteRestrictionsType entityDeleteRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.DeleteRestrictions); - deleteRestrictions?.MergePropertiesIfNull(entityDeleteRestrictions); - deleteRestrictions ??= entityDeleteRestrictions; + var deleteRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); + + if (Context is not null && EntitySet is not null) + { + var entityDeleteRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.DeleteRestrictions); + deleteRestrictions?.MergePropertiesIfNull(entityDeleteRestrictions); + deleteRestrictions ??= entityDeleteRestrictions; + } if (deleteRestrictions?.IsDeletable ?? true) { AddOperation(item, HttpMethod.Delete); @@ -75,10 +89,13 @@ protected override void SetOperations(OpenApiPathItem item) } /// - protected override void SetExtensions(OpenApiPathItem pathItem) + protected override void SetExtensions(OpenApiPathItem item) { - base.SetExtensions(pathItem); - pathItem.Extensions.AddCustomAttributesToExtensions(Context, EntitySet.EntityType); + base.SetExtensions(item); + if (EntitySet is null || Context is null) return; + + item.Extensions ??= new Dictionary(); + item.Extensions.AddCustomAttributesToExtensions(Context, EntitySet.EntityType); } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/EntitySetPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/EntitySetPathItemHandler.cs index 0240a0fea..403250959 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/EntitySetPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/EntitySetPathItemHandler.cs @@ -3,8 +3,10 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Collections.Generic; using System.Net.Http; using Microsoft.OData.Edm; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; @@ -31,24 +33,32 @@ public EntitySetPathItemHandler(OpenApiDocument document) : base(document) /// /// Gets the entity set. /// - protected IEdmEntitySet EntitySet { get; private set; } + protected IEdmEntitySet? EntitySet { get; private set; } /// protected override void SetOperations(OpenApiPathItem item) { - ReadRestrictionsType readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - ReadRestrictionsType entityReadRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.ReadRestrictions); - readRestrictions?.MergePropertiesIfNull(entityReadRestrictions); - readRestrictions ??= entityReadRestrictions; + var readRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + + if (Context is not null && EntitySet is not null) + { + var entityReadRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.ReadRestrictions); + readRestrictions?.MergePropertiesIfNull(entityReadRestrictions); + readRestrictions ??= entityReadRestrictions; + } if (readRestrictions?.IsReadable ?? true) { AddOperation(item, HttpMethod.Get); } - InsertRestrictionsType insertRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); - InsertRestrictionsType entityInsertRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.InsertRestrictions); - insertRestrictions?.MergePropertiesIfNull(entityInsertRestrictions); - insertRestrictions ??= entityInsertRestrictions; + var insertRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); + + if (Context is not null && EntitySet is not null) + { + var entityInsertRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.InsertRestrictions); + insertRestrictions?.MergePropertiesIfNull(entityInsertRestrictions); + insertRestrictions ??= entityInsertRestrictions; + } if (insertRestrictions?.IsInsertable ?? true) { AddOperation(item, HttpMethod.Post); @@ -61,21 +71,23 @@ protected override void Initialize(ODataContext context, ODataPath path) base.Initialize(context, path); // The first segment should be the entity set segment. - ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; - EntitySet = navigationSourceSegment.NavigationSource as IEdmEntitySet; + if (path.FirstSegment is ODataNavigationSourceSegment {NavigationSource: IEdmEntitySet sourceSet}) + EntitySet = sourceSet; } /// protected override void SetBasicInfo(OpenApiPathItem pathItem) { base.SetBasicInfo(pathItem); - pathItem.Description = $"Provides operations to manage the collection of {EntitySet.EntityType.Name} entities."; + pathItem.Description = $"Provides operations to manage the collection of {EntitySet?.EntityType.Name} entities."; } /// - protected override void SetExtensions(OpenApiPathItem pathItem) + protected override void SetExtensions(OpenApiPathItem item) { - base.SetExtensions(pathItem); - pathItem.Extensions.AddCustomAttributesToExtensions(Context, EntitySet); + base.SetExtensions(item); + if (EntitySet is null || Context is null) return; + item.Extensions ??= new Dictionary(); + item.Extensions.AddCustomAttributesToExtensions(Context, EntitySet); } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/MediaEntityPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/MediaEntityPathItemHandler.cs index 0abd02072..bacbcd9e4 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/MediaEntityPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/MediaEntityPathItemHandler.cs @@ -30,20 +30,20 @@ public MediaEntityPathItemHandler(OpenApiDocument document) : base(document) /// /// Gets the entity set. /// - protected IEdmEntitySet EntitySet { get; private set; } + protected IEdmEntitySet? EntitySet { get; private set; } /// /// Gets the singleton. /// - protected IEdmSingleton Singleton { get; private set; } + protected IEdmSingleton? Singleton { get; private set; } /// protected override void SetOperations(OpenApiPathItem item) { - ReadRestrictionsType readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - ReadRestrictionsType navSourceReadRestrictions = EntitySet != null + var readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + var navSourceReadRestrictions = EntitySet != null ? Context.Model.GetRecord(EntitySet) - : Context.Model.GetRecord(Singleton); + : (Singleton is null ? null : Context.Model.GetRecord(Singleton)); readRestrictions ??= navSourceReadRestrictions; if (readRestrictions == null || (readRestrictions.ReadByKeyRestrictions == null && readRestrictions.IsReadable) || @@ -52,20 +52,20 @@ protected override void SetOperations(OpenApiPathItem item) AddOperation(item, HttpMethod.Get); } - UpdateRestrictionsType updateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); - UpdateRestrictionsType navSourceUpdateRestrictions = EntitySet != null + var updateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); + var navSourceUpdateRestrictions = EntitySet != null ? Context.Model.GetRecord(EntitySet) - : Context.Model.GetRecord(Singleton); + : (Singleton is null ? null : Context.Model.GetRecord(Singleton)); updateRestrictions ??= navSourceUpdateRestrictions; if (updateRestrictions?.IsUpdatable ?? true) { AddOperation(item, HttpMethod.Put); } - DeleteRestrictionsType deleteRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); - DeleteRestrictionsType navSourceDeleteRestrictions = EntitySet != null + var deleteRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); + var navSourceDeleteRestrictions = EntitySet != null ? Context.Model.GetRecord(EntitySet) - : Context.Model.GetRecord(Singleton); + : (Singleton is null ? null : Context.Model.GetRecord(Singleton)); deleteRestrictions ??= navSourceDeleteRestrictions; if (deleteRestrictions?.IsDeletable ?? true) { @@ -88,7 +88,7 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetBasicInfo(OpenApiPathItem pathItem) { base.SetBasicInfo(pathItem); - pathItem.Description = $"Provides operations to manage the media for the {(EntitySet?.EntityType ?? Singleton?.EntityType).Name} entity."; + pathItem.Description = $"Provides operations to manage the media for the {(EntitySet?.EntityType ?? Singleton?.EntityType)?.Name} entity."; } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/OperationImportPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/OperationImportPathItemHandler.cs index 2d3eab0a6..a7a53286d 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/OperationImportPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/OperationImportPathItemHandler.cs @@ -3,8 +3,10 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Collections.Generic; using System.Net.Http; using Microsoft.OData.Edm; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; @@ -31,7 +33,7 @@ public OperationImportPathItemHandler(OpenApiDocument document) : base(document) /// /// Gets the operation import. /// - public IEdmOperationImport EdmOperationImport { get; private set; } + public IEdmOperationImport? EdmOperationImport { get; private set; } /// protected override void SetOperations(OpenApiPathItem item) @@ -52,10 +54,13 @@ protected override void SetOperations(OpenApiPathItem item) // how to invoke the function import. // so far, - ReadRestrictionsType readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - ReadRestrictionsType operationReadRestrictions = Context.Model.GetRecord(EdmOperationImport, CapabilitiesConstants.ReadRestrictions); - readRestrictions?.MergePropertiesIfNull(operationReadRestrictions); - readRestrictions ??= operationReadRestrictions; + var readRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + if (Context is not null && EdmOperationImport is not null) + { + var operationReadRestrictions = Context.Model.GetRecord(EdmOperationImport, CapabilitiesConstants.ReadRestrictions); + readRestrictions?.MergePropertiesIfNull(operationReadRestrictions); + readRestrictions ??= operationReadRestrictions; + } if (readRestrictions?.IsReadable ?? true) { AddOperation(item, HttpMethod.Get); @@ -68,21 +73,23 @@ protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - ODataOperationImportSegment operationImportSegment = path.FirstSegment as ODataOperationImportSegment; - EdmOperationImport = operationImportSegment.OperationImport; + if (path.FirstSegment is ODataOperationImportSegment {OperationImport: {} import}) + EdmOperationImport = import; } /// protected override void SetBasicInfo(OpenApiPathItem pathItem) { base.SetBasicInfo(pathItem); - pathItem.Description = $"Provides operations to call the {EdmOperationImport.Name} method."; + pathItem.Description = $"Provides operations to call the {EdmOperationImport?.Name} method."; } /// protected override void SetExtensions(OpenApiPathItem item) { base.SetExtensions(item); + if (EdmOperationImport is null || Context is null) return; + item.Extensions ??= new Dictionary(); item.Extensions.AddCustomAttributesToExtensions(Context, EdmOperationImport); } } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/PathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/PathItemHandler.cs index 97e9c8805..0d20abedc 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/PathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/PathItemHandler.cs @@ -7,7 +7,6 @@ using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; using Microsoft.OpenApi.OData.Generator; -using Microsoft.OpenApi.OData.Operation; using Microsoft.OpenApi.OData.Properties; using System; using System.Net.Http; @@ -37,17 +36,17 @@ protected PathItemHandler(OpenApiDocument document) /// /// Gets the OData Context. /// - protected ODataContext Context { get; private set; } + protected ODataContext? Context { get; private set; } /// /// Gets the OData Path. /// - protected ODataPath Path { get; private set; } + protected ODataPath? Path { get; private set; } /// /// Gets the string representation of the Edm target path for annotations. /// - protected string TargetPath; + protected string? TargetPath; /// public virtual OpenApiPathItem CreatePathItem(ODataContext context, ODataPath path) @@ -115,14 +114,14 @@ protected virtual void SetExtensions(OpenApiPathItem item) protected virtual void AddOperation(OpenApiPathItem item, HttpMethod operationType) { string httpMethod = operationType.ToString(); - if (!Path.SupportHttpMethod(httpMethod)) + if (Path is null || !Path.SupportHttpMethod(httpMethod)) { return; } - IOperationHandlerProvider provider = Context.OperationHandlerProvider; - IOperationHandler operationHandler = provider.GetHandler(Path.Kind, operationType, _document); - item.AddOperation(operationType, operationHandler.CreateOperation(Context, Path)); + if (Context?.OperationHandlerProvider is {} provider && + provider.GetHandler(Path.Kind, operationType, _document) is {} operationHandler) + item.AddOperation(operationType, operationHandler.CreateOperation(Context, Path)); } /// @@ -131,9 +130,13 @@ protected virtual void AddOperation(OpenApiPathItem item, HttpMethod operationTy /// The . protected virtual void SetParameters(OpenApiPathItem item) { - foreach (var parameter in Path.CreatePathParameters(Context, _document)) + if (Context is not null && Path?.CreatePathParameters(Context, _document) is { Count:> 0} parameters) { - item.Parameters.AppendParameter(parameter); + item.Parameters ??= []; + foreach (var parameter in parameters) + { + item.Parameters.AppendParameter(parameter); + } } } } From 5362d832e09ff254c2265bdd750022c61578713a Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 26 Mar 2025 14:45:16 -0400 Subject: [PATCH 13/24] chore: additional NRT fixes Signed-off-by: Vincent Biret --- .../Edm/ODataContext.cs | 11 +- .../Edm/ODataPathProvider.cs | 100 +++++++++--------- .../Generator/OpenApiParameterGenerator.cs | 27 ++--- .../Operation/EdmActionOperationHandler.cs | 17 ++- .../Operation/EdmFunctionOperationHandler.cs | 10 +- .../Operation/RefGetOperationHandler.cs | 58 +++++----- .../Operation/RefPutOperationHandler.cs | 11 +- .../PathItem/ODataTypeCastPathItemHandler.cs | 15 ++- 8 files changed, 138 insertions(+), 111 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataContext.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataContext.cs index 300accc9f..1441a32fd 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataContext.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataContext.cs @@ -9,6 +9,7 @@ using Microsoft.OData.Edm; using Microsoft.OData.Edm.Vocabularies; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Generator; @@ -24,7 +25,7 @@ namespace Microsoft.OpenApi.OData.Edm /// internal class ODataContext { - private IEnumerable _allPaths; + private IEnumerable? _allPaths; private readonly IODataPathProvider _pathProvider; /// @@ -135,7 +136,7 @@ public IEnumerable AllPaths /// /// Gets all tags. /// - public ISet Tags { get; private set; } + public ISet? Tags { get; private set; } /// /// Append tag. @@ -145,7 +146,7 @@ internal void AppendTag(OpenApiTag tagItem) { Tags ??= new HashSet(); - if (FindTagByName(tagItem.Name) is not null) + if (tagItem.Name is not null && FindTagByName(tagItem.Name) is not null) { return; } @@ -158,7 +159,7 @@ internal void AppendTag(OpenApiTag tagItem) /// /// The name to lookup the tag. /// - internal OpenApiTag FindTagByName(string name) + internal OpenApiTag? FindTagByName(string name) { Utils.CheckArgumentNullOrEmpty(name, nameof(name)); return Tags?.FirstOrDefault(t => StringComparer.Ordinal.Equals(t.Name, name)); @@ -180,11 +181,13 @@ internal void AddExtensionToTag(string tagName, string extensionName, OpenApiAny if (FindTagByName(tagName) is {} foundTag) { + foundTag.Extensions ??= new Dictionary(); foundTag.Extensions.TryAdd(extensionName, extensionValue); } else { var tag = initialValueFactory(); + tag.Extensions ??= new Dictionary(); tag.Extensions.TryAdd(extensionName, extensionValue); AppendTag(tag); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs index 896f36068..a4fe2031f 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs @@ -346,7 +346,7 @@ private void RetrieveComplexPropertyPaths(IEdmEntityType entityType, ODataPath c // Append navigation property paths for this complex property RetrieveComplexTypeNavigationPropertyPaths(complexType, currentPath, convertSettings); - // Traverse this complex property to rerieve nested navigation property paths + // Traverse this complex property to retrieve nested navigation property paths TraverseComplexProperty(sp, currentPath, convertSettings); } @@ -519,12 +519,11 @@ private void RetrieveNavigationPropertyPaths( } // Get the annotatable navigation source for this navigation property. - IEdmVocabularyAnnotatable annotatableNavigationSource = (currentPath.FirstSegment as ODataNavigationSourceSegment)?.NavigationSource as IEdmVocabularyAnnotatable; NavigationRestrictionsType? navSourceRestrictionType = null; NavigationRestrictionsType? navPropRestrictionType = null; // Get the NavigationRestrictions referenced by this navigation property: Can be defined in the navigation source or in-lined in the navigation property. - if (annotatableNavigationSource != null && _model is not null) + if (currentPath.FirstSegment is ODataNavigationSourceSegment { NavigationSource: IEdmVocabularyAnnotatable annotatableNavigationSource } && _model is not null) { navSourceRestrictionType = _model.GetRecord(annotatableNavigationSource, CapabilitiesConstants.NavigationRestrictions); navPropRestrictionType = _model.GetRecord(navigationProperty, CapabilitiesConstants.NavigationRestrictions); @@ -550,22 +549,13 @@ private void RetrieveNavigationPropertyPaths( visitedNavigationProperties.Push(navPropFullyQualifiedName); // For fetching annotations - var targetPath = currentPath.GetTargetPath(_model); + var targetPath = _model is null ? null : currentPath.GetTargetPath(_model); // Check whether a collection-valued navigation property should be indexed by key value(s). // Find indexability annotation annotated directly via NavigationPropertyRestriction. - bool? annotatedIndexability = _model.GetBoolean(targetPath, CapabilitiesConstants.IndexableByKey) - ?? _model.GetBoolean(navigationProperty, CapabilitiesConstants.IndexableByKey); - bool indexableByKey = true; - - if (restriction?.IndexableByKey != null) - { - indexableByKey = (bool)restriction.IndexableByKey; - } - else if (annotatedIndexability != null) - { - indexableByKey = annotatedIndexability.Value; - } + bool? annotatedIndexability = (string.IsNullOrEmpty(targetPath) ? null : _model?.GetBoolean(targetPath, CapabilitiesConstants.IndexableByKey)) + ?? _model?.GetBoolean(navigationProperty, CapabilitiesConstants.IndexableByKey); + bool indexableByKey = restriction?.IndexableByKey ?? annotatedIndexability ?? true; if (indexableByKey) { @@ -578,8 +568,8 @@ private void RetrieveNavigationPropertyPaths( if (count == null) { // First, get the directly annotated restriction annotation of the navigation property - count = _model.GetRecord(targetPath, CapabilitiesConstants.CountRestrictions) - ?? _model.GetRecord(navigationProperty, CapabilitiesConstants.CountRestrictions); + count = (string.IsNullOrEmpty(targetPath) ? null : _model?.GetRecord(targetPath, CapabilitiesConstants.CountRestrictions)) + ?? _model?.GetRecord(navigationProperty, CapabilitiesConstants.CountRestrictions); createCountPath = count?.Countable; } @@ -740,8 +730,6 @@ private void CreateTypeCastPaths(ODataPath currentPath, OpenApiConvertSettings c if(!annotedTypeNames.Any() && convertSettings.RequireDerivedTypesConstraintForODataTypeCastSegments) return; // we don't want to generate any downcast path item if there is no type cast annotation. - var annotedTypeNamesSet = new HashSet(annotedTypeNames, StringComparer.OrdinalIgnoreCase); - bool filter(IEdmStructuredType x) => convertSettings.RequireDerivedTypesConstraintForODataTypeCastSegments && annotedTypeNames.Contains(x.FullTypeName()) || !convertSettings.RequireDerivedTypesConstraintForODataTypeCastSegments && ( @@ -750,16 +738,18 @@ bool filter(IEdmStructuredType x) => ); var targetTypes = _model - .FindAllDerivedTypes(structuredType) + ?.FindAllDerivedTypes(structuredType) .Where(x => (x.TypeKind == EdmTypeKind.Entity || x.TypeKind == EdmTypeKind.Complex) && filter(x)) .OfType() .ToArray(); + if (targetTypes is not { Length: > 0} || _model is null) return; + foreach (var targetType in targetTypes) { var targetTypeSegment = new ODataTypeCastSegment(targetType, _model); - if (currentPath.Segments.Any(x => x.Identifier.Equals(targetTypeSegment.Identifier))) + if (currentPath.Segments.Any(x => x.Identifier?.Equals(targetTypeSegment.Identifier) ?? false)) { // In case we have expanded a derived type's navigation property // and we are in a cyclic loop where the expanded navigation property @@ -802,7 +792,7 @@ bool filter(IEdmStructuredType x) => /// private void RetrieveBoundOperationPaths(OpenApiConvertSettings convertSettings) { - var edmOperations = _model.GetAllElements().OfType().Where(x => x.IsBound).ToArray(); + var edmOperations = _model?.GetAllElements().OfType().Where(x => x.IsBound).ToArray() ?? []; foreach (var edmOperation in edmOperations) { if (!CanFilter(edmOperation)) @@ -876,7 +866,7 @@ private void RetrieveBoundOperationPaths(OpenApiConvertSettings convertSettings) && operationSegment.Operation is IEdmFunction edmFunction && edmFunction.IsComposable && edmFunction.ReturnType != null - && edmFunction.ReturnType.Definition is IEdmEntityType returnBindingEntityType); + && edmFunction.ReturnType.Definition is IEdmEntityType); foreach( var functionPath in functionPaths) { @@ -902,11 +892,11 @@ functionPath.LastSegment is ODataOperationSegment && { /* Get number of segments already appended after the first composable function segment */ - int composableFuncSegIndex = functionPath.Segments.IndexOf( - functionPath.Segments.FirstOrDefault( - x => x is ODataOperationSegment operationSegment && - operationSegment.Operation is IEdmFunction edmFunction && - edmFunction.IsComposable)); + int composableFuncSegIndex = functionPath + .Segments + .OfType() + .FirstOrDefault(x => x.Operation is IEdmFunction {IsComposable: true}) is {} firstOperationSegment ? + functionPath.Segments.IndexOf(firstOperationSegment) : -1; int currentDepth = functionPath.Count - composableFuncSegIndex - 1; if (currentDepth < convertSettings.ComposableFunctionsExpansionDepth) @@ -928,10 +918,10 @@ bool filter(IEdmNavigationSource z) => z.EntityType.FindAllBaseTypes().Contains(firstEntityType); return new IEdmEntityType[] { firstEntityType } - .Union(_model.EntityContainer.EntitySets() - .Where(filter).Select(x => x.EntityType)) //Search all EntitySets - .Union(_model.EntityContainer.Singletons() - .Where(filter).Select(x => x.EntityType)) //Search all singletons + .Union(_model?.EntityContainer.EntitySets() + .Where(filter).Select(x => x.EntityType) ?? []) //Search all EntitySets + .Union(_model?.EntityContainer.Singletons() + .Where(filter).Select(x => x.EntityType) ?? []) //Search all singletons .Distinct() .ToList(); } @@ -944,9 +934,9 @@ bool filter(IEdmNavigationSource z) => }; private void AppendBoundOperationOnNavigationSourcePath(IEdmOperation edmOperation, bool isCollection, IEdmEntityType bindingEntityType, OpenApiConvertSettings convertSettings) { - if (_allNavigationSourcePaths.TryGetValue(bindingEntityType, out IList value)) + if (_allNavigationSourcePaths.TryGetValue(bindingEntityType, out var value)) { - bool isEscapedFunction = _model.IsUrlEscapeFunction(edmOperation); + bool isEscapedFunction = _model?.IsUrlEscapeFunction(edmOperation) ?? false; foreach (var subPath in value) { @@ -973,7 +963,7 @@ secondLastPathSegment is not ODataKeySegment && var annotatable = (lastPathSegment as ODataNavigationSourceSegment)?.NavigationSource as IEdmVocabularyAnnotatable; annotatable ??= (lastPathSegment as ODataKeySegment)?.EntityType; - if (annotatable != null && !EdmModelHelper.IsOperationAllowed(_model, edmOperation, annotatable)) + if (annotatable != null && _model is not null && !EdmModelHelper.IsOperationAllowed(_model, edmOperation, annotatable)) { // Check whether the navigation source is allowed to have an operation on the entity type annotatable = (secondLastPathSegment as ODataNavigationSourceSegment)?.NavigationSource as IEdmVocabularyAnnotatable; @@ -983,9 +973,12 @@ secondLastPathSegment is not ODataKeySegment && } } - ODataPath newPath = subPath.Clone(); - newPath.Push(new ODataOperationSegment(edmOperation, isEscapedFunction, _model)); - AppendPath(newPath); + if (_model is not null) + { + ODataPath newPath = subPath.Clone(); + newPath.Push(new ODataOperationSegment(edmOperation, isEscapedFunction, _model)); + AppendPath(newPath); + } } } } @@ -995,15 +988,15 @@ secondLastPathSegment is not ODataKeySegment && }; private void AppendBoundOperationOnNavigationPropertyPath(IEdmOperation edmOperation, bool isCollection, IEdmEntityType bindingEntityType) { - bool isEscapedFunction = _model.IsUrlEscapeFunction(edmOperation); + bool isEscapedFunction = _model?.IsUrlEscapeFunction(edmOperation) ?? false; - if (_allNavigationPropertyPaths.TryGetValue(bindingEntityType, out IList value)) + if (_allNavigationPropertyPaths.TryGetValue(bindingEntityType, out var value)) { foreach (var path in value.Where(x => !_pathKindToSkipForNavigationProperties.Contains(x.Kind))) { - ODataNavigationPropertySegment npSegment = path.Segments.Last(s => s is ODataNavigationPropertySegment) as ODataNavigationPropertySegment; + ODataNavigationPropertySegment npSegment = path.Segments.OfType().Last(); - if (!EdmModelHelper.IsOperationAllowed(_model, edmOperation, npSegment.NavigationProperty, npSegment.NavigationProperty.ContainsTarget)) + if (_model is not null && !EdmModelHelper.IsOperationAllowed(_model, edmOperation, npSegment.NavigationProperty, npSegment.NavigationProperty.ContainsTarget)) { continue; } @@ -1030,9 +1023,12 @@ private void AppendBoundOperationOnNavigationPropertyPath(IEdmOperation edmOpera } } - ODataPath newPath = path.Clone(); - newPath.Push(new ODataOperationSegment(edmOperation, isEscapedFunction, _model)); - AppendPath(newPath); + if (_model is not null) + { + ODataPath newPath = path.Clone(); + newPath.Push(new ODataOperationSegment(edmOperation, isEscapedFunction, _model)); + AppendPath(newPath); + } } } } @@ -1044,22 +1040,24 @@ private void AppendBoundOperationOnDerived( OpenApiConvertSettings convertSettings) { if (!convertSettings.AppendBoundOperationsOnDerivedTypeCastSegments) return; - bool isEscapedFunction = _model.IsUrlEscapeFunction(edmOperation); + bool isEscapedFunction = _model?.IsUrlEscapeFunction(edmOperation) ?? false; + if (_allNavigationSources is null) return; foreach (var baseType in bindingEntityType.FindAllBaseTypes()) { - if (_allNavigationSources.TryGetValue(baseType, out IList baseNavigationSource)) + if (_allNavigationSources.TryGetValue(baseType, out var baseNavigationSource)) { foreach (var ns in baseNavigationSource) { - if (HasUnsatisfiedDerivedTypeConstraint( - ns as IEdmVocabularyAnnotatable, + if (ns is not IEdmVocabularyAnnotatable nsAnnotable || + HasUnsatisfiedDerivedTypeConstraint( + nsAnnotable, baseType, convertSettings)) { continue; } - if (!EdmModelHelper.IsOperationAllowed(_model, edmOperation, ns as IEdmVocabularyAnnotatable)) + if (_model is null || !EdmModelHelper.IsOperationAllowed(_model, edmOperation, nsAnnotable)) { continue; } diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiParameterGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiParameterGenerator.cs index f3ad4900f..8c986e22b 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiParameterGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiParameterGenerator.cs @@ -17,6 +17,7 @@ using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Models.Interfaces; +using Microsoft.OpenApi.Interfaces; namespace Microsoft.OpenApi.OData.Generator { @@ -160,7 +161,7 @@ public static IList CreateParameters(this ODataContext contex /// The created list of . public static IList CreateKeyParameters(this ODataContext context, ODataKeySegment keySegment, OpenApiDocument document, - IDictionary parameterNameMapping = null) + IDictionary? parameterNameMapping = null) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(keySegment, nameof(keySegment)); @@ -193,6 +194,7 @@ public static IList CreateKeyParameters(this ODataContext cont Schema = context.CreateEdmTypeSchemaForParameter(keys[0].Type, document) }; + parameter.Extensions ??= new Dictionary(); parameter.Extensions.Add(Constants.xMsKeyType, new OpenApiAny(entityType.Name)); parameters.Add(parameter); } @@ -218,6 +220,7 @@ public static IList CreateKeyParameters(this ODataContext cont parameter.Description += $", {keyProperty.Name}={quote}{{{parameter.Name}}}{quote}"; } + parameter.Extensions ??= new Dictionary(); parameter.Extensions.Add(Constants.xMsKeyType, new OpenApiAny(entityType.Name)); parameters.Add(parameter); } @@ -341,21 +344,21 @@ public static List CreatePathParameters(this ODataPath path, /// The new OpenApiParameter to be appended public static void AppendParameter(this IList parameters, IOpenApiParameter parameter) { - HashSet parametersSet = new(parameters.Select(p => p.Name)); - - string parameterName = parameter.Name; - int index = 1; - while (parametersSet.Contains(parameterName)) - { - parameterName += index.ToString(); - index++; - } + HashSet parametersSet = new(parameters.Select(p => p.Name).OfType()); - if (parameter is OpenApiParameter openApiParameter) + if (parameter.Name is not string parameterName && + parameter is OpenApiParameter openApiParameter) { + parameterName = string.Empty; + int index = 1; + while (parametersSet.Contains(parameterName)) + { + parameterName += index.ToString(); + index++; + } openApiParameter.Name = parameterName; } - parametersSet.Add(parameterName); + parameters.Add(parameter); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionOperationHandler.cs index 057147b30..0aed94706 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionOperationHandler.cs @@ -3,9 +3,11 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Collections.Generic; using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.OData.Common; @@ -36,10 +38,14 @@ protected override void SetBasicInfo(OpenApiOperation operation) { base.SetBasicInfo(operation); - InsertRestrictionsType insertRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); - InsertRestrictionsType operationReadRestrictions = Context.Model.GetRecord(EdmOperation, CapabilitiesConstants.InsertRestrictions); - insertRestrictions?.MergePropertiesIfNull(operationReadRestrictions); - insertRestrictions ??= operationReadRestrictions; + var insertRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); + + if (Context is not null && EdmOperation is not null) + { + var operationReadRestrictions = Context?.Model.GetRecord(EdmOperation, CapabilitiesConstants.InsertRestrictions); + insertRestrictions?.MergePropertiesIfNull(operationReadRestrictions); + insertRestrictions ??= operationReadRestrictions; + } // Description if (!string.IsNullOrWhiteSpace(insertRestrictions?.LongDescription)) @@ -51,7 +57,7 @@ protected override void SetBasicInfo(OpenApiOperation operation) /// protected override void SetRequestBody(OpenApiOperation operation) { - if (EdmOperation is IEdmAction action && Context.CreateRequestBody(action, _document) is OpenApiRequestBody requestBody) + if (EdmOperation is IEdmAction action && Context?.CreateRequestBody(action, _document) is OpenApiRequestBody requestBody) { if (Context.Model.OperationTargetsMultiplePaths(action)) { @@ -69,6 +75,7 @@ protected override void SetRequestBody(OpenApiOperation operation) /// protected override void SetExtensions(OpenApiOperation operation) { + operation.Extensions ??= new Dictionary(); operation.Extensions.Add(Constants.xMsDosOperationType, new OpenApiAny("action")); base.SetExtensions(operation); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionOperationHandler.cs index b291a33ad..bbe0c4bb5 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionOperationHandler.cs @@ -42,9 +42,13 @@ protected override void SetBasicInfo(OpenApiOperation operation) base.SetBasicInfo(operation); var readRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - var operationReadRestrictions = Context?.Model.GetRecord(EdmOperation, CapabilitiesConstants.ReadRestrictions); - readRestrictions?.MergePropertiesIfNull(operationReadRestrictions); - readRestrictions ??= operationReadRestrictions; + + if (Context is not null && EdmOperation is not null) + { + var operationReadRestrictions = Context.Model.GetRecord(EdmOperation, CapabilitiesConstants.ReadRestrictions); + readRestrictions?.MergePropertiesIfNull(operationReadRestrictions); + readRestrictions ??= operationReadRestrictions; + } // Description if (!string.IsNullOrWhiteSpace(readRestrictions?.LongDescription)) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/RefGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/RefGetOperationHandler.cs index 6f4138194..a70765b21 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/RefGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/RefGetOperationHandler.cs @@ -9,6 +9,7 @@ using System.Text.Json.Nodes; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; @@ -34,7 +35,7 @@ public RefGetOperationHandler(OpenApiDocument document) : base(document) } /// public override HttpMethod OperationType => HttpMethod.Get; - private ReadRestrictionsType _readRestriction; + private ReadRestrictionsType? _readRestriction; /// protected override void Initialize(ODataContext context, ODataPath path) @@ -47,13 +48,13 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetBasicInfo(OpenApiOperation operation) { // Summary and Description - string placeHolder = "Get ref of " + NavigationProperty.Name + " from " + NavigationSource.Name; + string placeHolder = "Get ref of " + NavigationProperty?.Name + " from " + NavigationSource?.Name; operation.Summary = (LastSegmentIsKeySegment ? _readRestriction?.ReadByKeyRestrictions?.Description : _readRestriction?.Description) ?? placeHolder; operation.Description = (LastSegmentIsKeySegment ? _readRestriction?.ReadByKeyRestrictions?.LongDescription : _readRestriction?.LongDescription) - ?? Context.Model.GetDescriptionAnnotation(NavigationProperty); + ?? Context?.Model.GetDescriptionAnnotation(NavigationProperty); // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true}) { string prefix = "GetRef"; if (!LastSegmentIsKeySegment && NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) @@ -67,18 +68,16 @@ protected override void SetBasicInfo(OpenApiOperation operation) protected override void SetExtensions(OpenApiOperation operation) { - if (Context.Settings.EnablePagination) + if (Context is { Settings.EnablePagination: true } && NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) { - if (NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) - { - JsonObject extension = new JsonObject + JsonObject extension = new JsonObject { { "nextLinkName", "@odata.nextLink"}, { "operationName", Context.Settings.PageableOperationName} }; - operation.Extensions.Add(Constants.xMsPageable, new OpenApiAny(extension)); - } + operation.Extensions ??= new Dictionary(); + operation.Extensions.Add(Constants.xMsPageable, new OpenApiAny(extension)); } base.SetExtensions(operation); @@ -92,7 +91,7 @@ protected override void SetResponses(OpenApiOperation operation) operation.Responses = new OpenApiResponses { { - Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, + Context?.Settings.UseSuccessStatusCodeRange ?? false ? Constants.StatusCodeClass2XX : Constants.StatusCode200, new OpenApiResponseReference($"String{Constants.CollectionSchemaSuffix}", _document) } }; @@ -104,10 +103,10 @@ protected override void SetResponses(OpenApiOperation operation) // $ref returns string for the Uri? Type = JsonSchemaType.String }; - IDictionary links = null; - if (Context.Settings.ShowLinks) + IDictionary? links = null; + if (Context is {Settings.ShowLinks: true} && NavigationProperty is not null && Path is not null) { - string operationId = GetOperationId(); + var operationId = GetOperationId(); links = Context.CreateLinks(entityType: NavigationProperty.ToEntityType(), entityName: NavigationProperty.Name, entityKind: NavigationProperty.PropertyKind.ToString(), parameters: PathParameters, path: Path, @@ -117,7 +116,7 @@ protected override void SetResponses(OpenApiOperation operation) operation.Responses = new OpenApiResponses { { - Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, + Context?.Settings.UseSuccessStatusCodeRange ?? false ? Constants.StatusCodeClass2XX : Constants.StatusCode200, new OpenApiResponse { Description = "Retrieved navigation property link", @@ -137,7 +136,8 @@ protected override void SetResponses(OpenApiOperation operation) }; } - operation.AddErrorResponses(Context.Settings, _document, false); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, false); base.SetResponses(operation); } @@ -147,41 +147,48 @@ protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); - if (NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) + if (NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many && Context is not null) { // Need to verify that TopSupported or others should be applied to navigaiton source. // So, how about for the navigation property. - var parameter = Context.CreateTop(TargetPath, _document) ?? Context.CreateTop(NavigationProperty, _document); + var parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateTop(TargetPath, _document)) ?? + (NavigationProperty is null ? null : Context.CreateTop(NavigationProperty, _document)); + operation.Parameters ??= []; if (parameter != null) { operation.Parameters.Add(parameter); } - parameter = Context.CreateSkip(TargetPath, _document) ?? Context.CreateSkip(NavigationProperty, _document); + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateSkip(TargetPath, _document)) ?? + (NavigationProperty is null ? null : Context.CreateSkip(NavigationProperty, _document)); if (parameter != null) { operation.Parameters.Add(parameter); } - parameter = Context.CreateSearch(TargetPath, _document) ?? Context.CreateSearch(NavigationProperty, _document); + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateSearch(TargetPath, _document)) ?? + (NavigationProperty is null ? null : Context.CreateSearch(NavigationProperty, _document)); if (parameter != null) { operation.Parameters.Add(parameter); } - parameter = Context.CreateFilter(TargetPath, _document) ?? Context.CreateFilter(NavigationProperty, _document); + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateFilter(TargetPath, _document)) ?? + (NavigationProperty is null ? null : Context.CreateFilter(NavigationProperty, _document)); if (parameter != null) { operation.Parameters.Add(parameter); } - parameter = Context.CreateCount(TargetPath, _document) ?? Context.CreateCount(NavigationProperty, _document); + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateCount(TargetPath, _document)) ?? + (NavigationProperty is null ? null : Context.CreateCount(NavigationProperty, _document)); if (parameter != null) { operation.Parameters.Add(parameter); } - parameter = Context.CreateOrderBy(TargetPath, NavigationProperty.ToEntityType()) ?? Context.CreateOrderBy(NavigationProperty); + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateOrderBy(TargetPath, NavigationProperty.ToEntityType())) ?? + (NavigationProperty is null ? null : Context.CreateOrderBy(NavigationProperty)); if (parameter != null) { operation.Parameters.Add(parameter); @@ -191,13 +198,12 @@ protected override void SetParameters(OpenApiOperation operation) protected override void SetSecurity(OpenApiOperation operation) { - if (_readRestriction == null) + if (_readRestriction?.Permissions == null) { return; } - ReadRestrictionsBase readBase = _readRestriction; - operation.Security = Context.CreateSecurityRequirements(readBase.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_readRestriction.Permissions, _document).ToList(); } protected override void AppendCustomParameters(OpenApiOperation operation) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/RefPutOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/RefPutOperationHandler.cs index 984be2386..db539b243 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/RefPutOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/RefPutOperationHandler.cs @@ -29,7 +29,7 @@ public RefPutOperationHandler(OpenApiDocument document) : base(document) } /// public override HttpMethod OperationType => HttpMethod.Patch; - private UpdateRestrictionsType _updateRestriction; + private UpdateRestrictionsType? _updateRestriction; /// protected override void Initialize(ODataContext context, ODataPath path) @@ -42,12 +42,12 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetBasicInfo(OpenApiOperation operation) { // Summary and Description - string placeHolder = "Update the ref of navigation property " + NavigationProperty.Name + " in " + NavigationSource.Name; + string placeHolder = "Update the ref of navigation property " + NavigationProperty?.Name + " in " + NavigationSource?.Name; operation.Summary = _updateRestriction?.Description ?? placeHolder; operation.Description = _updateRestriction?.LongDescription; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true}) { string prefix = "UpdateRef"; operation.OperationId = GetOperationId(prefix); @@ -73,7 +73,8 @@ protected override void SetResponses(OpenApiOperation operation) } }; - operation.AddErrorResponses(Context.Settings, _document, false); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, false); base.SetResponses(operation); } @@ -84,7 +85,7 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_updateRestriction.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_updateRestriction.Permissions, _document).ToList(); } protected override void AppendCustomParameters(OpenApiOperation operation) diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/ODataTypeCastPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/ODataTypeCastPathItemHandler.cs index 38e4e224e..36cdd7cd5 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/ODataTypeCastPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/ODataTypeCastPathItemHandler.cs @@ -3,8 +3,10 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Collections.Generic; using System.Net.Http; using Microsoft.OData.Edm; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; @@ -41,19 +43,22 @@ protected override void Initialize(ODataContext context, ODataPath path) StructuredType = castSegment.StructuredType; } } - private IEdmStructuredType StructuredType { get; set; } + private IEdmStructuredType? StructuredType { get; set; } /// protected override void SetBasicInfo(OpenApiPathItem pathItem) { base.SetBasicInfo(pathItem); - pathItem.Description = $"Casts the previous resource to {(StructuredType as IEdmNamedElement).Name}."; + if (StructuredType is IEdmNamedElement namedElement) + pathItem.Description = $"Casts the previous resource to {namedElement.Name}."; } /// - protected override void SetExtensions(OpenApiPathItem pathItem) + protected override void SetExtensions(OpenApiPathItem item) { - base.SetExtensions(pathItem); - pathItem.Extensions.AddCustomAttributesToExtensions(Context, StructuredType); + base.SetExtensions(item); + if (StructuredType is null || Context is null) return; + item.Extensions ??= new Dictionary(); + item.Extensions.AddCustomAttributesToExtensions(Context, StructuredType); } } From 46722a967ba63d8eec1ae2cbb62dca3bfb5461ef Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 27 Mar 2025 12:35:58 -0400 Subject: [PATCH 14/24] chore: additional NRT fixes Signed-off-by: Vincent Biret --- .../Operation/RefPostOperationHandler.cs | 13 ++-- .../PathItem/OperationPathItemHandler.cs | 67 ++++++++++--------- .../PathItem/RefPathItemHandler.cs | 53 ++++++++------- .../NavigationRestrictionsType.cs | 2 +- 4 files changed, 73 insertions(+), 62 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/RefPostOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/RefPostOperationHandler.cs index 04c82e54b..228019c3a 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/RefPostOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/RefPostOperationHandler.cs @@ -29,7 +29,7 @@ public RefPostOperationHandler(OpenApiDocument document) : base(document) } /// public override HttpMethod OperationType => HttpMethod.Post; - private InsertRestrictionsType _insertRestriction; + private InsertRestrictionsType? _insertRestriction; /// protected override void Initialize(ODataContext context, ODataPath path) @@ -42,12 +42,12 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetBasicInfo(OpenApiOperation operation) { // Summary and Description - string placeHolder = "Create new navigation property ref to " + NavigationProperty.Name + " for " + NavigationSource.Name; + string placeHolder = "Create new navigation property ref to " + NavigationProperty?.Name + " for " + NavigationSource?.Name; operation.Summary = _insertRestriction?.Description ?? placeHolder; operation.Description = _insertRestriction?.LongDescription; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true}) { string prefix = "CreateRef"; operation.OperationId = GetOperationId(prefix); @@ -73,19 +73,20 @@ protected override void SetResponses(OpenApiOperation operation) } }; - operation.AddErrorResponses(Context.Settings, _document, false); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, false); base.SetResponses(operation); } protected override void SetSecurity(OpenApiOperation operation) { - if (_insertRestriction == null) + if (_insertRestriction?.Permissions is null) { return; } - operation.Security = Context.CreateSecurityRequirements(_insertRestriction.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_insertRestriction.Permissions, _document).ToList(); } protected override void AppendCustomParameters(OpenApiOperation operation) diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/OperationPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/OperationPathItemHandler.cs index 899271924..b2ea58dab 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/OperationPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/OperationPathItemHandler.cs @@ -9,6 +9,7 @@ using System.Text.Json.Nodes; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; @@ -34,7 +35,7 @@ public OperationPathItemHandler(OpenApiDocument document) : base(document) /// /// Gets the Edm operation. /// - public IEdmOperation EdmOperation { get; private set; } + public IEdmOperation? EdmOperation { get; private set; } /// protected override void SetOperations(OpenApiPathItem item) @@ -58,61 +59,65 @@ protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - ODataOperationSegment operationSegment = path.LastSegment as ODataOperationSegment; - EdmOperation = operationSegment.Operation; + if (path.LastSegment is ODataOperationSegment {Operation: {} operation}) + EdmOperation = operation; } /// protected override void SetExtensions(OpenApiPathItem item) { - if (!Context.Settings.ShowMsDosGroupPath) + if (Context is null || !Context.Settings.ShowMsDosGroupPath) { return; } - ODataNavigationSourceSegment navigationSourceSegment = Path.FirstSegment as ODataNavigationSourceSegment; - IEdmNavigationSource currentNavSource = navigationSourceSegment.NavigationSource; - - IList samePaths = new List(); - foreach (var path in Context.AllPaths.Where(p => p.Kind == ODataPathKind.Operation && p != Path)) + if (Path?.FirstSegment is ODataNavigationSourceSegment {NavigationSource: IEdmNavigationSource currentNavSource}) { - navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; - if (currentNavSource != navigationSourceSegment.NavigationSource) - { - continue; - } - ODataOperationSegment operationSegment = path.LastSegment as ODataOperationSegment; - if (EdmOperation.FullName() != operationSegment.Operation.FullName()) + var samePaths = new List(); + foreach (var path in Context.AllPaths.Where(p => p.Kind == ODataPathKind.Operation && p != Path)) { - continue; - } + if (path.FirstSegment is ODataNavigationSourceSegment navigationSourceSegment && currentNavSource != navigationSourceSegment.NavigationSource) + { + continue; + } - samePaths.Add(path); - } + if (path.LastSegment is ODataOperationSegment operationSegment && EdmOperation.FullName() != operationSegment.Operation.FullName()) + { + continue; + } - if (samePaths.Any()) - { - JsonArray array = new JsonArray(); - OpenApiConvertSettings settings = Context.Settings.Clone(); - settings.EnableKeyAsSegment = Context.KeyAsSegment; - foreach (var p in samePaths) - { - array.Add(p.GetPathItemName(settings)); + samePaths.Add(path); } - item.Extensions.Add(Constants.xMsDosGroupPath, new OpenApiAny(array)); + if (samePaths.Any()) + { + JsonArray array = new JsonArray(); + OpenApiConvertSettings settings = Context.Settings.Clone(); + settings.EnableKeyAsSegment = Context.KeyAsSegment; + foreach (var p in samePaths) + { + array.Add(p.GetPathItemName(settings)); + } + + item.Extensions ??= new Dictionary(); + item.Extensions.Add(Constants.xMsDosGroupPath, new OpenApiAny(array)); + } } base.SetExtensions(item); - item.Extensions.AddCustomAttributesToExtensions(Context, EdmOperation); + if (EdmOperation is not null) + { + item.Extensions ??= new Dictionary(); + item.Extensions.AddCustomAttributesToExtensions(Context, EdmOperation); + } } /// protected override void SetBasicInfo(OpenApiPathItem pathItem) { base.SetBasicInfo(pathItem); - pathItem.Description = $"Provides operations to call the {EdmOperation.Name} method."; + pathItem.Description = $"Provides operations to call the {EdmOperation?.Name} method."; } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/RefPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/RefPathItemHandler.cs index fffef6015..f54a88702 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/RefPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/RefPathItemHandler.cs @@ -34,28 +34,32 @@ public RefPathItemHandler(OpenApiDocument document) : base(document) /// /// Gets the navigation property. /// - public IEdmNavigationProperty NavigationProperty { get; private set; } + public IEdmNavigationProperty? NavigationProperty { get; private set; } /// /// Gets the navigation source. /// - public IEdmNavigationSource NavigationSource { get; private set; } + public IEdmNavigationSource? NavigationSource { get; private set; } /// protected override void SetOperations(OpenApiPathItem item) { - IEdmEntitySet entitySet = NavigationSource as IEdmEntitySet; - IEdmVocabularyAnnotatable target = entitySet; - target ??= NavigationSource as IEdmSingleton; + if (NavigationSource is not IEdmVocabularyAnnotatable target) + throw new InvalidOperationException($"The navigation source {NavigationSource?.Name} is not a vocabulary annotatable."); - string navigationPropertyPath = String.Join("/", - Path.Segments.Where(s => !(s is ODataKeySegment || s is ODataNavigationSourceSegment)).Select(e => e.Identifier)); + string navigationPropertyPath = string.Join("/", + Path?.Segments.Where(s => !(s is ODataKeySegment || s is ODataNavigationSourceSegment)).Select(e => e.Identifier) ?? []); - NavigationRestrictionsType navigationRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.NavigationRestrictions); - NavigationRestrictionsType sourceNavigationRestrictions = Context.Model.GetRecord(target, CapabilitiesConstants.NavigationRestrictions); - navigationRestrictions?.MergePropertiesIfNull(sourceNavigationRestrictions); - navigationRestrictions ??= sourceNavigationRestrictions; - NavigationPropertyRestriction restriction = navigationRestrictions?.RestrictedProperties?.FirstOrDefault(r => r.NavigationProperty == navigationPropertyPath); + var navigationRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.NavigationRestrictions); + + if (Context is not null && target is not null) + { + var sourceNavigationRestrictions = Context.Model.GetRecord(target, CapabilitiesConstants.NavigationRestrictions); + navigationRestrictions?.MergePropertiesIfNull(sourceNavigationRestrictions); + navigationRestrictions ??= sourceNavigationRestrictions; + } + + var restriction = navigationRestrictions?.RestrictedProperties?.FirstOrDefault(r => r.NavigationProperty == navigationPropertyPath); // verify using individual first if (restriction?.Navigability != null && restriction.Navigability.Value == NavigationType.None) @@ -77,8 +81,7 @@ protected override void SetOperations(OpenApiPathItem item) // Create the ref if (NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) { - ODataSegment penultimateSegment = Path.Segments.Reverse().Skip(1).First(); - if (penultimateSegment is ODataKeySegment) + if (Path?.Segments.Reverse().Skip(1).First() is ODataKeySegment) { // Collection-valued indexed: DELETE ~/entityset/{key}/collection-valued-Nav/{key}/$ref AddDeleteOperation(item, restriction); @@ -99,9 +102,9 @@ protected override void SetOperations(OpenApiPathItem item) } } - private void AddDeleteOperation(OpenApiPathItem item, NavigationPropertyRestriction restriction) + private void AddDeleteOperation(OpenApiPathItem item, NavigationPropertyRestriction? restriction) { - DeleteRestrictionsType deleteRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); + var deleteRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); deleteRestrictions?.MergePropertiesIfNull(restriction?.DeleteRestrictions); deleteRestrictions ??= restriction?.DeleteRestrictions; if (deleteRestrictions?.IsDeletable ?? true) @@ -110,9 +113,9 @@ private void AddDeleteOperation(OpenApiPathItem item, NavigationPropertyRestrict } } - private void AddReadOperation(OpenApiPathItem item, NavigationPropertyRestriction restriction) + private void AddReadOperation(OpenApiPathItem item, NavigationPropertyRestriction? restriction) { - ReadRestrictionsType readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + var readRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); readRestrictions?.MergePropertiesIfNull(restriction?.ReadRestrictions); readRestrictions ??= restriction?.ReadRestrictions; if (readRestrictions?.IsReadable ?? true) @@ -121,9 +124,9 @@ private void AddReadOperation(OpenApiPathItem item, NavigationPropertyRestrictio } } - private void AddInsertOperation(OpenApiPathItem item, NavigationPropertyRestriction restriction) + private void AddInsertOperation(OpenApiPathItem item, NavigationPropertyRestriction? restriction) { - InsertRestrictionsType insertRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); + var insertRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); insertRestrictions?.MergePropertiesIfNull(restriction?.InsertRestrictions); insertRestrictions ??= restriction?.InsertRestrictions; if (insertRestrictions?.IsInsertable ?? true) @@ -132,9 +135,9 @@ private void AddInsertOperation(OpenApiPathItem item, NavigationPropertyRestrict } } - private void AddUpdateOperation(OpenApiPathItem item, NavigationPropertyRestriction restriction) + private void AddUpdateOperation(OpenApiPathItem item, NavigationPropertyRestriction? restriction) { - UpdateRestrictionsType updateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); + var updateRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); updateRestrictions?.MergePropertiesIfNull(restriction?.UpdateRestrictions); updateRestrictions ??= restriction?.UpdateRestrictions; if (updateRestrictions?.IsUpdatable ?? true) @@ -148,8 +151,10 @@ protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; - NavigationSource = navigationSourceSegment.NavigationSource; + if (path.FirstSegment is ODataNavigationSourceSegment {NavigationSource: {} source}) + { + NavigationSource = source; + } NavigationProperty = path.OfType().Last().NavigationProperty; } diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/NavigationRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/NavigationRestrictionsType.cs index e0ff6696a..278f734f0 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/NavigationRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/NavigationRestrictionsType.cs @@ -244,7 +244,7 @@ public void Initialize(IEdmRecordExpression record) /// Merges properties of the specified object into this instance if they are null. /// /// The object containing properties to merge. - public void MergePropertiesIfNull(NavigationRestrictionsType source) + public void MergePropertiesIfNull(NavigationRestrictionsType? source) { if (source == null) return; From 05faaebafc56ded06eb2860c45156f24cec7041e Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 27 Mar 2025 12:58:55 -0400 Subject: [PATCH 15/24] chore: additional NRT fixes Signed-off-by: Vincent Biret --- .../ComplexPropertyBaseOperationHandler.cs | 27 +++++++----- .../ComplexPropertyGetOperationHandler.cs | 41 ++++++++++------- .../Operation/SingletonGetOperationHandler.cs | 39 +++++++++------- .../PathItem/ComplexPropertyItemHandler.cs | 33 +++++++------- .../PathItem/SingletonPathItemHandler.cs | 44 ++++++++++++------- .../Vocabulary/Authorization/Authorization.cs | 22 ++++------ .../Authorization/AuthorizationScope.cs | 6 +-- .../CollectionPropertyRestrictionsType.cs | 12 ++--- .../Capabilities/DeleteRestrictionsType.cs | 16 +++---- 9 files changed, 134 insertions(+), 106 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyBaseOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyBaseOperationHandler.cs index 79843b934..57dc7accc 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyBaseOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyBaseOperationHandler.cs @@ -23,7 +23,7 @@ protected ComplexPropertyBaseOperationHandler(OpenApiDocument document) : base(d { } - protected ODataComplexPropertySegment ComplexPropertySegment; + protected ODataComplexPropertySegment? ComplexPropertySegment; /// protected override void Initialize(ODataContext context, ODataPath path) @@ -35,15 +35,18 @@ protected override void Initialize(ODataContext context, ODataPath path) /// protected override void SetTags(OpenApiOperation operation) { - string tagName = EdmModelHelper.GenerateComplexPropertyPathTagName(Path, Context); - operation.Tags ??= new HashSet(); - if (!string.IsNullOrEmpty(tagName)) + if (Context is not null && Path is not null) { - Context.AddExtensionToTag(tagName, Constants.xMsTocType, new OpenApiAny("page"), () => new OpenApiTag() - { - Name = tagName - }); - operation.Tags.Add(new OpenApiTagReference(tagName, _document)); + string tagName = EdmModelHelper.GenerateComplexPropertyPathTagName(Path, Context); + operation.Tags ??= new HashSet(); + if (!string.IsNullOrEmpty(tagName)) + { + Context.AddExtensionToTag(tagName, Constants.xMsTocType, new OpenApiAny("page"), () => new OpenApiTag() + { + Name = tagName + }); + operation.Tags.Add(new OpenApiTagReference(tagName, _document)); + } } base.SetTags(operation); @@ -52,10 +55,10 @@ protected override void SetTags(OpenApiOperation operation) /// protected override void SetExternalDocs(OpenApiOperation operation) { - if (Context.Settings.ShowExternalDocs) + if (Context is {Settings.ShowExternalDocs: true} && CustomLinkRel is not null) { - var externalDocs = Context.Model.GetLinkRecord(TargetPath, CustomLinkRel) ?? - Context.Model.GetLinkRecord(ComplexPropertySegment.Property, CustomLinkRel); + var externalDocs = (string.IsNullOrEmpty(TargetPath) ? null : Context.Model.GetLinkRecord(TargetPath, CustomLinkRel)) ?? + (ComplexPropertySegment is null ? null : Context.Model.GetLinkRecord(ComplexPropertySegment.Property, CustomLinkRel)); if (externalDocs != null) { diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyGetOperationHandler.cs index 6e873c83c..1bce957fe 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyGetOperationHandler.cs @@ -3,11 +3,13 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Text.Json.Nodes; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; @@ -31,14 +33,14 @@ public ComplexPropertyGetOperationHandler(OpenApiDocument document):base(documen /// public override HttpMethod OperationType => HttpMethod.Get; - private ReadRestrictionsType _readRestrictions; + private ReadRestrictionsType? _readRestrictions; protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - _readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - var complexPropertyReadRestrictions = Context.Model.GetRecord(ComplexPropertySegment.Property, CapabilitiesConstants.ReadRestrictions); + _readRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + var complexPropertyReadRestrictions = Context?.Model.GetRecord(ComplexPropertySegment.Property, CapabilitiesConstants.ReadRestrictions); _readRestrictions?.MergePropertiesIfNull(complexPropertyReadRestrictions); _readRestrictions ??= complexPropertyReadRestrictions; } @@ -47,7 +49,7 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetBasicInfo(OpenApiOperation operation) { // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true} && Path is not null) { string prefix = ComplexPropertySegment.Property.Type.IsCollection() ? "List" : "Get"; operation.OperationId = EdmModelHelper.GenerateComplexPropertyPathOperationId(Path, Context, prefix); @@ -56,7 +58,7 @@ protected override void SetBasicInfo(OpenApiOperation operation) // Summary and Description string placeHolder = $"Get {ComplexPropertySegment.Property.Name} property value"; operation.Summary = _readRestrictions?.Description ?? placeHolder; - operation.Description = _readRestrictions?.LongDescription ?? Context.Model.GetDescriptionAnnotation(ComplexPropertySegment.Property); + operation.Description = _readRestrictions?.LongDescription ?? Context?.Model.GetDescriptionAnnotation(ComplexPropertySegment.Property); base.SetBasicInfo(operation); } @@ -65,7 +67,10 @@ protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); - IOpenApiParameter parameter; + if (Context is null) return; + + IOpenApiParameter? parameter; + operation.Parameters ??= []; if(ComplexPropertySegment.Property.Type.IsCollection()) { // The parameters array contains Parameter Objects for all system query options allowed for this collection, @@ -73,35 +78,35 @@ protected override void SetParameters(OpenApiOperation operation) // Capabilities.TopSupported, Capabilities.SkipSupported, Capabilities.SearchRestrictions, // Capabilities.FilterRestrictions, and Capabilities.CountRestrictions // $top - parameter = Context.CreateTop(TargetPath, _document) ?? Context.CreateTop(ComplexPropertySegment.Property, _document); + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateTop(TargetPath, _document)) ?? Context.CreateTop(ComplexPropertySegment.Property, _document); if (parameter != null) { operation.Parameters.Add(parameter); } // $skip - parameter = Context.CreateSkip(TargetPath, _document) ?? Context.CreateSkip(ComplexPropertySegment.Property, _document); + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateSkip(TargetPath, _document)) ?? Context.CreateSkip(ComplexPropertySegment.Property, _document); if (parameter != null) { operation.Parameters.Add(parameter); } // $search - parameter = Context.CreateSearch(TargetPath, _document) ?? Context.CreateSearch(ComplexPropertySegment.Property, _document); + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateSearch(TargetPath, _document)) ?? Context.CreateSearch(ComplexPropertySegment.Property, _document); if (parameter != null) { operation.Parameters.Add(parameter); } // $filter - parameter = Context.CreateFilter(TargetPath, _document) ?? Context.CreateFilter(ComplexPropertySegment.Property, _document); + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateFilter(TargetPath, _document)) ?? Context.CreateFilter(ComplexPropertySegment.Property, _document); if (parameter != null) { operation.Parameters.Add(parameter); } // $count - parameter = Context.CreateCount(TargetPath, _document) ?? Context.CreateCount(ComplexPropertySegment.Property, _document); + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateCount(TargetPath, _document)) ?? Context.CreateCount(ComplexPropertySegment.Property, _document); if (parameter != null) { operation.Parameters.Add(parameter); @@ -112,7 +117,7 @@ protected override void SetParameters(OpenApiOperation operation) // of just providing a comma-separated list of properties can be expressed via an array-valued // parameter with an enum constraint // $order - parameter = Context.CreateOrderBy(TargetPath, ComplexPropertySegment.ComplexType) + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateOrderBy(TargetPath, ComplexPropertySegment.ComplexType)) ?? Context.CreateOrderBy(ComplexPropertySegment.Property, ComplexPropertySegment.ComplexType); if (parameter != null) { @@ -121,7 +126,7 @@ protected override void SetParameters(OpenApiOperation operation) } // $select - parameter = Context.CreateSelect(TargetPath, ComplexPropertySegment.ComplexType) + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateSelect(TargetPath, ComplexPropertySegment.ComplexType)) ?? Context.CreateSelect(ComplexPropertySegment.Property, ComplexPropertySegment.ComplexType); if (parameter != null) { @@ -129,7 +134,7 @@ protected override void SetParameters(OpenApiOperation operation) } // $expand - parameter = Context.CreateExpand(TargetPath, ComplexPropertySegment.ComplexType) + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateExpand(TargetPath, ComplexPropertySegment.ComplexType)) ?? Context.CreateExpand(ComplexPropertySegment.Property, ComplexPropertySegment.ComplexType); if (parameter != null) { @@ -139,13 +144,14 @@ protected override void SetParameters(OpenApiOperation operation) protected override void SetExtensions(OpenApiOperation operation) { - if (Context.Settings.EnablePagination && ComplexPropertySegment.Property.Type.IsCollection()) + if (Context is {Settings.EnablePagination: true} && ComplexPropertySegment.Property.Type.IsCollection()) { JsonObject extension = new() { { "nextLinkName", "@odata.nextLink"}, { "operationName", Context.Settings.PageableOperationName} }; + operation.Extensions ??= new Dictionary(); operation.Extensions.Add(Constants.xMsPageable, new OpenApiAny(extension)); base.SetExtensions(operation); @@ -165,7 +171,8 @@ protected override void SetResponses(OpenApiOperation operation) SetSingleResponse(operation, schema); } - operation.AddErrorResponses(Context.Settings, _document, false); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, false); base.SetResponses(operation); } @@ -176,7 +183,7 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_readRestrictions.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_readRestrictions.Permissions, _document).ToList(); } protected override void AppendCustomParameters(OpenApiOperation operation) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonGetOperationHandler.cs index 76e9232c4..1cc5e2498 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonGetOperationHandler.cs @@ -35,16 +35,21 @@ public SingletonGetOperationHandler(OpenApiDocument document) : base(document) /// public override HttpMethod OperationType => HttpMethod.Get; - private ReadRestrictionsType _readRestrictions; + private ReadRestrictionsType? _readRestrictions; protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - _readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - var singletonReadRestrictions = Context.Model.GetRecord(Singleton, CapabilitiesConstants.ReadRestrictions); - _readRestrictions?.MergePropertiesIfNull(singletonReadRestrictions); - _readRestrictions ??= singletonReadRestrictions; + if (!string.IsNullOrEmpty(TargetPath)) + _readRestrictions = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + + if (Context is not null) + { + var singletonReadRestrictions = Context.Model.GetRecord(Singleton, CapabilitiesConstants.ReadRestrictions); + _readRestrictions?.MergePropertiesIfNull(singletonReadRestrictions); + _readRestrictions ??= singletonReadRestrictions; + } } /// @@ -53,10 +58,10 @@ protected override void SetBasicInfo(OpenApiOperation operation) // Summary and Descriptions string placeHolder = "Get " + Singleton.Name; operation.Summary = _readRestrictions?.Description ?? placeHolder; - operation.Description = _readRestrictions?.LongDescription ?? Context.Model.GetDescriptionAnnotation(Singleton); + operation.Description = _readRestrictions?.LongDescription ?? Context?.Model.GetDescriptionAnnotation(Singleton); // OperationId, it should be unique among all operations described in the API. - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true}) { string typeName = Singleton.EntityType.Name; operation.OperationId = Singleton.Name + "." + typeName + ".Get" + Utils.UpperFirstChar(typeName); @@ -69,14 +74,15 @@ protected override void SetParameters(OpenApiOperation operation) base.SetParameters(operation); // $select - OpenApiParameter parameter = Context.CreateSelect(Singleton); + var parameter = Context?.CreateSelect(Singleton); + operation.Parameters ??= []; if (parameter != null) { operation.Parameters.Add(parameter); } // $expand - parameter = Context.CreateExpand(Singleton); + parameter = Context?.CreateExpand(Singleton); if (parameter != null) { operation.Parameters.Add(parameter); @@ -86,15 +92,15 @@ protected override void SetParameters(OpenApiOperation operation) /// protected override void SetResponses(OpenApiOperation operation) { - IOpenApiSchema schema = null; - IDictionary links = null; + IOpenApiSchema? schema = null; + IDictionary? links = null; - if (Context.Settings.EnableDerivedTypesReferencesForResponses) + if (Context is {Settings.EnableDerivedTypesReferencesForResponses: true}) { schema = EdmModelHelper.GetDerivedTypesReferenceSchema(Singleton.EntityType, Context.Model, _document); } - if (Context.Settings.ShowLinks) + if (Context is {Settings.ShowLinks: true} && Path is not null) { links = Context.CreateLinks(entityType: Singleton.EntityType, entityName: Singleton.Name, entityKind: Singleton.ContainerElementKind.ToString(), path: Path, parameters: PathParameters); @@ -105,7 +111,7 @@ protected override void SetResponses(OpenApiOperation operation) operation.Responses = new OpenApiResponses { { - Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, + Context?.Settings.UseSuccessStatusCodeRange ?? false ? Constants.StatusCodeClass2XX : Constants.StatusCode200, new OpenApiResponse { Description = "Retrieved entity", @@ -124,7 +130,8 @@ protected override void SetResponses(OpenApiOperation operation) } }; - operation.AddErrorResponses(Context.Settings, _document, false); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, false); base.SetResponses(operation); } @@ -137,7 +144,7 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_readRestrictions.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_readRestrictions.Permissions, _document).ToList(); } /// diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/ComplexPropertyItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/ComplexPropertyItemHandler.cs index db185db72..c83d881ef 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/ComplexPropertyItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/ComplexPropertyItemHandler.cs @@ -42,16 +42,16 @@ protected override void SetOperations(OpenApiPathItem item) public void AddReadOperation(OpenApiPathItem item) { - var readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + var readRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); if (ComplexProperty is not null) { - var complexTypeReadRestrictions = Context.Model.GetRecord(ComplexProperty, CapabilitiesConstants.ReadRestrictions); + var complexTypeReadRestrictions = Context?.Model.GetRecord(ComplexProperty, CapabilitiesConstants.ReadRestrictions); readRestrictions?.MergePropertiesIfNull(complexTypeReadRestrictions); readRestrictions ??= complexTypeReadRestrictions; } bool isReadable = readRestrictions?.Readable ?? false; - if ((Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths && isReadable) || - !Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths) + if (Context is not null && ((Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths && isReadable) || + !Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths)) { AddOperation(item, HttpMethod.Get); } @@ -59,18 +59,18 @@ public void AddReadOperation(OpenApiPathItem item) public void AddInsertOperation(OpenApiPathItem item) { - if (Path.LastSegment is ODataComplexPropertySegment segment && segment.Property.Type.IsCollection()) + if (Path?.LastSegment is ODataComplexPropertySegment segment && segment.Property.Type.IsCollection()) { - var insertRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); + var insertRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); if (ComplexProperty is not null) { - var entityInsertRestrictions = Context.Model.GetRecord(ComplexProperty, CapabilitiesConstants.InsertRestrictions); + var entityInsertRestrictions = Context?.Model.GetRecord(ComplexProperty, CapabilitiesConstants.InsertRestrictions); insertRestrictions?.MergePropertiesIfNull(entityInsertRestrictions); insertRestrictions ??= entityInsertRestrictions; } bool isInsertable = insertRestrictions?.Insertable ?? false; - if ((Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths && isInsertable) || - !Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths) + if (Context is not null && ((Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths && isInsertable) || + !Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths)) { AddOperation(item, HttpMethod.Post); } @@ -79,16 +79,16 @@ public void AddInsertOperation(OpenApiPathItem item) public void AddUpdateOperation(OpenApiPathItem item) { - var updateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); + var updateRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); if (ComplexProperty is not null) { - var complexTypeUpdateRestrictions = Context.Model.GetRecord(ComplexProperty, CapabilitiesConstants.UpdateRestrictions); + var complexTypeUpdateRestrictions = Context?.Model.GetRecord(ComplexProperty, CapabilitiesConstants.UpdateRestrictions); updateRestrictions?.MergePropertiesIfNull(complexTypeUpdateRestrictions); updateRestrictions ??= complexTypeUpdateRestrictions; } bool isUpdatable = updateRestrictions?.Updatable ?? false; - if ((Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths && isUpdatable) || - !Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths) + if (Context is not null && ((Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths && isUpdatable) || + !Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths)) { if (updateRestrictions?.IsUpdateMethodPutAndPatch == true) { @@ -121,7 +121,10 @@ protected override void SetExtensions(OpenApiPathItem item) { if (ComplexProperty is null) return; - item.Extensions ??= new Dictionary(); - item.Extensions.AddCustomAttributesToExtensions(Context, ComplexProperty); + if (Context is not null) + { + item.Extensions ??= new Dictionary(); + item.Extensions.AddCustomAttributesToExtensions(Context, ComplexProperty); + } } } \ No newline at end of file diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/SingletonPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/SingletonPathItemHandler.cs index e288e1bac..d3fb7937b 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/SingletonPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/SingletonPathItemHandler.cs @@ -3,8 +3,10 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Collections.Generic; using System.Net.Http; using Microsoft.OData.Edm; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; @@ -31,26 +33,33 @@ public SingletonPathItemHandler(OpenApiDocument document): base(document) /// /// Gets the singleton. /// - protected IEdmSingleton Singleton { get; private set; } + protected IEdmSingleton? Singleton { get; private set; } /// protected override void SetOperations(OpenApiPathItem item) { // Retrieve a singleton. - ReadRestrictionsType readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - ReadRestrictionsType singletonReadRestrictions = Context.Model.GetRecord(Singleton, CapabilitiesConstants.ReadRestrictions); - readRestrictions?.MergePropertiesIfNull(singletonReadRestrictions); - readRestrictions ??= singletonReadRestrictions; + var readRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + + if (Context is not null && Singleton is not null) + { + var singletonReadRestrictions = Context.Model.GetRecord(Singleton, CapabilitiesConstants.ReadRestrictions); + readRestrictions?.MergePropertiesIfNull(singletonReadRestrictions); + readRestrictions ??= singletonReadRestrictions; + } if (readRestrictions?.IsReadable ?? true) { AddOperation(item, HttpMethod.Get); } // Update a singleton - UpdateRestrictionsType updateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); - UpdateRestrictionsType singletonUpdateRestrictions = Context.Model.GetRecord(Singleton, CapabilitiesConstants.UpdateRestrictions); - updateRestrictions?.MergePropertiesIfNull(singletonUpdateRestrictions); - updateRestrictions ??= singletonUpdateRestrictions; + var updateRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); + if (Context is not null && Singleton is not null) + { + var singletonUpdateRestrictions = Context.Model.GetRecord(Singleton, CapabilitiesConstants.UpdateRestrictions); + updateRestrictions?.MergePropertiesIfNull(singletonUpdateRestrictions); + updateRestrictions ??= singletonUpdateRestrictions; + } if (updateRestrictions?.IsUpdatable ?? true) { AddOperation(item, HttpMethod.Patch); @@ -62,22 +71,27 @@ protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; - Singleton = navigationSourceSegment.NavigationSource as IEdmSingleton; + if (path.FirstSegment is ODataNavigationSourceSegment {NavigationSource: IEdmSingleton source}) + Singleton = source; } /// protected override void SetBasicInfo(OpenApiPathItem pathItem) { base.SetBasicInfo(pathItem); - pathItem.Description = $"Provides operations to manage the {Singleton.EntityType.Name} singleton."; + pathItem.Description = $"Provides operations to manage the {Singleton?.EntityType.Name} singleton."; } /// - protected override void SetExtensions(OpenApiPathItem pathItem) + protected override void SetExtensions(OpenApiPathItem item) { - base.SetExtensions(pathItem); - pathItem.Extensions.AddCustomAttributesToExtensions(Context, Singleton); + base.SetExtensions(item); + + if (Context is not null && Singleton is not null) + { + item.Extensions ??= new Dictionary(); + item.Extensions.AddCustomAttributesToExtensions(Context, Singleton); + } } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/Authorization.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/Authorization.cs index 4c3bfb475..520c99732 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/Authorization.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/Authorization.cs @@ -23,12 +23,12 @@ internal abstract class Authorization : IRecord /// /// Name that can be used to reference the authorization flow. /// - public string Name { get; set; } + public string? Name { get; set; } /// /// Description of the authorization method. /// - public string Description { get; set; } + public string? Description { get; set; } /// /// Gets the security scheme type. @@ -55,20 +55,19 @@ public virtual void Initialize(IEdmRecordExpression record) /// /// The input record. /// The created object. - public static Authorization CreateAuthorization(IEdmRecordExpression record) + public static Authorization? CreateAuthorization(IEdmRecordExpression record) { if (record == null || record.DeclaredType == null) { return null; } - IEdmComplexType complexType = record.DeclaredType.Definition as IEdmComplexType; - if (complexType == null) - { - return null; - } + if (record.DeclaredType.Definition is not IEdmComplexType complexType) + { + return null; + } - Authorization auth; + Authorization auth; switch (complexType.FullTypeName()) { case AuthorizationConstants.OpenIDConnect: // OpenIDConnect @@ -104,10 +103,7 @@ public static Authorization CreateAuthorization(IEdmRecordExpression record) throw new OpenApiException(String.Format(SRResource.AuthorizationRecordTypeNameNotCorrect, complexType.FullTypeName())); } - if (auth != null) - { - auth.Initialize(record); - } + auth?.Initialize(record); return auth; } diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/AuthorizationScope.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/AuthorizationScope.cs index b42721a8e..b59cb9bbf 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/AuthorizationScope.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/AuthorizationScope.cs @@ -17,18 +17,18 @@ internal class AuthorizationScope : IRecord /// /// Scope name. /// - public string Scope { get; set; } + public string? Scope { get; set; } /// /// Scope Grant. /// Identity that has access to the scope or can grant access to the scope. /// - public string Grant { get; set; } + public string? Grant { get; set; } /// /// Description of the scope. /// - public string Description { get; set; } + public string? Description { get; set; } /// /// Init the . diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/CollectionPropertyRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/CollectionPropertyRestrictionsType.cs index d125e0046..c89ad5b2b 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/CollectionPropertyRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/CollectionPropertyRestrictionsType.cs @@ -19,27 +19,27 @@ internal class CollectionPropertyRestrictionsType : IRecord /// /// Gets the Restricted Collection-valued property. /// - public string CollectionProperty { get; private set; } + public string? CollectionProperty { get; private set; } /// /// Gets the List of functions and operators supported in filter expressions.. /// - public IList FilterFunctions { get; private set; } + public IList? FilterFunctions { get; private set; } /// /// Gets Restrictions on filter expressions. /// - public FilterRestrictionsType FilterRestrictions { get; private set; } + public FilterRestrictionsType? FilterRestrictions { get; private set; } /// /// Gets Restrictions on search expressions. /// - public SearchRestrictionsType SearchRestrictions { get; private set; } + public SearchRestrictionsType? SearchRestrictions { get; private set; } /// /// Gets Restrictions on orderby expressions. /// - public SortRestrictionsType SortRestrictions { get; private set; } + public SortRestrictionsType? SortRestrictions { get; private set; } /// /// Gets Supports $top. @@ -54,7 +54,7 @@ internal class CollectionPropertyRestrictionsType : IRecord /// /// Gets Support for $select. /// - public SelectSupportType SelectSupport { get; private set; } + public SelectSupportType? SelectSupport { get; private set; } /// /// Gets the collection supports positional inserts. diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/DeleteRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/DeleteRestrictionsType.cs index e772d8297..f036983be 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/DeleteRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/DeleteRestrictionsType.cs @@ -25,7 +25,7 @@ internal class DeleteRestrictionsType : IRecord /// /// Gets the navigation properties which do not allow DeleteLink requests. /// - public IList NonDeletableNavigationProperties { get; private set; } + public IList? NonDeletableNavigationProperties { get; private set; } /// /// Gets the maximum number of navigation properties that can be traversed. @@ -45,27 +45,27 @@ internal class DeleteRestrictionsType : IRecord /// /// Gets the required scopes to perform the insert. /// - public IList Permissions { get; private set; } + public IList? Permissions { get; private set; } /// /// Gets the Supported or required custom headers. /// - public IList CustomHeaders { get; private set; } + public IList? CustomHeaders { get; private set; } /// /// Gets the Supported or required custom query options. /// - public IList CustomQueryOptions { get; private set; } + public IList? CustomQueryOptions { get; private set; } /// /// Gets A brief description of the request. /// - public string Description { get; private set; } + public string? Description { get; private set; } /// /// Gets A lengthy description of the request. /// - public string LongDescription { get; private set; } + public string? LongDescription { get; private set; } /// /// Test the target supports delete. @@ -80,9 +80,7 @@ internal class DeleteRestrictionsType : IRecord /// True/False. public bool IsNonDeletableNavigationProperty(string navigationPropertyPath) { - return NonDeletableNavigationProperties != null ? - NonDeletableNavigationProperties.Any(a => a == navigationPropertyPath) : - false; + return NonDeletableNavigationProperties != null && NonDeletableNavigationProperties.Any(a => a == navigationPropertyPath); } /// From 3ae498cb1b72e4abeb1cbc7d2adc3cae4f8ff6f9 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 27 Mar 2025 13:19:55 -0400 Subject: [PATCH 16/24] chore: additional NRT fixes Signed-off-by: Vincent Biret --- .../ComplexPropertyGetOperationHandler.cs | 42 ++++++++----- .../Operation/SingletonGetOperationHandler.cs | 63 ++++++++++--------- .../Operation/SingletonOperationHandler.cs | 19 +++--- .../SingletonPatchOperationHandler.cs | 29 +++++---- .../NavigationPropertyPathItemHandler.cs | 36 +++++------ .../Capabilities/CustomParameter.cs | 8 +-- 6 files changed, 109 insertions(+), 88 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyGetOperationHandler.cs index 1bce957fe..ed303fc47 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyGetOperationHandler.cs @@ -40,9 +40,13 @@ protected override void Initialize(ODataContext context, ODataPath path) base.Initialize(context, path); _readRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - var complexPropertyReadRestrictions = Context?.Model.GetRecord(ComplexPropertySegment.Property, CapabilitiesConstants.ReadRestrictions); - _readRestrictions?.MergePropertiesIfNull(complexPropertyReadRestrictions); - _readRestrictions ??= complexPropertyReadRestrictions; + + if (ComplexPropertySegment is not null) + { + var complexPropertyReadRestrictions = Context?.Model.GetRecord(ComplexPropertySegment.Property, CapabilitiesConstants.ReadRestrictions); + _readRestrictions?.MergePropertiesIfNull(complexPropertyReadRestrictions); + _readRestrictions ??= complexPropertyReadRestrictions; + } } /// @@ -51,14 +55,15 @@ protected override void SetBasicInfo(OpenApiOperation operation) // OperationId if (Context is {Settings.EnableOperationId: true} && Path is not null) { - string prefix = ComplexPropertySegment.Property.Type.IsCollection() ? "List" : "Get"; + string prefix = ComplexPropertySegment is not null && ComplexPropertySegment.Property.Type.IsCollection() ? "List" : "Get"; operation.OperationId = EdmModelHelper.GenerateComplexPropertyPathOperationId(Path, Context, prefix); } // Summary and Description - string placeHolder = $"Get {ComplexPropertySegment.Property.Name} property value"; + string placeHolder = $"Get {ComplexPropertySegment?.Property.Name} property value"; operation.Summary = _readRestrictions?.Description ?? placeHolder; - operation.Description = _readRestrictions?.LongDescription ?? Context?.Model.GetDescriptionAnnotation(ComplexPropertySegment.Property); + operation.Description = _readRestrictions?.LongDescription ?? + (ComplexPropertySegment is null ? null : Context?.Model.GetDescriptionAnnotation(ComplexPropertySegment.Property)); base.SetBasicInfo(operation); } @@ -67,7 +72,7 @@ protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); - if (Context is null) return; + if (Context is null || ComplexPropertySegment is null) return; IOpenApiParameter? parameter; operation.Parameters ??= []; @@ -144,7 +149,9 @@ protected override void SetParameters(OpenApiOperation operation) protected override void SetExtensions(OpenApiOperation operation) { - if (Context is {Settings.EnablePagination: true} && ComplexPropertySegment.Property.Type.IsCollection()) + if (Context is {Settings.EnablePagination: true} && + ComplexPropertySegment is not null && + ComplexPropertySegment.Property.Type.IsCollection()) { JsonObject extension = new() { @@ -160,16 +167,17 @@ protected override void SetExtensions(OpenApiOperation operation) /// protected override void SetResponses(OpenApiOperation operation) { - if (ComplexPropertySegment.Property.Type.IsCollection()) - { - SetCollectionResponse(operation, ComplexPropertySegment.ComplexType.FullName()); - } - else - { - var schema = new OpenApiSchemaReference(ComplexPropertySegment.ComplexType.FullName(), _document); + if (ComplexPropertySegment is not null) + if (ComplexPropertySegment.Property.Type.IsCollection()) + { + SetCollectionResponse(operation, ComplexPropertySegment.ComplexType.FullName()); + } + else + { + var schema = new OpenApiSchemaReference(ComplexPropertySegment.ComplexType.FullName(), _document); - SetSingleResponse(operation, schema); - } + SetSingleResponse(operation, schema); + } if (Context is not null) operation.AddErrorResponses(Context.Settings, _document, false); diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonGetOperationHandler.cs index 1cc5e2498..d4f90bc31 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonGetOperationHandler.cs @@ -44,7 +44,7 @@ protected override void Initialize(ODataContext context, ODataPath path) if (!string.IsNullOrEmpty(TargetPath)) _readRestrictions = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - if (Context is not null) + if (Context is not null && Singleton is not null) { var singletonReadRestrictions = Context.Model.GetRecord(Singleton, CapabilitiesConstants.ReadRestrictions); _readRestrictions?.MergePropertiesIfNull(singletonReadRestrictions); @@ -56,12 +56,12 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetBasicInfo(OpenApiOperation operation) { // Summary and Descriptions - string placeHolder = "Get " + Singleton.Name; + string placeHolder = "Get " + Singleton?.Name; operation.Summary = _readRestrictions?.Description ?? placeHolder; operation.Description = _readRestrictions?.LongDescription ?? Context?.Model.GetDescriptionAnnotation(Singleton); // OperationId, it should be unique among all operations described in the API. - if (Context is {Settings.EnableOperationId: true}) + if (Context is {Settings.EnableOperationId: true} && Singleton is not null) { string typeName = Singleton.EntityType.Name; operation.OperationId = Singleton.Name + "." + typeName + ".Get" + Utils.UpperFirstChar(typeName); @@ -72,6 +72,8 @@ protected override void SetBasicInfo(OpenApiOperation operation) protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); + + if (Singleton is null) return; // $select var parameter = Context?.CreateSelect(Singleton); @@ -92,43 +94,46 @@ protected override void SetParameters(OpenApiOperation operation) /// protected override void SetResponses(OpenApiOperation operation) { - IOpenApiSchema? schema = null; - IDictionary? links = null; - - if (Context is {Settings.EnableDerivedTypesReferencesForResponses: true}) + if (Singleton is not null) { - schema = EdmModelHelper.GetDerivedTypesReferenceSchema(Singleton.EntityType, Context.Model, _document); - } + IOpenApiSchema? schema = null; + IDictionary? links = null; - if (Context is {Settings.ShowLinks: true} && Path is not null) - { - links = Context.CreateLinks(entityType: Singleton.EntityType, entityName: Singleton.Name, - entityKind: Singleton.ContainerElementKind.ToString(), path: Path, parameters: PathParameters); - } + if (Context is {Settings.EnableDerivedTypesReferencesForResponses: true}) + { + schema = EdmModelHelper.GetDerivedTypesReferenceSchema(Singleton.EntityType, Context.Model, _document); + } - schema ??= new OpenApiSchemaReference(Singleton.EntityType.FullName(), _document); + if (Context is {Settings.ShowLinks: true} && Path is not null) + { + links = Context.CreateLinks(entityType: Singleton.EntityType, entityName: Singleton.Name, + entityKind: Singleton.ContainerElementKind.ToString(), path: Path, parameters: PathParameters); + } - operation.Responses = new OpenApiResponses - { + schema ??= new OpenApiSchemaReference(Singleton.EntityType.FullName(), _document); + + operation.Responses = new OpenApiResponses { - Context?.Settings.UseSuccessStatusCodeRange ?? false ? Constants.StatusCodeClass2XX : Constants.StatusCode200, - new OpenApiResponse { - Description = "Retrieved entity", - Content = new Dictionary + Context?.Settings.UseSuccessStatusCodeRange ?? false ? Constants.StatusCodeClass2XX : Constants.StatusCode200, + new OpenApiResponse { + Description = "Retrieved entity", + Content = new Dictionary { - Constants.ApplicationJsonMediaType, - new OpenApiMediaType { - Schema = schema + Constants.ApplicationJsonMediaType, + new OpenApiMediaType + { + Schema = schema + } } - } - }, - Links = links + }, + Links = links + } } - } - }; + }; + } if (Context is not null) operation.AddErrorResponses(Context.Settings, _document, false); diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonOperationHandler.cs index 7e8baa6b0..e49713ccf 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonOperationHandler.cs @@ -5,6 +5,7 @@ using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.OData.Common; @@ -30,7 +31,7 @@ protected SingletonOperationHandler(OpenApiDocument document):base(document) /// /// Gets the . /// - protected IEdmSingleton Singleton { get; private set; } + protected IEdmSingleton? Singleton { get; private set; } /// protected override void Initialize(ODataContext context, ODataPath path) @@ -38,9 +39,8 @@ protected override void Initialize(ODataContext context, ODataPath path) // Base Initialize should be called at top of this method. base.Initialize(context, path); - ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; - - Singleton = navigationSourceSegment.NavigationSource as IEdmSingleton; + if (path.FirstSegment is ODataNavigationSourceSegment {NavigationSource: IEdmSingleton source}) + Singleton = source; } /// @@ -48,9 +48,9 @@ protected override void SetTags(OpenApiOperation operation) { // In this SDK, we use "[Singleton Name].[Singleton Entity Type Name] // For example: "Me.User" - var tagName = Singleton.Name + "." + Singleton.EntityType.Name; + var tagName = Singleton?.Name + "." + Singleton?.EntityType.Name; - Context.AddExtensionToTag(tagName, Constants.xMsTocType, new OpenApiAny("page"), () => new OpenApiTag() + Context?.AddExtensionToTag(tagName, Constants.xMsTocType, new OpenApiAny("page"), () => new OpenApiTag() { Name = tagName }); @@ -64,6 +64,7 @@ protected override void SetTags(OpenApiOperation operation) /// protected override void SetExtensions(OpenApiOperation operation) { + operation.Extensions ??= new Dictionary(); operation.Extensions.Add(Constants.xMsDosOperationType, new OpenApiAny("operation")); base.SetExtensions(operation); @@ -72,10 +73,10 @@ protected override void SetExtensions(OpenApiOperation operation) /// protected override void SetExternalDocs(OpenApiOperation operation) { - if (Context.Settings.ShowExternalDocs) + if (Context is {Settings.ShowExternalDocs: true} && CustomLinkRel is not null) { - var externalDocs = Context.Model.GetLinkRecord(TargetPath, CustomLinkRel) ?? - Context.Model.GetLinkRecord(Singleton, CustomLinkRel); + var externalDocs = (string.IsNullOrEmpty(TargetPath) ? null : Context.Model.GetLinkRecord(TargetPath, CustomLinkRel)) ?? + (Singleton is null ? null : Context.Model.GetLinkRecord(Singleton, CustomLinkRel)); if (externalDocs != null) { diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonPatchOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonPatchOperationHandler.cs index 4342f8f64..cd4f56dea 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonPatchOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonPatchOperationHandler.cs @@ -35,28 +35,33 @@ public SingletonPatchOperationHandler(OpenApiDocument document) : base(document) /// public override HttpMethod OperationType => HttpMethod.Patch; - private UpdateRestrictionsType _updateRestrictions; + private UpdateRestrictionsType? _updateRestrictions; protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - _updateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); - var singletonUpdateRestrictions = Context.Model.GetRecord(Singleton, CapabilitiesConstants.UpdateRestrictions); - _updateRestrictions?.MergePropertiesIfNull(singletonUpdateRestrictions); - _updateRestrictions ??= singletonUpdateRestrictions; + if (!string.IsNullOrEmpty(TargetPath)) + _updateRestrictions = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); + + if (Context is not null && Singleton is not null) + { + var singletonUpdateRestrictions = Context.Model.GetRecord(Singleton, CapabilitiesConstants.UpdateRestrictions); + _updateRestrictions?.MergePropertiesIfNull(singletonUpdateRestrictions); + _updateRestrictions ??= singletonUpdateRestrictions; + } } /// protected override void SetBasicInfo(OpenApiOperation operation) { // Summary and Descriptions - string placeHolder = "Update " + Singleton.Name; + string placeHolder = "Update " + Singleton?.Name; operation.Summary = _updateRestrictions?.Description ?? placeHolder; operation.Description = _updateRestrictions?.LongDescription; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true} && Singleton is not null) { string typeName = Singleton.EntityType.Name; operation.OperationId = Singleton.Name + "." + typeName + ".Update" + Utils.UpperFirstChar(typeName); @@ -87,7 +92,8 @@ protected override void SetRequestBody(OpenApiOperation operation) /// protected override void SetResponses(OpenApiOperation operation) { - operation.AddErrorResponses(Context.Settings, _document, true, GetOpenApiSchema()); + if (Context is not null && GetOpenApiSchema() is {} schema) + operation.AddErrorResponses(Context.Settings, _document, true, schema); base.SetResponses(operation); } @@ -99,7 +105,7 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_updateRestrictions.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_updateRestrictions.Permissions, _document).ToList(); } /// @@ -121,9 +127,10 @@ protected override void AppendCustomParameters(OpenApiOperation operation) } } - private IOpenApiSchema GetOpenApiSchema() + private IOpenApiSchema? GetOpenApiSchema() { - return Context.Settings.EnableDerivedTypesReferencesForRequestBody ? + if (Singleton is null) return null; + return Context is {Settings.EnableDerivedTypesReferencesForRequestBody: true} ? EdmModelHelper.GetDerivedTypesReferenceSchema(Singleton.EntityType, Context.Model, _document) : new OpenApiSchemaReference(Singleton.EntityType.FullName(), _document); } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs index 751190923..f657944f5 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs @@ -69,12 +69,12 @@ protected override void SetOperations(OpenApiPathItem item) _ => null }; - var targetPathRestrictionType = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.NavigationRestrictions); - var navSourceRestrictionType = target is null ? null : Context.Model.GetRecord(target, CapabilitiesConstants.NavigationRestrictions); - var navPropRestrictionType = NavigationProperty is null ? null : Context.Model.GetRecord(NavigationProperty, CapabilitiesConstants.NavigationRestrictions); + var targetPathRestrictionType = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.NavigationRestrictions); + var navSourceRestrictionType = target is null ? null : Context?.Model.GetRecord(target, CapabilitiesConstants.NavigationRestrictions); + var navPropRestrictionType = NavigationProperty is null ? null : Context?.Model.GetRecord(NavigationProperty, CapabilitiesConstants.NavigationRestrictions); var restriction = targetPathRestrictionType?.RestrictedProperties?.FirstOrDefault() - ?? navSourceRestrictionType?.RestrictedProperties?.FirstOrDefault(r => r.NavigationProperty == Path.NavigationPropertyPath()) + ?? (Path is null ? null : navSourceRestrictionType?.RestrictedProperties?.FirstOrDefault(r => r.NavigationProperty == Path.NavigationPropertyPath())) ?? navPropRestrictionType?.RestrictedProperties?.FirstOrDefault(); // Check whether the navigation property should be part of the path @@ -87,10 +87,10 @@ protected override void SetOperations(OpenApiPathItem item) AddGetOperation(item, restriction); // Update restrictions - var navPropUpdateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); + var navPropUpdateRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); navPropUpdateRestrictions?.MergePropertiesIfNull(restriction?.UpdateRestrictions); navPropUpdateRestrictions ??= restriction?.UpdateRestrictions; - if (NavigationProperty is not null) + if (NavigationProperty is not null && Context is not null) { var updateRestrictions = Context.Model.GetRecord(NavigationProperty); navPropUpdateRestrictions?.MergePropertiesIfNull(updateRestrictions); @@ -98,10 +98,10 @@ protected override void SetOperations(OpenApiPathItem item) } // Insert restrictions - var navPropInsertRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); + var navPropInsertRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); navPropInsertRestrictions?.MergePropertiesIfNull(restriction?.InsertRestrictions); navPropInsertRestrictions ??= restriction?.InsertRestrictions; - if (NavigationProperty is not null) + if (NavigationProperty is not null && Context is not null) { var insertRestrictions = Context.Model.GetRecord(NavigationProperty); navPropInsertRestrictions?.MergePropertiesIfNull(insertRestrictions); @@ -109,7 +109,7 @@ protected override void SetOperations(OpenApiPathItem item) } // Entity insert restrictions - var entityUpdateRestrictions = Context.Model.GetRecord(_navPropEntityType); + var entityUpdateRestrictions = _navPropEntityType is null ? null : Context?.Model.GetRecord(_navPropEntityType); // containment: (Post - Collection | Patch/Put - Single) if (NavigationProperty?.ContainsTarget ?? false) @@ -129,7 +129,7 @@ protected override void SetOperations(OpenApiPathItem item) } else { - var entityInsertRestrictions = Context.Model.GetRecord(_navPropEntityType); + var entityInsertRestrictions = _navPropEntityType is null ? null : Context?.Model.GetRecord(_navPropEntityType); bool isInsertableDefault = navPropInsertRestrictions == null && entityInsertRestrictions == null; if (isInsertableDefault || @@ -180,18 +180,18 @@ protected override void SetOperations(OpenApiPathItem item) private void AddGetOperation(OpenApiPathItem item, NavigationPropertyRestriction? restriction) { - var navPropReadRestriction = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + var navPropReadRestriction = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); navPropReadRestriction?.MergePropertiesIfNull(restriction?.ReadRestrictions); navPropReadRestriction ??= restriction?.ReadRestrictions; - if (NavigationProperty is not null) + if (NavigationProperty is not null && Context is not null) { var readRestrictions = Context.Model.GetRecord(NavigationProperty); navPropReadRestriction?.MergePropertiesIfNull(readRestrictions); navPropReadRestriction ??= readRestrictions; } - var entityReadRestriction = _navPropEntityType is null ? null : Context.Model.GetRecord(_navPropEntityType); + var entityReadRestriction = _navPropEntityType is null ? null : Context?.Model.GetRecord(_navPropEntityType); bool isReadableDefault = navPropReadRestriction == null && entityReadRestriction == null; if (isReadableDefault) { @@ -234,10 +234,10 @@ private void AddDeleteOperation(OpenApiPathItem item, NavigationPropertyRestrict { Debug.Assert(!LastSegmentIsRefSegment); - var navPropDeleteRestriction = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); + var navPropDeleteRestriction = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); navPropDeleteRestriction?.MergePropertiesIfNull(restriction?.DeleteRestrictions); navPropDeleteRestriction ??= restriction?.DeleteRestrictions; - if (NavigationProperty is not null) + if (NavigationProperty is not null && Context is not null) { var insertRestrictions = Context.Model.GetRecord(NavigationProperty); navPropDeleteRestriction?.MergePropertiesIfNull(insertRestrictions); @@ -247,7 +247,7 @@ private void AddDeleteOperation(OpenApiPathItem item, NavigationPropertyRestrict if (!(NavigationProperty.TargetMultiplicity() != EdmMultiplicity.Many || LastSegmentIsKeySegment)) return; - var entityDeleteRestriction = _navPropEntityType is null ? null : Context.Model.GetRecord(_navPropEntityType); + var entityDeleteRestriction = _navPropEntityType is null ? null : Context?.Model.GetRecord(_navPropEntityType); bool isDeletable = (navPropDeleteRestriction == null && entityDeleteRestriction == null) || ((entityDeleteRestriction?.IsDeletable ?? true) && @@ -305,12 +305,12 @@ protected override void Initialize(ODataContext context, ODataPath path) /// protected override void SetExtensions(OpenApiPathItem item) { - if (!Context.Settings.ShowMsDosGroupPath) + if (Context is null || !Context.Settings.ShowMsDosGroupPath) { return; } - IList samePaths = new List(); + var samePaths = new List(); foreach (var path in Context.AllPaths.Where(p => p.Kind == ODataPathKind.NavigationProperty && p != Path)) { bool lastIsKeySegment = path.LastSegment is ODataKeySegment; diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/CustomParameter.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/CustomParameter.cs index d4243260d..e390304e4 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/CustomParameter.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/CustomParameter.cs @@ -21,17 +21,17 @@ internal class CustomParameter : IRecord /// /// Gets/sets the name of the custom parameter. /// - public string Name { get; set; } + public string? Name { get; set; } /// /// Gets/sets the description of the custom parameter. /// - public string Description { get; set; } + public string? Description { get; set; } /// /// Gets/sets the documentationURL of the custom parameter. /// - public string DocumentationURL { get; set; } + public string? DocumentationURL { get; set; } /// /// Gets/sets the reuired of the custom parameter. true: parameter is required, false or not specified: parameter is optional. @@ -41,7 +41,7 @@ internal class CustomParameter : IRecord /// /// Gets the list of scopes that can provide access to the resource. /// s - public IList ExampleValues { get; set; } + public IList? ExampleValues { get; set; } /// /// Init the . From db8b41aa9c0d0c599907be058f0e30786d767a3f Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 27 Mar 2025 13:34:31 -0400 Subject: [PATCH 17/24] chore: additional NRT fixes Signed-off-by: Vincent Biret --- .../Common/EdmModelHelper.cs | 2 +- .../Common/OpenApiOperationExtensions.cs | 4 +- .../Common/Utils.cs | 26 ++++++------- .../Edm/ODataComplexPropertySegment.cs | 6 +-- .../Generator/OpenApiInfoGenerator.cs | 6 +-- .../OpenApiConvertSettings.cs | 8 ++-- .../ComplexPropertyGetOperationHandler.cs | 38 +++++++++++-------- .../PublicAPI.Unshipped.txt | 16 ++++---- .../NavigationRestrictionsType.cs | 32 ++++++++-------- .../Capabilities/OperationRestrictionsType.cs | 6 +-- 10 files changed, 74 insertions(+), 70 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Common/EdmModelHelper.cs b/src/Microsoft.OpenApi.OData.Reader/Common/EdmModelHelper.cs index 7c057ab11..fde9784c8 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Common/EdmModelHelper.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Common/EdmModelHelper.cs @@ -433,7 +433,7 @@ internal static string GenerateComplexPropertyPathTagName(ODataPath path, ODataC /// Optional: The Edm model. Used for searching for the namespace alias. /// The OpenAPI convert settings. /// The element name, alias-prefixed or namespace-stripped if applicable. - internal static string StripOrAliasNamespacePrefix(IEdmSchemaElement element, OpenApiConvertSettings settings, IEdmModel model = null) + internal static string StripOrAliasNamespacePrefix(IEdmSchemaElement element, OpenApiConvertSettings settings, IEdmModel? model = null) { Utils.CheckArgumentNull(element, nameof(element)); Utils.CheckArgumentNull(settings, nameof(settings)); diff --git a/src/Microsoft.OpenApi.OData.Reader/Common/OpenApiOperationExtensions.cs b/src/Microsoft.OpenApi.OData.Reader/Common/OpenApiOperationExtensions.cs index 5d5e6ca7e..ced0fd483 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Common/OpenApiOperationExtensions.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Common/OpenApiOperationExtensions.cs @@ -24,7 +24,7 @@ internal static class OpenApiOperationExtensions /// Optional: Whether to add a 204 no content response. /// Optional: The OpenAPI schema of the response. /// The OpenAPI document to lookup references. - public static void AddErrorResponses(this OpenApiOperation operation, OpenApiConvertSettings settings, OpenApiDocument document, bool addNoContent = false, IOpenApiSchema schema = null) + public static void AddErrorResponses(this OpenApiOperation operation, OpenApiConvertSettings settings, OpenApiDocument document, bool addNoContent = false, IOpenApiSchema? schema = null) { Utils.CheckArgumentNull(operation, nameof(operation)); Utils.CheckArgumentNull(settings, nameof(settings)); @@ -39,7 +39,7 @@ public static void AddErrorResponses(this OpenApiOperation operation, OpenApiCon { if (settings.UseSuccessStatusCodeRange) { - OpenApiResponse response = null; + OpenApiResponse? response = null; if (schema != null) { response = new() diff --git a/src/Microsoft.OpenApi.OData.Reader/Common/Utils.cs b/src/Microsoft.OpenApi.OData.Reader/Common/Utils.cs index 7438e6e84..13887692a 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Common/Utils.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Common/Utils.cs @@ -28,10 +28,10 @@ public static class Utils /// /// The type of the term. /// The qualified name. - public static string GetTermQualifiedName() + public static string? GetTermQualifiedName() { object[] attributes = typeof(T).GetCustomAttributes(typeof(TermAttribute), false); - if (attributes == null && attributes.Length == 0) + if (attributes == null || attributes.Length == 0) { return null; } @@ -45,7 +45,7 @@ public static string GetTermQualifiedName() /// /// The input string. /// The changed string. - public static string UpperFirstChar(string input) + public static string? UpperFirstChar(string input) { if (input == null) { @@ -129,7 +129,7 @@ internal static string ToFirstCharacterLowerCase(this string input) /// /// The . /// Optional: The navigation property name. - internal static string NavigationPropertyPath(this ODataPath path, string navigationPropertyName = null) + internal static string NavigationPropertyPath(this ODataPath path, string? navigationPropertyName = null) { string value = string.Join("/", path.Segments.OfType().Select(e => e.Identifier)); @@ -176,7 +176,7 @@ private static Dictionary GetCustomXMLAttributesValueMapping(IEd { Dictionary attributesValueMap = new(); - if ((!customXMLAttributesMapping?.Any() ?? true) || + if (customXMLAttributesMapping is not {Count:>0} || model == null || element == null) { @@ -187,10 +187,10 @@ private static Dictionary GetCustomXMLAttributesValueMapping(IEd { string attributeName = item.Key.Split(':').Last(); // example, 'ags:IsHidden' --> 'IsHidden' string extensionName = item.Value; - EdmStringConstant customXMLAttribute = model.DirectValueAnnotationsManager.GetDirectValueAnnotations(element)? + var customXMLAttribute = model.DirectValueAnnotationsManager.GetDirectValueAnnotations(element)? .Where(x => x.Name.Equals(attributeName, StringComparison.OrdinalIgnoreCase))? .FirstOrDefault()?.Value as EdmStringConstant; - string attributeValue = customXMLAttribute?.Value; + var attributeValue = customXMLAttribute?.Value; if (!string.IsNullOrEmpty(attributeValue)) { @@ -253,7 +253,7 @@ internal static bool IsBaseTypeReferencedAsTypeInModel( /// /// The target . /// The entity type of the target . - internal static IEdmEntityType EntityTypeFromPathSegment(this ODataSegment segment) + internal static IEdmEntityType? EntityTypeFromPathSegment(this ODataSegment segment) { CheckArgumentNull(segment, nameof(segment)); @@ -279,12 +279,12 @@ internal static IEdmEntityType EntityTypeFromPathSegment(this ODataSegment segme /// /// The target . /// The entity type of the target . - private static IEdmEntityType EntityTypeFromOperationSegment(this ODataSegment segment) + private static IEdmEntityType? EntityTypeFromOperationSegment(this ODataSegment segment) { CheckArgumentNull(segment, nameof(segment)); if (segment is ODataOperationSegment operationSegment && - operationSegment.Operation.Parameters.FirstOrDefault() is IEdmOperationParameter bindingParameter) + operationSegment.Operation?.Parameters.FirstOrDefault() is IEdmOperationParameter bindingParameter) { IEdmTypeReference bindingType = bindingParameter.Type; @@ -339,10 +339,10 @@ internal static bool TryAddPath(this IDictionary pathI } ODataSegment lastSecondSegment = path.Segments.ElementAt(path.Count - secondLastSegmentIndex); - IEdmEntityType boundEntityType = lastSecondSegment?.EntityTypeFromPathSegment(); + var boundEntityType = lastSecondSegment?.EntityTypeFromPathSegment(); - IEdmEntityType operationEntityType = lastSegment.EntityTypeFromOperationSegment(); - IEnumerable derivedTypes = (operationEntityType != null) + var operationEntityType = lastSegment.EntityTypeFromOperationSegment(); + var derivedTypes = (operationEntityType != null) ? context.Model.FindAllDerivedTypes(operationEntityType) : null; diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataComplexPropertySegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataComplexPropertySegment.cs index 5c74f5b1e..904935fdd 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataComplexPropertySegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataComplexPropertySegment.cs @@ -26,7 +26,7 @@ public ODataComplexPropertySegment(IEdmStructuralProperty property) } /// - public override IEdmEntityType EntityType => null; + public override IEdmEntityType? EntityType => null; /// public override ODataSegmentKind Kind => ODataSegmentKind.ComplexProperty; @@ -42,13 +42,13 @@ public ODataComplexPropertySegment(IEdmStructuralProperty property) /// /// Gets the type definition of the property this segment was inserted for. /// - public IEdmComplexType ComplexType => + public IEdmComplexType? ComplexType => (Property.Type.IsCollection() ? Property.Type.Definition.AsElementType() : Property.Type.AsComplex().Definition) as IEdmComplexType; /// public override IEnumerable GetAnnotables() { - return new IEdmVocabularyAnnotatable[] { Property, ComplexType }.Union(ComplexType.FindAllBaseTypes()); + return new IEdmVocabularyAnnotatable[] { Property }.Union(ComplexType is null ? [] : [ComplexType]).Union(ComplexType?.FindAllBaseTypes() ?? []); } /// diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiInfoGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiInfoGenerator.cs index 085cb5bb8..c6d4a7162 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiInfoGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiInfoGenerator.cs @@ -61,7 +61,7 @@ private static string GetTitle(this ODataContext context) } // If no Core.Description is present, a default title has to be provided as this is a required OpenAPI field. - string namespaceName = context.Model.EntityContainer != null ? + var namespaceName = context.Model.EntityContainer != null ? context.Model.EntityContainer.Namespace : context.Model.DeclaredNamespaces.FirstOrDefault(); @@ -113,12 +113,12 @@ private static Dictionary GetExtensions(this ODataCon new OpenApiAny(new JsonObject { { "toolName", "Microsoft.OpenApi.OData" }, - { "toolVersion", Assembly.GetExecutingAssembly().GetName().Version.ToString() } + { "toolVersion", Assembly.GetExecutingAssembly().GetName().Version?.ToString() } }) } }; } - return null; + return []; } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs b/src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs index ecb73a7d4..5615f3ff0 100644 --- a/src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs +++ b/src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs @@ -138,7 +138,7 @@ public class OpenApiConvertSettings /// /// Gets/sets a value that specifies a prefix to be prepended to all generated paths. /// - public string PathPrefix + public string? PathPrefix { get { @@ -166,7 +166,7 @@ public string PathPrefix /// /// Gets/sets a route path prefix provider. /// - public IODataRoutePathPrefixProvider RoutePathPrefixProvider { get; set; } + public IODataRoutePathPrefixProvider? RoutePathPrefixProvider { get; set; } /// /// Gets/Sets a value indicating whether or not to show the OpenAPI links in the responses. @@ -203,7 +203,7 @@ public string PathPrefix /// /// Gets/sets a the path provider. /// - public IODataPathProvider PathProvider { get; set; } + public IODataPathProvider? PathProvider { get; set; } /// /// Gets/sets a value indicating whether or not add OData $count segments in the description for collections. @@ -315,7 +315,7 @@ public string PathPrefix /// /// The namespace prefix to be stripped from the in method paths. /// - public string NamespacePrefixToStripForInMethodPaths { get; set; } + public string? NamespacePrefixToStripForInMethodPaths { get; set; } /// /// Enables the use of aliases for the type cast segments to shorten the url path. diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyGetOperationHandler.cs index ed303fc47..51db8e26c 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyGetOperationHandler.cs @@ -122,28 +122,34 @@ protected override void SetParameters(OpenApiOperation operation) // of just providing a comma-separated list of properties can be expressed via an array-valued // parameter with an enum constraint // $order - parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateOrderBy(TargetPath, ComplexPropertySegment.ComplexType)) - ?? Context.CreateOrderBy(ComplexPropertySegment.Property, ComplexPropertySegment.ComplexType); - if (parameter != null) + if (ComplexPropertySegment.ComplexType is not null) { - operation.Parameters.Add(parameter); + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateOrderBy(TargetPath, ComplexPropertySegment.ComplexType)) + ?? Context.CreateOrderBy(ComplexPropertySegment.Property, ComplexPropertySegment.ComplexType); + if (parameter != null) + { + operation.Parameters.Add(parameter); + } } } - // $select - parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateSelect(TargetPath, ComplexPropertySegment.ComplexType)) - ?? Context.CreateSelect(ComplexPropertySegment.Property, ComplexPropertySegment.ComplexType); - if (parameter != null) + if (ComplexPropertySegment.ComplexType is not null) { - operation.Parameters.Add(parameter); - } + // $select + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateSelect(TargetPath, ComplexPropertySegment.ComplexType)) + ?? Context.CreateSelect(ComplexPropertySegment.Property, ComplexPropertySegment.ComplexType); + if (parameter != null) + { + operation.Parameters.Add(parameter); + } - // $expand - parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateExpand(TargetPath, ComplexPropertySegment.ComplexType)) - ?? Context.CreateExpand(ComplexPropertySegment.Property, ComplexPropertySegment.ComplexType); - if (parameter != null) - { - operation.Parameters.Add(parameter); + // $expand + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateExpand(TargetPath, ComplexPropertySegment.ComplexType)) + ?? Context.CreateExpand(ComplexPropertySegment.Property, ComplexPropertySegment.ComplexType); + if (parameter != null) + { + operation.Parameters.Add(parameter); + } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt index acd486f25..7a9561ccd 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt +++ b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt @@ -10,7 +10,7 @@ Microsoft.OpenApi.OData.Edm.IODataPathProvider Microsoft.OpenApi.OData.Edm.IODataPathProvider.CanFilter(Microsoft.OData.Edm.IEdmElement! element) -> bool Microsoft.OpenApi.OData.Edm.IODataPathProvider.GetPaths(Microsoft.OData.Edm.IEdmModel! model, Microsoft.OpenApi.OData.OpenApiConvertSettings! settings) -> System.Collections.Generic.IEnumerable! Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment -Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.ComplexType.get -> Microsoft.OData.Edm.IEdmComplexType! +Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.ComplexType.get -> Microsoft.OData.Edm.IEdmComplexType? Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.ODataComplexPropertySegment(Microsoft.OData.Edm.IEdmStructuralProperty! property) -> void Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.Property.get -> Microsoft.OData.Edm.IEdmStructuralProperty! Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment @@ -178,16 +178,16 @@ Microsoft.OpenApi.OData.OpenApiConvertSettings.IncludeAssemblyInfo.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.IncludeAssemblyInfo.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.InnerErrorComplexTypeName.get -> string! Microsoft.OpenApi.OData.OpenApiConvertSettings.InnerErrorComplexTypeName.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.NamespacePrefixToStripForInMethodPaths.get -> string! +Microsoft.OpenApi.OData.OpenApiConvertSettings.NamespacePrefixToStripForInMethodPaths.get -> string? Microsoft.OpenApi.OData.OpenApiConvertSettings.NamespacePrefixToStripForInMethodPaths.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.OpenApiConvertSettings() -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.OpenApiSpecVersion.get -> Microsoft.OpenApi.OpenApiSpecVersion Microsoft.OpenApi.OData.OpenApiConvertSettings.OpenApiSpecVersion.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.PageableOperationName.get -> string! Microsoft.OpenApi.OData.OpenApiConvertSettings.PageableOperationName.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.PathPrefix.get -> string! +Microsoft.OpenApi.OData.OpenApiConvertSettings.PathPrefix.get -> string? Microsoft.OpenApi.OData.OpenApiConvertSettings.PathPrefix.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.PathProvider.get -> Microsoft.OpenApi.OData.Edm.IODataPathProvider! +Microsoft.OpenApi.OData.OpenApiConvertSettings.PathProvider.get -> Microsoft.OpenApi.OData.Edm.IODataPathProvider? Microsoft.OpenApi.OData.OpenApiConvertSettings.PathProvider.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.PrefixEntityTypeNameBeforeKey.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.PrefixEntityTypeNameBeforeKey.set -> void @@ -197,7 +197,7 @@ Microsoft.OpenApi.OData.OpenApiConvertSettings.RequireDerivedTypesConstraintForO Microsoft.OpenApi.OData.OpenApiConvertSettings.RequireDerivedTypesConstraintForODataTypeCastSegments.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.RoutePathPrefixProvider.get -> Microsoft.OpenApi.OData.Extensions.IODataRoutePathPrefixProvider! +Microsoft.OpenApi.OData.OpenApiConvertSettings.RoutePathPrefixProvider.get -> Microsoft.OpenApi.OData.Extensions.IODataRoutePathPrefixProvider? Microsoft.OpenApi.OData.OpenApiConvertSettings.RoutePathPrefixProvider.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.SemVerVersion.get -> string! Microsoft.OpenApi.OData.OpenApiConvertSettings.SemVerVersion.set -> void @@ -231,7 +231,7 @@ Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.Function = 5 -> Microsoft.Ope Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.List = 1 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.ReadByKey = 0 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.Update = 3 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey -override Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType! +override Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType? override Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! override Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! override Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.Identifier.get -> string! @@ -292,9 +292,9 @@ override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.GetAnnotables() -> Sys override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.Identifier.get -> string! override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -static Microsoft.OpenApi.OData.Common.Utils.GetTermQualifiedName() -> string! +static Microsoft.OpenApi.OData.Common.Utils.GetTermQualifiedName() -> string? static Microsoft.OpenApi.OData.Common.Utils.GetUniqueName(string! input, System.Collections.Generic.HashSet! set) -> string! -static Microsoft.OpenApi.OData.Common.Utils.UpperFirstChar(string! input) -> string! +static Microsoft.OpenApi.OData.Common.Utils.UpperFirstChar(string! input) -> string? static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.FindAllBaseTypes(this Microsoft.OData.Edm.IEdmComplexType! complexType) -> System.Collections.Generic.IEnumerable! static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.FindAllBaseTypes(this Microsoft.OData.Edm.IEdmEntityType! entityType) -> System.Collections.Generic.IEnumerable! static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.GetAllElements(this Microsoft.OData.Edm.IEdmModel! model) -> System.Collections.Generic.IEnumerable! diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/NavigationRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/NavigationRestrictionsType.cs index 278f734f0..9f4fea30f 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/NavigationRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/NavigationRestrictionsType.cs @@ -40,7 +40,7 @@ internal class NavigationPropertyRestriction : IRecord /// /// Navigation properties can be navigated /// - public string NavigationProperty { get; set; } + public string? NavigationProperty { get; set; } /// /// Navigation properties can be navigated to this level. @@ -50,22 +50,22 @@ internal class NavigationPropertyRestriction : IRecord /// /// List of functions and operators supported in filter expressions. /// - public IList FilterFunctions { get; set; } + public IList? FilterFunctions { get; set; } /// /// Restrictions on filter expressions. /// - public FilterRestrictionsType FilterRestrictions { get; set; } + public FilterRestrictionsType? FilterRestrictions { get; set; } /// /// Restrictions on search expressions. /// - public SearchRestrictionsType SearchRestrictions { get; set; } + public SearchRestrictionsType? SearchRestrictions { get; set; } /// /// Restrictions on orderby expressions. /// - public SortRestrictionsType SortRestrictions { get; set; } + public SortRestrictionsType? SortRestrictions { get; set; } /// /// Supports $top. @@ -80,7 +80,7 @@ internal class NavigationPropertyRestriction : IRecord /// /// Supports $select. /// - public SelectSupportType SelectSupport { get; set; } + public SelectSupportType? SelectSupport { get; set; } /// /// Supports key values according to OData URL conventions. @@ -90,27 +90,27 @@ internal class NavigationPropertyRestriction : IRecord /// /// Restrictions on insert operations. /// - public InsertRestrictionsType InsertRestrictions { get; set; } + public InsertRestrictionsType? InsertRestrictions { get; set; } /// /// Deep Insert Support of the annotated resource (the whole service, an entity set, or a collection-valued resource). /// - public DeepInsertSupportType DeepInsertSupport { get; set; } + public DeepInsertSupportType? DeepInsertSupport { get; set; } /// /// Restrictions on update operations. /// - public UpdateRestrictionsType UpdateRestrictions { get; set; } + public UpdateRestrictionsType? UpdateRestrictions { get; set; } /// /// Deep Update Support of the annotated resource (the whole service, an entity set, or a collection-valued resource). /// - public DeepUpdateSupportType DeepUpdateSupport { get; set; } + public DeepUpdateSupportType? DeepUpdateSupport { get; set; } /// /// Restrictions on delete operations. /// - public DeleteRestrictionsType DeleteRestrictions { get; set; } + public DeleteRestrictionsType? DeleteRestrictions { get; set; } /// /// Data modification (including insert) along this navigation property requires the use of ETags. @@ -120,7 +120,7 @@ internal class NavigationPropertyRestriction : IRecord /// /// Restrictions for retrieving entities. /// - public ReadRestrictionsType ReadRestrictions { get; set; } + public ReadRestrictionsType? ReadRestrictions { get; set; } /// /// Init the . @@ -197,7 +197,7 @@ internal class NavigationRestrictionsType : IRecord /// /// Gets the navigation properties which has navigation restrictions. /// - public IList RestrictedProperties { get; private set; } + public IList? RestrictedProperties { get; private set; } /// /// Gets the navigation property referenceable value. @@ -216,10 +216,8 @@ internal class NavigationRestrictionsType : IRecord /// True/False. public bool IsRestrictedProperty(string navigationPropertyPath) { - return RestrictedProperties != null ? - RestrictedProperties.Where(a => a.NavigationProperty == navigationPropertyPath) - .Any(b => b.Navigability != null && b.Navigability.Value == NavigationType.None) : - false; + return RestrictedProperties != null && RestrictedProperties.Where(a => a.NavigationProperty == navigationPropertyPath) + .Any(b => b.Navigability != null && b.Navigability.Value == NavigationType.None); } /// diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/OperationRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/OperationRestrictionsType.cs index c5613d2e7..b8caa1362 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/OperationRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/OperationRestrictionsType.cs @@ -24,17 +24,17 @@ internal class OperationRestrictionsType : IRecord /// /// Gets the List of required scopes to invoke an action or function. /// - public IList Permissions { get; private set; } + public IList? Permissions { get; private set; } /// /// Gets the Supported or required custom headers. /// - public IList CustomHeaders { get; private set; } + public IList? CustomHeaders { get; private set; } /// /// Gets the Supported or required custom query options. /// - public IList CustomQueryOptions { get; private set; } + public IList? CustomQueryOptions { get; private set; } /// /// Init the . From 3737e0b7fd4e4495450a2fad2e3eb543cb74bb3f Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 27 Mar 2025 14:31:47 -0400 Subject: [PATCH 18/24] chore: additional NRT fixes Signed-off-by: Vincent Biret --- .../Common/OpenApiOperationExtensions.cs | 17 +++++++------ .../Edm/EdmModelExtensions.cs | 21 ++++++++-------- .../Edm/ODataTypeCastSegment.cs | 4 +-- .../Edm/RecordExpressionExtensions.cs | 12 ++++----- .../Generator/OpenApiLinkGenerator.cs | 3 ++- .../Generator/OpenApiPathItemGenerator.cs | 4 +-- .../Generator/OpenApiRequestBodyGenerator.cs | 4 +-- .../Generator/OpenApiResponseGenerator.cs | 25 +++++++++---------- .../ComplexPropertyPostOperationHandler.cs | 7 +++--- .../ComplexPropertyUpdateOperationHandler.cs | 14 +++++++---- .../EdmActionImportOperationHandler.cs | 8 +++--- .../Operation/RefDeleteOperationHandler.cs | 2 +- .../Operation/RefPutOperationHandler.cs | 2 +- .../PublicAPI.Unshipped.txt | 6 ++--- .../Vocabulary/Authorization/Http.cs | 4 +-- .../Authorization/OAuth2AuthCode.cs | 4 +-- .../Authorization/OAuth2ClientCredentials.cs | 2 +- .../Authorization/OAuth2Implicit.cs | 2 +- .../Authorization/OAuthAuthorization.cs | 4 +-- .../Vocabulary/Authorization/OpenIDConnect.cs | 2 +- .../Authorization/SecurityScheme.cs | 4 +-- .../Capabilities/CountRestrictionsType.cs | 4 +-- .../Capabilities/ExpandRestrictionsType.cs | 4 +-- .../FilterExpressionRestrictionType.cs | 4 +-- .../Capabilities/FilterRestrictionsType.cs | 10 ++++---- .../Capabilities/UpdateRestrictionsType.cs | 22 ++++++++-------- 26 files changed, 100 insertions(+), 95 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Common/OpenApiOperationExtensions.cs b/src/Microsoft.OpenApi.OData.Reader/Common/OpenApiOperationExtensions.cs index ced0fd483..592100fe7 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Common/OpenApiOperationExtensions.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Common/OpenApiOperationExtensions.cs @@ -57,22 +57,25 @@ public static void AddErrorResponses(this OpenApiOperation operation, OpenApiCon } }; } - operation.Responses.Add(Constants.StatusCodeClass2XX, response ?? Constants.StatusCodeClass2XX.GetResponse(document)); + if ((response ?? Constants.StatusCodeClass2XX.GetResponse(document)) is {} x2xxResponse) + operation.Responses.Add(Constants.StatusCodeClass2XX, x2xxResponse); } - else + else if (Constants.StatusCode204.GetResponse(document) is {} x204Response) { - operation.Responses.Add(Constants.StatusCode204, Constants.StatusCode204.GetResponse(document)); + operation.Responses.Add(Constants.StatusCode204, x204Response); } } - if (settings.ErrorResponsesAsDefault) + if (settings.ErrorResponsesAsDefault && Constants.StatusCodeDefault.GetResponse(document) is {} defaultResponse) { - operation.Responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse(document)); + operation.Responses.Add(Constants.StatusCodeDefault, defaultResponse); } else { - operation.Responses.Add(Constants.StatusCodeClass4XX, Constants.StatusCodeClass4XX.GetResponse(document)); - operation.Responses.Add(Constants.StatusCodeClass5XX, Constants.StatusCodeClass5XX.GetResponse(document)); + if (Constants.StatusCodeClass4XX.GetResponse(document) is {} x4xxResponse) + operation.Responses.Add(Constants.StatusCodeClass4XX, x4xxResponse); + if (Constants.StatusCodeClass5XX.GetResponse(document) is {} x5xxResponse) + operation.Responses.Add(Constants.StatusCodeClass5XX, x5xxResponse); } } } \ No newline at end of file diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs index e6e156a17..f93c10a31 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs @@ -48,7 +48,7 @@ private static bool IsUrlEscapeFunction(this IEdmModel model, IEdmFunction funct Utils.CheckArgumentNull(model, nameof(model)); Utils.CheckArgumentNull(function, nameof(function)); - IEdmVocabularyAnnotation annotation = model.FindVocabularyAnnotations(function, + var annotation = model.FindVocabularyAnnotations(function, CommunityVocabularyModel.UrlEscapeFunctionTerm).FirstOrDefault(); if (annotation != null) { @@ -58,12 +58,11 @@ private static bool IsUrlEscapeFunction(this IEdmModel model, IEdmFunction funct return true; } - IEdmBooleanConstantExpression tagConstant = annotation.Value as IEdmBooleanConstantExpression; - if (tagConstant != null) - { - return tagConstant.Value; - } - } + if (annotation.Value is IEdmBooleanConstantExpression tagConstant) + { + return tagConstant.Value; + } + } return false; } @@ -110,11 +109,11 @@ public static Dictionary> LoadAllNav /// /// The given entity type. /// All base types or null. - public static IEnumerable FindAllBaseTypes(this IEdmEntityType entityType) + public static IEnumerable? FindAllBaseTypes(this IEdmEntityType entityType) { if (entityType == null) { - yield return null; + yield break; } IEdmEntityType current = entityType.BaseEntityType(); @@ -130,11 +129,11 @@ public static IEnumerable FindAllBaseTypes(this IEdmEntityType e /// /// The given complex type. /// All base types or null. - public static IEnumerable FindAllBaseTypes(this IEdmComplexType complexType) + public static IEnumerable? FindAllBaseTypes(this IEdmComplexType complexType) { if (complexType == null) { - yield return null; + yield break; } IEdmComplexType current = complexType.BaseComplexType(); diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataTypeCastSegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataTypeCastSegment.cs index 47da7fd4f..e7a3ff3c0 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataTypeCastSegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataTypeCastSegment.cs @@ -27,7 +27,7 @@ public ODataTypeCastSegment(IEdmStructuredType structuredType, IEdmModel model) private readonly IEdmModel _model; /// - public override IEdmEntityType EntityType => null; + public override IEdmEntityType? EntityType => null; /// public override ODataSegmentKind Kind => ODataSegmentKind.TypeCast; @@ -43,7 +43,7 @@ public ODataTypeCastSegment(IEdmStructuredType structuredType, IEdmModel model) /// public override IEnumerable GetAnnotables() { - return [StructuredType as IEdmVocabularyAnnotatable]; + return StructuredType is IEdmVocabularyAnnotatable annotable ? [annotable] : []; } /// diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/RecordExpressionExtensions.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/RecordExpressionExtensions.cs index 5d8dc6d4a..3010a06c9 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/RecordExpressionExtensions.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/RecordExpressionExtensions.cs @@ -41,7 +41,7 @@ internal static class RecordExpressionExtensions /// The given record. /// The property name. /// The property string value. - public static string GetString(this IEdmRecordExpression record, string propertyName) + public static string? GetString(this IEdmRecordExpression record, string propertyName) { Utils.CheckArgumentNull(record, nameof(record)); Utils.CheckArgumentNull(propertyName, nameof(propertyName)); @@ -127,7 +127,7 @@ property.Value is IEdmEnumMemberExpression value && /// The record expression. /// The property name. /// The collection or null. - public static T GetRecord(this IEdmRecordExpression record, string propertyName) + public static T? GetRecord(this IEdmRecordExpression record, string propertyName) where T : IRecord, new() { Utils.CheckArgumentNull(record, nameof(record)); @@ -150,7 +150,7 @@ public static T GetRecord(this IEdmRecordExpression record, string propertyNa /// The record expression. /// The property name. /// The property path or null. - public static string GetPropertyPath(this IEdmRecordExpression record, string propertyName) + public static string? GetPropertyPath(this IEdmRecordExpression record, string propertyName) { Utils.CheckArgumentNull(record, nameof(record)); Utils.CheckArgumentNull(propertyName, nameof(propertyName)); @@ -167,7 +167,7 @@ public static string GetPropertyPath(this IEdmRecordExpression record, string pr /// The record expression. /// The property name. /// The collection of property path or null. - public static IList GetCollectionPropertyPath(this IEdmRecordExpression record, string propertyName) + public static IList? GetCollectionPropertyPath(this IEdmRecordExpression record, string propertyName) { Utils.CheckArgumentNull(record, nameof(record)); Utils.CheckArgumentNull(propertyName, nameof(propertyName)); @@ -196,7 +196,7 @@ public static IList GetCollectionPropertyPath(this IEdmRecordExpression /// The record expression. /// The property name. /// The collection of string or null. - public static IList GetCollection(this IEdmRecordExpression record, string propertyName) + public static IList? GetCollection(this IEdmRecordExpression record, string propertyName) { Utils.CheckArgumentNull(record, nameof(record)); Utils.CheckArgumentNull(propertyName, nameof(propertyName)); @@ -221,7 +221,7 @@ public static IList GetCollection(this IEdmRecordExpression record, stri /// The record expression. /// The property name. /// The collection or null. - public static IList GetCollection(this IEdmRecordExpression record, string propertyName) + public static IList? GetCollection(this IEdmRecordExpression record, string propertyName) where T : IRecord, new() { Utils.CheckArgumentNull(record, nameof(record)); diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiLinkGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiLinkGenerator.cs index 63d42da11..b852e2e43 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiLinkGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiLinkGenerator.cs @@ -117,11 +117,12 @@ public static IDictionary CreateLinks(this ODataContext co { foreach (var operationPath in operationPaths) { + if (operationPath.LastSegment?.Identifier is null) continue; OpenApiLink link = new() { OperationId = string.Join(".", operationPath.Segments.Select(x => { - return x.Kind.Equals(ODataSegmentKind.Key) ? x.EntityType.Name : x.Identifier; + return x.Kind.Equals(ODataSegmentKind.Key) && x.EntityType is not null ? x.EntityType.Name : x.Identifier; })) }; diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiPathItemGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiPathItemGenerator.cs index 5aa19ad11..4be929c70 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiPathItemGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiPathItemGenerator.cs @@ -4,7 +4,6 @@ // ------------------------------------------------------------ using System.Collections.Generic; -using System.Linq; using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Models; @@ -46,8 +45,7 @@ public static void AddPathItemsToDocument(this ODataContext context, OpenApiDocu continue; } - OpenApiPathItem pathItem = handler.CreatePathItem(context, path); - if (!pathItem.Operations.Any()) + if (handler.CreatePathItem(context, path) is not {Operations.Count: > 0} pathItem) { continue; } diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiRequestBodyGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiRequestBodyGenerator.cs index ffb8f0c10..2e23c398a 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiRequestBodyGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiRequestBodyGenerator.cs @@ -26,7 +26,7 @@ internal static class OpenApiRequestBodyGenerator /// The Edm action import. /// The OpenApi document to lookup references. /// The created or null. - public static OpenApiRequestBody CreateRequestBody(this ODataContext context, IEdmActionImport actionImport, OpenApiDocument document) + public static OpenApiRequestBody? CreateRequestBody(this ODataContext context, IEdmActionImport actionImport, OpenApiDocument document) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(actionImport, nameof(actionImport)); @@ -42,7 +42,7 @@ public static OpenApiRequestBody CreateRequestBody(this ODataContext context, IE /// The Edm action. /// The OpenApi document to lookup references. /// The created or null. - public static OpenApiRequestBody CreateRequestBody(this ODataContext context, IEdmAction action, OpenApiDocument document) + public static OpenApiRequestBody? CreateRequestBody(this ODataContext context, IEdmAction action, OpenApiDocument document) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(action, nameof(action)); diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs index c0cfa4f01..81abc660e 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Linq; using Microsoft.OData.Edm; using Microsoft.OpenApi.Models; @@ -28,7 +27,7 @@ internal static class OpenApiResponseGenerator /// The status code. /// The OpenApi document to lookup references. /// The created . - public static IOpenApiResponse GetResponse(this string statusCode, OpenApiDocument document) + public static IOpenApiResponse? GetResponse(this string statusCode, OpenApiDocument document) { return statusCode switch { Constants.StatusCodeDefault => new OpenApiResponseReference(Constants.Error, document), @@ -82,8 +81,7 @@ public static void AddResponsesToDocument(this ODataContext context, OpenApiDocu foreach (IEdmOperation operation in context.Model.SchemaElements.OfType() .Where(op => context.Model.OperationTargetsMultiplePaths(op))) { - OpenApiResponse response = context.CreateOperationResponse(operation, document); - if (response != null) + if (context.CreateOperationResponse(operation, document) is {} response) responses[$"{operation.Name}Response"] = response; } @@ -134,26 +132,27 @@ public static OpenApiResponses CreateResponses(this ODataContext context, IEdmOp new OpenApiResponseReference($"{operation.Name}Response", document) ); } - else + else if (context.CreateOperationResponse(operation, document) is {} successResponse) { - OpenApiResponse response = context.CreateOperationResponse(operation, document); - responses.Add(context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, response); + responses.Add(context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, successResponse); } - if (context.Settings.ErrorResponsesAsDefault) + if (context.Settings.ErrorResponsesAsDefault && Constants.StatusCodeDefault.GetResponse(document) is {} defaultResponse) { - responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse(document)); + responses.Add(Constants.StatusCodeDefault, defaultResponse); } else { - responses.Add(Constants.StatusCodeClass4XX, Constants.StatusCodeClass4XX.GetResponse(document)); - responses.Add(Constants.StatusCodeClass5XX, Constants.StatusCodeClass5XX.GetResponse(document)); + if (Constants.StatusCodeClass4XX.GetResponse(document) is {} x4Response) + responses.Add(Constants.StatusCodeClass4XX, x4Response); + if (Constants.StatusCodeClass5XX.GetResponse(document) is {} x5Response) + responses.Add(Constants.StatusCodeClass5XX, x5Response); } return responses; } - public static OpenApiResponse CreateOperationResponse(this ODataContext context, IEdmOperation operation, OpenApiDocument document) + public static OpenApiResponse? CreateOperationResponse(this ODataContext context, IEdmOperation operation, OpenApiDocument document) { if (operation.ReturnType == null) return null; @@ -232,7 +231,7 @@ public static OpenApiResponse CreateOperationResponse(this ODataContext context, schema = context.CreateEdmTypeSchema(operation.ReturnType, document); } - string mediaType = Constants.ApplicationJsonMediaType; + string? mediaType = Constants.ApplicationJsonMediaType; if (operation.ReturnType.AsPrimitive()?.PrimitiveKind() == EdmPrimitiveTypeKind.Stream) { mediaType = context.Model.GetString(operation, CoreConstants.MediaType); diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPostOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPostOperationHandler.cs index 6afcd91bb..2bb2e2cf0 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPostOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPostOperationHandler.cs @@ -31,7 +31,7 @@ public ComplexPropertyPostOperationHandler(OpenApiDocument document):base(docume protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - if (!ComplexPropertySegment.Property.Type.IsCollection()) + if (ComplexPropertySegment is null || !ComplexPropertySegment.Property.Type.IsCollection()) { throw new InvalidOperationException("OData conventions do not support POSTing to a complex property that is not a collection."); } @@ -60,7 +60,7 @@ protected override void SetBasicInfo(OpenApiOperation operation) } // Summary and Description - string placeHolder = $"Sets a new value for the collection of {ComplexPropertySegment.ComplexType.Name}."; + string placeHolder = $"Sets a new value for the collection of {ComplexPropertySegment?.ComplexType?.Name}."; operation.Summary = _insertRestrictions?.Description ?? placeHolder; operation.Description = _insertRestrictions?.LongDescription; @@ -140,8 +140,9 @@ protected override void AppendCustomParameters(OpenApiOperation operation) } } - private OpenApiSchema GetOpenApiSchema() + private OpenApiSchema? GetOpenApiSchema() { + if (ComplexPropertySegment is null) return null; return new() { Type = JsonSchemaType.Array, diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyUpdateOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyUpdateOperationHandler.cs index 27de2675c..59532cf66 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyUpdateOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyUpdateOperationHandler.cs @@ -37,16 +37,19 @@ protected override void Initialize(ODataContext context, ODataPath path) if (!string.IsNullOrEmpty(TargetPath)) _updateRestrictions = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); - var complexPropertyUpdateRestrictions = Context?.Model.GetRecord(ComplexPropertySegment.Property, CapabilitiesConstants.UpdateRestrictions); - _updateRestrictions?.MergePropertiesIfNull(complexPropertyUpdateRestrictions); - _updateRestrictions ??= complexPropertyUpdateRestrictions; + if (ComplexPropertySegment is not null) + { + var complexPropertyUpdateRestrictions = Context?.Model.GetRecord(ComplexPropertySegment.Property, CapabilitiesConstants.UpdateRestrictions); + _updateRestrictions?.MergePropertiesIfNull(complexPropertyUpdateRestrictions); + _updateRestrictions ??= complexPropertyUpdateRestrictions; + } } /// protected override void SetBasicInfo(OpenApiOperation operation) { // Summary and Description - string placeHolder = $"Update property {ComplexPropertySegment.Property.Name} value."; + string placeHolder = $"Update property {ComplexPropertySegment?.Property.Name} value."; operation.Summary = _updateRestrictions?.Description ?? placeHolder; operation.Description = _updateRestrictions?.LongDescription; @@ -114,8 +117,9 @@ protected override void AppendCustomParameters(OpenApiOperation operation) } } - private IOpenApiSchema GetOpenApiSchema() + private IOpenApiSchema? GetOpenApiSchema() { + if (ComplexPropertySegment is null) return null; var schema = new OpenApiSchemaReference(ComplexPropertySegment.ComplexType.FullName(), _document); if (ComplexPropertySegment.Property.Type.IsCollection()) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionImportOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionImportOperationHandler.cs index 4111f9ddf..f5b94190f 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionImportOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionImportOperationHandler.cs @@ -3,9 +3,11 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Collections.Generic; using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Generator; @@ -30,11 +32,10 @@ public EdmActionImportOperationHandler(OpenApiDocument document):base(document) protected override void SetRequestBody(OpenApiOperation operation) { - IEdmActionImport actionImport = EdmOperationImport as IEdmActionImport; - // The requestBody field contains a Request Body Object describing the structure of the request body. // Its schema value follows the rules for Schema Objects for complex types, with one property per action parameter. - operation.RequestBody = Context.CreateRequestBody(actionImport, _document); + if (EdmOperationImport is IEdmActionImport actionImport) + operation.RequestBody = Context?.CreateRequestBody(actionImport, _document); base.SetRequestBody(operation); } @@ -42,6 +43,7 @@ protected override void SetRequestBody(OpenApiOperation operation) /// protected override void SetExtensions(OpenApiOperation operation) { + operation.Extensions ??= new Dictionary(); operation.Extensions.Add(Constants.xMsDosOperationType, new OpenApiAny("actionImport")); base.SetExtensions(operation); diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/RefDeleteOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/RefDeleteOperationHandler.cs index f0f544400..dab9aadb0 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/RefDeleteOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/RefDeleteOperationHandler.cs @@ -106,7 +106,7 @@ protected override void SetParameters(OpenApiOperation operation) /// protected override void SetSecurity(OpenApiOperation operation) { - if (_deleteRestriction == null) + if (_deleteRestriction?.Permissions == null) { return; } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/RefPutOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/RefPutOperationHandler.cs index db539b243..4d0e85cee 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/RefPutOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/RefPutOperationHandler.cs @@ -80,7 +80,7 @@ protected override void SetResponses(OpenApiOperation operation) protected override void SetSecurity(OpenApiOperation operation) { - if (_updateRestriction == null) + if (_updateRestriction?.Permissions == null) { return; } diff --git a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt index 7a9561ccd..836a59939 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt +++ b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt @@ -287,7 +287,7 @@ override Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.GetAnnotables() override Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! override Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.Identifier.get -> string! override Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType! +override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType? override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.Identifier.get -> string! @@ -295,8 +295,8 @@ override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.Kind.get -> Microsoft. static Microsoft.OpenApi.OData.Common.Utils.GetTermQualifiedName() -> string? static Microsoft.OpenApi.OData.Common.Utils.GetUniqueName(string! input, System.Collections.Generic.HashSet! set) -> string! static Microsoft.OpenApi.OData.Common.Utils.UpperFirstChar(string! input) -> string? -static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.FindAllBaseTypes(this Microsoft.OData.Edm.IEdmComplexType! complexType) -> System.Collections.Generic.IEnumerable! -static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.FindAllBaseTypes(this Microsoft.OData.Edm.IEdmEntityType! entityType) -> System.Collections.Generic.IEnumerable! +static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.FindAllBaseTypes(this Microsoft.OData.Edm.IEdmComplexType! complexType) -> System.Collections.Generic.IEnumerable? +static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.FindAllBaseTypes(this Microsoft.OData.Edm.IEdmEntityType! entityType) -> System.Collections.Generic.IEnumerable? static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.GetAllElements(this Microsoft.OData.Edm.IEdmModel! model) -> System.Collections.Generic.IEnumerable! static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.IsOperationImportOverload(this Microsoft.OData.Edm.IEdmModel! model, Microsoft.OData.Edm.IEdmOperationImport! operationImport) -> bool static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.IsOperationOverload(this Microsoft.OData.Edm.IEdmModel! model, Microsoft.OData.Edm.IEdmOperation! operation) -> bool diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/Http.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/Http.cs index 6234b48b6..8a44d4361 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/Http.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/Http.cs @@ -17,12 +17,12 @@ internal class Http : Authorization /// /// HTTP Authorization scheme to be used in the Authorization header, as per RFC7235. /// - public string Scheme { get; set; } + public string? Scheme { get; set; } /// /// Format of the bearer token. /// - public string BearerFormat { get; set; } + public string? BearerFormat { get; set; } /// /// Gets the security scheme type. diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2AuthCode.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2AuthCode.cs index 7cbf2fdb9..5e47755ad 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2AuthCode.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2AuthCode.cs @@ -16,12 +16,12 @@ internal class OAuth2AuthCode : OAuthAuthorization /// /// Authorization URL. /// - public string AuthorizationUrl { get; set; } + public string? AuthorizationUrl { get; set; } /// /// Token Url. /// - public string TokenUrl { get; set; } + public string? TokenUrl { get; set; } /// /// Gets the OAuth2 type. diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2ClientCredentials.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2ClientCredentials.cs index 5cb38578f..74b8b8973 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2ClientCredentials.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2ClientCredentials.cs @@ -16,7 +16,7 @@ internal class OAuth2ClientCredentials : OAuthAuthorization /// /// Token Url. /// - public string TokenUrl { get; set; } + public string? TokenUrl { get; set; } /// /// Gets the OAuth2 type. diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2Implicit.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2Implicit.cs index db02422b2..8b827047a 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2Implicit.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2Implicit.cs @@ -16,7 +16,7 @@ internal class OAuth2Implicit : OAuthAuthorization /// /// Authorization URL. /// - public string AuthorizationUrl { get; set; } + public string? AuthorizationUrl { get; set; } /// /// Gets the OAuth2 type. diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuthAuthorization.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuthAuthorization.cs index 73df17002..ce8c1550a 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuthAuthorization.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuthAuthorization.cs @@ -44,12 +44,12 @@ internal abstract class OAuthAuthorization : Authorization /// /// Available scopes. /// - public IList Scopes { get; set; } + public IList? Scopes { get; set; } /// /// Refresh Url /// - public string RefreshUrl { get; set; } + public string? RefreshUrl { get; set; } /// /// Gets the security scheme type. diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OpenIDConnect.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OpenIDConnect.cs index 8ef4562fd..d444119db 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OpenIDConnect.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OpenIDConnect.cs @@ -18,7 +18,7 @@ internal class OpenIDConnect : Authorization /// Issuer location for the OpenID Provider. /// Configuration information can be obtained by appending `/.well-known/openid-configuration` to this Url. /// - public string IssuerUrl { get; set; } + public string? IssuerUrl { get; set; } /// /// Gets the security scheme type. diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/SecurityScheme.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/SecurityScheme.cs index 54aec311a..15ab64ae5 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/SecurityScheme.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/SecurityScheme.cs @@ -19,12 +19,12 @@ internal class SecurityScheme : IRecord /// /// The name of a required authorization scheme. /// - public string Authorization { get; set; } + public string? Authorization { get; set; } /// /// The names of scopes required from this authorization scheme. /// - public IList RequiredScopes { get; set; } + public IList? RequiredScopes { get; set; } /// /// Init the . diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/CountRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/CountRestrictionsType.cs index 17447ca92..ad248cd9f 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/CountRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/CountRestrictionsType.cs @@ -25,12 +25,12 @@ internal class CountRestrictionsType : IRecord /// /// Gets the properties which do not allow /$count segments. /// - public IList NonCountableProperties { get; private set; } + public IList? NonCountableProperties { get; private set; } /// /// Gets the navigation properties which do not allow /$count segments. /// - public IList NonCountableNavigationProperties { get; private set; } + public IList? NonCountableNavigationProperties { get; private set; } /// /// Test the target supports count. diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ExpandRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ExpandRestrictionsType.cs index 60b797afa..df25b6624 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ExpandRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ExpandRestrictionsType.cs @@ -30,7 +30,7 @@ internal class ExpandRestrictionsType : IRecord /// /// Gets the properties which cannot be used in $expand expressions. /// - public IList NonExpandableProperties { get; private set; } + public IList? NonExpandableProperties { get; private set; } /// /// Gets the maximum number of levels that can be expanded in a expand expression. @@ -50,7 +50,7 @@ internal class ExpandRestrictionsType : IRecord /// True/False. public bool IsNonExpandableProperty(string navigationPropertyPath) { - return NonExpandableProperties != null ? NonExpandableProperties.Any(a => a == navigationPropertyPath) : false; + return NonExpandableProperties != null && NonExpandableProperties.Any(a => a == navigationPropertyPath); } public void Initialize(IEdmRecordExpression record) diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/FilterExpressionRestrictionType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/FilterExpressionRestrictionType.cs index 6ed387261..39377f3f3 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/FilterExpressionRestrictionType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/FilterExpressionRestrictionType.cs @@ -17,14 +17,14 @@ internal class FilterExpressionRestrictionType : IRecord /// /// Gets the Path to the restricted property. /// - public string Property { get; private set; } + public string? Property { get; private set; } /// /// Gets the RequiresFilter value. /// /// /// - public string AllowedExpressions { get; private set; } + public string? AllowedExpressions { get; private set; } /// /// Init the . diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/FilterRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/FilterRestrictionsType.cs index 7cd05d444..8093b7e8d 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/FilterRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/FilterRestrictionsType.cs @@ -30,12 +30,12 @@ internal class FilterRestrictionsType : IRecord /// /// Gets the properties which must be specified in the $filter clause. /// - public IList RequiredProperties { get; private set; } + public IList? RequiredProperties { get; private set; } /// /// Gets the properties which cannot be used in $filter expressions. /// - public IList NonFilterableProperties { get; private set; } + public IList? NonFilterableProperties { get; private set; } /// /// Gets The maximum number of levels (including recursion) that can be traversed in a filter expression. A value of -1 indicates there is no restriction. @@ -46,7 +46,7 @@ internal class FilterRestrictionsType : IRecord /// Gets These properties only allow a subset of filter expressions. /// A valid filter expression for a single property can be enclosed in parentheses and combined by `and` with valid expressions for other properties. /// - public IList FilterExpressionRestrictions { get; private set; } + public IList? FilterExpressionRestrictions { get; private set; } /// /// Test the target supports filter. @@ -61,7 +61,7 @@ internal class FilterRestrictionsType : IRecord /// True/False. public bool IsRequiredProperty(string propertyPath) { - return RequiredProperties != null ? RequiredProperties.Any(a => a == propertyPath) : false; + return RequiredProperties != null && RequiredProperties.Any(a => a == propertyPath); } /// @@ -71,7 +71,7 @@ public bool IsRequiredProperty(string propertyPath) /// True/False. public bool IsNonFilterableProperty(string propertyPath) { - return NonFilterableProperties != null ? NonFilterableProperties.Any(a => a == propertyPath) : false; + return NonFilterableProperties != null && NonFilterableProperties.Any(a => a == propertyPath); } /// diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/UpdateRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/UpdateRestrictionsType.cs index 7cbd6a460..9484edbc5 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/UpdateRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/UpdateRestrictionsType.cs @@ -69,7 +69,7 @@ internal class UpdateRestrictionsType : IRecord /// /// Gets the navigation properties which do not allow rebinding. /// - public IList NonUpdatableNavigationProperties { get; private set; } + public IList? NonUpdatableNavigationProperties { get; private set; } /// /// Gets the maximum number of navigation properties that can be traversed when addressing the collection or entity to update. @@ -80,32 +80,32 @@ internal class UpdateRestrictionsType : IRecord /// /// Gets the Required permissions. One of the specified sets of scopes is required to perform the update. /// - public IList Permissions { get; private set; } + public IList? Permissions { get; private set; } /// /// Gets/sets the support for query options with update requests. /// - public ModificationQueryOptionsType QueryOptions { get; private set; } + public ModificationQueryOptionsType? QueryOptions { get; private set; } /// /// Gets/sets the supported or required custom headers. /// - public IList CustomHeaders { get; private set; } + public IList? CustomHeaders { get; private set; } /// /// Gets/sets the supported or required custom query options. /// - public IList CustomQueryOptions { get; private set; } + public IList? CustomQueryOptions { get; private set; } /// /// Gets A brief description of the request. /// - public string Description { get; private set; } + public string? Description { get; private set; } /// /// Gets A lengthy description of the request. /// - public string LongDescription { get; private set; } + public string? LongDescription { get; private set; } /// /// Test the target supports update. @@ -120,9 +120,7 @@ internal class UpdateRestrictionsType : IRecord /// True/False. public bool IsNonUpdatableNavigationProperty(string navigationPropertyPath) { - return NonUpdatableNavigationProperties != null ? - NonUpdatableNavigationProperties.Any(a => a == navigationPropertyPath) : - false; + return NonUpdatableNavigationProperties != null && NonUpdatableNavigationProperties.Any(a => a == navigationPropertyPath); } /// @@ -140,13 +138,13 @@ public bool IsNonUpdatableNavigationProperty(string navigationPropertyPath) /// Lists the media types acceptable for the request content /// /// This is not an official OASIS standard property. - public IList RequestContentTypes { get; private set; } + public IList? RequestContentTypes { get; private set; } /// /// Lists the media types acceptable for the response content /// /// This is not an official OASIS standard property. - public IList ResponseContentTypes { get; private set; } + public IList? ResponseContentTypes { get; private set; } /// /// Init the . From 4f8fe8788dc64f73f2a33a41d8f873d27bb9a216 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 27 Mar 2025 14:50:22 -0400 Subject: [PATCH 19/24] chore: additional NRT fixes Signed-off-by: Vincent Biret --- .../EdmModelOpenApiExtensions.cs | 24 ++++++------ .../IODataRoutePathPrefixProvider.cs | 4 +- .../ODataRoutePathPrefixProvider.cs | 4 +- .../OpenApiSecuritySchemeGenerator.cs | 31 +++++++++------ .../OData/ODataResourceValue.cs | 2 +- .../OData/ODataValue.cs | 2 +- .../PathItem/MediaEntityPathItemHandler.cs | 2 +- .../PublicAPI.Unshipped.txt | 8 ++-- .../Vocabulary/Authorization/ApiKey.cs | 2 +- .../Authorization/OAuth2Password.cs | 4 +- .../Authorization/OAuthAuthorization.cs | 4 +- .../Vocabulary/Capabilities/PermissionType.cs | 5 +-- .../Vocabulary/Capabilities/ScopeType.cs | 4 +- .../Capabilities/SearchRestrictionsType.cs | 38 ++++++++----------- .../Capabilities/SortRestrictionsType.cs | 8 ++-- .../Vocabulary/Core/ExampleValue.cs | 2 +- .../Vocabulary/Core/ExternalExampleValue.cs | 2 +- .../Vocabulary/Core/LinkType.cs | 6 +-- .../Vocabulary/Core/PrimitiveExampleValue.cs | 2 +- .../Vocabulary/Core/ResourceExampleValue.cs | 2 +- .../Vocabulary/Core/RevisionRecord.cs | 4 +- .../Vocabulary/Core/RevisionType.cs | 4 +- .../Authorization/OAuth2PasswordTests.cs | 2 +- 23 files changed, 83 insertions(+), 83 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/EdmModelOpenApiExtensions.cs b/src/Microsoft.OpenApi.OData.Reader/EdmModelOpenApiExtensions.cs index 5fe3f4b07..a1af2a25e 100644 --- a/src/Microsoft.OpenApi.OData.Reader/EdmModelOpenApiExtensions.cs +++ b/src/Microsoft.OpenApi.OData.Reader/EdmModelOpenApiExtensions.cs @@ -3,9 +3,11 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Collections.Generic; using Microsoft.OData.Edm; using Microsoft.OData.Edm.Validation; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; @@ -39,22 +41,20 @@ public static OpenApiDocument ConvertToOpenApi(this IEdmModel model, OpenApiConv Utils.CheckArgumentNull(model, nameof(model)); Utils.CheckArgumentNull(settings, nameof(settings)); - if (settings.VerifyEdmModel) - { - if (!model.Validate(out var errors)) + if (settings.VerifyEdmModel && !model.Validate(out var errors)) + { + OpenApiDocument document = new(); + int index = 1; + document.Extensions ??= new Dictionary(); + foreach (var error in errors) { - OpenApiDocument document = new(); - int index = 1; - foreach (var error in errors) - { - document.Extensions.Add(Constants.xMsEdmModelError + index++, new OpenApiAny(error.ToString())); - } - - return document; + document.Extensions.Add(Constants.xMsEdmModelError + index++, new OpenApiAny(error.ToString())); } + + return document; } - ODataContext context = new(model, settings); + ODataContext context = new(model, settings); return context.CreateDocument(); } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Extensions/IODataRoutePathPrefixProvider.cs b/src/Microsoft.OpenApi.OData.Reader/Extensions/IODataRoutePathPrefixProvider.cs index 22b33398f..edff4e306 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Extensions/IODataRoutePathPrefixProvider.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Extensions/IODataRoutePathPrefixProvider.cs @@ -16,11 +16,11 @@ public interface IODataRoutePathPrefixProvider /// /// The route prefix. /// - public string PathPrefix { get; } + public string? PathPrefix { get; } /// /// The route prefix parameters. /// - public IEnumerable Parameters { get; } + public IEnumerable? Parameters { get; } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Extensions/ODataRoutePathPrefixProvider.cs b/src/Microsoft.OpenApi.OData.Reader/Extensions/ODataRoutePathPrefixProvider.cs index 61b409269..5a9d864c3 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Extensions/ODataRoutePathPrefixProvider.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Extensions/ODataRoutePathPrefixProvider.cs @@ -16,11 +16,11 @@ public class ODataRoutePathPrefixProvider : IODataRoutePathPrefixProvider /// /// Gets/sets the path prefix. /// - public string PathPrefix { get; set; } + public string? PathPrefix { get; set; } /// /// Gets/sets the associated parameters for the path prefix. /// - public IEnumerable Parameters { get; set; } + public IEnumerable? Parameters { get; set; } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSecuritySchemeGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSecuritySchemeGenerator.cs index e5156a837..0bcdfd517 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSecuritySchemeGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSecuritySchemeGenerator.cs @@ -4,7 +4,6 @@ // ------------------------------------------------------------ using System; -using System.Collections.Generic; using System.Diagnostics; using System.Linq; using Microsoft.OpenApi.Models; @@ -37,6 +36,10 @@ public static void AddSecuritySchemesToDocument(this ODataContext context, OpenA foreach (var authorization in authorizations) { + if (string.IsNullOrEmpty(authorization.Name)) + { + continue; + } OpenApiSecurityScheme scheme = new OpenApiSecurityScheme { Type = authorization.SchemeType, @@ -104,7 +107,8 @@ private static void AppendOpenIdConnect(OpenApiSecurityScheme scheme, OpenIDConn Debug.Assert(scheme != null); Debug.Assert(openIdConnect != null); - scheme.OpenIdConnectUrl = new Uri(openIdConnect.IssuerUrl); + if (!string.IsNullOrEmpty(openIdConnect.IssuerUrl)) + scheme.OpenIdConnectUrl = new Uri(openIdConnect.IssuerUrl); } private static void AppendOAuth2(OpenApiSecurityScheme scheme, OAuthAuthorization oAuth2) @@ -113,11 +117,11 @@ private static void AppendOAuth2(OpenApiSecurityScheme scheme, OAuthAuthorizatio Debug.Assert(oAuth2 != null); scheme.Flows = new OpenApiOAuthFlows(); - OpenApiOAuthFlow flow = null; + OpenApiOAuthFlow? flow = null; switch (oAuth2.OAuth2Type) { - case OAuth2Type.AuthCode: // AuthCode - OAuth2AuthCode authCode = (OAuth2AuthCode)oAuth2; + case OAuth2Type.AuthCode when oAuth2 is OAuth2AuthCode {AuthorizationUrl: not null, TokenUrl: not null} authCode: + // AuthCode flow = new OpenApiOAuthFlow { AuthorizationUrl = new Uri(authCode.AuthorizationUrl), @@ -126,7 +130,7 @@ private static void AppendOAuth2(OpenApiSecurityScheme scheme, OAuthAuthorizatio scheme.Flows.AuthorizationCode = flow; break; - case OAuth2Type.Pasword: // Password + case OAuth2Type.Password: // Password OAuth2Password password = (OAuth2Password)oAuth2; flow = new OpenApiOAuthFlow { @@ -135,8 +139,8 @@ private static void AppendOAuth2(OpenApiSecurityScheme scheme, OAuthAuthorizatio scheme.Flows.Password = flow; break; - case OAuth2Type.Implicit: // Implicit - OAuth2Implicit @implicit = (OAuth2Implicit)oAuth2; + case OAuth2Type.Implicit when oAuth2 is OAuth2Implicit {AuthorizationUrl: not null} @implicit: + // Implicit flow = new OpenApiOAuthFlow { AuthorizationUrl = new Uri(@implicit.AuthorizationUrl) @@ -144,8 +148,8 @@ private static void AppendOAuth2(OpenApiSecurityScheme scheme, OAuthAuthorizatio scheme.Flows.Implicit = flow; break; - case OAuth2Type.ClientCredentials: // ClientCredentials - OAuth2ClientCredentials credentials = (OAuth2ClientCredentials)oAuth2; + case OAuth2Type.ClientCredentials when oAuth2 is OAuth2ClientCredentials {TokenUrl: not null} credentials: + // ClientCredentials flow = new OpenApiOAuthFlow { TokenUrl = new Uri(credentials.TokenUrl) @@ -155,11 +159,14 @@ private static void AppendOAuth2(OpenApiSecurityScheme scheme, OAuthAuthorizatio } Debug.Assert(flow != null); - flow.RefreshUrl = new Uri(oAuth2.RefreshUrl); + if (!string.IsNullOrEmpty(oAuth2.RefreshUrl)) + flow.RefreshUrl = new Uri(oAuth2.RefreshUrl); if (oAuth2.Scopes != null) { - flow.Scopes = oAuth2.Scopes.ToDictionary(s => s.Scope, s => s.Description); + flow.Scopes = oAuth2.Scopes + .Where(static x => !string.IsNullOrEmpty(x.Scope) && !string.IsNullOrEmpty(x.Description)) + .ToDictionary(s => s.Scope!, s => s.Description!); } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/OData/ODataResourceValue.cs b/src/Microsoft.OpenApi.OData.Reader/OData/ODataResourceValue.cs index c0990e097..c22f731e6 100644 --- a/src/Microsoft.OpenApi.OData.Reader/OData/ODataResourceValue.cs +++ b/src/Microsoft.OpenApi.OData.Reader/OData/ODataResourceValue.cs @@ -15,6 +15,6 @@ internal class ODataResourceValue : ODataValue /// /// Gets or sets the properties. /// - public IDictionary Properties { get; set; } + public IDictionary? Properties { get; set; } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/OData/ODataValue.cs b/src/Microsoft.OpenApi.OData.Reader/OData/ODataValue.cs index d51c0173a..ee8e6bf93 100644 --- a/src/Microsoft.OpenApi.OData.Reader/OData/ODataValue.cs +++ b/src/Microsoft.OpenApi.OData.Reader/OData/ODataValue.cs @@ -15,6 +15,6 @@ internal abstract class ODataValue /// /// Gets or set the type reference of this value. /// - public IEdmTypeReference TypeReference { get; set; } + public IEdmTypeReference? TypeReference { get; set; } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/MediaEntityPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/MediaEntityPathItemHandler.cs index bacbcd9e4..257dd3fe5 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/MediaEntityPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/MediaEntityPathItemHandler.cs @@ -40,7 +40,7 @@ public MediaEntityPathItemHandler(OpenApiDocument document) : base(document) /// protected override void SetOperations(OpenApiPathItem item) { - var readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + var readRestrictions = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); var navSourceReadRestrictions = EntitySet != null ? Context.Model.GetRecord(EntitySet) : (Singleton is null ? null : Context.Model.GetRecord(Singleton)); diff --git a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt index 836a59939..cbe5fd744 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt +++ b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt @@ -103,13 +103,13 @@ Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.ODataTypeCastSegment(Microsoft. Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.StructuredType.get -> Microsoft.OData.Edm.IEdmStructuredType! Microsoft.OpenApi.OData.EdmModelOpenApiExtensions Microsoft.OpenApi.OData.Extensions.IODataRoutePathPrefixProvider -Microsoft.OpenApi.OData.Extensions.IODataRoutePathPrefixProvider.Parameters.get -> System.Collections.Generic.IEnumerable! -Microsoft.OpenApi.OData.Extensions.IODataRoutePathPrefixProvider.PathPrefix.get -> string! +Microsoft.OpenApi.OData.Extensions.IODataRoutePathPrefixProvider.Parameters.get -> System.Collections.Generic.IEnumerable? +Microsoft.OpenApi.OData.Extensions.IODataRoutePathPrefixProvider.PathPrefix.get -> string? Microsoft.OpenApi.OData.Extensions.ODataRoutePathPrefixProvider Microsoft.OpenApi.OData.Extensions.ODataRoutePathPrefixProvider.ODataRoutePathPrefixProvider() -> void -Microsoft.OpenApi.OData.Extensions.ODataRoutePathPrefixProvider.Parameters.get -> System.Collections.Generic.IEnumerable! +Microsoft.OpenApi.OData.Extensions.ODataRoutePathPrefixProvider.Parameters.get -> System.Collections.Generic.IEnumerable? Microsoft.OpenApi.OData.Extensions.ODataRoutePathPrefixProvider.Parameters.set -> void -Microsoft.OpenApi.OData.Extensions.ODataRoutePathPrefixProvider.PathPrefix.get -> string! +Microsoft.OpenApi.OData.Extensions.ODataRoutePathPrefixProvider.PathPrefix.get -> string? Microsoft.OpenApi.OData.Extensions.ODataRoutePathPrefixProvider.PathPrefix.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings Microsoft.OpenApi.OData.OpenApiConvertSettings.AddAlternateKeyPaths.get -> bool diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/ApiKey.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/ApiKey.cs index bfdf14ed9..d41e96dcf 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/ApiKey.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/ApiKey.cs @@ -38,7 +38,7 @@ internal class ApiKey : Authorization /// /// The name of the header or query parameter. /// - public string KeyName { get; set; } + public string? KeyName { get; set; } /// /// Whether the API Key is passed in the header or as a query option. diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2Password.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2Password.cs index 0305b74a2..e5d72a780 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2Password.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2Password.cs @@ -16,12 +16,12 @@ internal class OAuth2Password : OAuthAuthorization /// /// Token Url. /// - public string TokenUrl { get; set; } + public string? TokenUrl { get; set; } /// /// Gets the OAuth2 type. /// - public override OAuth2Type OAuth2Type => OAuth2Type.Pasword; + public override OAuth2Type OAuth2Type => OAuth2Type.Password; /// /// Init . diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuthAuthorization.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuthAuthorization.cs index ce8c1550a..79434342f 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuthAuthorization.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuthAuthorization.cs @@ -26,9 +26,9 @@ internal enum OAuth2Type Implicit, /// - /// Pasword + /// Password /// - Pasword, + Password, /// /// AuthCode diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/PermissionType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/PermissionType.cs index 16b3bcddf..edbeb66be 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/PermissionType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/PermissionType.cs @@ -3,7 +3,6 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ -using System.Collections; using System.Collections.Generic; using Microsoft.OData.Edm.Vocabularies; using Microsoft.OpenApi.OData.Common; @@ -19,12 +18,12 @@ internal class PermissionType : IRecord /// /// Gets the Authorization flow scheme name. /// - public string SchemeName { get; private set; } + public string? SchemeName { get; private set; } /// /// Gets the list of scopes that can provide access to the resource. /// - public IList Scopes { get; private set; } + public IList? Scopes { get; private set; } /// /// Init the . diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ScopeType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ScopeType.cs index 0a7d24236..c181a1459 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ScopeType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ScopeType.cs @@ -17,14 +17,14 @@ internal class ScopeType : IRecord /// /// Gets the names of the scope. /// - public string Scope { get; private set; } + public string? Scope { get; private set; } /// /// Gets the restricted properties. /// Comma-separated string value of all properties that will be included or excluded when using the scope. /// Possible string value identifiers when specifying properties are '*', _PropertyName_, '-'_PropertyName_. /// - public string RestrictedProperties { get; private set; } + public string? RestrictedProperties { get; private set; } /// /// Init the . diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/SearchRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/SearchRestrictionsType.cs index e001f5273..dce043cc0 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/SearchRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/SearchRestrictionsType.cs @@ -102,29 +102,23 @@ public void Initialize(IEdmRecordExpression record) Searchable = record.GetBoolean("Searchable"); // read the "UnsupportedExpressions" - IEdmPropertyConstructor property = record.Properties.FirstOrDefault(e => e.Name == "UnsupportedExpressions"); - if (property != null) + if (record.Properties.FirstOrDefault(e => e.Name == "UnsupportedExpressions") is {Value: IEdmEnumMemberExpression {EnumMembers: not null} value}) { - IEdmEnumMemberExpression value = property.Value as IEdmEnumMemberExpression; - if (value != null && value.EnumMembers != null) - { - SearchExpressions result; - foreach (var v in value.EnumMembers) - { - if (Enum.TryParse(v.Name, out result)) - { - if (UnsupportedExpressions == null) - { - UnsupportedExpressions = result; - } - else - { - UnsupportedExpressions = UnsupportedExpressions | result; - } - } - } - } - } + foreach (var v in value.EnumMembers) + { + if (Enum.TryParse(v.Name, out SearchExpressions result)) + { + if (UnsupportedExpressions == null) + { + UnsupportedExpressions = result; + } + else + { + UnsupportedExpressions |= result; + } + } + } + } } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/SortRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/SortRestrictionsType.cs index 3559341fb..8d38c583e 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/SortRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/SortRestrictionsType.cs @@ -25,17 +25,17 @@ internal class SortRestrictionsType : IRecord /// /// Gets the properties which can only be used for sorting in Ascending order. /// - public IList AscendingOnlyProperties { get; private set; } + public IList? AscendingOnlyProperties { get; private set; } /// /// Gets the properties which can only be used for sorting in Descending order. /// - public IList DescendingOnlyProperties { get; private set; } + public IList? DescendingOnlyProperties { get; private set; } /// /// Gets the properties which cannot be used in $orderby expressions. /// - public IList NonSortableProperties { get; private set; } + public IList? NonSortableProperties { get; private set; } /// /// Gets a boolean value indicating whether the target supports $orderby. @@ -89,7 +89,7 @@ public void Initialize(IEdmRecordExpression record) // DescendingOnlyProperties DescendingOnlyProperties = record.GetCollectionPropertyPath("DescendingOnlyProperties"); - // NonSortablePropeties + // NonSortableProperties NonSortableProperties = record.GetCollectionPropertyPath("NonSortableProperties"); } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/ExampleValue.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/ExampleValue.cs index e0f7b2047..ba41116a5 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/ExampleValue.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/ExampleValue.cs @@ -17,7 +17,7 @@ internal class ExampleValue : IRecord /// /// Gets the description of the example value. /// - public string Description { get; private set; } + public string? Description { get; private set; } /// /// Init the diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/ExternalExampleValue.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/ExternalExampleValue.cs index 5afceefd5..97e2ee0e2 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/ExternalExampleValue.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/ExternalExampleValue.cs @@ -16,7 +16,7 @@ internal class ExternalExampleValue : ExampleValue /// /// Gets the Url reference to the value in its literal format /// - public string ExternalValue { get; set; } + public string? ExternalValue { get; set; } /// /// Init the diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/LinkType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/LinkType.cs index cbec48e03..194186fc7 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/LinkType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/LinkType.cs @@ -19,12 +19,12 @@ internal class LinkType : IRecord /// /// The link relation type. /// - public string Rel { get; private set; } + public string? Rel { get; private set; } /// /// The link to the documentation. /// - public Uri Href { get; private set; } + public Uri? Href { get; private set; } /// /// Init the . @@ -34,7 +34,7 @@ public virtual void Initialize(IEdmRecordExpression record) { Utils.CheckArgumentNull(record, nameof(record)); Rel = record.GetString("rel"); - Href = new Uri(record.GetString("href")); + Href = record.GetString("href") is string href ? new Uri(href) : null; } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/PrimitiveExampleValue.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/PrimitiveExampleValue.cs index c91a87c19..b90e1d883 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/PrimitiveExampleValue.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/PrimitiveExampleValue.cs @@ -17,7 +17,7 @@ internal class PrimitiveExampleValue : ExampleValue /// /// Gets the Example value for the custom parameter /// - public ODataPrimitiveValue Value { get; private set; } + public ODataPrimitiveValue? Value { get; private set; } /// /// Init the diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/ResourceExampleValue.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/ResourceExampleValue.cs index bc7c40da0..71ab995a6 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/ResourceExampleValue.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/ResourceExampleValue.cs @@ -16,7 +16,7 @@ internal abstract class ResourceExampleValue : ExampleValue /// /// Gets the Example value for the custom parameter /// - public ODataResourceValue Value { get; private set; } + public ODataResourceValue? Value { get; private set; } /// /// Init the diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/RevisionRecord.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/RevisionRecord.cs index 27a36a45c..3252a1d15 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/RevisionRecord.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/RevisionRecord.cs @@ -39,8 +39,8 @@ internal OpenApiDeprecationExtension GetOpenApiExtension() { Date = Date.HasValue ? new DateTimeOffset(Date.Value, TimeSpan.Zero) : default, RemovalDate = RemovalDate.HasValue ? new DateTimeOffset(RemovalDate.Value, TimeSpan.Zero) : default, - Description = Description, - Version = Version, + Description = string.IsNullOrEmpty(Description) ? string.Empty : Description, + Version = string.IsNullOrEmpty(Version) ? string.Empty : Version, }; } } \ No newline at end of file diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/RevisionType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/RevisionType.cs index c530f8cdc..f8d09b25e 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/RevisionType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/RevisionType.cs @@ -14,7 +14,7 @@ internal class RevisionType : IRecord /// /// The version this revision was introduced. /// - public string Version { get; private set; } + public string? Version { get; private set; } /// /// The kind of the revision /// @@ -22,7 +22,7 @@ internal class RevisionType : IRecord /// /// The description of the revision. /// - public string Description { get; private set; } + public string? Description { get; private set; } /// /// Init the . /// diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Authorization/OAuth2PasswordTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Authorization/OAuth2PasswordTests.cs index d193f0794..166e364dc 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Authorization/OAuth2PasswordTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Authorization/OAuth2PasswordTests.cs @@ -25,7 +25,7 @@ public void SchemeTypeKindAndOAuthTypeSetCorrectly() // Act & Assert Assert.Equal(SecuritySchemeType.OAuth2, password.SchemeType); - Assert.Equal(OAuth2Type.Pasword, password.OAuth2Type); + Assert.Equal(OAuth2Type.Password, password.OAuth2Type); } [Fact] From 661b05a6141bae7e4649e348acb4922eae9d1722 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 27 Mar 2025 15:08:58 -0400 Subject: [PATCH 20/24] chore: additional NRT fixes Signed-off-by: Vincent Biret --- .../Common/CryptographyExtensions.cs | 2 +- .../Common/EdmModelHelper.cs | 10 +++++----- .../Common/Utils.cs | 2 +- .../Edm/EdmAnnotationExtensions.cs | 11 ++++------- .../Edm/EdmModelExtensions.cs | 4 ++-- .../Edm/ODataNavigationPropertySegment.cs | 2 +- .../Edm/ODataRefSegment.cs | 2 +- .../Edm/ODataStreamContentSegment.cs | 2 +- .../Edm/ODataStreamPropertySegment.cs | 2 +- .../OpenApiSecurityRequirementGenerator.cs | 9 ++++++--- .../OpenApiSecuritySchemeGenerator.cs | 4 ++-- .../Generator/OpenApiTagGenerator.cs | 6 +++--- .../OData/IEdmExpressionExtensions.cs | 6 +++--- .../OData/ODataCollectValue.cs | 2 +- .../OData/ODataPrimitiveValue.cs | 2 +- .../PathItem/MediaEntityPathItemHandler.cs | 18 +++++++++--------- .../PublicAPI.Unshipped.txt | 12 ++++++------ 17 files changed, 48 insertions(+), 48 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Common/CryptographyExtensions.cs b/src/Microsoft.OpenApi.OData.Reader/Common/CryptographyExtensions.cs index de93a5cba..249db5591 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Common/CryptographyExtensions.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Common/CryptographyExtensions.cs @@ -22,7 +22,7 @@ public static string GetHashSHA256(this string input) Utils.CheckArgumentNull(input, nameof(input)); var inputBytes = Encoding.UTF8.GetBytes(input); - var hashBytes = hasher.Value.ComputeHash(inputBytes); + if (hasher.Value?.ComputeHash(inputBytes) is not {} hashBytes) return string.Empty; var hash = new StringBuilder(); foreach (var b in hashBytes) { diff --git a/src/Microsoft.OpenApi.OData.Reader/Common/EdmModelHelper.cs b/src/Microsoft.OpenApi.OData.Reader/Common/EdmModelHelper.cs index fde9784c8..1603761c7 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Common/EdmModelHelper.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Common/EdmModelHelper.cs @@ -95,9 +95,9 @@ internal static bool NavigationRestrictionsAllowsNavigability( { items[lastItemIndex] = prefix + Utils.UpperFirstChar(items[lastItemIndex]); } - else + else if (Utils.UpperFirstChar(items[lastItemIndex]) is string lastIdentifier) { - items[lastItemIndex] = Utils.UpperFirstChar(items[lastItemIndex]); + items[lastItemIndex] = lastIdentifier; } return GenerateNavigationPropertyPathOperationId(items); @@ -122,9 +122,9 @@ internal static bool NavigationRestrictionsAllowsNavigability( { items.Add(prefix + Utils.UpperFirstChar(lastSegmentIdentifier)); } - else + else if (Utils.UpperFirstChar(lastSegmentIdentifier) is string lastIdentifier) { - items.Add(Utils.UpperFirstChar(lastSegmentIdentifier)); + items.Add(lastIdentifier); } return GenerateNavigationPropertyPathOperationId(items); @@ -327,7 +327,7 @@ internal static string GenerateComplexPropertyPathTagName(ODataPath path, ODataC List tagNameItems = tagName?.Split('.').ToList() ?? []; - if (tagNameItems.Count < context.Settings.TagDepth) + if (tagNameItems.Count < context.Settings.TagDepth && complexSegment.ComplexType is not null) { tagNameItems.Add(complexSegment.ComplexType.Name); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Common/Utils.cs b/src/Microsoft.OpenApi.OData.Reader/Common/Utils.cs index 13887692a..8f27b9d7b 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Common/Utils.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Common/Utils.cs @@ -45,7 +45,7 @@ public static class Utils /// /// The input string. /// The changed string. - public static string? UpperFirstChar(string input) + public static string? UpperFirstChar(string? input) { if (input == null) { diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmAnnotationExtensions.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmAnnotationExtensions.cs index 3046e3d03..901079bef 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmAnnotationExtensions.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmAnnotationExtensions.cs @@ -128,8 +128,7 @@ internal static class EdmVocabularyAnnotationExtensions public static T? GetRecord(this IEdmModel model, IEdmVocabularyAnnotatable target) where T : class, IRecord, new() { - string qualifiedName = Utils.GetTermQualifiedName(); - return model.GetRecord(target, qualifiedName); + return Utils.GetTermQualifiedName() is string qualifiedName ? model.GetRecord(target, qualifiedName) : null; } /// @@ -243,8 +242,7 @@ internal static class EdmVocabularyAnnotationExtensions public static IEnumerable? GetCollection(this IEdmModel model, IEdmVocabularyAnnotatable target) where T : IRecord, new() { - string qualifiedName = Utils.GetTermQualifiedName(); - return GetCollection(model, target, qualifiedName); + return Utils.GetTermQualifiedName() is string qualifiedName ? GetCollection(model, target, qualifiedName) : null; } /// @@ -349,9 +347,8 @@ internal static class EdmVocabularyAnnotationExtensions Debug.Assert(e.ExpressionKind == EdmExpressionKind.Record); IEdmRecordExpression recordExpression = (IEdmRecordExpression)e; - Authorization auth = Authorization.CreateAuthorization(recordExpression); - return auth; - }); + return Authorization.CreateAuthorization(recordExpression); + }).OfType(); } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs index f93c10a31..6c3650578 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs @@ -109,7 +109,7 @@ public static Dictionary> LoadAllNav /// /// The given entity type. /// All base types or null. - public static IEnumerable? FindAllBaseTypes(this IEdmEntityType entityType) + public static IEnumerable FindAllBaseTypes(this IEdmEntityType entityType) { if (entityType == null) { @@ -129,7 +129,7 @@ public static Dictionary> LoadAllNav /// /// The given complex type. /// All base types or null. - public static IEnumerable? FindAllBaseTypes(this IEdmComplexType complexType) + public static IEnumerable FindAllBaseTypes(this IEdmComplexType complexType) { if (complexType == null) { diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataNavigationPropertySegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataNavigationPropertySegment.cs index 69ea6f562..6c725f58f 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataNavigationPropertySegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataNavigationPropertySegment.cs @@ -42,7 +42,7 @@ public ODataNavigationPropertySegment(IEdmNavigationProperty navigationProperty) /// public override IEnumerable GetAnnotables() { - return new IEdmVocabularyAnnotatable[] { NavigationProperty, EntityType }.Union(EntityType.FindAllBaseTypes()); + return new IEdmVocabularyAnnotatable[] { NavigationProperty, EntityType }.Union(EntityType.FindAllBaseTypes() ?? []); } /// diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataRefSegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataRefSegment.cs index a1047d724..471e5ed63 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataRefSegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataRefSegment.cs @@ -28,7 +28,7 @@ private ODataRefSegment() } /// - public override IEdmEntityType EntityType => null; + public override IEdmEntityType? EntityType => null; /// public override ODataSegmentKind Kind => ODataSegmentKind.Ref; diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataStreamContentSegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataStreamContentSegment.cs index 02101a887..01cd11425 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataStreamContentSegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataStreamContentSegment.cs @@ -16,7 +16,7 @@ namespace Microsoft.OpenApi.OData.Edm public class ODataStreamContentSegment : ODataSegment { /// - public override IEdmEntityType EntityType => null; + public override IEdmEntityType? EntityType => null; /// public override ODataSegmentKind Kind => ODataSegmentKind.StreamContent; diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataStreamPropertySegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataStreamPropertySegment.cs index 06d52c365..0ee79bb6b 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataStreamPropertySegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataStreamPropertySegment.cs @@ -26,7 +26,7 @@ public ODataStreamPropertySegment(string streamPropertyName) } /// - public override IEdmEntityType EntityType => null; + public override IEdmEntityType? EntityType => null; /// public override ODataSegmentKind Kind => ODataSegmentKind.StreamProperty; diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSecurityRequirementGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSecurityRequirementGenerator.cs index 3aa231f98..5a6c39257 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSecurityRequirementGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSecurityRequirementGenerator.cs @@ -8,7 +8,6 @@ using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; -using Microsoft.OpenApi.OData.Vocabulary.Authorization; using Microsoft.OpenApi.OData.Vocabulary.Capabilities; using Microsoft.OpenApi.Models.References; @@ -36,12 +35,16 @@ public static IEnumerable CreateSecurityRequirements { foreach (PermissionType permission in permissions) { + if (string.IsNullOrEmpty(permission.SchemeName)) + { + continue; + } yield return new OpenApiSecurityRequirement { [ new OpenApiSecuritySchemeReference(permission.SchemeName, document) - ] = new List(permission.Scopes?.Select(c => c.Scope) ?? new List()) - }; + ] = [.. permission.Scopes?.Select(c => c.Scope).OfType() ?? []] + }; } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSecuritySchemeGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSecuritySchemeGenerator.cs index 0bcdfd517..5c3469351 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSecuritySchemeGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSecuritySchemeGenerator.cs @@ -130,8 +130,8 @@ private static void AppendOAuth2(OpenApiSecurityScheme scheme, OAuthAuthorizatio scheme.Flows.AuthorizationCode = flow; break; - case OAuth2Type.Password: // Password - OAuth2Password password = (OAuth2Password)oAuth2; + case OAuth2Type.Password when oAuth2 is OAuth2Password { TokenUrl: not null} password: + // Password flow = new OpenApiOAuthFlow { TokenUrl = new Uri(password.TokenUrl) diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiTagGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiTagGenerator.cs index c96d76952..192d2fc18 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiTagGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiTagGenerator.cs @@ -66,7 +66,7 @@ public static ISet CreateTags(this ODataContext context) // The tags array can contain additional Tag Objects for other logical groups, // e.g. for action imports or function imports that are not associated with an entity set. case EdmContainerElementKind.ActionImport: // Action Import - OpenApiTag actionImportTag = context.CreateOperationImportTag((IEdmActionImport)element); + var actionImportTag = context.CreateOperationImportTag((IEdmActionImport)element); if (actionImportTag != null) { tags.Add(actionImportTag); @@ -74,7 +74,7 @@ public static ISet CreateTags(this ODataContext context) break; case EdmContainerElementKind.FunctionImport: // Function Import - OpenApiTag functionImportTag = context.CreateOperationImportTag((IEdmFunctionImport)element); + var functionImportTag = context.CreateOperationImportTag((IEdmFunctionImport)element); if (functionImportTag != null) { tags.Add(functionImportTag); @@ -87,7 +87,7 @@ public static ISet CreateTags(this ODataContext context) return tags; } - private static OpenApiTag CreateOperationImportTag(this ODataContext context, IEdmOperationImport operationImport) + private static OpenApiTag? CreateOperationImportTag(this ODataContext context, IEdmOperationImport operationImport) { Debug.Assert(context != null); diff --git a/src/Microsoft.OpenApi.OData.Reader/OData/IEdmExpressionExtensions.cs b/src/Microsoft.OpenApi.OData.Reader/OData/IEdmExpressionExtensions.cs index 679a0bdfb..64b6878ab 100644 --- a/src/Microsoft.OpenApi.OData.Reader/OData/IEdmExpressionExtensions.cs +++ b/src/Microsoft.OpenApi.OData.Reader/OData/IEdmExpressionExtensions.cs @@ -21,7 +21,7 @@ internal static class IEdmExpressionExtensions /// /// The . /// The null or . - public static ODataValue Convert(this IEdmExpression expression) + public static ODataValue? Convert(this IEdmExpression expression) { if (expression == null) { @@ -112,7 +112,7 @@ public static ODataValue Convert(this IEdmExpression expression) return new ODataResourceValue { TypeReference = recordExpression.DeclaredType, - Properties = recordExpression.Properties.ToDictionary(p => p.Name, p => p.Value.Convert()) + Properties = recordExpression.Properties.Select(p => (p.Name, p.Value.Convert())).Where(p => p.Item2 is not null).ToDictionary(p => p.Item1, p => p.Item2!) }; case EdmExpressionKind.Collection: @@ -122,7 +122,7 @@ public static ODataValue Convert(this IEdmExpression expression) TypeReference = collectionExpression.DeclaredType }; - collectionValue.Elements = collectionExpression.Elements.Select(e => e.Convert()).ToList(); + collectionValue.Elements = collectionExpression.Elements.Select(e => e.Convert()).OfType().ToList(); return collectionValue; case EdmExpressionKind.Path: diff --git a/src/Microsoft.OpenApi.OData.Reader/OData/ODataCollectValue.cs b/src/Microsoft.OpenApi.OData.Reader/OData/ODataCollectValue.cs index a0c27e8d9..c78378286 100644 --- a/src/Microsoft.OpenApi.OData.Reader/OData/ODataCollectValue.cs +++ b/src/Microsoft.OpenApi.OData.Reader/OData/ODataCollectValue.cs @@ -12,6 +12,6 @@ namespace Microsoft.OpenApi.OData /// internal class ODataCollectValue : ODataValue { - public IList Elements { get; set; } + public IList? Elements { get; set; } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/OData/ODataPrimitiveValue.cs b/src/Microsoft.OpenApi.OData.Reader/OData/ODataPrimitiveValue.cs index 4bab519d5..24a616723 100644 --- a/src/Microsoft.OpenApi.OData.Reader/OData/ODataPrimitiveValue.cs +++ b/src/Microsoft.OpenApi.OData.Reader/OData/ODataPrimitiveValue.cs @@ -20,7 +20,7 @@ public ODataPrimitiveValue(object value) /// public object Value { get; private set; } - public override string ToString() + public override string? ToString() { return Value.ToString(); } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/MediaEntityPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/MediaEntityPathItemHandler.cs index 257dd3fe5..7498243f3 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/MediaEntityPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/MediaEntityPathItemHandler.cs @@ -40,10 +40,10 @@ public MediaEntityPathItemHandler(OpenApiDocument document) : base(document) /// protected override void SetOperations(OpenApiPathItem item) { - var readRestrictions = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + var readRestrictions = string.IsNullOrEmpty(TargetPath) ? null :Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); var navSourceReadRestrictions = EntitySet != null - ? Context.Model.GetRecord(EntitySet) - : (Singleton is null ? null : Context.Model.GetRecord(Singleton)); + ? Context?.Model.GetRecord(EntitySet) + : (Singleton is null ? null : Context?.Model.GetRecord(Singleton)); readRestrictions ??= navSourceReadRestrictions; if (readRestrictions == null || (readRestrictions.ReadByKeyRestrictions == null && readRestrictions.IsReadable) || @@ -52,20 +52,20 @@ protected override void SetOperations(OpenApiPathItem item) AddOperation(item, HttpMethod.Get); } - var updateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); + var updateRestrictions = string.IsNullOrEmpty(TargetPath) ? null :Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); var navSourceUpdateRestrictions = EntitySet != null - ? Context.Model.GetRecord(EntitySet) - : (Singleton is null ? null : Context.Model.GetRecord(Singleton)); + ? Context?.Model.GetRecord(EntitySet) + : (Singleton is null ? null : Context?.Model.GetRecord(Singleton)); updateRestrictions ??= navSourceUpdateRestrictions; if (updateRestrictions?.IsUpdatable ?? true) { AddOperation(item, HttpMethod.Put); } - var deleteRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); + var deleteRestrictions = string.IsNullOrEmpty(TargetPath) ? null :Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); var navSourceDeleteRestrictions = EntitySet != null - ? Context.Model.GetRecord(EntitySet) - : (Singleton is null ? null : Context.Model.GetRecord(Singleton)); + ? Context?.Model.GetRecord(EntitySet) + : (Singleton is null ? null : Context?.Model.GetRecord(Singleton)); deleteRestrictions ??= navSourceDeleteRestrictions; if (deleteRestrictions?.IsDeletable ?? true) { diff --git a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt index cbe5fd744..3ec8dd4b4 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt +++ b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt @@ -272,17 +272,17 @@ override Microsoft.OpenApi.OData.Edm.ODataOperationSegment.GetPathItemName(Micro override Microsoft.OpenApi.OData.Edm.ODataOperationSegment.Identifier.get -> string? override Microsoft.OpenApi.OData.Edm.ODataOperationSegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind override Microsoft.OpenApi.OData.Edm.ODataPath.ToString() -> string! -override Microsoft.OpenApi.OData.Edm.ODataRefSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType! +override Microsoft.OpenApi.OData.Edm.ODataRefSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType? override Microsoft.OpenApi.OData.Edm.ODataRefSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! override Microsoft.OpenApi.OData.Edm.ODataRefSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! override Microsoft.OpenApi.OData.Edm.ODataRefSegment.Identifier.get -> string! override Microsoft.OpenApi.OData.Edm.ODataRefSegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataStreamContentSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType! +override Microsoft.OpenApi.OData.Edm.ODataStreamContentSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType? override Microsoft.OpenApi.OData.Edm.ODataStreamContentSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! override Microsoft.OpenApi.OData.Edm.ODataStreamContentSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! override Microsoft.OpenApi.OData.Edm.ODataStreamContentSegment.Identifier.get -> string! override Microsoft.OpenApi.OData.Edm.ODataStreamContentSegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType! +override Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType? override Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! override Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! override Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.Identifier.get -> string! @@ -294,9 +294,9 @@ override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.Identifier.get -> stri override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind static Microsoft.OpenApi.OData.Common.Utils.GetTermQualifiedName() -> string? static Microsoft.OpenApi.OData.Common.Utils.GetUniqueName(string! input, System.Collections.Generic.HashSet! set) -> string! -static Microsoft.OpenApi.OData.Common.Utils.UpperFirstChar(string! input) -> string? -static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.FindAllBaseTypes(this Microsoft.OData.Edm.IEdmComplexType! complexType) -> System.Collections.Generic.IEnumerable? -static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.FindAllBaseTypes(this Microsoft.OData.Edm.IEdmEntityType! entityType) -> System.Collections.Generic.IEnumerable? +static Microsoft.OpenApi.OData.Common.Utils.UpperFirstChar(string? input) -> string? +static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.FindAllBaseTypes(this Microsoft.OData.Edm.IEdmComplexType! complexType) -> System.Collections.Generic.IEnumerable! +static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.FindAllBaseTypes(this Microsoft.OData.Edm.IEdmEntityType! entityType) -> System.Collections.Generic.IEnumerable! static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.GetAllElements(this Microsoft.OData.Edm.IEdmModel! model) -> System.Collections.Generic.IEnumerable! static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.IsOperationImportOverload(this Microsoft.OData.Edm.IEdmModel! model, Microsoft.OData.Edm.IEdmOperationImport! operationImport) -> bool static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.IsOperationOverload(this Microsoft.OData.Edm.IEdmModel! model, Microsoft.OData.Edm.IEdmOperation! operation) -> bool From b15301d9e5280162cd6b67b32ca45130c31b0dd5 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 27 Mar 2025 15:18:20 -0400 Subject: [PATCH 21/24] chore: additional NRT fixes Signed-off-by: Vincent Biret --- .../Edm/ODataDollarCountSegment.cs | 4 +- .../Edm/ODataKeySegment.cs | 2 +- .../Edm/ODataMetadataSegment.cs | 2 +- .../Edm/ODataNavigationSourceSegment.cs | 4 +- .../Edm/ODataPathProvider.cs | 46 +++++++++++-------- .../Generator/OpenApiComponentsGenerator.cs | 9 ++-- .../Generator/OpenApiExampleGenerator.cs | 2 +- .../Generator/OpenApiPathItemGenerator.cs | 2 +- .../Generator/OpenApiResponseGenerator.cs | 4 +- .../EdmFunctionImportOperationHandler.cs | 2 +- ...avigationPropertyDeleteOperationHandler.cs | 2 +- ...avigationPropertyUpdateOperationHandler.cs | 2 +- .../Operation/OperationHandler.cs | 2 +- .../PathItem/IPathItemHandlerProvider.cs | 2 +- .../PathItem/PathItemHandlerProvider.cs | 2 +- .../PublicAPI.Unshipped.txt | 4 +- 16 files changed, 51 insertions(+), 40 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataDollarCountSegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataDollarCountSegment.cs index ac0a04d27..841df8cd3 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataDollarCountSegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataDollarCountSegment.cs @@ -17,10 +17,10 @@ public class ODataDollarCountSegment : ODataSegment /// /// Get the static instance of $count segment. /// - internal static ODataDollarCountSegment Instance = new(); + internal static readonly ODataDollarCountSegment Instance = new(); /// - public override IEdmEntityType EntityType => null; + public override IEdmEntityType? EntityType => null; /// public override ODataSegmentKind Kind => ODataSegmentKind.DollarCount; diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataKeySegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataKeySegment.cs index ebef313d0..748b5b811 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataKeySegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataKeySegment.cs @@ -59,7 +59,7 @@ public override string Identifier get { IList keys = IsAlternateKey ? - KeyMappings.Values.ToList() : + KeyMappings?.Values.ToList() ?? [] : EntityType.Key().Select(static x => x.Name).ToList(); return string.Join(",", keys); diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataMetadataSegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataMetadataSegment.cs index 859c30dec..ab28b7668 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataMetadataSegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataMetadataSegment.cs @@ -16,7 +16,7 @@ namespace Microsoft.OpenApi.OData.Edm public class ODataMetadataSegment : ODataSegment { /// - public override IEdmEntityType EntityType => null; + public override IEdmEntityType? EntityType => null; /// public override ODataSegmentKind Kind => ODataSegmentKind.Metadata; diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataNavigationSourceSegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataNavigationSourceSegment.cs index 8981af686..a4143d504 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataNavigationSourceSegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataNavigationSourceSegment.cs @@ -42,7 +42,9 @@ public ODataNavigationSourceSegment(IEdmNavigationSource navigationSource) /// public override IEnumerable GetAnnotables() { - return new IEdmVocabularyAnnotatable[] { NavigationSource as IEdmVocabularyAnnotatable, EntityType }.Union(EntityType.FindAllBaseTypes()); + return (NavigationSource is IEdmVocabularyAnnotatable source ? new IEdmVocabularyAnnotatable[]{source} : []) + .Union([EntityType]) + .Union(EntityType.FindAllBaseTypes()); } /// diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs index a4fe2031f..e09511fe4 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs @@ -57,34 +57,40 @@ public virtual IEnumerable GetPaths(IEdmModel model, OpenApiConvertSe Initialize(model); - // entity set - foreach (IEdmEntitySet entitySet in _model.EntityContainer.EntitySets()) + if (_model is not null) { - if (CanFilter(entitySet)) - { - RetrieveNavigationSourcePaths(entitySet, settings); - } - } + // entity set + foreach (var entitySet in _model.EntityContainer.EntitySets()) + { + if (CanFilter(entitySet)) + { + RetrieveNavigationSourcePaths(entitySet, settings); + } + } - // singleton - foreach (IEdmSingleton singleton in _model.EntityContainer.Singletons()) - { - if (CanFilter(singleton)) - { - RetrieveNavigationSourcePaths(singleton, settings); - } + // singleton + foreach (var singleton in _model.EntityContainer.Singletons()) + { + if (CanFilter(singleton)) + { + RetrieveNavigationSourcePaths(singleton, settings); + } + } } // bound operations RetrieveBoundOperationPaths(settings); - // unbound operations - foreach (IEdmOperationImport import in _model.EntityContainer.OperationImports()) + if (_model is not null) { - if (CanFilter(import)) - { - AppendPath(new ODataPath(new ODataOperationImportSegment(import))); - } + // unbound operations + foreach (IEdmOperationImport import in _model.EntityContainer.OperationImports()) + { + if (CanFilter(import)) + { + AppendPath(new ODataPath(new ODataOperationImportSegment(import))); + } + } } return MergePaths(); diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiComponentsGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiComponentsGenerator.cs index 64fe4417a..5d5ff3997 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiComponentsGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiComponentsGenerator.cs @@ -32,9 +32,12 @@ public static void AddComponentsToDocument(this ODataContext context, OpenApiDoc context.AddRequestBodiesToDocument(document); context.AddExamplesToDocument(document); context.AddSecuritySchemesToDocument(document); - document.Components.Links = null; - document.Components.Callbacks = null; - document.Components.Extensions = null; + if (document.Components is not null) + { + document.Components.Links = null; + document.Components.Callbacks = null; + document.Components.Extensions = null; + } } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiExampleGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiExampleGenerator.cs index fc315fdcb..1315f99e3 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiExampleGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiExampleGenerator.cs @@ -47,7 +47,7 @@ public static void AddExamplesToDocument(this ODataContext context, OpenApiDocum } } - private static OpenApiExample CreateExample(this ODataContext context, IEdmType edmType, OpenApiDocument document) + private static OpenApiExample? CreateExample(this ODataContext context, IEdmType edmType, OpenApiDocument document) { Debug.Assert(context != null); Debug.Assert(edmType != null); diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiPathItemGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiPathItemGenerator.cs index 4be929c70..69f824475 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiPathItemGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiPathItemGenerator.cs @@ -39,7 +39,7 @@ public static void AddPathItemsToDocument(this ODataContext context, OpenApiDocu settings.EnableKeyAsSegment = context.KeyAsSegment; foreach (ODataPath path in context.AllPaths) { - IPathItemHandler handler = context.PathItemHandlerProvider.GetHandler(path.Kind, document); + var handler = context.PathItemHandlerProvider.GetHandler(path.Kind, document); if (handler == null) { continue; diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs index 81abc660e..25ec6f75c 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs @@ -121,9 +121,9 @@ public static OpenApiResponses CreateResponses(this ODataContext context, IEdmOp OpenApiResponses responses = new(); - if (operation.IsAction() && operation.ReturnType == null) + if (operation.IsAction() && operation.ReturnType == null && Constants.StatusCode204.GetResponse(document) is {} x204Response) { - responses.Add(Constants.StatusCode204, Constants.StatusCode204.GetResponse(document)); + responses.Add(Constants.StatusCode204, x204Response); } else if (context.Model.OperationTargetsMultiplePaths(operation)) { diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionImportOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionImportOperationHandler.cs index a49b34ca2..5c6e6c6a0 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionImportOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionImportOperationHandler.cs @@ -40,7 +40,7 @@ protected override void SetParameters(OpenApiOperation operation) return; } - if (OperationImportSegment.ParameterMappings != null && + if (OperationImportSegment?.ParameterMappings != null && Context?.CreateParameters(functionImport.Function, _document, OperationImportSegment.ParameterMappings) is {} functionParamMappings) { operation.Parameters ??= []; diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyDeleteOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyDeleteOperationHandler.cs index 3fa154048..51f2cb085 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyDeleteOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyDeleteOperationHandler.cs @@ -79,7 +79,7 @@ protected override void SetParameters(OpenApiOperation operation) /// protected override void SetSecurity(OpenApiOperation operation) { - if (_deleteRestriction == null) + if (_deleteRestriction?.Permissions == null) { return; } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyUpdateOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyUpdateOperationHandler.cs index 98b7479d6..566196258 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyUpdateOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyUpdateOperationHandler.cs @@ -84,7 +84,7 @@ protected override void SetResponses(OpenApiOperation operation) protected override void SetSecurity(OpenApiOperation operation) { - if (_updateRestriction == null) + if (_updateRestriction?.Permissions == null) { return; } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandler.cs index ea345dbe0..f09ff552b 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandler.cs @@ -283,7 +283,7 @@ protected static void AppendCustomParameters(OpenApiOperation operation, IListThe path kind. /// The Open API document to use to lookup references. /// The . - IPathItemHandler GetHandler(ODataPathKind pathKind, OpenApiDocument document); + IPathItemHandler? GetHandler(ODataPathKind pathKind, OpenApiDocument document); } } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/PathItemHandlerProvider.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/PathItemHandlerProvider.cs index 90c82c47a..51fdd24fc 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/PathItemHandlerProvider.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/PathItemHandlerProvider.cs @@ -14,7 +14,7 @@ namespace Microsoft.OpenApi.OData.PathItem internal class PathItemHandlerProvider : IPathItemHandlerProvider { /// - public IPathItemHandler GetHandler(ODataPathKind pathKind, OpenApiDocument document) + public IPathItemHandler? GetHandler(ODataPathKind pathKind, OpenApiDocument document) { return pathKind switch { // EntitySet diff --git a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt index 3ec8dd4b4..283e9f540 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt +++ b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt @@ -236,7 +236,7 @@ override Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.GetAnnotables() override Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! override Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.Identifier.get -> string! override Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType! +override Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType? override Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! override Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! override Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment.Identifier.get -> string! @@ -246,7 +246,7 @@ override Microsoft.OpenApi.OData.Edm.ODataKeySegment.GetAnnotables() -> System.C override Microsoft.OpenApi.OData.Edm.ODataKeySegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! override Microsoft.OpenApi.OData.Edm.ODataKeySegment.Identifier.get -> string! override Microsoft.OpenApi.OData.Edm.ODataKeySegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataMetadataSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType! +override Microsoft.OpenApi.OData.Edm.ODataMetadataSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType? override Microsoft.OpenApi.OData.Edm.ODataMetadataSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! override Microsoft.OpenApi.OData.Edm.ODataMetadataSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! override Microsoft.OpenApi.OData.Edm.ODataMetadataSegment.Identifier.get -> string! From 269c0d5a5aa7f46e57e1006c85e0ec6307bba5d2 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 27 Mar 2025 15:30:02 -0400 Subject: [PATCH 22/24] chore: additional NRT fixes --- .../Operation/EntitySetPostOperationHandler.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetPostOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetPostOperationHandler.cs index cb81cacee..235b8fd2e 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetPostOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetPostOperationHandler.cs @@ -136,10 +136,10 @@ protected override void AppendCustomParameters(OpenApiOperation operation) /// Get the entity content description. /// /// The entity content description. - private IDictionary GetContentDescription() + private IDictionary GetContentDescription() { var schema = GetEntitySchema(); - var content = new Dictionary(); + var content = new Dictionary(); if (EntitySet is {EntityType.HasStream: true}) { @@ -148,7 +148,7 @@ protected override void AppendCustomParameters(OpenApiOperation operation) { foreach (string item in mediaTypes) { - content.Add(item, null); + content.Add(item, new()); } } else From 618e727df1b4bafb51ff8e7a1c4d3ef82e777bf5 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 1 Apr 2025 14:39:50 -0400 Subject: [PATCH 23/24] chore: changes extensions to return null value when assembly info is disabled Signed-off-by: Vincent Biret --- .../Generator/OpenApiInfoGenerator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiInfoGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiInfoGenerator.cs index c6d4a7162..195893ef8 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiInfoGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiInfoGenerator.cs @@ -100,7 +100,7 @@ private static string GetDescription(this ODataContext context) return "This OData service is located at " + context.Settings.ServiceRoot.OriginalString; } - private static Dictionary GetExtensions(this ODataContext context) + private static Dictionary? GetExtensions(this ODataContext context) { Debug.Assert(context != null); @@ -118,7 +118,7 @@ private static Dictionary GetExtensions(this ODataCon } }; } - return []; + return null; } } } From fa5c1d333360276772c753da11fe900f29bdabc0 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 1 Apr 2025 14:48:26 -0400 Subject: [PATCH 24/24] chore: typo fix Signed-off-by: Vincent Biret --- src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs index 1c30e36b5..c2d5c79d9 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs @@ -1055,16 +1055,16 @@ private void AppendBoundOperationOnDerived( { foreach (var ns in baseNavigationSource) { - if (ns is not IEdmVocabularyAnnotatable nsAnnotable || + if (ns is not IEdmVocabularyAnnotatable nsAnnotatable || HasUnsatisfiedDerivedTypeConstraint( - nsAnnotable, + nsAnnotatable, baseType, convertSettings)) { continue; } - if (_model is null || !EdmModelHelper.IsOperationAllowed(_model, edmOperation, nsAnnotable)) + if (_model is null || !EdmModelHelper.IsOperationAllowed(_model, edmOperation, nsAnnotatable)) { continue; }