@@ -33,7 +33,7 @@ internal sealed class ResourceCollectionClientProvider : TypeProvider
3333 private readonly IReadOnlyList < ParameterProvider > _extraCtorParameters ;
3434 private readonly IReadOnlyList < FieldProvider > _extraFields ;
3535 private readonly ResourceClientProvider _resource ;
36- private readonly ResourceMethod ? _getAll ;
36+ private readonly IReadOnlyList < ResourceMethod > _getAlls ;
3737 private readonly ResourceMethod ? _create ;
3838 private readonly ResourceMethod ? _get ;
3939
@@ -60,35 +60,33 @@ internal ResourceCollectionClientProvider(ResourceClientProvider resource, Input
6060
6161 _resourceTypeExpression = Static ( _resource . Type ) . As < ArmResource > ( ) . ResourceType ( ) ;
6262
63- InitializeMethods ( resourceMethods , ref _get , ref _create , ref _getAll ) ;
64- _operationContext = InitializeContext ( this , resourceMetadata , _getAll ) ;
63+ var contextualPath = GetContextualPath ( resourceMetadata ) ;
64+ ( _get , _create , _getAlls ) = InitializeMethods ( resourceMethods , contextualPath ) ;
65+ _operationContext = InitializeContext ( this , contextualPath , _getAlls . Count > 0 ? _getAlls [ 0 ] : null ) ;
6566
66- // this depends on _getAll being initialized
67+ // this depends on _getAlls being initialized
6768 ( _extraCtorParameters , _extraFields ) = BuildExtraConstructorParametersAndFields ( ) ;
6869 }
6970
70- private static OperationContext InitializeContext ( ResourceCollectionClientProvider enclosingType , ArmResourceMetadata resourceMetadata , ResourceMethod ? getAll )
71+ private static OperationContext InitializeContext ( ResourceCollectionClientProvider enclosingType , RequestPathPattern contextualPath , ResourceMethod ? canonicalGetAll )
7172 {
72- var contextualPath = GetContextualPath ( resourceMetadata ) ;
73- if ( getAll is not null )
73+ if ( canonicalGetAll is null )
7474 {
75- var secondaryContextualPath = getAll . OperationPath ;
76- // validate the contextualPath should be an ancestor of the secondaryContextualPath, otherwise report diagnostic.
77- if ( ! contextualPath . IsAncestorOf ( secondaryContextualPath ) )
78- {
79- // Report diagnostic
80- ManagementClientGenerator . Instance . Emitter . ReportDiagnostic (
81- code : "malformed-resource-detected" ,
82- message : $ "The contextual path '{ contextualPath } ' is not an ancestor of the secondary contextual path '{ secondaryContextualPath } '.",
83- targetCrossLanguageDefinitionId : getAll . InputMethod . CrossLanguageDefinitionId
84- ) ;
85- }
86- return OperationContext . Create ( contextualPath , secondaryContextualPath , enclosingType . FindField ) ;
75+ return OperationContext . Create ( contextualPath ) ;
8776 }
88- else
77+
78+ var secondaryContextualPath = canonicalGetAll . OperationPath ;
79+ // validate the contextualPath should be an ancestor of the secondaryContextualPath, otherwise report diagnostic.
80+ if ( ! contextualPath . IsAncestorOf ( secondaryContextualPath ) )
8981 {
90- return OperationContext . Create ( contextualPath ) ;
82+ // Report diagnostic
83+ ManagementClientGenerator . Instance . Emitter . ReportDiagnostic (
84+ code : "malformed-resource-detected" ,
85+ message : $ "The contextual path '{ contextualPath } ' is not an ancestor of the secondary contextual path '{ secondaryContextualPath } '.",
86+ targetCrossLanguageDefinitionId : canonicalGetAll . InputMethod . CrossLanguageDefinitionId
87+ ) ;
9188 }
89+ return OperationContext . Create ( contextualPath , secondaryContextualPath , enclosingType . FindField ) ;
9290 }
9391
9492 private FieldProvider FindField ( string variableName )
@@ -128,7 +126,7 @@ private static RequestPathPattern GetContextualPath(ArmResourceMetadata resource
128126 var parameter = new ParameterProvider (
129127 contextualParameter . VariableName ,
130128 $ "The { contextualParameter . VariableName } for the resource.",
131- ResourceHelpers . GetRequestPathParameterType ( contextualParameter . VariableName , _getAll ! . InputMethod ) ) ;
129+ ResourceHelpers . GetRequestPathParameterType ( contextualParameter . VariableName , _getAlls [ 0 ] . InputMethod ) ) ;
132130 var field = new FieldProvider ( FieldModifiers . Private | FieldModifiers . ReadOnly , parameter . Type , $ "_{ contextualParameter . VariableName } ", this , description : $ "The { contextualParameter . VariableName } .") ;
133131 parameter . Field = field ;
134132 extraParameters . Add ( parameter ) ;
@@ -137,32 +135,64 @@ private static RequestPathPattern GetContextualPath(ArmResourceMetadata resource
137135 return ( extraParameters , extraFields ) ;
138136 }
139137
140- private static void InitializeMethods (
138+ private static ( ResourceMethod ? Get , ResourceMethod ? Create , IReadOnlyList < ResourceMethod > GetAlls ) InitializeMethods (
141139 IReadOnlyList < ResourceMethod > resourceMethods ,
142- ref ResourceMethod ? getMethod ,
143- ref ResourceMethod ? createMethod ,
144- ref ResourceMethod ? getAllMethod )
140+ RequestPathPattern contextualPath )
145141 {
142+ ResourceMethod ? getMethod = null ;
143+ ResourceMethod ? createMethod = null ;
144+ var listMethods = new List < ResourceMethod > ( ) ;
145+
146146 foreach ( var method in resourceMethods )
147147 {
148- if ( getAllMethod is not null && createMethod is not null && getMethod is not null )
149- {
150- break ; // we already have all methods we need
151- }
152-
153148 switch ( method . Kind )
154149 {
155150 case ResourceOperationKind . Read :
156- getMethod = method ;
151+ getMethod ?? = method ;
157152 break ;
158153 case ResourceOperationKind . List :
159- getAllMethod = method ;
154+ listMethods . Add ( method ) ;
160155 break ;
161156 case ResourceOperationKind . Create :
162- createMethod = method ;
157+ createMethod ?? = method ;
163158 break ;
164159 }
165160 }
161+
162+ return ( getMethod , createMethod , SortGetAllMethodsByScopeBreadth ( listMethods , contextualPath ) ) ;
163+ }
164+
165+ private static IReadOnlyList < ResourceMethod > SortGetAllMethodsByScopeBreadth (
166+ IReadOnlyList < ResourceMethod > listMethods ,
167+ RequestPathPattern contextualPath )
168+ {
169+ if ( listMethods . Count <= 1 )
170+ {
171+ return listMethods ;
172+ }
173+
174+ return [ .. listMethods
175+ . OrderBy ( m => CountExtraVariableSegments ( contextualPath , m . OperationPath ) )
176+ . ThenBy ( m => m . OperationPath . Count ) ] ;
177+ }
178+
179+ private static int CountExtraVariableSegments ( RequestPathPattern contextualPath , RequestPathPattern operationPath )
180+ {
181+ if ( ! contextualPath . IsAncestorOf ( operationPath ) )
182+ {
183+ return int . MaxValue ;
184+ }
185+
186+ var extra = contextualPath . TrimAncestorFrom ( operationPath ) ;
187+ int count = 0 ;
188+ foreach ( var segment in extra )
189+ {
190+ if ( ! segment . IsConstant )
191+ {
192+ count ++ ;
193+ }
194+ }
195+ return count ;
166196 }
167197
168198 public ResourceClientProvider Resource => _resource ;
@@ -340,16 +370,28 @@ protected override MethodProvider[] BuildMethods()
340370
341371 private MethodProvider [ ] BuildGetAllMethods ( )
342372 {
343- if ( _getAll is null )
373+ if ( _getAlls . Count == 0 )
344374 {
345375 return [ ] ;
346376 }
347377
348- // implement paging method GetAll
349- _getAllSyncMethodProvider = BuildGetAllMethod ( _getAll , false ) ;
350- var getAllAsync = BuildGetAllMethod ( _getAll , true ) ;
378+ var methods = new List < MethodProvider > ( _getAlls . Count * 2 ) ;
379+ for ( int i = 0 ; i < _getAlls . Count ; i ++ )
380+ {
381+ var listMethod = _getAlls [ i ] ;
382+ var sync = BuildGetAllMethod ( listMethod , false ) ;
383+ var async = BuildGetAllMethod ( listMethod , true ) ;
384+
385+ if ( i == 0 )
386+ {
387+ _getAllSyncMethodProvider = sync ;
388+ }
389+
390+ methods . Add ( async ) ;
391+ methods . Add ( sync ) ;
392+ }
351393
352- return [ getAllAsync , _getAllSyncMethodProvider ] ;
394+ return [ .. methods ] ;
353395 }
354396
355397 private MethodProvider [ ] BuildEnumeratorMethods ( )
0 commit comments