3
3
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
4
4
// ------------------------------------------------------------
5
5
6
+ using System ;
6
7
using System . Collections . Generic ;
7
8
using System . Diagnostics ;
8
9
using System . Linq ;
9
10
using Microsoft . OData . Edm ;
11
+ using Microsoft . OData . Edm . Vocabularies ;
10
12
11
13
namespace Microsoft . OpenApi . OData . Edm
12
14
{
@@ -38,8 +40,9 @@ public class ODataPathProvider : IODataPathProvider
38
40
/// Generate the list of <see cref="ODataPath"/> based on the given <see cref="IEdmModel"/>.
39
41
/// </summary>
40
42
/// <param name="model">The Edm model.</param>
43
+ /// <param name="settings">The conversion settings.</param>
41
44
/// <returns>The collection of built <see cref="ODataPath"/>.</returns>
42
- public virtual IEnumerable < ODataPath > GetPaths ( IEdmModel model )
45
+ public virtual IEnumerable < ODataPath > GetPaths ( IEdmModel model , OpenApiConvertSettings settings )
43
46
{
44
47
if ( model == null || model . EntityContainer == null )
45
48
{
@@ -67,7 +70,7 @@ public virtual IEnumerable<ODataPath> GetPaths(IEdmModel model)
67
70
}
68
71
69
72
// bound operations
70
- RetrieveBoundOperationPaths ( ) ;
73
+ RetrieveBoundOperationPaths ( settings ) ;
71
74
72
75
// unbound operations
73
76
foreach ( IEdmOperationImport import in _model . EntityContainer . OperationImports ( ) )
@@ -338,7 +341,7 @@ private bool ShouldExpandNavigationProperty(IEdmNavigationProperty navigationPro
338
341
/// <summary>
339
342
/// Retrieve all bounding <see cref="IEdmOperation"/>.
340
343
/// </summary>
341
- private void RetrieveBoundOperationPaths ( )
344
+ private void RetrieveBoundOperationPaths ( OpenApiConvertSettings convertSettings )
342
345
{
343
346
foreach ( var edmOperation in _model . GetAllElements ( ) . OfType < IEdmOperation > ( ) . Where ( e => e . IsBound ) )
344
347
{
@@ -396,10 +399,17 @@ private void RetrieveBoundOperationPaths()
396
399
}
397
400
398
401
// 3. Search for derived
399
- if ( AppendBoundOperationOnDerived ( edmOperation , isCollection , bindingEntityType ) )
402
+ if ( AppendBoundOperationOnDerived ( edmOperation , isCollection , bindingEntityType , convertSettings ) )
400
403
{
401
404
continue ;
402
405
}
406
+
407
+ // 4. Search for derived generated navigation property
408
+ if ( AppendBoundOperationOnDerivedNavigationPropertyPath ( edmOperation , isCollection , bindingEntityType , convertSettings ) )
409
+ {
410
+ continue ;
411
+ }
412
+
403
413
}
404
414
}
405
415
}
@@ -477,7 +487,11 @@ private bool AppendBoundOperationOnNavigationPropertyPath(IEdmOperation edmOpera
477
487
return found ;
478
488
}
479
489
480
- private bool AppendBoundOperationOnDerived ( IEdmOperation edmOperation , bool isCollection , IEdmEntityType bindingEntityType )
490
+ private bool AppendBoundOperationOnDerived (
491
+ IEdmOperation edmOperation ,
492
+ bool isCollection ,
493
+ IEdmEntityType bindingEntityType ,
494
+ OpenApiConvertSettings convertSettings )
481
495
{
482
496
bool found = false ;
483
497
@@ -488,6 +502,14 @@ private bool AppendBoundOperationOnDerived(IEdmOperation edmOperation, bool isCo
488
502
{
489
503
foreach ( var ns in baseNavigationSource )
490
504
{
505
+ if ( HasUnsatisfiedDerivedTypeConstraint (
506
+ ns as IEdmVocabularyAnnotatable ,
507
+ baseType ,
508
+ convertSettings ) )
509
+ {
510
+ continue ;
511
+ }
512
+
491
513
if ( isCollection )
492
514
{
493
515
if ( ns is IEdmEntitySet )
@@ -523,5 +545,84 @@ private bool AppendBoundOperationOnDerived(IEdmOperation edmOperation, bool isCo
523
545
return found ;
524
546
}
525
547
548
+ private bool HasUnsatisfiedDerivedTypeConstraint (
549
+ IEdmVocabularyAnnotatable annotatable ,
550
+ IEdmEntityType baseType ,
551
+ OpenApiConvertSettings convertSettings )
552
+ {
553
+ return convertSettings . RequireDerivedTypesConstraintForBoundOperations &&
554
+ ! ( _model . GetCollection ( annotatable , "Org.OData.Validation.V1.DerivedTypeConstraint" ) ?? Enumerable . Empty < string > ( ) )
555
+ . Any ( c => c . Equals ( baseType . FullName ( ) , StringComparison . OrdinalIgnoreCase ) ) ;
556
+ }
557
+
558
+ private bool AppendBoundOperationOnDerivedNavigationPropertyPath (
559
+ IEdmOperation edmOperation ,
560
+ bool isCollection ,
561
+ IEdmEntityType bindingEntityType ,
562
+ OpenApiConvertSettings convertSettings )
563
+ {
564
+ bool found = false ;
565
+ bool isEscapedFunction = _model . IsUrlEscapeFunction ( edmOperation ) ;
566
+
567
+ foreach ( var baseType in bindingEntityType . FindAllBaseTypes ( ) )
568
+ {
569
+ if ( _allNavigationPropertyPaths . TryGetValue ( baseType , out IList < ODataPath > paths ) )
570
+ {
571
+ foreach ( var path in paths )
572
+ {
573
+ if ( path . Kind == ODataPathKind . Ref )
574
+ {
575
+ continue ;
576
+ }
577
+
578
+ var npSegment = path . Segments . Last ( s => s is ODataNavigationPropertySegment )
579
+ as ODataNavigationPropertySegment ;
580
+ if ( npSegment == null )
581
+ {
582
+ continue ;
583
+ }
584
+
585
+ bool isLastKeySegment = path . LastSegment is ODataKeySegment ;
586
+
587
+ if ( isCollection )
588
+ {
589
+ if ( isLastKeySegment )
590
+ {
591
+ continue ;
592
+ }
593
+
594
+ if ( npSegment . NavigationProperty . TargetMultiplicity ( ) != EdmMultiplicity . Many )
595
+ {
596
+ continue ;
597
+ }
598
+ }
599
+ else
600
+ {
601
+ if ( ! isLastKeySegment && npSegment . NavigationProperty . TargetMultiplicity ( ) ==
602
+ EdmMultiplicity . Many )
603
+ {
604
+ continue ;
605
+ }
606
+ }
607
+
608
+ if ( HasUnsatisfiedDerivedTypeConstraint (
609
+ npSegment . NavigationProperty as IEdmVocabularyAnnotatable ,
610
+ baseType ,
611
+ convertSettings ) )
612
+ {
613
+ continue ;
614
+ }
615
+
616
+ ODataPath newPath = path . Clone ( ) ;
617
+ newPath . Push ( new ODataTypeCastSegment ( bindingEntityType ) ) ;
618
+ newPath . Push ( new ODataOperationSegment ( edmOperation , isEscapedFunction ) ) ;
619
+ AppendPath ( newPath ) ;
620
+ found = true ;
621
+ }
622
+ }
623
+ }
624
+
625
+ return found ;
626
+ }
526
627
}
527
628
}
0 commit comments