Skip to content

Commit 682005d

Browse files
authored
Fixes generation of ODataTypeCast paths (#212)
* Pass entity type targeted by nav. prop. instead of declaring entity type * Update tests appropriately * Update tests * Minor space refactor * Code refactor * Do not generate type casts already generated in the path * Refactor method * Add new convert setting to control expansion of derived types nav. props * Use setting to control expansion of derived types nav. properties * Attempt to fix breaking test in pipeline * Revert 'fix attempt' * Do not expand derived types' nav. properties in test
1 parent 429e664 commit 682005d

File tree

6 files changed

+46
-29
lines changed

6 files changed

+46
-29
lines changed

src/Microsoft.OpenApi.OData.Reader/Common/Utils.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,7 @@ internal static string ToFirstCharacterLowerCase(this string input)
125125
internal static string NavigationPropertyPath(this ODataPath path, string navigationPropertyName = null)
126126
{
127127
string value = string.Join("/",
128-
path.Segments.Where(s => !(s is ODataKeySegment || s is ODataNavigationSourceSegment
129-
|| s is ODataStreamContentSegment || s is ODataStreamPropertySegment)).Select(e => e.Identifier));
130-
128+
path.Segments.OfType<ODataNavigationPropertySegment>().Select(e => e.Identifier));
131129
return navigationPropertyName == null ? value : $"{value}/{navigationPropertyName}";
132130
}
133131
}

src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ private void RetrieveNavigationPropertyPaths(
423423
}
424424
// ~/entityset/{key}/collection-valued-Nav/subtype
425425
// ~/entityset/{key}/single-valued-Nav/subtype
426-
CreateTypeCastPaths(currentPath, convertSettings, navigationProperty.DeclaringType, navigationProperty, targetsMany);
426+
CreateTypeCastPaths(currentPath, convertSettings, navEntityType, navigationProperty, targetsMany);
427427

428428
if ((navSourceRestrictionType?.Referenceable ?? false) ||
429429
(navPropRestrictionType?.Referenceable ?? false))
@@ -439,7 +439,7 @@ private void RetrieveNavigationPropertyPaths(
439439
currentPath.Push(new ODataKeySegment(navEntityType));
440440
CreateRefPath(currentPath);
441441

442-
CreateTypeCastPaths(currentPath, convertSettings, navigationProperty.DeclaringType, navigationProperty, false); // ~/entityset/{key}/collection-valued-Nav/{id}/subtype
442+
CreateTypeCastPaths(currentPath, convertSettings, navEntityType, navigationProperty, false); // ~/entityset/{key}/collection-valued-Nav/{id}/subtype
443443
}
444444

445445
// Get possible stream paths for the navigation entity type
@@ -456,7 +456,7 @@ private void RetrieveNavigationPropertyPaths(
456456
currentPath.Push(new ODataKeySegment(navEntityType));
457457
AppendPath(currentPath.Clone());
458458

459-
CreateTypeCastPaths(currentPath, convertSettings, navigationProperty.DeclaringType, navigationProperty, false); // ~/entityset/{key}/collection-valued-Nav/{id}/subtype
459+
CreateTypeCastPaths(currentPath, convertSettings, navEntityType, navigationProperty, false); // ~/entityset/{key}/collection-valued-Nav/{id}/subtype
460460
}
461461

462462
// Get possible stream paths for the navigation entity type
@@ -548,21 +548,26 @@ bool filter(IEdmStructuredType x) =>
548548
.OfType<IEdmStructuredType>()
549549
.ToArray();
550550

551-
foreach(var targetType in targetTypes)
551+
foreach(var targetType in targetTypes)
552552
{
553553
var castPath = currentPath.Clone();
554-
castPath.Push(new ODataTypeCastSegment(targetType));
554+
var targetTypeSegment = new ODataTypeCastSegment(targetType);
555+
556+
castPath.Push(targetTypeSegment);
555557
AppendPath(castPath);
556558
if(targetsMany)
557559
{
558560
CreateCountPath(castPath, convertSettings);
559561
}
560562
else
561563
{
562-
foreach(var declaredNavigationProperty in targetType.DeclaredNavigationProperties())
564+
if (convertSettings.ExpandDerivedTypesNavigationProperties)
563565
{
564-
RetrieveNavigationPropertyPaths(declaredNavigationProperty, null, castPath, convertSettings);
565-
}
566+
foreach (var declaredNavigationProperty in targetType.DeclaredNavigationProperties())
567+
{
568+
RetrieveNavigationPropertyPaths(declaredNavigationProperty, null, castPath, convertSettings);
569+
}
570+
}
566571
}
567572
}
568573
}

src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,11 @@ public string PathPrefix
203203
/// </summary>
204204
public bool RequireDerivedTypesConstraintForODataTypeCastSegments { get; set; } = true;
205205

206+
/// <summary>
207+
/// Gets/Sets a value indicating whether or not to expand derived types to retrieve their declared navigation properties.
208+
/// </summary>
209+
public bool ExpandDerivedTypesNavigationProperties { get; set; } = true;
210+
206211
/// <summary>
207212
/// 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.
208213
/// </summary>
@@ -275,7 +280,8 @@ internal OpenApiConvertSettings Clone()
275280
AddEnumDescriptionExtension = this.AddEnumDescriptionExtension,
276281
ErrorResponsesAsDefault = this.ErrorResponsesAsDefault,
277282
InnerErrorComplexTypeName = this.InnerErrorComplexTypeName,
278-
RequireRestrictionAnnotationsToGenerateComplexPropertyPaths = this.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths
283+
RequireRestrictionAnnotationsToGenerateComplexPropertyPaths = this.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths,
284+
ExpandDerivedTypesNavigationProperties = this.ExpandDerivedTypesNavigationProperties
279285
};
280286

281287
return newSettings;

src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
abstract Microsoft.OpenApi.OData.Edm.ODataSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, System.Collections.Generic.HashSet<string> parameters) -> string
1+
abstract Microsoft.OpenApi.OData.Edm.ODataSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, System.Collections.Generic.HashSet<string> parameters) -> string
22
abstract Microsoft.OpenApi.OData.Edm.ODataSegment.Identifier.get -> string
33
abstract Microsoft.OpenApi.OData.Edm.ODataSegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind
44
abstract Microsoft.OpenApi.OData.Edm.ODataSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable<Microsoft.OData.Edm.Vocabularies.IEdmVocabularyAnnotatable>
55
Microsoft.OpenApi.OData.Common.Utils
66
Microsoft.OpenApi.OData.Edm.EdmModelExtensions
77
Microsoft.OpenApi.OData.Edm.EdmTypeExtensions
8+
Microsoft.OpenApi.OData.OpenApiConvertSettings.ExpandDerivedTypesNavigationProperties.get -> bool
9+
Microsoft.OpenApi.OData.OpenApiConvertSettings.ExpandDerivedTypesNavigationProperties.set -> void
810
Microsoft.OpenApi.OData.OpenApiConvertSettings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths.get -> bool
911
Microsoft.OpenApi.OData.OpenApiConvertSettings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths.set -> void
1012
static Microsoft.OpenApi.OData.Edm.EdmTypeExtensions.ShouldPathParameterBeQuoted(this Microsoft.OData.Edm.IEdmType edmType, Microsoft.OpenApi.OData.OpenApiConvertSettings settings) -> bool

test/Microsoft.OpenAPI.OData.Reader.Tests/Edm/ODataPathProviderTests.cs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,18 @@ public void GetPathsForGraphBetaModelReturnsAllPaths()
4040
{
4141
// Arrange
4242
IEdmModel model = EdmModelHelper.GraphBetaModel;
43-
var settings = new OpenApiConvertSettings();
43+
var settings = new OpenApiConvertSettings()
44+
{
45+
ExpandDerivedTypesNavigationProperties = false
46+
};
4447
ODataPathProvider provider = new ODataPathProvider();
4548

4649
// Act
4750
var paths = provider.GetPaths(model, settings);
4851

4952
// Assert
5053
Assert.NotNull(paths);
51-
Assert.Equal(12261, paths.Count());
54+
Assert.Equal(14624, paths.Count());
5255
}
5356

5457
[Fact]
@@ -59,15 +62,16 @@ public void GetPathsForGraphBetaModelWithDerivedTypesConstraintReturnsAllPaths()
5962
ODataPathProvider provider = new ODataPathProvider();
6063
var settings = new OpenApiConvertSettings
6164
{
62-
RequireDerivedTypesConstraintForBoundOperations = true
65+
RequireDerivedTypesConstraintForBoundOperations = true,
66+
ExpandDerivedTypesNavigationProperties = false
6367
};
6468

6569
// Act
6670
var paths = provider.GetPaths(model, settings);
6771

6872
// Assert
6973
Assert.NotNull(paths);
70-
Assert.Equal(12219, paths.Count());
74+
Assert.Equal(14582, paths.Count());
7175
}
7276

7377
[Fact]
@@ -102,8 +106,8 @@ public void GetPathsDoesntReturnPathsForCountWhenDisabled()
102106
[InlineData(true, false, false, 7)]
103107
[InlineData(false, true, false, 5)]
104108
[InlineData(false, true, true, 4)]
105-
[InlineData(true, true, true, 5)]
106-
[InlineData(true, true, false, 5)]
109+
[InlineData(true, true, true, 8)]
110+
[InlineData(true, true, false, 8)]
107111
public void GetOperationPathsForModelWithDerivedTypesConstraint(bool addAnnotation, bool getNavPropModel, bool requireConstraint, int expectedCount)
108112
{
109113
// Arrange
@@ -124,18 +128,16 @@ public void GetOperationPathsForModelWithDerivedTypesConstraint(bool addAnnotati
124128
var dollarCountPathsWithCastSegment = paths.Where(x => x.Kind == ODataPathKind.DollarCount && x.Any(y => y.Kind == ODataSegmentKind.TypeCast));
125129
if(addAnnotation && !getNavPropModel)
126130
Assert.Single(dollarCountPathsWithCastSegment);
127-
else
128-
Assert.Empty(dollarCountPathsWithCastSegment);
129131
}
130132
[Theory]
131133
[InlineData(false, false, true, 4)]
132134
[InlineData(false, false, false, 7)]
133135
[InlineData(true, false, true, 7)]
134136
[InlineData(true, false, false, 7)]
135-
[InlineData(false, true, false, 5)]
137+
[InlineData(false, true, false, 8)]
136138
[InlineData(false, true, true, 5)]
137-
[InlineData(true, true, true, 5)]
138-
[InlineData(true, true, false, 5)]
139+
[InlineData(true, true, true, 8)]
140+
[InlineData(true, true, false, 8)]
139141
public void GetTypeCastPathsForModelWithDerivedTypesConstraint(bool addAnnotation, bool getNavPropModel, bool requireConstraint, int expectedCount)
140142
{
141143
// Arrange
@@ -154,7 +156,7 @@ public void GetTypeCastPathsForModelWithDerivedTypesConstraint(bool addAnnotatio
154156
Assert.NotNull(paths);
155157
Assert.Equal(expectedCount, paths.Count());
156158
var dollarCountPathsWithCastSegment = paths.Where(x => x.Kind == ODataPathKind.DollarCount && x.Any(y => y.Kind == ODataSegmentKind.TypeCast));
157-
if((addAnnotation || !requireConstraint) && !getNavPropModel)
159+
if(addAnnotation || !requireConstraint)
158160
Assert.Single(dollarCountPathsWithCastSegment);
159161
else
160162
Assert.Empty(dollarCountPathsWithCastSegment);

test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiLinkGeneratorTests.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ public void CreateLinksForSingleValuedNavigationProperties()
2222
IEdmModel model = EdmModelHelper.GraphBetaModel;
2323
OpenApiConvertSettings settings = new()
2424
{
25-
ShowLinks = true
25+
ShowLinks = true,
26+
ExpandDerivedTypesNavigationProperties = false
2627
};
2728
ODataContext context = new(model, settings);
2829
IEdmSingleton admin = model.EntityContainer.FindSingleton("admin");
@@ -70,7 +71,8 @@ public void CreateLinksForCollectionValuedNavigationProperties()
7071
IEdmModel model = EdmModelHelper.GraphBetaModel;
7172
OpenApiConvertSettings settings = new()
7273
{
73-
ShowLinks = true
74+
ShowLinks = true,
75+
ExpandDerivedTypesNavigationProperties = false
7476
};
7577
ODataContext context = new(model, settings);
7678
IEdmSingleton singleton = model.EntityContainer.FindSingleton("admin");
@@ -137,7 +139,8 @@ public void CreateLinksForSingletons()
137139
IEdmModel model = EdmModelHelper.GraphBetaModel;
138140
OpenApiConvertSettings settings = new()
139141
{
140-
ShowLinks = true
142+
ShowLinks = true,
143+
ExpandDerivedTypesNavigationProperties = false
141144
};
142145
ODataContext context = new(model, settings);
143146
IEdmSingleton singleton = model.EntityContainer.FindSingleton("admin");
@@ -176,7 +179,8 @@ public void CreateLinksForEntities()
176179
IEdmModel model = EdmModelHelper.GraphBetaModel;
177180
OpenApiConvertSettings settings = new()
178181
{
179-
ShowLinks = true
182+
ShowLinks = true,
183+
ExpandDerivedTypesNavigationProperties = false
180184
};
181185
ODataContext context = new(model, settings);
182186
IEdmEntitySet entityset = model.EntityContainer.FindEntitySet("agreements");

0 commit comments

Comments
 (0)