@@ -57,7 +57,7 @@ public virtual IEnumerable<ODataPath> GetPaths(IEdmModel model, OpenApiConvertSe
57
57
{
58
58
if ( CanFilter ( entitySet ) )
59
59
{
60
- RetrieveNavigationSourcePaths ( entitySet ) ;
60
+ RetrieveNavigationSourcePaths ( entitySet , settings ) ;
61
61
}
62
62
}
63
63
@@ -66,7 +66,7 @@ public virtual IEnumerable<ODataPath> GetPaths(IEdmModel model, OpenApiConvertSe
66
66
{
67
67
if ( CanFilter ( singleton ) )
68
68
{
69
- RetrieveNavigationSourcePaths ( singleton ) ;
69
+ RetrieveNavigationSourcePaths ( singleton , settings ) ;
70
70
}
71
71
}
72
72
@@ -102,7 +102,7 @@ protected virtual void Initialize(IEdmModel model)
102
102
103
103
private IEnumerable < ODataPath > MergePaths ( )
104
104
{
105
- List < ODataPath > allODataPaths = new List < ODataPath > ( ) ;
105
+ List < ODataPath > allODataPaths = new ( ) ;
106
106
foreach ( var item in _allNavigationSourcePaths . Values )
107
107
{
108
108
allODataPaths . AddRange ( item ) ;
@@ -127,6 +127,7 @@ private void AppendPath(ODataPath path)
127
127
ODataPathKind kind = path . Kind ;
128
128
switch ( kind )
129
129
{
130
+ case ODataPathKind . DollarCount :
130
131
case ODataPathKind . Entity :
131
132
case ODataPathKind . EntitySet :
132
133
case ODataPathKind . Singleton :
@@ -143,8 +144,7 @@ private void AppendPath(ODataPath path)
143
144
144
145
case ODataPathKind . NavigationProperty :
145
146
case ODataPathKind . Ref :
146
- ODataNavigationPropertySegment navigationPropertySegment = path . Last ( p => p is ODataNavigationPropertySegment )
147
- as ODataNavigationPropertySegment ;
147
+ ODataNavigationPropertySegment navigationPropertySegment = path . OfType < ODataNavigationPropertySegment > ( ) . Last ( ) ;
148
148
149
149
if ( ! _allNavigationPropertyPaths . TryGetValue ( navigationPropertySegment . EntityType , out IList < ODataPath > npList ) )
150
150
{
@@ -169,20 +169,26 @@ private void AppendPath(ODataPath path)
169
169
/// Retrieve the paths for <see cref="IEdmNavigationSource"/>.
170
170
/// </summary>
171
171
/// <param name="navigationSource">The navigation source.</param>
172
- private void RetrieveNavigationSourcePaths ( IEdmNavigationSource navigationSource )
172
+ /// <param name="convertSettings">The settings for the current conversion.</param>
173
+ private void RetrieveNavigationSourcePaths ( IEdmNavigationSource navigationSource , OpenApiConvertSettings convertSettings )
173
174
{
174
175
Debug . Assert ( navigationSource != null ) ;
175
176
176
177
// navigation source itself
177
- ODataPath path = new ODataPath ( new ODataNavigationSourceSegment ( navigationSource ) ) ;
178
+ ODataPath path = new ( new ODataNavigationSourceSegment ( navigationSource ) ) ;
178
179
AppendPath ( path . Clone ( ) ) ;
179
180
180
181
IEdmEntitySet entitySet = navigationSource as IEdmEntitySet ;
181
182
IEdmEntityType entityType = navigationSource . EntityType ( ) ;
183
+ CountRestrictionsType count = null ;
182
184
183
- // for entity set, create a path with key
185
+ // for entity set, create a path with key and a $count path
184
186
if ( entitySet != null )
185
187
{
188
+ count = _model . GetRecord < CountRestrictionsType > ( entitySet , CapabilitiesConstants . CountRestrictions ) ;
189
+ if ( count ? . Countable ?? true )
190
+ CreateCountPath ( path , convertSettings ) ;
191
+
186
192
path . Push ( new ODataKeySegment ( entityType ) ) ;
187
193
AppendPath ( path . Clone ( ) ) ;
188
194
}
@@ -195,7 +201,7 @@ private void RetrieveNavigationSourcePaths(IEdmNavigationSource navigationSource
195
201
{
196
202
if ( CanFilter ( np ) )
197
203
{
198
- RetrieveNavigationPropertyPaths ( np , path ) ;
204
+ RetrieveNavigationPropertyPaths ( np , count , path , convertSettings ) ;
199
205
}
200
206
}
201
207
@@ -249,8 +255,10 @@ private void RetrieveMediaEntityStreamPaths(IEdmEntityType entityType, ODataPath
249
255
/// Retrieve the path for <see cref="IEdmNavigationProperty"/>.
250
256
/// </summary>
251
257
/// <param name="navigationProperty">The navigation property.</param>
258
+ /// <param name="count">The count restrictions.</param>
252
259
/// <param name="currentPath">The current OData path.</param>
253
- private void RetrieveNavigationPropertyPaths ( IEdmNavigationProperty navigationProperty , ODataPath currentPath )
260
+ /// <param name="convertSettings">The settings for the current conversion.</param>
261
+ private void RetrieveNavigationPropertyPaths ( IEdmNavigationProperty navigationProperty , CountRestrictionsType count , ODataPath currentPath , OpenApiConvertSettings convertSettings )
254
262
{
255
263
Debug . Assert ( navigationProperty != null ) ;
256
264
Debug . Assert ( currentPath != null ) ;
@@ -275,6 +283,15 @@ private void RetrieveNavigationPropertyPaths(IEdmNavigationProperty navigationPr
275
283
if ( restriction == null || restriction . IndexableByKey == true )
276
284
{
277
285
IEdmEntityType navEntityType = navigationProperty . ToEntityType ( ) ;
286
+ var targetsMany = navigationProperty . TargetMultiplicity ( ) == EdmMultiplicity . Many ;
287
+ var propertyPath = navigationProperty . GetPartnerPath ( ) ? . Path ;
288
+
289
+ if ( targetsMany && ( string . IsNullOrEmpty ( propertyPath ) ||
290
+ ( count ? . IsNonCountableNavigationProperty ( propertyPath ) ?? true ) ) )
291
+ {
292
+ // ~/entityset/{key}/collection-valued-Nav/$count
293
+ CreateCountPath ( currentPath , convertSettings ) ;
294
+ }
278
295
279
296
if ( ! navigationProperty . ContainsTarget )
280
297
{
@@ -283,7 +300,7 @@ private void RetrieveNavigationPropertyPaths(IEdmNavigationProperty navigationPr
283
300
// Collection-valued: ~/entityset/{key}/collection-valued-Nav/$ref?$id ={navKey}
284
301
CreateRefPath ( currentPath ) ;
285
302
286
- if ( navigationProperty . TargetMultiplicity ( ) == EdmMultiplicity . Many )
303
+ if ( targetsMany )
287
304
{
288
305
// Collection-valued: DELETE ~/entityset/{key}/collection-valued-Nav/{key}/$ref
289
306
currentPath . Push ( new ODataKeySegment ( navEntityType ) ) ;
@@ -296,7 +313,7 @@ private void RetrieveNavigationPropertyPaths(IEdmNavigationProperty navigationPr
296
313
else
297
314
{
298
315
// append a navigation property key.
299
- if ( navigationProperty . TargetMultiplicity ( ) == EdmMultiplicity . Many )
316
+ if ( targetsMany )
300
317
{
301
318
currentPath . Push ( new ODataKeySegment ( navEntityType ) ) ;
302
319
AppendPath ( currentPath . Clone ( ) ) ;
@@ -312,13 +329,13 @@ private void RetrieveNavigationPropertyPaths(IEdmNavigationProperty navigationPr
312
329
{
313
330
if ( CanFilter ( subNavProperty ) )
314
331
{
315
- RetrieveNavigationPropertyPaths ( subNavProperty , currentPath ) ;
332
+ RetrieveNavigationPropertyPaths ( subNavProperty , count , currentPath , convertSettings ) ;
316
333
}
317
334
}
318
335
}
319
336
}
320
337
321
- if ( navigationProperty . TargetMultiplicity ( ) == EdmMultiplicity . Many )
338
+ if ( targetsMany )
322
339
{
323
340
currentPath . Pop ( ) ;
324
341
}
@@ -361,6 +378,21 @@ private void CreateRefPath(ODataPath currentPath)
361
378
AppendPath ( newPath ) ;
362
379
}
363
380
381
+ /// <summary>
382
+ /// Create $count paths.
383
+ /// </summary>
384
+ /// <param name="currentPath">The current OData path.</param>
385
+ /// <param name="convertSettings">The settings for the current conversion.</param>
386
+ private void CreateCountPath ( ODataPath currentPath , OpenApiConvertSettings convertSettings )
387
+ {
388
+ if ( currentPath == null ) throw new ArgumentNullException ( nameof ( currentPath ) ) ;
389
+ if ( convertSettings == null ) throw new ArgumentNullException ( nameof ( convertSettings ) ) ;
390
+ if ( ! convertSettings . EnableDollarCountPath ) return ;
391
+ var countPath = currentPath . Clone ( ) ;
392
+ countPath . Push ( ODataDollarCountSegment . Instance ) ;
393
+ AppendPath ( countPath ) ;
394
+ }
395
+
364
396
/// <summary>
365
397
/// Retrieve all bounding <see cref="IEdmOperation"/>.
366
398
/// </summary>
@@ -436,7 +468,11 @@ private void RetrieveBoundOperationPaths(OpenApiConvertSettings convertSettings)
436
468
}
437
469
}
438
470
}
439
-
471
+ private static readonly HashSet < ODataPathKind > _oDataPathKindsToSkipForOperations = new HashSet < ODataPathKind > ( ) {
472
+ ODataPathKind . EntitySet ,
473
+ ODataPathKind . MediaEntity ,
474
+ ODataPathKind . DollarCount
475
+ } ;
440
476
private bool AppendBoundOperationOnNavigationSourcePath ( IEdmOperation edmOperation , bool isCollection , IEdmEntityType bindingEntityType )
441
477
{
442
478
bool found = false ;
@@ -448,8 +484,7 @@ private bool AppendBoundOperationOnNavigationSourcePath(IEdmOperation edmOperati
448
484
foreach ( var subPath in value )
449
485
{
450
486
if ( ( isCollection && subPath . Kind == ODataPathKind . EntitySet ) ||
451
- ( ! isCollection && subPath . Kind != ODataPathKind . EntitySet &&
452
- subPath . Kind != ODataPathKind . MediaEntity ) )
487
+ ( ! isCollection && ! _oDataPathKindsToSkipForOperations . Contains ( subPath . Kind ) ) )
453
488
{
454
489
ODataPath newPath = subPath . Clone ( ) ;
455
490
newPath . Push ( new ODataOperationSegment ( edmOperation , isEscapedFunction ) ) ;
@@ -461,21 +496,18 @@ private bool AppendBoundOperationOnNavigationSourcePath(IEdmOperation edmOperati
461
496
462
497
return found ;
463
498
}
464
-
499
+ private static readonly HashSet < ODataPathKind > _pathKindToSkipForNavigationProperties = new ( ) {
500
+ ODataPathKind . Ref ,
501
+ } ;
465
502
private bool AppendBoundOperationOnNavigationPropertyPath ( IEdmOperation edmOperation , bool isCollection , IEdmEntityType bindingEntityType )
466
503
{
467
504
bool found = false ;
468
505
bool isEscapedFunction = _model . IsUrlEscapeFunction ( edmOperation ) ;
469
506
470
507
if ( _allNavigationPropertyPaths . TryGetValue ( bindingEntityType , out IList < ODataPath > value ) )
471
508
{
472
- foreach ( var path in value )
509
+ foreach ( var path in value . Where ( x => ! _pathKindToSkipForNavigationProperties . Contains ( x . Kind ) ) )
473
510
{
474
- if ( path . Kind == ODataPathKind . Ref )
475
- {
476
- continue ;
477
- }
478
-
479
511
ODataNavigationPropertySegment npSegment = path . Segments . Last ( s => s is ODataNavigationPropertySegment ) as ODataNavigationPropertySegment ;
480
512
481
513
if ( ! npSegment . NavigationProperty . ContainsTarget )
@@ -596,15 +628,9 @@ private bool AppendBoundOperationOnDerivedNavigationPropertyPath(
596
628
{
597
629
if ( _allNavigationPropertyPaths . TryGetValue ( baseType , out IList < ODataPath > paths ) )
598
630
{
599
- foreach ( var path in paths )
631
+ foreach ( var path in paths . Where ( x => ! _pathKindToSkipForNavigationProperties . Contains ( x . Kind ) ) )
600
632
{
601
- if ( path . Kind == ODataPathKind . Ref )
602
- {
603
- continue ;
604
- }
605
-
606
- var npSegment = path . Segments . Last ( s => s is ODataNavigationPropertySegment )
607
- as ODataNavigationPropertySegment ;
633
+ var npSegment = path . Segments . OfType < ODataNavigationPropertySegment > ( ) . LastOrDefault ( ) ;
608
634
if ( npSegment == null )
609
635
{
610
636
continue ;
0 commit comments