-
Notifications
You must be signed in to change notification settings - Fork 65
fixes a bug where OData Count path items would be missing from the description #141
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
883ca92
d2bb4bd
70aefe9
960b31b
f08be64
ae11d65
2fee91b
76cfc30
10b99ca
032fbae
f87c2b4
4093249
5d910fd
892003e
a8bb14f
00b605f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -146,8 +146,8 @@ public string GetPathItemName(OpenApiConvertSettings settings) | |
|
||
// From Open API spec, parameter name is case sensitive, so don't use the IgnoreCase HashSet. | ||
// HashSet<string> parameters = new HashSet<string>(StringComparer.OrdinalIgnoreCase); | ||
HashSet<string> parameters = new HashSet<string>(); | ||
StringBuilder sb = new StringBuilder(); | ||
HashSet<string> parameters = new(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If possible, let's keep it unchanged? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what's the harm in using the newer syntax that saves code writing and removes squiggles when we're editing the code? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think it can save a lot of time. It's the same as:
Actually, it's no harm, but for readability. |
||
StringBuilder sb = new(); | ||
|
||
if (!string.IsNullOrWhiteSpace(settings.PathPrefix)) | ||
{ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -57,7 +57,7 @@ public virtual IEnumerable<ODataPath> GetPaths(IEdmModel model, OpenApiConvertSe | |
{ | ||
if (CanFilter(entitySet)) | ||
{ | ||
RetrieveNavigationSourcePaths(entitySet); | ||
RetrieveNavigationSourcePaths(entitySet, settings); | ||
} | ||
} | ||
|
||
|
@@ -66,7 +66,7 @@ public virtual IEnumerable<ODataPath> GetPaths(IEdmModel model, OpenApiConvertSe | |
{ | ||
if (CanFilter(singleton)) | ||
{ | ||
RetrieveNavigationSourcePaths(singleton); | ||
RetrieveNavigationSourcePaths(singleton, settings); | ||
} | ||
} | ||
|
||
|
@@ -102,7 +102,7 @@ protected virtual void Initialize(IEdmModel model) | |
|
||
private IEnumerable<ODataPath> MergePaths() | ||
{ | ||
List<ODataPath> allODataPaths = new List<ODataPath>(); | ||
List<ODataPath> allODataPaths = new(); | ||
foreach (var item in _allNavigationSourcePaths.Values) | ||
{ | ||
allODataPaths.AddRange(item); | ||
|
@@ -127,6 +127,7 @@ private void AppendPath(ODataPath path) | |
ODataPathKind kind = path.Kind; | ||
switch(kind) | ||
{ | ||
case ODataPathKind.DollarCount: | ||
case ODataPathKind.Entity: | ||
case ODataPathKind.EntitySet: | ||
case ODataPathKind.Singleton: | ||
|
@@ -143,8 +144,7 @@ private void AppendPath(ODataPath path) | |
|
||
case ODataPathKind.NavigationProperty: | ||
case ODataPathKind.Ref: | ||
ODataNavigationPropertySegment navigationPropertySegment = path.Last(p => p is ODataNavigationPropertySegment) | ||
as ODataNavigationPropertySegment; | ||
ODataNavigationPropertySegment navigationPropertySegment = path.OfType<ODataNavigationPropertySegment>().Last(); | ||
|
||
if (!_allNavigationPropertyPaths.TryGetValue(navigationPropertySegment.EntityType, out IList<ODataPath> npList)) | ||
{ | ||
|
@@ -169,20 +169,26 @@ private void AppendPath(ODataPath path) | |
/// Retrieve the paths for <see cref="IEdmNavigationSource"/>. | ||
/// </summary> | ||
/// <param name="navigationSource">The navigation source.</param> | ||
private void RetrieveNavigationSourcePaths(IEdmNavigationSource navigationSource) | ||
/// <param name="convertSettings">The settings for the current conversion.</param> | ||
private void RetrieveNavigationSourcePaths(IEdmNavigationSource navigationSource, OpenApiConvertSettings convertSettings) | ||
{ | ||
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(); | ||
CountRestrictionsType count = null; | ||
|
||
// for entity set, create a path with key | ||
// for entity set, create a path with key and a $count path | ||
if (entitySet != null) | ||
{ | ||
count = _model.GetRecord<CountRestrictionsType>(entitySet, CapabilitiesConstants.CountRestrictions); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. shall we add a config in the settings to allow/disallow the $count segment There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, I see that. IncludeDollarCountPathSegments. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the setting is already read in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if (setting.IncludeDollarCountPathSegments) in the CreateCountPath() There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why read the setting in the before the call to CreateCountPath? It's only going to lead to code/logic duplication. |
||
if(count?.Countable ?? true) | ||
CreateCountPath(path, convertSettings); | ||
|
||
path.Push(new ODataKeySegment(entityType)); | ||
AppendPath(path.Clone()); | ||
} | ||
|
@@ -195,7 +201,7 @@ private void RetrieveNavigationSourcePaths(IEdmNavigationSource navigationSource | |
{ | ||
if (CanFilter(np)) | ||
{ | ||
RetrieveNavigationPropertyPaths(np, path); | ||
RetrieveNavigationPropertyPaths(np, count, path, convertSettings); | ||
} | ||
} | ||
|
||
|
@@ -249,8 +255,10 @@ private void RetrieveMediaEntityStreamPaths(IEdmEntityType entityType, ODataPath | |
/// Retrieve the path for <see cref="IEdmNavigationProperty"/>. | ||
/// </summary> | ||
/// <param name="navigationProperty">The navigation property.</param> | ||
/// <param name="count">The count restrictions.</param> | ||
/// <param name="currentPath">The current OData path.</param> | ||
private void RetrieveNavigationPropertyPaths(IEdmNavigationProperty navigationProperty, ODataPath currentPath) | ||
/// <param name="convertSettings">The settings for the current conversion.</param> | ||
private void RetrieveNavigationPropertyPaths(IEdmNavigationProperty navigationProperty, CountRestrictionsType count, ODataPath currentPath, OpenApiConvertSettings convertSettings) | ||
{ | ||
Debug.Assert(navigationProperty != null); | ||
Debug.Assert(currentPath != null); | ||
|
@@ -275,6 +283,15 @@ private void RetrieveNavigationPropertyPaths(IEdmNavigationProperty navigationPr | |
if (restriction == null || restriction.IndexableByKey == true) | ||
{ | ||
IEdmEntityType navEntityType = navigationProperty.ToEntityType(); | ||
var targetsMany = navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many; | ||
var propertyPath = navigationProperty.GetPartnerPath()?.Path; | ||
|
||
if (targetsMany && (string.IsNullOrEmpty(propertyPath) || | ||
(count?.IsNonCountableNavigationProperty(propertyPath) ?? true))) | ||
{ | ||
// ~/entityset/{key}/collection-valued-Nav/$count | ||
CreateCountPath(currentPath, convertSettings); | ||
} | ||
|
||
if (!navigationProperty.ContainsTarget) | ||
{ | ||
|
@@ -283,7 +300,7 @@ private void RetrieveNavigationPropertyPaths(IEdmNavigationProperty navigationPr | |
// 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 +313,7 @@ private void RetrieveNavigationPropertyPaths(IEdmNavigationProperty navigationPr | |
else | ||
{ | ||
// append a navigation property key. | ||
if (navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) | ||
if (targetsMany) | ||
{ | ||
currentPath.Push(new ODataKeySegment(navEntityType)); | ||
AppendPath(currentPath.Clone()); | ||
|
@@ -312,13 +329,13 @@ private void RetrieveNavigationPropertyPaths(IEdmNavigationProperty navigationPr | |
{ | ||
if (CanFilter(subNavProperty)) | ||
{ | ||
RetrieveNavigationPropertyPaths(subNavProperty, currentPath); | ||
RetrieveNavigationPropertyPaths(subNavProperty, count, currentPath, convertSettings); | ||
} | ||
} | ||
} | ||
} | ||
|
||
if (navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) | ||
if (targetsMany) | ||
{ | ||
currentPath.Pop(); | ||
} | ||
|
@@ -361,6 +378,21 @@ private void CreateRefPath(ODataPath currentPath) | |
AppendPath(newPath); | ||
} | ||
|
||
/// <summary> | ||
baywet marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// Create $count paths. | ||
/// </summary> | ||
/// <param name="currentPath">The current OData path.</param> | ||
/// <param name="convertSettings">The settings for the current conversion.</param> | ||
private void CreateCountPath(ODataPath currentPath, OpenApiConvertSettings convertSettings) | ||
{ | ||
if(currentPath == null) throw new ArgumentNullException(nameof(currentPath)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. make a better format There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. for others There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm assuming that you're referring to the curly brace not being on the next line. Fixed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if(currentPath == null) and, maybe to use Error.ArgumentNull(...) method? |
||
if(convertSettings == null) throw new ArgumentNullException(nameof(convertSettings)); | ||
if(!convertSettings.EnableDollarCountPath) return; | ||
var countPath = currentPath.Clone(); | ||
countPath.Push(ODataDollarCountSegment.Instance); | ||
AppendPath(countPath); | ||
} | ||
|
||
/// <summary> | ||
/// Retrieve all bounding <see cref="IEdmOperation"/>. | ||
/// </summary> | ||
|
@@ -436,7 +468,11 @@ private void RetrieveBoundOperationPaths(OpenApiConvertSettings convertSettings) | |
} | ||
} | ||
} | ||
|
||
private static readonly HashSet<ODataPathKind> _oDataPathKindsToSkipForOperations = new HashSet<ODataPathKind>() { | ||
ODataPathKind.EntitySet, | ||
ODataPathKind.MediaEntity, | ||
ODataPathKind.DollarCount | ||
}; | ||
private bool AppendBoundOperationOnNavigationSourcePath(IEdmOperation edmOperation, bool isCollection, IEdmEntityType bindingEntityType) | ||
{ | ||
bool found = false; | ||
|
@@ -448,8 +484,7 @@ private bool AppendBoundOperationOnNavigationSourcePath(IEdmOperation edmOperati | |
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,21 +496,18 @@ private bool AppendBoundOperationOnNavigationSourcePath(IEdmOperation edmOperati | |
|
||
return found; | ||
} | ||
|
||
private static readonly HashSet<ODataPathKind> _pathKindToSkipForNavigationProperties = new () { | ||
ODataPathKind.Ref, | ||
}; | ||
private bool AppendBoundOperationOnNavigationPropertyPath(IEdmOperation edmOperation, bool isCollection, IEdmEntityType bindingEntityType) | ||
{ | ||
bool found = false; | ||
bool isEscapedFunction = _model.IsUrlEscapeFunction(edmOperation); | ||
|
||
if (_allNavigationPropertyPaths.TryGetValue(bindingEntityType, out IList<ODataPath> 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 +628,9 @@ private bool AppendBoundOperationOnDerivedNavigationPropertyPath( | |
{ | ||
if (_allNavigationPropertyPaths.TryGetValue(baseType, out IList<ODataPath> 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<ODataNavigationPropertySegment>().LastOrDefault(); | ||
if (npSegment == null) | ||
{ | ||
continue; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I remember I have a separate solution for updateDocs.
Do you think it's convenient to have it into the main solution? Because it's only a helper tooling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having it in the main solution makes f5 debug work for VS code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also enables static analysis and more for that project with CI