77using System . Collections . Generic ;
88using System . Linq ;
99using Microsoft . OData . Edm ;
10+ using Microsoft . OpenApi . Any ;
1011using Microsoft . OpenApi . Models ;
1112using Microsoft . OpenApi . OData . Common ;
1213using Microsoft . OpenApi . OData . Edm ;
1314using Microsoft . OpenApi . OData . Generator ;
15+ using Microsoft . OpenApi . OData . Vocabulary . Capabilities ;
1416
1517namespace Microsoft . OpenApi . OData . Operation ;
1618
@@ -28,6 +30,8 @@ internal class ODataTypeCastGetOperationHandler : OperationHandler
2830 /// </summary>
2931 internal ODataSegment LastSecondSegment { get ; set ; }
3032
33+ private NavigationPropertyRestriction restriction ;
34+ private IEdmNavigationProperty navigationProperty ;
3135 private IEdmEntityType parentEntityType ;
3236 private IEdmEntityType targetEntityType ;
3337 private const int SecondLastSegmentIndex = 2 ;
@@ -42,6 +46,30 @@ protected override void Initialize(ODataContext context, ODataPath path)
4246 LastSecondSegment = path . Segments . ElementAt ( count - SecondLastSegmentIndex ) ;
4347
4448 parentEntityType = LastSecondSegment . EntityType ;
49+ if ( LastSecondSegment is ODataNavigationPropertySegment navigationPropertySegment )
50+ {
51+ navigationProperty = navigationPropertySegment . NavigationProperty ;
52+ var navigationPropertyPath = string . Join ( "/" ,
53+ Path . Segments . Where ( s => ! ( s is ODataKeySegment || s is ODataNavigationSourceSegment
54+ || s is ODataStreamContentSegment || s is ODataStreamPropertySegment ) ) . Select ( e => e . Identifier ) ) ;
55+
56+ if ( path . FirstSegment is ODataNavigationSourceSegment navigationSourceSegment )
57+ {
58+ NavigationRestrictionsType navigation = navigationSourceSegment . NavigationSource switch {
59+ IEdmEntitySet entitySet => Context . Model . GetRecord < NavigationRestrictionsType > ( entitySet , CapabilitiesConstants . NavigationRestrictions ) ,
60+ IEdmSingleton singleton => Context . Model . GetRecord < NavigationRestrictionsType > ( singleton , CapabilitiesConstants . NavigationRestrictions ) ,
61+ _ => null
62+ } ;
63+
64+ if ( navigation ? . RestrictedProperties != null )
65+ {
66+ restriction = navigation . RestrictedProperties . FirstOrDefault ( r => r . NavigationProperty != null && r . NavigationProperty == navigationPropertyPath ) ;
67+ }
68+ }
69+ }
70+ //TODO previous segment is a key
71+ //TODO previous segment is a single nav property
72+ //TODO previous segment is an entity set
4573 if ( path . Last ( ) is ODataTypeCastSegment oDataTypeCastSegment )
4674 {
4775 targetEntityType = oDataTypeCastSegment . EntityType ;
@@ -140,7 +168,130 @@ protected override void SetResponses(OpenApiOperation operation)
140168
141169 base . SetResponses ( operation ) ;
142170 }
143- //TODO query parameters?
144- //TODO extensions?
145- }
146- //TODO unit tests
171+ /// <inheritdoc/>
172+ protected override void SetTags ( OpenApiOperation operation )
173+ {
174+ IList < string > items = new List < string >
175+ {
176+ parentEntityType . Name ,
177+ targetEntityType . Name ,
178+ } ;
179+
180+ string name = string . Join ( "." , items ) ;
181+ OpenApiTag tag = new ( )
182+ {
183+ Name = name
184+ } ;
185+ tag . Extensions . Add ( Constants . xMsTocType , new OpenApiString ( "page" ) ) ;
186+ operation . Tags . Add ( tag ) ;
187+
188+ Context . AppendTag ( tag ) ;
189+
190+ base . SetTags ( operation ) ;
191+ }
192+ /// <inheritdoc/>
193+ protected override void SetParameters ( OpenApiOperation operation )
194+ {
195+ base . SetParameters ( operation ) ;
196+
197+ if ( navigationProperty != null ) {
198+ if ( navigationProperty . TargetMultiplicity ( ) == EdmMultiplicity . Many )
199+ {
200+ // Need to verify that TopSupported or others should be applied to navigation source.
201+ // So, how about for the navigation property.
202+ OpenApiParameter parameter = Context . CreateTop ( navigationProperty ) ;
203+ if ( parameter != null )
204+ {
205+ operation . Parameters . Add ( parameter ) ;
206+ }
207+
208+ parameter = Context . CreateSkip ( navigationProperty ) ;
209+ if ( parameter != null )
210+ {
211+ operation . Parameters . Add ( parameter ) ;
212+ }
213+
214+ parameter = Context . CreateSearch ( navigationProperty ) ;
215+ if ( parameter != null )
216+ {
217+ operation . Parameters . Add ( parameter ) ;
218+ }
219+
220+ parameter = Context . CreateFilter ( navigationProperty ) ;
221+ if ( parameter != null )
222+ {
223+ operation . Parameters . Add ( parameter ) ;
224+ }
225+
226+ parameter = Context . CreateCount ( navigationProperty ) ;
227+ if ( parameter != null )
228+ {
229+ operation . Parameters . Add ( parameter ) ;
230+ }
231+
232+ parameter = Context . CreateOrderBy ( navigationProperty ) ;
233+ if ( parameter != null )
234+ {
235+ operation . Parameters . Add ( parameter ) ;
236+ }
237+
238+ parameter = Context . CreateSelect ( navigationProperty ) ;
239+ if ( parameter != null )
240+ {
241+ operation . Parameters . Add ( parameter ) ;
242+ }
243+
244+ parameter = Context . CreateExpand ( navigationProperty ) ;
245+ if ( parameter != null )
246+ {
247+ operation . Parameters . Add ( parameter ) ;
248+ }
249+ }
250+ else
251+ {
252+ OpenApiParameter parameter = Context . CreateSelect ( navigationProperty ) ;
253+ if ( parameter != null )
254+ {
255+ operation . Parameters . Add ( parameter ) ;
256+ }
257+
258+ parameter = Context . CreateExpand ( navigationProperty ) ;
259+ if ( parameter != null )
260+ {
261+ operation . Parameters . Add ( parameter ) ;
262+ }
263+ }
264+ }
265+ }
266+
267+ protected override void SetSecurity ( OpenApiOperation operation )
268+ {
269+ if ( restriction == null || restriction . ReadRestrictions == null )
270+ {
271+ return ;
272+ }
273+
274+ ReadRestrictionsBase readBase = restriction . ReadRestrictions ;
275+
276+ operation . Security = Context . CreateSecurityRequirements ( readBase . Permissions ) . ToList ( ) ;
277+ }
278+
279+ protected override void SetExtensions ( OpenApiOperation operation )
280+ {
281+ if ( Context . Settings . EnablePagination )
282+ {
283+ if ( navigationProperty != null && navigationProperty . TargetMultiplicity ( ) == EdmMultiplicity . Many )
284+ {
285+ OpenApiObject extension = new ( )
286+ {
287+ { "nextLinkName" , new OpenApiString ( "@odata.nextLink" ) } ,
288+ { "operationName" , new OpenApiString ( Context . Settings . PageableOperationName ) }
289+ } ;
290+
291+ operation . Extensions . Add ( Constants . xMsPageable , extension ) ;
292+ }
293+ }
294+
295+ base . SetExtensions ( operation ) ;
296+ }
297+ }
0 commit comments