2424using System . Diagnostics ;
2525using System . IO ;
2626using System . Linq ;
27+ using System . Text ;
2728using static Microsoft . TypeSpec . Generator . Snippets . Snippet ;
2829using OperationKind = Azure . Generator . Management . Models . OperationKind ;
2930
@@ -53,13 +54,19 @@ public static ResourceClientProvider Create(InputModelType model, ResourceMetada
5354 private bool _hasGetMethod = false ;
5455 private bool _shouldGenerateTagMethods = false ;
5556
57+ private RequestPath _requestPath ;
58+ private ResourceMetadata _resourceMetadata ;
59+ private InputOperation _inputOperationForRequestPath ;
60+
5661 protected ClientProvider _restClientProvider ;
5762 protected FieldProvider _clientDiagnosticsField ;
5863 protected FieldProvider _clientField ;
5964
6065 private protected ResourceClientProvider ( InputModelType model , ResourceMetadata resourceMetadata )
6166 {
6267 IsSingleton = resourceMetadata . IsSingleton ;
68+ _resourceMetadata = resourceMetadata ;
69+ _inputOperationForRequestPath = ManagementClientGenerator . Instance . InputLibrary . GetMethodByCrossLanguageDefinitionId ( _resourceMetadata . Methods . First ( ) . Id ) ! . Operation ;
6370 ResourceScope = resourceMetadata . ResourceScope ;
6471 var resourceType = resourceMetadata . ResourceType ;
6572 _hasGetMethod = resourceMetadata . Methods . Any ( m => m . Kind == OperationKind . Get ) ;
@@ -70,15 +77,15 @@ private protected ResourceClientProvider(InputModelType model, ResourceMetadata
7077 SpecName = model . Name . ToIdentifierName ( ) ;
7178
7279 // We should be able to assume that all operations in the resource client are for the same resource
73- var requestPath = new RequestPath ( ManagementClientGenerator . Instance . InputLibrary . GetMethodByCrossLanguageDefinitionId ( resourceMetadata . Methods . First ( ) . Id ) ! . Operation . Path ) ;
80+ _requestPath = new RequestPath ( _inputOperationForRequestPath . Path ) ;
7481 _resourceServiceMethods = resourceMetadata . Methods . Select ( m => ( m . Kind , ManagementClientGenerator . Instance . InputLibrary . GetMethodByCrossLanguageDefinitionId ( m . Id ) ! ) ) ;
7582 ResourceData = ManagementClientGenerator . Instance . TypeFactory . CreateModel ( model ) ! ;
7683
7784 // TODO: handle multiple clients in the future, for now we assume that there is only one client for the resource.
7885 var inputClients = resourceMetadata . Methods . Select ( m => ManagementClientGenerator . Instance . InputLibrary . GetClientByMethod ( ManagementClientGenerator . Instance . InputLibrary . GetMethodByCrossLanguageDefinitionId ( m . Id ) ! ) ! ) . Distinct ( ) ;
7986 _restClientProvider = ManagementClientGenerator . Instance . TypeFactory . CreateClient ( inputClients . First ( ) ) ! ;
8087
81- ContextualParameters = GetContextualParameters ( requestPath ) ;
88+ ContextualParameters = GetContextualParameters ( _requestPath ) ;
8289
8390 _dataField = new FieldProvider ( FieldModifiers . Private | FieldModifiers . ReadOnly , ResourceData . Type , "_data" , this ) ;
8491 _clientDiagnosticsField = new FieldProvider ( FieldModifiers . Private | FieldModifiers . ReadOnly , typeof ( ClientDiagnostics ) , $ "_{ SpecName . ToLower ( ) } ClientDiagnostics", this ) ;
@@ -89,6 +96,8 @@ private protected ResourceClientProvider(InputModelType model, ResourceMetadata
8996
9097 internal ResourceCollectionClientProvider ? ResourceCollection { get ; private set ; }
9198
99+ private InputOperation InputOperationForRequestPath => _inputOperationForRequestPath ;
100+
92101 private IReadOnlyList < string > GetContextualParameters ( string contextualRequestPath )
93102 {
94103 var contextualParametersList = new List < string > ( ) ;
@@ -225,6 +234,65 @@ protected MethodProvider BuildValidateResourceIdMethod()
225234 return new MethodProvider ( signature , bodyStatements , this ) ;
226235 }
227236
237+ private CSharpType GetPathParameterType ( string parameterName )
238+ {
239+ var operation = InputOperationForRequestPath ;
240+
241+ var operationParameter = operation . Parameters . First ( p => p . Name . Equals ( parameterName , StringComparison . OrdinalIgnoreCase ) ) ;
242+
243+ var csharpType = ManagementClientGenerator . Instance . TypeFactory . CreateCSharpType ( operationParameter . Type ) ?? throw new InvalidOperationException ( $ "Could not create C# type for parameter '{ parameterName } ' with type '{ operationParameter . Type } ' in operation '{ operation . Name } '.") ;
244+ return parameterName switch
245+ {
246+ "subscriptionId" when csharpType . Equals ( typeof ( Guid ) ) => typeof ( string ) ,
247+ // Cases will be added later
248+ _ => csharpType
249+ } ;
250+ }
251+
252+ private MethodProvider BuildCreateResourceIdentifierMethod ( )
253+ {
254+ var parameters = new List < ParameterProvider > ( ) ;
255+ var formatBuilder = new StringBuilder ( ) ;
256+ var refCount = 0 ;
257+
258+ foreach ( var segment in _requestPath )
259+ {
260+ bool isConstant = RequestPath . IsSegmentConstant ( segment ) ;
261+
262+ if ( isConstant )
263+ {
264+ formatBuilder . Append ( $ "/{ segment } ") ;
265+ }
266+ else
267+ {
268+ if ( formatBuilder . Length > 0 )
269+ {
270+ formatBuilder . Append ( '/' ) ;
271+ }
272+ var trimmed = RequestPath . TrimSegment ( segment ) ;
273+ var parameter = new ParameterProvider ( trimmed , $ "The { trimmed } ", GetPathParameterType ( trimmed ) ) ;
274+ parameters . Add ( parameter ) ;
275+ formatBuilder . Append ( $ "{{{refCount++}}}") ;
276+ }
277+ }
278+
279+ var signature = new MethodSignature (
280+ "CreateResourceIdentifier" ,
281+ $ "Generate the resource identifier for this resource.",
282+ MethodSignatureModifiers . Public | MethodSignatureModifiers . Static ,
283+ typeof ( ResourceIdentifier ) ,
284+ null ,
285+ parameters ) ;
286+
287+ var bodyStatements = new MethodBodyStatement [ ]
288+ {
289+ Declare ( "resourceId" , typeof ( string ) , new FormattableStringExpression ( formatBuilder . ToString ( ) , parameters . Select ( p => p . AsExpression ( ) ) . ToArray ( ) ) , out var resourceIdVar ) ,
290+ Return ( New . Instance ( typeof ( ResourceIdentifier ) , resourceIdVar ) )
291+ } ;
292+
293+ return new MethodProvider ( signature , bodyStatements , this ) ;
294+ }
295+
228296 protected virtual ScopedApi < ResourceType > ResourceTypeExpression => _resourceTypeField . As < ResourceType > ( ) ;
229297
230298 protected internal virtual CSharpType ResourceClientCSharpType => Type ;
@@ -283,6 +351,7 @@ protected override MethodProvider[] BuildMethods()
283351
284352 var methods = new List < MethodProvider >
285353 {
354+ BuildCreateResourceIdentifierMethod ( ) ,
286355 BuildValidateResourceIdMethod ( )
287356 } ;
288357 methods . AddRange ( operationMethods ) ;
0 commit comments