Skip to content

Commit b52faaf

Browse files
refactor RestClientInfo stuff for preparation of non-resource operations in extension classes (#51752)
* refactor * fix test cases
1 parent 86f9fd4 commit b52faaf

File tree

9 files changed

+82
-113
lines changed

9 files changed

+82
-113
lines changed

eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Management/src/ManagementInputLibrary.cs

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ private InputNamespace BuildInputNamespaceInternal()
5959

6060
private IReadOnlyDictionary<string, InputServiceMethod> InputMethodsByCrossLanguageDefinitionId => _inputServiceMethodsByCrossLanguageDefinitionId ??= InputNamespace.Clients.SelectMany(c => c.Methods).ToDictionary(m => m.CrossLanguageDefinitionId, m => m);
6161

62-
private IReadOnlyDictionary<InputServiceMethod, InputClient> IntMethodClientMap => _intMethodClientMap ??= ConstructMethodClientMap();
62+
private IReadOnlyDictionary<InputServiceMethod, InputClient> InputMethodClientMap => _intMethodClientMap ??= ConstructMethodClientMap();
6363

6464
private IReadOnlyDictionary<InputModelType, string> ResourceUpdateModelToResourceNameMap => _resourceUpdateModelToResourceNameMap ??= BuildResourceUpdateModelToResourceNameMap();
6565

@@ -69,10 +69,10 @@ private IReadOnlyDictionary<InputModelType, string> BuildResourceUpdateModelToRe
6969

7070
foreach (var (resourceModel, metadata) in ResourceMetadata)
7171
{
72-
var id = metadata.Methods.Where(m => m.Kind == ResourceOperationKind.Update).FirstOrDefault()?.Id;
73-
if (id != null && InputMethodsByCrossLanguageDefinitionId.GetValueOrDefault(id) is { Operation.HttpMethod: "PATCH" } method)
72+
var inputMethod = metadata.Methods.Where(m => m.Kind == ResourceOperationKind.Update).FirstOrDefault()?.InputMethod;
73+
if (inputMethod is { Operation.HttpMethod: "PATCH" } patchMethod)
7474
{
75-
foreach (var parameter in method.Parameters)
75+
foreach (var parameter in patchMethod.Parameters)
7676
{
7777
if (parameter.Location == InputRequestLocation.Body && parameter.Type is InputModelType updateModel && updateModel != resourceModel)
7878
{
@@ -103,7 +103,7 @@ private IReadOnlyDictionary<InputServiceMethod, InputClient> ConstructMethodClie
103103
=> InputMethodsByCrossLanguageDefinitionId.TryGetValue(crossLanguageDefinitionId, out var method) ? method : null;
104104

105105
internal InputClient? GetClientByMethod(InputServiceMethod method)
106-
=> IntMethodClientMap.TryGetValue(method, out var client) ? client : null;
106+
=> InputMethodClientMap.TryGetValue(method, out var client) ? client : null;
107107

108108
internal ResourceMetadata? GetResourceMetadata(InputModelType model)
109109
=> ResourceMetadata.TryGetValue(model, out var metadata) ? metadata : null;
@@ -184,7 +184,13 @@ ResourceMetadata BuildResourceMetadata(InputDecoratorInfo decorator, InputModelT
184184
operationKind = kind;
185185
}
186186
}
187-
methods.Add(new ResourceMethod(id ?? throw new InvalidOperationException("id cannot be null"), operationKind ?? throw new InvalidOperationException("operationKind cannot be null")));
187+
var inputMethod = GetMethodByCrossLanguageDefinitionId(id ?? throw new InvalidOperationException("id cannot be null"));
188+
var inputClient = GetClientByMethod(inputMethod ?? throw new InvalidOperationException($"cannot find InputServiceMethod {id}"));
189+
methods.Add(
190+
new ResourceMethod(
191+
operationKind ?? throw new InvalidOperationException("operationKind cannot be null"),
192+
inputMethod,
193+
inputClient ?? throw new InvalidOperationException($"cannot find method {inputMethod.CrossLanguageDefinitionId}'s client")));
188194
}
189195
}
190196

@@ -198,16 +204,6 @@ ResourceMetadata BuildResourceMetadata(InputDecoratorInfo decorator, InputModelT
198204
resourceName = resourceNameData.ToObjectFromJson<string>();
199205
}
200206

201-
var methodToClientMap = new Dictionary<string, InputClient>();
202-
foreach (var method in methods)
203-
{
204-
var inputClient = GetClientByMethod(GetMethodByCrossLanguageDefinitionId(method.Id)!);
205-
if (inputClient != null)
206-
{
207-
methodToClientMap[method.Id] = inputClient;
208-
}
209-
}
210-
211207
// TODO -- I know we should never throw the exception, but here we just put it here and refine it later
212208
return new(
213209
resourceIdPattern ?? throw new InvalidOperationException("resourceIdPattern cannot be null"),
@@ -216,8 +212,7 @@ ResourceMetadata BuildResourceMetadata(InputDecoratorInfo decorator, InputModelT
216212
methods,
217213
singletonResourceName,
218214
parentResource,
219-
resourceName ?? throw new InvalidOperationException("resourceName cannot be null"),
220-
methodToClientMap);
215+
resourceName ?? throw new InvalidOperationException("resourceName cannot be null"));
221216
}
222217
}
223218

eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Management/src/Models/ResourceMetadata.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Licensed under the MIT License.
33

44
using System.Collections.Generic;
5-
using Microsoft.TypeSpec.Generator.Input;
65

76
namespace Azure.Generator.Management.Models
87
{
@@ -13,6 +12,5 @@ internal record ResourceMetadata(
1312
IReadOnlyList<ResourceMethod> Methods,
1413
string? SingletonResourceName,
1514
string? ParentResourceId,
16-
string ResourceName,
17-
IReadOnlyDictionary<string, InputClient> MethodToClientMap);
15+
string ResourceName);
1816
}
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

4+
using Microsoft.TypeSpec.Generator.Input;
5+
46
namespace Azure.Generator.Management.Models
57
{
6-
internal record ResourceMethod(string Id, ResourceOperationKind Kind);
8+
internal record ResourceMethod(ResourceOperationKind Kind, InputServiceMethod InputMethod, InputClient InputClient);
79
}

eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Management/src/Models/RestClientInfo.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,11 @@ namespace Azure.Generator.Management.Models
99
/// <summary>
1010
/// Record to combine client provider and related field providers
1111
/// </summary>
12-
internal record RestClientInfo(ClientProvider RestClientProvider, FieldProvider RestClientField, FieldProvider DiagnosticsField);
12+
internal record RestClientInfo(ClientProvider RestClientProvider, FieldProvider RestClientField, PropertyProvider? RestClientProperty, FieldProvider DiagnosticsField, PropertyProvider? DiagnosticProperty)
13+
{
14+
internal RestClientInfo(ClientProvider restClientProvider, FieldProvider restClientField, FieldProvider diagnosticsField)
15+
: this(restClientProvider, restClientField, null, diagnosticsField, null)
16+
{
17+
}
18+
}
1319
}

eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Management/src/Providers/ResourceClientProvider.cs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ internal static ResourceClientProvider Create(InputModelType model, ResourceMeta
4848
return resource;
4949
}
5050

51-
private IEnumerable<(ResourceOperationKind, InputServiceMethod)> _resourceServiceMethods;
51+
private IReadOnlyList<ResourceMethod> _resourceServiceMethods;
5252

5353
private readonly FieldProvider _dataField;
5454
private readonly FieldProvider _resourceTypeField;
@@ -69,8 +69,7 @@ private ResourceClientProvider(string resourceName, InputModelType model, Resour
6969

7070
ResourceName = resourceName;
7171

72-
// We should be able to assume that all operations in the resource client are for the same resource
73-
_resourceServiceMethods = resourceMetadata.Methods.Select(m => (m.Kind, ManagementClientGenerator.Instance.InputLibrary.GetMethodByCrossLanguageDefinitionId(m.Id)!));
72+
_resourceServiceMethods = resourceMetadata.Methods;
7473
ResourceData = ManagementClientGenerator.Instance.TypeFactory.CreateModel(model)!;
7574

7675
// Initialize client info dictionary using extension method
@@ -93,7 +92,8 @@ private ResourceClientProvider(string resourceName, InputModelType model, Resour
9392

9493
internal ModelProvider ResourceData { get; }
9594
internal string ResourceName { get; }
96-
internal IEnumerable<(ResourceOperationKind Kind, InputServiceMethod Method)> ResourceServiceMethods => _resourceServiceMethods;
95+
// TODO -- we should not need to expose this.
96+
internal IEnumerable<ResourceMethod> ResourceServiceMethods => _resourceServiceMethods;
9797

9898
internal string? SingletonResourceName => _resourceMetadata.SingletonResourceName;
9999

@@ -233,7 +233,7 @@ private ConstructorProvider BuildResourceIdentifierConstructor()
233233
// TODO -- this is temporary. We should change this to find the corresponding parameters in ContextualParameters after it is refactored to consume parent resources.
234234
private CSharpType GetPathParameterType(string parameterName)
235235
{
236-
foreach (var (kind, method) in _resourceServiceMethods)
236+
foreach (var (kind, method, _) in _resourceServiceMethods)
237237
{
238238
if (!kind.IsCrudKind())
239239
{
@@ -319,7 +319,7 @@ protected override MethodProvider[] BuildMethods()
319319
var operationMethods = new List<MethodProvider>();
320320
UpdateOperationMethodProvider? updateMethodProvider = null;
321321

322-
foreach (var (methodKind, method) in _resourceServiceMethods)
322+
foreach (var (methodKind, method, inputClient) in _resourceServiceMethods)
323323
{
324324
// exclude the List operations for resource and Create operations for non-singleton resources (they will be in ResourceCollection)
325325
if (methodKind == ResourceOperationKind.List || (!IsSingleton && methodKind == ResourceOperationKind.Create))
@@ -330,7 +330,7 @@ protected override MethodProvider[] BuildMethods()
330330
var isFakeLro = ResourceHelpers.ShouldMakeLro(methodKind);
331331

332332
// Get the appropriate rest client for this specific method
333-
var restClientInfo = _resourceMetadata.GetRestClientForServiceMethod(method, _clientInfos);
333+
var restClientInfo = _clientInfos[inputClient];
334334

335335
var convenienceMethod = restClientInfo.RestClientProvider.GetConvenienceMethodByOperation(method.Operation, false);
336336
var asyncConvenienceMethod = restClientInfo.RestClientProvider.GetConvenienceMethodByOperation(method.Operation, true);
@@ -378,8 +378,7 @@ protected override MethodProvider[] BuildMethods()
378378
var updateMethod = _resourceMetadata.Methods.FirstOrDefault(m => m.Kind == ResourceOperationKind.Update || m.Kind == ResourceOperationKind.Create);
379379
if (updateMethod is not null)
380380
{
381-
var updateRestClientInfo = _resourceMetadata.GetRestClientForServiceMethod(
382-
ManagementClientGenerator.Instance.InputLibrary.GetMethodByCrossLanguageDefinitionId(updateMethod.Id)!, _clientInfos);
381+
var updateRestClientInfo = _clientInfos[updateMethod.InputClient];
383382

384383
methods.AddRange([
385384
new AddTagMethodProvider(this, updateMethodProvider, updateRestClientInfo, true),

eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Management/src/Providers/ResourceCollectionClientProvider.cs

Lines changed: 31 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
using System.Collections;
2121
using System.Collections.Generic;
2222
using System.IO;
23-
using System.Runtime.CompilerServices;
2423
using static Microsoft.TypeSpec.Generator.Snippets.Snippet;
2524

2625
namespace Azure.Generator.Management.Providers
@@ -30,9 +29,9 @@ internal sealed class ResourceCollectionClientProvider : TypeProvider
3029
private readonly ResourceMetadata _resourceMetadata;
3130

3231
private readonly ResourceClientProvider _resource;
33-
private readonly InputServiceMethod? _getAll;
34-
private readonly InputServiceMethod? _create;
35-
private readonly InputServiceMethod? _get;
32+
private readonly ResourceMethod? _getAll;
33+
private readonly ResourceMethod? _create;
34+
private readonly ResourceMethod? _get;
3635

3736
// Support for multiple rest clients
3837
private readonly Dictionary<InputClient, RestClientInfo> _clientInfos;
@@ -79,9 +78,9 @@ private static RequestPathPattern GetContextualRequestPattern(ResourceMetadata r
7978

8079
private static void InitializeMethods(
8180
ResourceMetadata resourceMetadata,
82-
ref InputServiceMethod? getMethod,
83-
ref InputServiceMethod? createMethod,
84-
ref InputServiceMethod? getAllMethod)
81+
ref ResourceMethod? getMethod,
82+
ref ResourceMethod? createMethod,
83+
ref ResourceMethod? getAllMethod)
8584
{
8685
foreach (var method in resourceMetadata.Methods)
8786
{
@@ -93,32 +92,16 @@ private static void InitializeMethods(
9392
switch (method.Kind)
9493
{
9594
case ResourceOperationKind.Get:
96-
AssignMethodKind(ref getMethod, resourceMetadata.ResourceIdPattern, method);
95+
getMethod = method;
9796
break;
9897
case ResourceOperationKind.List:
99-
AssignMethodKind(ref getAllMethod, resourceMetadata.ResourceIdPattern, method);
98+
getAllMethod = method;
10099
break;
101100
case ResourceOperationKind.Create:
102-
AssignMethodKind(ref createMethod, resourceMetadata.ResourceIdPattern, method);
101+
createMethod = method;
103102
break;
104103
}
105104
}
106-
107-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
108-
static void AssignMethodKind(ref InputServiceMethod? method, string resourceIdPattern, ResourceMethod resourceMethod)
109-
{
110-
if (method is not null)
111-
{
112-
ManagementClientGenerator.Instance.Emitter.ReportDiagnostic(
113-
"general-warning", // TODO -- in the near future, we should have a resource-specific diagnostic ID
114-
$"Resource {resourceIdPattern} has multiple '{resourceMethod.Kind}' methods."
115-
);
116-
}
117-
else
118-
{
119-
method = ManagementClientGenerator.Instance.InputLibrary.GetMethodByCrossLanguageDefinitionId(resourceMethod.Id);
120-
}
121-
}
122105
}
123106

124107
public ResourceClientProvider Resource => _resource;
@@ -262,64 +245,64 @@ private MethodProvider[] BuildEnumeratorMethods()
262245

263246
private List<MethodProvider> BuildCreateOrUpdateMethods()
264247
{
265-
var result = new List<MethodProvider>();
266248
if (_create is null)
267249
{
268-
return result;
250+
return [];
269251
}
270252

271-
var restClientInfo = _resourceMetadata.GetRestClientForServiceMethod(_create, _clientInfos);
253+
var result = new List<MethodProvider>();
254+
var restClientInfo = _clientInfos[_create.InputClient];
272255
foreach (var isAsync in new List<bool> { true, false })
273256
{
274-
var convenienceMethod = restClientInfo.RestClientProvider.GetConvenienceMethodByOperation(_create!.Operation, isAsync);
257+
var convenienceMethod = restClientInfo.RestClientProvider.GetConvenienceMethodByOperation(_create.InputMethod.Operation, isAsync);
275258
var methodName = ResourceHelpers.GetOperationMethodName(ResourceOperationKind.Create, isAsync);
276-
result.Add(new ResourceOperationMethodProvider(this, ContextualPath, restClientInfo, _create, isAsync, methodName, forceLro: true));
259+
result.Add(new ResourceOperationMethodProvider(this, ContextualPath, restClientInfo, _create.InputMethod, isAsync, methodName: methodName, forceLro: true));
277260
}
278261

279262
return result;
280263
}
281264

282-
private MethodProvider BuildGetAllMethod(InputServiceMethod getAll, bool isAsync)
265+
private MethodProvider BuildGetAllMethod(ResourceMethod getAll, bool isAsync)
283266
{
284-
var restClientInfo = _resourceMetadata.GetRestClientForServiceMethod(getAll, _clientInfos);
285-
return getAll switch
267+
var restClientInfo = _clientInfos[getAll.InputClient];
268+
return getAll.InputMethod switch
286269
{
287270
InputPagingServiceMethod pagingGetAll => new PageableOperationMethodProvider(this, ContextualPath, restClientInfo, pagingGetAll, isAsync, ResourceOperationKind.List),
288-
_ => new ResourceOperationMethodProvider(this, ContextualPath, restClientInfo, getAll, isAsync, ResourceHelpers.GetOperationMethodName(ResourceOperationKind.List, isAsync))
271+
_ => new ResourceOperationMethodProvider(this, ContextualPath, restClientInfo, getAll.InputMethod, isAsync, ResourceHelpers.GetOperationMethodName(ResourceOperationKind.List, isAsync))
289272
};
290273
}
291274

292275
private List<MethodProvider> BuildGetMethods()
293276
{
294-
var result = new List<MethodProvider>();
295277
if (_get is null)
296278
{
297-
return result;
279+
return [];
298280
}
299281

300-
var restClientInfo = _resourceMetadata.GetRestClientForServiceMethod(_get, _clientInfos);
282+
var result = new List<MethodProvider>();
283+
var restClientInfo = _clientInfos[_get.InputClient];
301284
foreach (var isAsync in new List<bool> { true, false })
302285
{
303-
var convenienceMethod = restClientInfo.RestClientProvider.GetConvenienceMethodByOperation(_get!.Operation, isAsync);
304-
result.Add(new ResourceOperationMethodProvider(this, ContextualPath, restClientInfo, _get, isAsync));
286+
var convenienceMethod = restClientInfo.RestClientProvider.GetConvenienceMethodByOperation(_get.InputMethod.Operation, isAsync);
287+
result.Add(new ResourceOperationMethodProvider(this, ContextualPath, restClientInfo, _get.InputMethod, isAsync));
305288
}
306289

307290
return result;
308291
}
309292

310293
private List<MethodProvider> BuildExistsMethods()
311294
{
312-
var result = new List<MethodProvider>();
313295
if (_get is null)
314296
{
315-
return result;
297+
return [];
316298
}
317299

318-
var restClientInfo = _resourceMetadata.GetRestClientForServiceMethod(_get, _clientInfos);
300+
var result = new List<MethodProvider>();
301+
var restClientInfo = _clientInfos[_get.InputClient];
319302
foreach (var isAsync in new List<bool> { true, false })
320303
{
321-
var convenienceMethod = restClientInfo.RestClientProvider.GetConvenienceMethodByOperation(_get!.Operation, isAsync);
322-
var existsMethodProvider = new ExistsOperationMethodProvider(this, restClientInfo, _get, isAsync);
304+
var convenienceMethod = restClientInfo.RestClientProvider.GetConvenienceMethodByOperation(_get.InputMethod.Operation, isAsync);
305+
var existsMethodProvider = new ExistsOperationMethodProvider(this, restClientInfo, _get.InputMethod, isAsync);
323306
result.Add(existsMethodProvider);
324307
}
325308

@@ -334,11 +317,11 @@ private List<MethodProvider> BuildGetIfExistsMethods()
334317
return result;
335318
}
336319

337-
var restClientInfo = _resourceMetadata.GetRestClientForServiceMethod(_get, _clientInfos);
320+
var restClientInfo = _clientInfos[_get.InputClient];
338321
foreach (var isAsync in new List<bool> { true, false })
339322
{
340-
var convenienceMethod = restClientInfo.RestClientProvider.GetConvenienceMethodByOperation(_get!.Operation, isAsync);
341-
var getIfExistsMethodProvider = new GetIfExistsOperationMethodProvider(this, restClientInfo, _get, isAsync);
323+
var convenienceMethod = restClientInfo.RestClientProvider.GetConvenienceMethodByOperation(_get.InputMethod.Operation, isAsync);
324+
var getIfExistsMethodProvider = new GetIfExistsOperationMethodProvider(this, restClientInfo, _get.InputMethod, isAsync);
342325
result.Add(getIfExistsMethodProvider);
343326
}
344327

0 commit comments

Comments
 (0)