Skip to content

Commit 42607c5

Browse files
Support collection parameters in functions. Fixes #999
1 parent be7021c commit 42607c5

File tree

1 file changed

+70
-0
lines changed

1 file changed

+70
-0
lines changed

Diff for: src/AspNetCore/OData/src/Asp.Versioning.OData.ApiExplorer/ApiExplorer/ODataApiDescriptionProvider.cs

+70
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ public virtual void OnProvidersExecuted( ApiDescriptionProviderContext context )
142142
else
143143
{
144144
UpdateModelTypes( result, matched );
145+
UpdateFunctionCollectionParameters( result, matched );
145146
}
146147
}
147148

@@ -456,6 +457,75 @@ private void UpdateModelTypes( ApiDescription description, IODataRoutingMetadata
456457
}
457458
}
458459

460+
private static void UpdateFunctionCollectionParameters( ApiDescription description, IODataRoutingMetadata metadata )
461+
{
462+
var parameters = description.ParameterDescriptions;
463+
464+
if ( parameters.Count == 0 )
465+
{
466+
return;
467+
}
468+
469+
var function = default( IEdmFunction );
470+
var mapping = default( IDictionary<string, string> );
471+
472+
for ( var i = 0; i < metadata.Template.Count; i++ )
473+
{
474+
var segment = metadata.Template[i];
475+
476+
if ( segment is FunctionSegmentTemplate func )
477+
{
478+
function = func.Function;
479+
mapping = func.ParameterMappings;
480+
break;
481+
}
482+
else if ( segment is FunctionImportSegmentTemplate import )
483+
{
484+
function = import.FunctionImport.Function;
485+
mapping = import.ParameterMappings;
486+
break;
487+
}
488+
}
489+
490+
if ( function is null || mapping is null )
491+
{
492+
return;
493+
}
494+
495+
var name = default( string );
496+
497+
foreach ( var parameter in function.Parameters )
498+
{
499+
if ( parameter.Type.IsCollection() &&
500+
mapping.TryGetValue( parameter.Name, out name ) &&
501+
parameters.SingleOrDefault( p => p.Name == name ) is { } param )
502+
{
503+
param.Source = BindingSource.Path;
504+
break;
505+
}
506+
}
507+
508+
var path = description.RelativePath;
509+
510+
if ( string.IsNullOrEmpty( name ) || string.IsNullOrEmpty( path ) )
511+
{
512+
return;
513+
}
514+
515+
var span = name.AsSpan();
516+
Span<char> oldValue = stackalloc char[name.Length + 2];
517+
Span<char> newValue = stackalloc char[name.Length + 4];
518+
519+
newValue[1] = oldValue[0] = '{';
520+
newValue[^2] = oldValue[^1] = '}';
521+
newValue[0] = '[';
522+
newValue[^1] = ']';
523+
span.CopyTo( oldValue.Slice( 1, name.Length ) );
524+
span.CopyTo( newValue.Slice( 2, name.Length ) );
525+
526+
description.RelativePath = path.Replace( oldValue.ToString(), newValue.ToString(), Ordinal );
527+
}
528+
459529
private sealed class ApiDescriptionComparer : IEqualityComparer<ApiDescription>
460530
{
461531
private readonly IEqualityComparer<string?> comparer = StringComparer.OrdinalIgnoreCase;

0 commit comments

Comments
 (0)