Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion src/Microsoft.OpenApi.OData.Reader/Common/EdmModelHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -163,11 +163,13 @@ internal static IList<string> RetrieveNavigationPropertyPathsOperationIdSegments

// For navigation property paths with odata type cast segments
// the OData type cast segments identifiers will be used in the operation id
// The same applies for navigation property paths with operation segments.
IEnumerable<ODataSegment> segments = path.Segments.Skip(1)
.Where(static s =>
s is ODataNavigationPropertySegment ||
s is ODataTypeCastSegment ||
s is ODataOperationSegment);
s is ODataOperationSegment ||
s is ODataKeySegment);
Utils.CheckArgumentNull(segments, nameof(segments));

string previousTypeCastSegmentId = null;
Expand All @@ -190,6 +192,18 @@ s is ODataTypeCastSegment ||
// Navigation property generated via composable function
items.Add(operationSegment.Identifier);
}
else if (segment is ODataKeySegment keySegment && keySegment.IsAlternateKey)
{
// We'll consider alternate keys in the operation id to eliminate potential duplicates with operation id of primary path
if (segment == segments.Last())
{
items.Add("By" + string.Join("", keySegment.Identifier.Split(',').Select(static x => Utils.UpperFirstChar(x))));
}
else
{
items.Add(keySegment.Identifier);
}
}
}

return items;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<PackageId>Microsoft.OpenApi.OData</PackageId>
<SignAssembly>true</SignAssembly>
<Version>1.6.0-preview.6</Version>
<Version>1.6.0-preview.7</Version>
<Description>This package contains the codes you need to convert OData CSDL to Open API Document of Model.</Description>
<Copyright>© Microsoft Corporation. All rights reserved.</Copyright>
<PackageTags>Microsoft OpenApi OData EDM</PackageTags>
Expand All @@ -28,6 +28,7 @@
- Generates $expand query parameter for operations whose return type is a collection #481
- Adds delete operation for non-contained navigation properties only if explicitly allowed via annotation #483
- Appends parameters and fixes operation ids of navigation property paths generated via composable functions #486
- Use alternate keys in the generation of operation ids of operations and navigation property alternate paths #488
</PackageReleaseNotes>
<AssemblyName>Microsoft.OpenApi.OData.Reader</AssemblyName>
<AssemblyOriginatorKeyFile>..\..\tool\Microsoft.OpenApi.OData.snk</AssemblyOriginatorKeyFile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,30 @@ protected override void SetBasicInfo(OpenApiOperation operation)
// in the operationId to avoid potential
// duplicates in entity vs entityset functions/actions

List<string> identifiers = new();
List<string> identifiers = [];
foreach (ODataSegment segment in Path.Segments)
{
if (segment is not ODataKeySegment)
if (segment is ODataKeySegment keySegment)
{
identifiers.Add(segment.Identifier);
if (!keySegment.IsAlternateKey)
{
identifiers.Add(segment.EntityType.Name);
continue;
}

// We'll consider alternate keys in the operation id to eliminate potential duplicates with operation id of primary path
if (segment == Path.Segments.Last())
{
identifiers.Add("By" + string.Join("", keySegment.Identifier.Split(',').Select(static x => Utils.UpperFirstChar(x))));
}
else
{
identifiers.Add(keySegment.Identifier);
}
}
else
{
identifiers.Add(segment.EntityType.Name);
identifiers.Add(segment.Identifier);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public void GetPathsForGraphBetaModelReturnsAllPaths()

// Assert
Assert.NotNull(paths);
Assert.Equal(16976, paths.Count());
Assert.Equal(16980, paths.Count());
AssertGraphBetaModelPaths(paths);
}

Expand Down Expand Up @@ -117,7 +117,7 @@ public void GetPathsForGraphBetaModelWithDerivedTypesConstraintReturnsAllPaths()

// Assert
Assert.NotNull(paths);
Assert.Equal(17627, paths.Count());
Assert.Equal(17631, paths.Count());
}

[Theory]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------

using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Microsoft.OData.Edm;
Expand Down Expand Up @@ -479,5 +480,37 @@ public void CreateOperationForFunctionWithDateTimeParametersReturnsCorrectPathIt
Assert.Equal("Usage: periodEnd={periodEnd}", operation.Parameters.First(x => x.Name == "periodEnd").Description);

}

[Fact]
public void CreateFunctionOperationWithAlternateKeyReturnsCorrectOperationId()
{
// Arrange
IEdmModel model = EdmModelHelper.GraphBetaModel;
ODataContext context = new(model, new OpenApiConvertSettings()
{
EnableOperationId = true
});

IEdmSingleton singleton = model.EntityContainer.FindSingleton("communications");
IEdmEntityType entityType = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "cloudCommunications");
IEdmNavigationProperty navProp = entityType.DeclaredNavigationProperties().First(c => c.Name == "onlineMeetings");
IEdmOperation action = model.SchemaElements.OfType<IEdmOperation>().First(f => f.Name == "sendVirtualAppointmentReminderSms");
IDictionary<string, string> keyMappings = new Dictionary<string, string> { { "joinWebUrl", "joinWebUrl" } };

ODataPath path = new(new ODataNavigationSourceSegment(singleton),
new ODataNavigationPropertySegment(navProp),
new ODataKeySegment(entityType, keyMappings)
{
IsAlternateKey = true
},
new ODataOperationSegment(action));

// Act
var operation = _operationHandler.CreateOperation(context, path);

// Assert
Assert.NotNull(operation);
Assert.Equal("communications.onlineMeetings.joinWebUrl.sendVirtualAppointmentReminderSms", operation.OperationId);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// ------------------------------------------------------------
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------

using System.Collections.Generic;
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Extensions;
Expand Down Expand Up @@ -242,5 +243,35 @@ public void CreateNavigationGetOperationReturnsSecurityForReadRestrictions(bool
Assert.Empty(operation.Security);
}
}

[Fact]
public void CreateNavigationGetOperationWithAlternateKeyReturnsCorrectOperationId()
{
// Arrange
IEdmModel model = EdmModelHelper.GraphBetaModel;
ODataContext context = new(model, new OpenApiConvertSettings()
{
EnableOperationId = true
});

IEdmSingleton singleton = model.EntityContainer.FindSingleton("communications");
IEdmEntityType entityType = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "cloudCommunications");
IEdmNavigationProperty navProp = entityType.DeclaredNavigationProperties().First(c => c.Name == "onlineMeetings");
IDictionary<string, string> keyMappings = new Dictionary<string, string> { { "joinWebUrl", "joinWebUrl" } };

ODataPath path = new(new ODataNavigationSourceSegment(singleton),
new ODataNavigationPropertySegment(navProp),
new ODataKeySegment(entityType, keyMappings)
{
IsAlternateKey = true
});

// Act
var operation = _operationHandler.CreateOperation(context, path);

// Assert
Assert.NotNull(operation);
Assert.Equal("communications.onlineMeetings.GetByJoinWebUrl", operation.OperationId);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -102459,6 +102459,11 @@
<Parameter Name="bindingParameter" Type="Collection(graph.deletedTeam)" />
<ReturnType Type="Collection(graph.chatMessage)" />
</Function>
<Action Name="sendVirtualAppointmentReminderSms" IsBound="true">
<Parameter Name="bindingParameter" Type="graph.onlineMeeting" />
<Parameter Name="remindBeforeTimeInMinutesType" Type="graph.remindBeforeTimeInMinutesType" />
<Parameter Name="attendees" Type="Collection(graph.attendeeNotificationInfo)" />
</Action>
<Action Name="complete" IsBound="true">
<Parameter Name="bindingParameter" Type="graph.impactedResource" Nullable="false" />
<ReturnType Type="graph.impactedResource" />
Expand Down Expand Up @@ -132565,6 +132570,10 @@
</Annotations>
</Schema>
<Schema Namespace="microsoft.graph.ediscovery" xmlns="http://docs.oasis-open.org/odata/ns/edm">
<EnumType Name="remindBeforeTimeInMinutesType">
<Member Name="mins15" Value="0" />
<Member Name="unknownFutureValue" Value="100" />
</EnumType>
<EnumType Name="additionalDataOptions" IsFlags="true">
<Member Name="allVersions" Value="1" />
<Member Name="linkedFiles" Value="2" />
Expand Down Expand Up @@ -133020,6 +133029,10 @@
</Property>
</EntityType>
<EntityType Name="tagOperation" BaseType="microsoft.graph.ediscovery.caseOperation" />
<ComplexType Name="attendeeNotificationInfo">
<Property Name="phoneNumber" Type="Edm.String" />
<Property Name="timeZone" Type="Edm.String" />
</ComplexType>
<ComplexType Name="ocrSettings">
<Property Name="isEnabled" Type="Edm.Boolean">
<Annotation Term="Org.OData.Core.V1.Description" String="Indicates whether or not OCR is enabled for the case." />
Expand Down