diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataDollarCountSegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataDollarCountSegment.cs
index 2109dad..5cad240 100644
--- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataDollarCountSegment.cs
+++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataDollarCountSegment.cs
@@ -12,6 +12,10 @@ namespace Microsoft.OpenApi.OData.Edm
///
public class ODataDollarCountSegment : ODataSegment
{
+ ///
+ /// Get the static instance of $count segment.
+ ///
+ internal static ODataDollarCountSegment Instance = new();
///
public override ODataSegmentKind Kind => ODataSegmentKind.DollarCount;
diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs
index 580d27a..2885827 100644
--- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs
+++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs
@@ -102,7 +102,7 @@ namespace Microsoft.OpenApi.OData.Edm
private IEnumerable MergePaths()
{
- List allODataPaths = new List();
+ List allODataPaths = new();
foreach (var item in _allNavigationSourcePaths.Values)
{
allODataPaths.AddRange(item);
@@ -127,6 +127,7 @@ namespace Microsoft.OpenApi.OData.Edm
ODataPathKind kind = path.Kind;
switch(kind)
{
+ case ODataPathKind.DollarCount:
case ODataPathKind.Entity:
case ODataPathKind.EntitySet:
case ODataPathKind.Singleton:
@@ -143,8 +144,7 @@ namespace Microsoft.OpenApi.OData.Edm
case ODataPathKind.NavigationProperty:
case ODataPathKind.Ref:
- ODataNavigationPropertySegment navigationPropertySegment = path.Last(p => p is ODataNavigationPropertySegment)
- as ODataNavigationPropertySegment;
+ ODataNavigationPropertySegment navigationPropertySegment = path.OfType().Last();
if (!_allNavigationPropertyPaths.TryGetValue(navigationPropertySegment.EntityType, out IList npList))
{
@@ -174,15 +174,17 @@ namespace Microsoft.OpenApi.OData.Edm
Debug.Assert(navigationSource != null);
// navigation source itself
- ODataPath path = new ODataPath(new ODataNavigationSourceSegment(navigationSource));
+ ODataPath path = new(new ODataNavigationSourceSegment(navigationSource));
AppendPath(path.Clone());
IEdmEntitySet entitySet = navigationSource as IEdmEntitySet;
IEdmEntityType entityType = navigationSource.EntityType();
- // for entity set, create a path with key
+ // for entity set, create a path with key and a $count path
if (entitySet != null)
{
+ CreateCountPath(path);
+
path.Push(new ODataKeySegment(entityType));
AppendPath(path.Clone());
}
@@ -275,6 +277,13 @@ namespace Microsoft.OpenApi.OData.Edm
if (restriction == null || restriction.IndexableByKey == true)
{
IEdmEntityType navEntityType = navigationProperty.ToEntityType();
+ var targetsMany = navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many;
+
+ if (targetsMany)
+ {
+ // ~/entityset/{key}/collection-valued-Nav/$count
+ CreateCountPath(currentPath);
+ }
if (!navigationProperty.ContainsTarget)
{
@@ -283,7 +292,7 @@ namespace Microsoft.OpenApi.OData.Edm
// Collection-valued: ~/entityset/{key}/collection-valued-Nav/$ref?$id ={navKey}
CreateRefPath(currentPath);
- if (navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many)
+ if (targetsMany)
{
// Collection-valued: DELETE ~/entityset/{key}/collection-valued-Nav/{key}/$ref
currentPath.Push(new ODataKeySegment(navEntityType));
@@ -296,7 +305,7 @@ namespace Microsoft.OpenApi.OData.Edm
else
{
// append a navigation property key.
- if (navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many)
+ if (targetsMany)
{
currentPath.Push(new ODataKeySegment(navEntityType));
AppendPath(currentPath.Clone());
@@ -318,7 +327,7 @@ namespace Microsoft.OpenApi.OData.Edm
}
}
- if (navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many)
+ if (targetsMany)
{
currentPath.Pop();
}
@@ -360,6 +369,16 @@ namespace Microsoft.OpenApi.OData.Edm
newPath.Push(ODataRefSegment.Instance); // $ref
AppendPath(newPath);
}
+ ///
+ /// Create $count paths.
+ ///
+ /// The current OData path.
+ private void CreateCountPath(ODataPath currentPath) {
+ if(currentPath == null) throw new ArgumentNullException(nameof(currentPath));
+ var countPath = currentPath.Clone();
+ countPath.Push(ODataDollarCountSegment.Instance);
+ AppendPath(countPath);
+ }
///
/// Retrieve all bounding .
@@ -436,7 +455,11 @@ namespace Microsoft.OpenApi.OData.Edm
}
}
}
-
+ private static readonly HashSet _oDataPathKindsToSkipForOperations = new HashSet() {
+ ODataPathKind.EntitySet,
+ ODataPathKind.MediaEntity,
+ ODataPathKind.DollarCount
+ };
private bool AppendBoundOperationOnNavigationSourcePath(IEdmOperation edmOperation, bool isCollection, IEdmEntityType bindingEntityType)
{
bool found = false;
@@ -448,8 +471,7 @@ namespace Microsoft.OpenApi.OData.Edm
foreach (var subPath in value)
{
if ((isCollection && subPath.Kind == ODataPathKind.EntitySet) ||
- (!isCollection && subPath.Kind != ODataPathKind.EntitySet &&
- subPath.Kind != ODataPathKind.MediaEntity))
+ (!isCollection && !_oDataPathKindsToSkipForOperations.Contains(subPath.Kind)))
{
ODataPath newPath = subPath.Clone();
newPath.Push(new ODataOperationSegment(edmOperation, isEscapedFunction));
@@ -461,7 +483,9 @@ namespace Microsoft.OpenApi.OData.Edm
return found;
}
-
+ private static readonly HashSet _pathKindToSkipForNavigationProperties = new () {
+ ODataPathKind.Ref,
+ };
private bool AppendBoundOperationOnNavigationPropertyPath(IEdmOperation edmOperation, bool isCollection, IEdmEntityType bindingEntityType)
{
bool found = false;
@@ -469,13 +493,8 @@ namespace Microsoft.OpenApi.OData.Edm
if (_allNavigationPropertyPaths.TryGetValue(bindingEntityType, out IList value))
{
- foreach (var path in value)
+ foreach (var path in value.Where(x => !_pathKindToSkipForNavigationProperties.Contains(x.Kind)))
{
- if (path.Kind == ODataPathKind.Ref)
- {
- continue;
- }
-
ODataNavigationPropertySegment npSegment = path.Segments.Last(s => s is ODataNavigationPropertySegment) as ODataNavigationPropertySegment;
if (!npSegment.NavigationProperty.ContainsTarget)
@@ -596,15 +615,9 @@ namespace Microsoft.OpenApi.OData.Edm
{
if (_allNavigationPropertyPaths.TryGetValue(baseType, out IList paths))
{
- foreach (var path in paths)
+ foreach (var path in paths.Where(x => !_pathKindToSkipForNavigationProperties.Contains(x.Kind)))
{
- if (path.Kind == ODataPathKind.Ref)
- {
- continue;
- }
-
- var npSegment = path.Segments.Last(s => s is ODataNavigationPropertySegment)
- as ODataNavigationPropertySegment;
+ var npSegment = path.Segments.OfType().LastOrDefault();
if (npSegment == null)
{
continue;