Skip to content

Commit

Permalink
[Feature] Retrieves complex properties of derived types (#438)
Browse files Browse the repository at this point in the history
* Retrieve type cast properties

Complex properties and navigation properties

* Refactor tag generation of complex props tag names

To factor in that a type cast segment could be the previous segment to a complex property

* Add new convert setting and deprecate current one doing similar task

* Rename convert setting

* Null check; update comment

* Update tests

* Update release notes

* Update integration test files

* Bumps up version

* Update number of paths in test
  • Loading branch information
irvinesunday authored Oct 26, 2023
1 parent 2a48a30 commit d2a97e5
Show file tree
Hide file tree
Showing 13 changed files with 10,785 additions and 4,859 deletions.
20 changes: 15 additions & 5 deletions src/Microsoft.OpenApi.OData.Reader/Common/EdmModelHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Csdl;
using Microsoft.OData.Edm.Vocabularies;
Expand Down Expand Up @@ -235,13 +234,24 @@ internal static string GenerateNavigationPropertyPathTagName(ODataPath path, ODa
internal static string GenerateComplexPropertyPathTagName(ODataPath path, ODataContext context)
{
Utils.CheckArgumentNull(path, nameof(path));
Utils.CheckArgumentNull(context, nameof(context));

// Get the segment before the last complex type segment
ODataComplexPropertySegment complexSegment = path.Segments.OfType<ODataComplexPropertySegment>()?.Last();
Utils.CheckArgumentNull(complexSegment, nameof(complexSegment));

// Get the segment before the last complex type segment
int complexSegmentIndex = path.Segments.IndexOf(complexSegment);
ODataSegment preComplexSegment = path.Segments.ElementAt(complexSegmentIndex - 1);
int preComplexSegmentIndex = path.Segments.IndexOf(preComplexSegment);

while (preComplexSegment is ODataTypeCastSegment)
{
// Skip this segment,
// Tag names don't include OData type cast segment identifiers
preComplexSegmentIndex--;
preComplexSegment = path.Segments.ElementAt(preComplexSegmentIndex);
}

string tagName = null;

if (preComplexSegment is ODataNavigationSourceSegment sourceSegment)
Expand All @@ -254,12 +264,12 @@ internal static string GenerateComplexPropertyPathTagName(ODataPath path, ODataC
}
else if (preComplexSegment is ODataKeySegment)
{
var thirdLastSegment = path.Segments.ElementAt(complexSegmentIndex - 2);
if (thirdLastSegment is ODataNavigationPropertySegment)
var prevKeySegment = path.Segments.ElementAt(preComplexSegmentIndex - 1);
if (prevKeySegment is ODataNavigationPropertySegment)
{
tagName = GenerateNavigationPropertyPathTagName(path, context);
}
else if (thirdLastSegment is ODataNavigationSourceSegment sourceSegment1)
else if (prevKeySegment is ODataNavigationSourceSegment sourceSegment1)
{
tagName = $"{sourceSegment1.NavigationSource.Name}";
}
Expand Down
7 changes: 6 additions & 1 deletion src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -687,7 +687,7 @@ bool filter(IEdmStructuredType x) =>
}
else
{
if (convertSettings.ExpandDerivedTypesNavigationProperties)
if (convertSettings.GenerateDerivedTypesProperties)
{
if (annotable is IEdmNavigationProperty navigationProperty && !navigationProperty.ContainsTarget)
{
Expand All @@ -698,6 +698,11 @@ bool filter(IEdmStructuredType x) =>
{
RetrieveNavigationPropertyPaths(declaredNavigationProperty, null, castPath, convertSettings);
}

if (targetType is IEdmEntityType entityType)
{
RetrieveComplexPropertyPaths(entityType, castPath, convertSettings);
}
}
}
}
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.5.0-preview6</Version>
<Version>1.5.0-preview7</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 @@ -27,6 +27,7 @@
- Adds support for `x-ms-enum-flags` extension for flagged enums
- Use containment together with RequiresExplicitBinding annotation to check whether to append bound operations to navigation properties #430
- Adds schema to content types of stream properties that have a collection of acceptable media types #435
- Retrieves complex properties of derived types #437
</PackageReleaseNotes>
<AssemblyName>Microsoft.OpenApi.OData.Reader</AssemblyName>
<AssemblyOriginatorKeyFile>..\..\tool\Microsoft.OpenApi.OData.snk</AssemblyOriginatorKeyFile>
Expand Down
14 changes: 12 additions & 2 deletions src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,18 @@ public string PathPrefix
/// <summary>
/// Gets/Sets a value indicating whether or not to expand derived types to retrieve their declared navigation properties.
/// </summary>
public bool ExpandDerivedTypesNavigationProperties { get; set; } = true;
[Obsolete("Use RetrieveDerivedTypesProperties to Get or Set the value.")]
public bool ExpandDerivedTypesNavigationProperties
{
get => GenerateDerivedTypesProperties;
set => GenerateDerivedTypesProperties = value;
}

/// <summary>
/// Gets/Sets a value indicating whether or not to retrieve complex or navigation properties declared in derived types.
/// </summary>
public bool GenerateDerivedTypesProperties { get; set; } = true;

/// <summary>
/// Gets/sets a value indicating whether or not to set the deprecated tag for the operation when a revision is present as well as the "x-ms-deprecation" extension with additional information.
/// </summary>
Expand Down Expand Up @@ -386,7 +396,7 @@ internal OpenApiConvertSettings Clone()
ErrorResponsesAsDefault = this.ErrorResponsesAsDefault,
InnerErrorComplexTypeName = this.InnerErrorComplexTypeName,
RequireRestrictionAnnotationsToGenerateComplexPropertyPaths = this.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths,
ExpandDerivedTypesNavigationProperties = this.ExpandDerivedTypesNavigationProperties,
GenerateDerivedTypesProperties = this.GenerateDerivedTypesProperties,
CustomXMLAttributesMapping = this.CustomXMLAttributesMapping,
CustomHttpMethodLinkRelMapping = this.CustomHttpMethodLinkRelMapping,
AppendBoundOperationsOnDerivedTypeCastSegments = this.AppendBoundOperationsOnDerivedTypeCastSegments,
Expand Down
2 changes: 2 additions & 0 deletions src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ Microsoft.OpenApi.OData.OpenApiConvertSettings.ExpandDerivedTypesNavigationPrope
Microsoft.OpenApi.OData.OpenApiConvertSettings.ExpandDerivedTypesNavigationProperties.set -> void
Microsoft.OpenApi.OData.OpenApiConvertSettings.CustomXMLAttributesMapping.get -> System.Collections.Generic.Dictionary<string, string>
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
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(18264, paths.Count());
Assert.Equal(18280, paths.Count());
AssertGraphBetaModelPaths(paths);
}

Expand Down Expand Up @@ -83,6 +83,12 @@ private void AssertGraphBetaModelPaths(IEnumerable<ODataPath> paths)
Assert.NotNull(paths.FirstOrDefault(p => p.GetPathItemName().Equals("/directoryObjects({id})/microsoft.graph.getMemberGroups")));
Assert.NotNull(paths.FirstOrDefault(p => p.GetPathItemName().Equals("/directoryObjects({id})/microsoft.graph.getMemberObjects")));
Assert.Null(paths.FirstOrDefault(p => p.GetPathItemName().Equals("/directoryObjects({id})/microsoft.graph.restore")));

// Test that complex and navigation properties on derived types are created
Assert.NotNull(paths.FirstOrDefault(p => p.GetPathItemName().Equals(
"/identity/authenticationEventsFlows({id})/microsoft.graph.externalUsersSelfServiceSignUpEventsFlow/onAttributeCollection/microsoft.graph.onAttributeCollectionExternalUsersSelfServiceSignUp/attributes")));
Assert.NotNull(paths.FirstOrDefault(p => p.GetPathItemName().Equals(
"/identity/authenticationEventsFlows({id})/microsoft.graph.externalUsersSelfServiceSignUpEventsFlow/onAuthenticationMethodLoadStart/microsoft.graph.onAuthenticationMethodLoadStartExternalUsersSelfServiceSignUp/identityProviders")));
}

[Fact]
Expand All @@ -103,7 +109,7 @@ public void GetPathsForGraphBetaModelWithDerivedTypesConstraintReturnsAllPaths()

// Assert
Assert.NotNull(paths);
Assert.Equal(18915, paths.Count());
Assert.Equal(18931, paths.Count());
}

[Theory]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public void CreateLinksForSingleValuedNavigationProperties()
OpenApiConvertSettings settings = new()
{
ShowLinks = true,
ExpandDerivedTypesNavigationProperties = false
GenerateDerivedTypesProperties = false
};
ODataContext context = new(model, settings);
IEdmSingleton admin = model.EntityContainer.FindSingleton("admin");
Expand Down Expand Up @@ -72,7 +72,7 @@ public void CreateLinksForCollectionValuedNavigationProperties()
OpenApiConvertSettings settings = new()
{
ShowLinks = true,
ExpandDerivedTypesNavigationProperties = false
GenerateDerivedTypesProperties = false
};
ODataContext context = new(model, settings);
IEdmSingleton singleton = model.EntityContainer.FindSingleton("admin");
Expand Down Expand Up @@ -140,7 +140,7 @@ public void CreateLinksForSingletons()
OpenApiConvertSettings settings = new()
{
ShowLinks = true,
ExpandDerivedTypesNavigationProperties = false
GenerateDerivedTypesProperties = false
};
ODataContext context = new(model, settings);
IEdmSingleton singleton = model.EntityContainer.FindSingleton("admin");
Expand Down Expand Up @@ -195,7 +195,7 @@ public void CreateLinksForEntities()
OpenApiConvertSettings settings = new()
{
ShowLinks = true,
ExpandDerivedTypesNavigationProperties = false
GenerateDerivedTypesProperties = false
};
ODataContext context = new(model, settings);
IEdmEntitySet entityset = model.EntityContainer.FindEntitySet("agreements");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,7 @@ public void CreatePathItemForNavigationPropertyWithRestrictionAnnotationsDefined
IEdmModel model = EdmModelHelper.GraphBetaModel;
OpenApiConvertSettings settings = new()
{
ExpandDerivedTypesNavigationProperties = false
GenerateDerivedTypesProperties = false
};
ODataContext context = new(model, settings);
IEdmSingleton ipSingleton = model.EntityContainer.FindSingleton("informationProtection");
Expand Down Expand Up @@ -543,7 +543,7 @@ public void CreatePathItemForNavigationPropertyWithOutOfLineRestrictionAnnotatio
IEdmModel model = EdmModelHelper.GraphBetaModel;
OpenApiConvertSettings settings = new()
{
ExpandDerivedTypesNavigationProperties = false
GenerateDerivedTypesProperties = false
};
ODataContext context = new(model, settings);
IEdmEntitySet users = model.EntityContainer.FindEntitySet("users");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61976,6 +61976,34 @@
</Property>
<Property Name="state" Type="graph.identityProviderState" />
</EntityType>
<EntityType Name="externalUsersSelfServiceSignUpEventsFlow" BaseType="graph.authenticationEventsFlow">
<Property Name="onAttributeCollection" Type="graph.onAttributeCollectionHandler">
<Annotation Term="Org.OData.Validation.V1.DerivedTypeConstraint">
<Collection>
<String>microsoft.graph.onAttributeCollectionExternalUsersSelfServiceSignUp</String>
</Collection>
</Annotation>
<Annotation Term="Org.OData.Capabilities.V1.ReadRestrictions">
<Record>
<PropertyValue Property="Readable" Bool="true" />
</Record>
</Annotation>
<Annotation Term="Org.OData.Core.V1.Description" String="The configuration for what to invoke when attributes are ready to be collected from the user." />
</Property>
<Property Name="onAuthenticationMethodLoadStart" Type="graph.onAuthenticationMethodLoadStartHandler">
<Annotation Term="Org.OData.Validation.V1.DerivedTypeConstraint">
<Collection>
<String>microsoft.graph.onAuthenticationMethodLoadStartExternalUsersSelfServiceSignUp</String>
</Collection>
</Annotation>
<Annotation Term="Org.OData.Capabilities.V1.ReadRestrictions">
<Record>
<PropertyValue Property="Readable" Bool="true" />
</Record>
</Annotation>
<Annotation Term="Org.OData.Core.V1.Description" String="Required. The configuration for what to invoke when authentication methods are ready to be presented to the user. Must have at least one identity provider linked." />
</Property>
</EntityType>
<EntityType Name="identityUserFlowAttribute" BaseType="graph.entity">
<Property Name="dataType" Type="graph.identityUserFlowAttributeDataType" Nullable="false">
<Annotation Term="Org.OData.Core.V1.Description" String="The data type of the user flow attribute. This cannot be modified after the custom user flow attribute is created. The supported values for dataType are: string , boolean , int64 , stringCollection , dateTime." />
Expand All @@ -61991,11 +62019,33 @@
</Property>
</EntityType>
<EntityType Name="identityBuiltInUserFlowAttribute" BaseType="graph.identityUserFlowAttribute" />
<EntityType Name="authenticationEventsFlow" BaseType="graph.entity" Abstract="true" OpenType="true">
<Property Name="conditions" Type="graph.authenticationConditions">
<Annotation Term="Org.OData.Core.V1.Description" String="The conditions representing the context of the authentication request that will be used to decide whether the events policy will be invoked." />
</Property>
<Property Name="description" Type="Edm.String">
<Annotation Term="Org.OData.Core.V1.Description" String="The description of the events policy." />
</Property>
<Property Name="displayName" Type="Edm.String" Nullable="false">
<Annotation Term="Org.OData.Core.V1.Description" String="Required. The display name for the events policy." />
</Property>
<Property Name="priority" Type="Edm.Int32" Nullable="false">
<Annotation Term="Org.OData.Core.V1.Description" String="The priority to use for each individual event of the events policy. If multiple competing listeners for an event have the same priority, one is chosen and an error is silently logged. Defaults to 500." />
</Property>
</EntityType>
<EntityType Name="identityContainer">
<NavigationProperty Name="apiConnectors" Type="Collection(graph.identityApiConnector)" ContainsTarget="true">
<Annotation Term="Org.OData.Core.V1.Description" String="Represents entry point for API connectors." />
</NavigationProperty>
<NavigationProperty Name="authenticationEventListeners" Type="Collection(graph.authenticationEventListener)" ContainsTarget="true" />
<NavigationProperty Name="authenticationEventsFlows" Type="Collection(graph.authenticationEventsFlow)" ContainsTarget="true">
<Annotation Term="Org.OData.Validation.V1.DerivedTypeConstraint">
<Collection>
<String>microsoft.graph.externalUsersSelfServiceSignUpEventsFlow</String>
</Collection>
</Annotation>
<Annotation Term="Org.OData.Core.V1.Description" String="Represents the entry point for self-service sign up and sign in user flows in both Microsoft Entra workforce and customer tenants." />
</NavigationProperty>
<NavigationProperty Name="b2cUserFlows" Type="Collection(graph.b2cIdentityUserFlow)" ContainsTarget="true">
<Annotation Term="Org.OData.Core.V1.Description" String="Represents entry point for B2C identity userflows." />
</NavigationProperty>
Expand Down Expand Up @@ -86400,6 +86450,14 @@
<ComplexType Name="httpRequestEndpoint" BaseType="graph.customExtensionEndpointConfiguration">
<Property Name="targetUrl" Type="Edm.String" />
</ComplexType>
<ComplexType Name="onAttributeCollectionHandler" Abstract="true" />
<ComplexType Name="onAuthenticationMethodLoadStartHandler" Abstract="true" />
<ComplexType Name="onAuthenticationMethodLoadStartExternalUsersSelfServiceSignUp" BaseType="graph.onAuthenticationMethodLoadStartHandler">
<NavigationProperty Name="identityProviders" Type="Collection(graph.identityProviderBase)" />
</ComplexType>
<ComplexType Name="onAttributeCollectionExternalUsersSelfServiceSignUp" BaseType="graph.onAttributeCollectionHandler">
<NavigationProperty Name="attributes" Type="Collection(graph.identityUserFlowAttribute)" />
</ComplexType>
<ComplexType Name="onTokenIssuanceStartHandler" Abstract="true" />
<ComplexType Name="onTokenIssuanceStartCustomExtensionHandler" BaseType="graph.onTokenIssuanceStartHandler">
<NavigationProperty Name="customExtension" Type="graph.onTokenIssuanceStartCustomExtension" />
Expand Down Expand Up @@ -112377,9 +112435,9 @@
<Annotation Term="Org.OData.Core.V1.ExplicitOperationBindings">
<Collection>
<String>microsoft.graph.checkMemberGroups</String>
<String>microsoft.graph.checkMemberObjects</String>
<String>microsoft.graph.getMemberGroups</String>
<String>microsoft.graph.getMemberObjects</String>
<String>microsoft.graph.checkMemberObjects</String>
<String>microsoft.graph.getMemberGroups</String>
<String>microsoft.graph.getMemberObjects</String>
</Collection>
</Annotation>
</Annotations>
Expand Down
Loading

0 comments on commit d2a97e5

Please sign in to comment.