in src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs [327:427]
private void RetrieveNavigationPropertyPaths(IEdmNavigationProperty navigationProperty, CountRestrictionsType count, ODataPath currentPath, OpenApiConvertSettings convertSettings)
{
Debug.Assert(navigationProperty != null);
Debug.Assert(currentPath != null);
// Check whether the navigation property should be part of the path
NavigationRestrictionsType navigation = _model.GetRecord<NavigationRestrictionsType>(navigationProperty, CapabilitiesConstants.NavigationRestrictions);
if (navigation != null && !navigation.IsNavigable)
{
return;
}
// test the expandable for the navigation property.
bool shouldExpand = ShouldExpandNavigationProperty(navigationProperty, currentPath);
// append a navigation property.
currentPath.Push(new ODataNavigationPropertySegment(navigationProperty));
AppendPath(currentPath.Clone());
// Check whether a collection-valued navigation property should be indexed by key value(s).
NavigationPropertyRestriction restriction = navigation?.RestrictedProperties?.FirstOrDefault();
if (restriction == null || restriction.IndexableByKey == true)
{
IEdmEntityType navEntityType = navigationProperty.ToEntityType();
var targetsMany = navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many;
var propertyPath = navigationProperty.GetPartnerPath()?.Path;
var propertyPathIsEmpty = string.IsNullOrEmpty(propertyPath);
if (targetsMany)
{
if(propertyPathIsEmpty ||
(count?.IsNonCountableNavigationProperty(propertyPath) ?? true))
{
// ~/entityset/{key}/collection-valued-Nav/$count
CreateCountPath(currentPath, convertSettings);
}
}
// ~/entityset/{key}/collection-valued-Nav/subtype
// ~/entityset/{key}/single-valued-Nav/subtype
CreateTypeCastPaths(currentPath, convertSettings, navigationProperty.DeclaringType, navigationProperty, targetsMany);
if (!navigationProperty.ContainsTarget)
{
// Non-Contained
// Single-Valued: ~/entityset/{key}/single-valued-Nav/$ref
// Collection-valued: ~/entityset/{key}/collection-valued-Nav/$ref?$id='{navKey}'
CreateRefPath(currentPath);
if (targetsMany)
{
// Collection-valued: DELETE ~/entityset/{key}/collection-valued-Nav/{key}/$ref
currentPath.Push(new ODataKeySegment(navEntityType));
CreateRefPath(currentPath);
CreateTypeCastPaths(currentPath, convertSettings, navigationProperty.DeclaringType, navigationProperty, false); // ~/entityset/{key}/collection-valued-Nav/{id}/subtype
}
// Get possible stream paths for the navigation entity type
RetrieveMediaEntityStreamPaths(navEntityType, currentPath);
// Get the paths for the navigation property entity type properties of type complex
RetrieveComplexPropertyPaths(navEntityType, currentPath, convertSettings);
}
else
{
// append a navigation property key.
if (targetsMany)
{
currentPath.Push(new ODataKeySegment(navEntityType));
AppendPath(currentPath.Clone());
CreateTypeCastPaths(currentPath, convertSettings, navigationProperty.DeclaringType, navigationProperty, false); // ~/entityset/{key}/collection-valued-Nav/{id}/subtype
}
// Get possible stream paths for the navigation entity type
RetrieveMediaEntityStreamPaths(navEntityType, currentPath);
// Get the paths for the navigation property entity type properties of type complex
RetrieveComplexPropertyPaths(navEntityType, currentPath, convertSettings);
if (shouldExpand)
{
// expand to sub navigation properties
foreach (IEdmNavigationProperty subNavProperty in navEntityType.DeclaredNavigationProperties())
{
if (CanFilter(subNavProperty))
{
RetrieveNavigationPropertyPaths(subNavProperty, count, currentPath, convertSettings);
}
}
}
}
if (targetsMany)
{
currentPath.Pop();
}
}
currentPath.Pop();
}