From f1ff80b0bb11edb4957688b4ee499fe64a3a8464 Mon Sep 17 00:00:00 2001 From: Irvine Sunday Date: Wed, 17 Jul 2024 16:46:59 +0300 Subject: [PATCH 1/5] Generate nav. props of composable functions based on depth setting --- .../Edm/ODataPathProvider.cs | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs index 3bde8489..6ab9a195 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs @@ -890,9 +890,24 @@ private void RetrieveBoundOperationPaths(OpenApiConvertSettings convertSettings) foreach (var navProperty in returnBindingEntityType.NavigationProperties()) { - ODataPath newNavigationPath = functionPath.Clone(); - newNavigationPath.Push(new ODataNavigationPropertySegment(navProperty)); - AppendPath(newNavigationPath); + if (convertSettings.ComposableFunctionsExpansionDepth > 0) + { // Generate nav. props of composable functions + ODataSegment secondLastSeg = functionPath.ElementAt(functionPath.Count - 2); + + if (convertSettings.ComposableFunctionsExpansionDepth < 2 && + functionPath.LastSegment is ODataOperationSegment && + secondLastSeg is ODataOperationSegment) + { + // Only one level of composable functions expansion allowed + continue; + } + else + { + ODataPath newNavigationPath = functionPath.Clone(); + newNavigationPath.Push(new ODataNavigationPropertySegment(navProperty)); + AppendPath(newNavigationPath); + } + } } } } @@ -1171,6 +1186,12 @@ private void AppendBoundOperationOnOperationPath(IEdmOperation edmOperation, boo continue; } + var segName = path.LastSegment as ODataOperationSegment; + if (edmOperation.Name.Equals(segName?.Identifier)) + { + continue; + } + ODataPath newOperationPath = path.Clone(); newOperationPath.Push(new ODataOperationSegment(edmOperation, isEscapedFunction, _model)); AppendPath(newOperationPath); From a47a90d1bf8e582779910c926435ce7f1bd7f17c Mon Sep 17 00:00:00 2001 From: Irvine Sunday Date: Wed, 17 Jul 2024 16:47:57 +0300 Subject: [PATCH 2/5] Add config setting for controlling depth of composable fxns expansion --- .../OpenApiConvertSettings.cs | 8 +++++++- .../PublicAPI.Unshipped.txt | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs b/src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs index 1e14f1f2..a6c538c8 100644 --- a/src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs +++ b/src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs @@ -362,6 +362,11 @@ public bool ExpandDerivedTypesNavigationProperties /// public bool UseStringArrayForQueryOptionsSchema { get; set; } = true; + /// + /// Gets/Sets a value indicating the depth to expand composable functions. + /// + public int ComposableFunctionsExpansionDepth { get; set; } = 1; + internal OpenApiConvertSettings Clone() { var newSettings = new OpenApiConvertSettings @@ -416,7 +421,8 @@ internal OpenApiConvertSettings Clone() EnableAliasForTypeCastSegments = this.EnableAliasForTypeCastSegments, SemVerVersion = this.SemVerVersion, EnableAliasForOperationSegments = this.EnableAliasForOperationSegments, - UseStringArrayForQueryOptionsSchema = this.UseStringArrayForQueryOptionsSchema + UseStringArrayForQueryOptionsSchema = this.UseStringArrayForQueryOptionsSchema, + ComposableFunctionsExpansionDepth = this.ComposableFunctionsExpansionDepth }; return newSettings; diff --git a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt index 0b13d3ba..f94e5952 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt +++ b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt @@ -21,6 +21,8 @@ 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 From bc16655bfe5915effeaac4a3a112597381f5bc8c Mon Sep 17 00:00:00 2001 From: Irvine Sunday Date: Wed, 17 Jul 2024 16:48:46 +0300 Subject: [PATCH 3/5] Update tests --- .../Edm/ODataPathProviderTests.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Edm/ODataPathProviderTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Edm/ODataPathProviderTests.cs index 2c01862f..a450bc04 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Edm/ODataPathProviderTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Edm/ODataPathProviderTests.cs @@ -52,7 +52,7 @@ public void GetPathsForGraphBetaModelReturnsAllPaths() // Assert Assert.NotNull(paths); - Assert.Equal(16980, paths.Count()); + Assert.Equal(15210, paths.Count()); AssertGraphBetaModelPaths(paths); } @@ -117,7 +117,7 @@ public void GetPathsForGraphBetaModelWithDerivedTypesConstraintReturnsAllPaths() // Assert Assert.NotNull(paths); - Assert.Equal(17631, paths.Count()); + Assert.Equal(15861, paths.Count()); } [Theory] @@ -208,9 +208,9 @@ public void GetPathsForComposableFunctionsReturnsAllPaths() // Assert Assert.NotNull(paths); - Assert.Equal(38, paths.Count()); - Assert.Equal(20, paths.Where(p => p.LastSegment is ODataOperationSegment).Count()); - Assert.Equal(12, paths.Where(p => p.Segments.Count > 1 && p.LastSegment is ODataNavigationPropertySegment && p.Segments[p.Segments.Count - 2] is ODataOperationSegment).Count()); + Assert.Equal(26, paths.Count()); + Assert.Equal(17, paths.Where(p => p.LastSegment is ODataOperationSegment).Count()); + Assert.Equal(3, paths.Where(p => p.Segments.Count > 1 && p.LastSegment is ODataNavigationPropertySegment && p.Segments[p.Segments.Count - 2] is ODataOperationSegment).Count()); } [Fact] From 64d109cf36c1718045a1bd2a783e1c1cfb31493b Mon Sep 17 00:00:00 2001 From: Irvine Sunday Date: Wed, 17 Jul 2024 16:49:02 +0300 Subject: [PATCH 4/5] Update release note --- .../Microsoft.OpenAPI.OData.Reader.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 cb79ac6c..bb5af0b3 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj +++ b/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj @@ -15,13 +15,13 @@ netstandard2.0 Microsoft.OpenApi.OData true - 1.6.7 + 1.6.8 This package contains the codes you need to convert OData CSDL to Open API Document of Model. © Microsoft Corporation. All rights reserved. Microsoft OpenApi OData EDM https://github.com/Microsoft/OpenAPI.NET.OData - - Fixes empty response objects for OData type cast paths. #546 + - Adds support for configuring composable functions generations #551 Microsoft.OpenApi.OData.Reader ..\..\tool\Microsoft.OpenApi.OData.snk From aafa95577ab8e55bb4cb9d3fae42905712bcdd1d Mon Sep 17 00:00:00 2001 From: Irvine Sunday Date: Mon, 22 Jul 2024 14:33:41 +0300 Subject: [PATCH 5/5] PR review suggestion --- .../Edm/ODataPathProvider.cs | 40 +++++++++++-------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs index 6ab9a195..0c5a17fb 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs @@ -888,25 +888,31 @@ private void RetrieveBoundOperationPaths(OpenApiConvertSettings convertSettings) continue; } - foreach (var navProperty in returnBindingEntityType.NavigationProperties()) - { - if (convertSettings.ComposableFunctionsExpansionDepth > 0) - { // Generate nav. props of composable functions - ODataSegment secondLastSeg = functionPath.ElementAt(functionPath.Count - 2); - - if (convertSettings.ComposableFunctionsExpansionDepth < 2 && + ODataSegment secondLastSeg = functionPath.ElementAt(functionPath.Count - 2); + if (convertSettings.ComposableFunctionsExpansionDepth < 2 && functionPath.LastSegment is ODataOperationSegment && secondLastSeg is ODataOperationSegment) - { - // Only one level of composable functions expansion allowed - continue; - } - else - { - ODataPath newNavigationPath = functionPath.Clone(); - newNavigationPath.Push(new ODataNavigationPropertySegment(navProperty)); - AppendPath(newNavigationPath); - } + { + // Only one level of composable functions expansion allowed + continue; + } + + foreach (var navProperty in returnBindingEntityType.NavigationProperties()) + { + /* 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 currentDepth = functionPath.Count - composableFuncSegIndex - 1; + + if (currentDepth < convertSettings.ComposableFunctionsExpansionDepth) + { + ODataPath newNavigationPath = functionPath.Clone(); + newNavigationPath.Push(new ODataNavigationPropertySegment(navProperty)); + AppendPath(newNavigationPath); } } }