From 7def900b8a0926dca46aecafdd432f94602a929f Mon Sep 17 00:00:00 2001 From: Millicent Achieng Date: Mon, 3 Oct 2022 15:55:59 +0300 Subject: [PATCH 1/2] Add alternate key parameters --- .../Generator/OpenApiParameterGenerator.cs | 44 ++++++++- .../OpenApiParameterGeneratorTests.cs | 89 +++++++++++++++++++ 2 files changed, 131 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiParameterGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiParameterGenerator.cs index 7f8efb7e..337b24c9 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiParameterGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiParameterGenerator.cs @@ -158,9 +158,9 @@ public static IList CreateKeyParameters(this ODataContext cont Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(keySegment, nameof(keySegment)); - IList parameters = new List(); + List parameters = new(); IEdmEntityType entityType = keySegment.EntityType; - + IList keys = entityType.Key().ToList(); if (keys.Count() == 1) { @@ -212,6 +212,46 @@ public static IList CreateKeyParameters(this ODataContext cont } } + IList alternateKeyParameters = CreateAlternateKeyParameters(entityType, context); + parameters.AddRange(alternateKeyParameters); + + return parameters; + } + + private static IList CreateAlternateKeyParameters(IEdmEntityType entityType, ODataContext context) + { + IList parameters = new List(); + IEnumerable> alternateKeys = context.Model.GetAlternateKeysAnnotation(entityType); + foreach (var alternateKey in alternateKeys) + { + if (alternateKey.Count() == 1) + { + parameters.Add( + new OpenApiParameter + { + Name = alternateKey.First().Key, + In = ParameterLocation.Path, + Description = $"Alternate key: {alternateKey.First().Value.Name} of {entityType.Name}", + Schema = context.CreateEdmTypeSchema(alternateKey.First().Value.Type) + } + ); + } + else + { + foreach (var compositekey in alternateKey) + { + parameters.Add( + new OpenApiParameter + { + Name = compositekey.Key, + In = ParameterLocation.Path, + Description = $"Composite alternate key: {compositekey.Value.Name} of {entityType.Name}", + Schema = context.CreateEdmTypeSchema(compositekey.Value.Type) + } + ); + } + } + } return parameters; } diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiParameterGeneratorTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiParameterGeneratorTests.cs index 08b483e7..5c6a39dd 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiParameterGeneratorTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiParameterGeneratorTests.cs @@ -279,6 +279,95 @@ public void CreateKeyParametersForCompositeKeyWorks(bool prefix) Assert.Equal(expected.ChangeLineBreaks(), json); } + [Fact] + public void CreateKeyParametersForAlternateKeyWithSinglePropertyWorks() + { + // Arrange + EdmModel model = new EdmModel(); + EdmEntityType customer = new EdmEntityType("NS", "Customer"); + customer.AddKeys(customer.AddStructuralProperty("Id", EdmPrimitiveTypeKind.String)); + + IEdmProperty alternateId = customer.AddStructuralProperty("AlternateId", EdmPrimitiveTypeKind.String); + model.AddAlternateKeyAnnotation(customer, new Dictionary { { "AltId", alternateId } }); + + model.AddElement(customer); + ODataContext context = new(model); + ODataKeySegment keySegment = new(customer); + + // Act + var parameters = context.CreateKeyParameters(keySegment); + var altParameter = parameters.Last(); + + // Assert + Assert.NotNull(parameters); + Assert.Equal(2, parameters.Count); + string json = altParameter.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); + Assert.Equal(@"{ + ""name"": ""AltId"", + ""in"": ""path"", + ""description"": ""Alternate key: AlternateId of Customer"", + ""style"": ""simple"", + ""schema"": { + ""type"": ""string"", + ""nullable"": true + } +}".ChangeLineBreaks(), json); + } + + [Fact] + public void CreateKeyParametersForAlternateKeyWithMultiplePropertiesWorks() + { + // Arrange + EdmModel model = new EdmModel(); + EdmEntityType customer = new EdmEntityType("NS", "Customer"); + customer.AddKeys(customer.AddStructuralProperty("Id", EdmPrimitiveTypeKind.String)); + + IEdmProperty alternateId1 = customer.AddStructuralProperty("AlternateId1", EdmPrimitiveTypeKind.String); + IEdmProperty alternateId2 = customer.AddStructuralProperty("AlternateId2", EdmPrimitiveTypeKind.String); + model.AddAlternateKeyAnnotation(customer, + new Dictionary + { + { "AltId1", alternateId1 }, + { "AltId2", alternateId2 } + }); + + model.AddElement(customer); + ODataContext context = new(model); + ODataKeySegment keySegment = new(customer); + + // Act + var parameters = context.CreateKeyParameters(keySegment); + var altParameter1 = parameters.Skip(1).First(); + var altParameter2 = parameters.Last(); + + // Assert + Assert.NotNull(parameters); + Assert.Equal(3, parameters.Count); + string json1 = altParameter1.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); + Assert.Equal(@"{ + ""name"": ""AltId1"", + ""in"": ""path"", + ""description"": ""Composite alternate key: AlternateId1 of Customer"", + ""style"": ""simple"", + ""schema"": { + ""type"": ""string"", + ""nullable"": true + } +}".ChangeLineBreaks(), json1); + + string json2 = altParameter2.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); + Assert.Equal(@"{ + ""name"": ""AltId2"", + ""in"": ""path"", + ""description"": ""Composite alternate key: AlternateId2 of Customer"", + ""style"": ""simple"", + ""schema"": { + ""type"": ""string"", + ""nullable"": true + } +}".ChangeLineBreaks(), json2); + } + [Fact] public void CreateOrderByAndSelectAndExpandParametersWorks() { From 79bcaa209d20b126c15564e63f701bc47a4262b7 Mon Sep 17 00:00:00 2001 From: Millicent Achieng Date: Mon, 3 Oct 2022 16:05:13 +0300 Subject: [PATCH 2/2] Add release notes --- .../Microsoft.OpenAPI.OData.Reader.csproj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 a21877a0..549abc06 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj +++ b/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj @@ -15,7 +15,7 @@ netstandard2.0 Microsoft.OpenApi.OData true - 1.2.0-preview2 + 1.2.0-preview3 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 @@ -23,6 +23,7 @@ - Use convert setting to toggle between referencing @odata.count and @odata.nextLink #282 - Fixes URL Path parameters of type datetime generated as strings with quotes #262 +- Add support for alternate keys #120 Microsoft.OpenApi.OData.Reader ..\..\tool\Microsoft.OpenApi.OData.snk