Skip to content
Merged
Prev Previous commit
Next Next commit
working in progress.
  • Loading branch information
haiyuazhang committed Sep 15, 2025
commit e672b46e1e41bc48634acfa2f493b276a43b83bb
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,18 @@ private IEnumerable<MethodProvider> BuildMethodsForResource(ResourceClientProvid
// the first method is returning the collection
var collection = resource.ResourceCollection!;
var collectionMethodSignature = resource.FactoryMethodSignature;

var bodyStatement = Return(This.As<ArmResource>().GetCachedClient(new CodeWriterDeclaration("client"), client => New.Instance(collection.Type, client, This.As<ArmResource>().Id())));
var pathFields = collection.PathParameterFields;
var pathParameters = pathFields.Select(f => new ParameterProvider(f.Name.Substring(1), $"The {f.Name.Substring(1)} for the parent resource.", f.Type)).ToList();
collectionMethodSignature = new MethodSignature(
collectionMethodSignature.Name,
collectionMethodSignature.Description,
collectionMethodSignature.Modifiers,
collectionMethodSignature.ReturnType,
collectionMethodSignature.ReturnDescription,
[.. collectionMethodSignature.Parameters, .. pathParameters],
collectionMethodSignature.Attributes);
var pathParameterArgs = pathParameters.Select(p => (ValueExpression)p).ToList();
var bodyStatement = Return(This.As<ArmResource>().GetCachedClient(new CodeWriterDeclaration("client"), client => New.Instance(collection.Type, [client, This.As<ArmResource>().Id(), .. pathParameterArgs])));
yield return new MethodProvider(
collectionMethodSignature,
bodyStatement,
Expand All @@ -233,24 +243,24 @@ private IEnumerable<MethodProvider> BuildMethodsForResource(ResourceClientProvid
if (getAsyncMethod is not null)
{
// we should be sure that this would never be null, but this null check here is just ensuring that we never crash
yield return BuildGetMethod(this, getAsyncMethod, collectionMethodSignature, $"Get{resource.ResourceName}Async");
yield return BuildGetMethod(this, getAsyncMethod, collectionMethodSignature, pathParameters, $"Get{resource.ResourceName}Async");
}

if (getMethod is not null)
{
// we should be sure that this would never be null, but this null check here is just ensuring that we never crash
yield return BuildGetMethod(this, getMethod, collectionMethodSignature, $"Get{resource.ResourceName}");
yield return BuildGetMethod(this, getMethod, collectionMethodSignature, pathParameters, $"Get{resource.ResourceName}");
}

static MethodProvider BuildGetMethod(TypeProvider enclosingType, MethodProvider resourceGetMethod, MethodSignature collectionGetSignature, string methodName)
static MethodProvider BuildGetMethod(TypeProvider enclosingType, MethodProvider resourceGetMethod, MethodSignature collectionGetSignature, List<ParameterProvider> pathParameters, string methodName)
{
var signature = new MethodSignature(
methodName,
resourceGetMethod.Signature.Description,
resourceGetMethod.Signature.Modifiers,
resourceGetMethod.Signature.ReturnType,
resourceGetMethod.Signature.ReturnDescription,
resourceGetMethod.Signature.Parameters,
[.. pathParameters, .. resourceGetMethod.Signature.Parameters],
Attributes: [new AttributeStatement(typeof(ForwardsClientCallsAttribute))]);

return new MethodProvider(
Expand All @@ -265,16 +275,16 @@ static MethodProvider BuildGetMethod(TypeProvider enclosingType, MethodProvider
private MethodProvider BuildResourceServiceMethod(ResourceClientProvider resource, ResourceMethod resourceMethod, bool isAsync)
{
var methodName = ResourceHelpers.GetExtensionOperationMethodName(resourceMethod.Kind, resource.ResourceName, isAsync);

return BuildServiceMethod(resourceMethod.InputMethod, resourceMethod.InputClient, isAsync, methodName);
}

private MethodProvider BuildServiceMethod(InputServiceMethod method, InputClient inputClient, bool isAsync, string? methodName = null)
{
var clientInfo = _clientInfos[inputClient];
List<FieldProvider> pathParameterFields = new List<FieldProvider>();
return method switch
{
InputPagingServiceMethod pagingMethod => new PageableOperationMethodProvider(this, _contextualPath, clientInfo, pagingMethod, isAsync, methodName: methodName),
InputPagingServiceMethod pagingMethod => new PageableOperationMethodProvider(this, _contextualPath, clientInfo, pagingMethod, pathParameterFields, isAsync, methodName),
_ => new ResourceOperationMethodProvider(this, _contextualPath, clientInfo, method, isAsync, methodName: methodName)
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,22 @@ internal class PageableOperationMethodProvider
private readonly string _methodName;
private readonly MethodSignature _signature;
private readonly MethodBodyStatement[] _bodyStatements;
private readonly IReadOnlyList<FieldProvider> _pathParameterFields;

public PageableOperationMethodProvider(
TypeProvider enclosingType,
RequestPathPattern contextualPath,
RestClientInfo restClientInfo,
InputPagingServiceMethod method,
IReadOnlyList<FieldProvider> pathParameterFields,
bool isAsync,
string? methodName = null)
{
_enclosingType = enclosingType;
_contextualPath = contextualPath;
_restClientInfo = restClientInfo;
_method = method;
_pathParameterFields = pathParameterFields;
_convenienceMethod = restClientInfo.RestClientProvider.GetConvenienceMethodByOperation(_method.Operation, isAsync);
_isAsync = isAsync;
_itemType = _convenienceMethod.Signature.ReturnType!.Arguments[0]; // a paging method's return type should be `Pageable<T>` or `AsyncPageable<T>`, so we can safely access the first argument as the item type.
Expand Down Expand Up @@ -94,7 +97,7 @@ protected MethodSignature CreateSignature()
_convenienceMethod.Signature.Modifiers,
returnType,
returnDescription,
OperationMethodParameterHelper.GetOperationMethodParameters(_method, _contextualPath),
OperationMethodParameterHelper.GetOperationMethodParameters(_method, _contextualPath, _enclosingType),
_convenienceMethod.Signature.Attributes,
_convenienceMethod.Signature.GenericArguments,
_convenienceMethod.Signature.GenericParameterConstraints,
Expand All @@ -119,7 +122,8 @@ protected MethodBodyStatement[] BuildBodyStatements()
{
_restClientInfo.RestClient,
};
arguments.AddRange(_contextualPath.PopulateArguments(This.As<ArmResource>().Id(), requestMethod.Signature.Parameters, contextVariable, _signature.Parameters));

arguments.AddRange(_contextualPath.PopulateArguments(This.As<ArmResource>().Id(), requestMethod.Signature.Parameters, contextVariable, _signature.Parameters, _enclosingType));

// Handle ResourceData type conversion if needed
if (_itemResourceClient != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Azure.Generator.Management.Extensions;
using Azure.Generator.Management.Models;
using Azure.Generator.Management.Primitives;
using Azure.Generator.Management.Providers;
using Azure.Generator.Management.Snippets;
using Azure.Generator.Management.Utilities;
using Azure.ResourceManager;
Expand All @@ -17,6 +18,7 @@
using Microsoft.TypeSpec.Generator.Statements;
using System;
using System.Collections.Generic;
using System.Linq;
using static Microsoft.TypeSpec.Generator.Snippets.Snippet;

namespace Azure.Generator.Management.Providers.OperationMethodProviders
Expand Down Expand Up @@ -150,7 +152,7 @@ protected virtual MethodBodyStatement[] BuildBodyStatements()

protected IReadOnlyList<ParameterProvider> GetOperationMethodParameters()
{
return OperationMethodParameterHelper.GetOperationMethodParameters(_serviceMethod, _contextualPath, _isFakeLongRunningOperation);
return OperationMethodParameterHelper.GetOperationMethodParameters(_serviceMethod, _contextualPath, _enclosingType, _isFakeLongRunningOperation);
}

protected virtual MethodSignature CreateSignature()
Expand Down Expand Up @@ -178,8 +180,22 @@ private TryExpression BuildTryExpression()
{
ResourceMethodSnippets.CreateRequestContext(cancellationTokenParameter, out var contextVariable)
};
// Populate arguments for the REST client method call
var arguments = _contextualPath.PopulateArguments(This.As<ArmResource>().Id(), requestMethod.Signature.Parameters, contextVariable, _signature.Parameters);

// Get contextual parameters from the request path pattern
var arguments = _contextualPath.PopulateArguments(This.As<ArmResource>().Id(), requestMethod.Signature.Parameters, contextVariable, _signature.Parameters, _enclosingType);

// // Get path field parameters if the enclosing type is ResourceCollectionClientProvider
// var pathFieldsParameters = new List<ValueExpression>();
// if (_enclosingType is ResourceCollectionClientProvider collectionProvider)
// {
// foreach (var pathField in collectionProvider.PathParameterFields)
// {
// pathFieldsParameters.Add(pathField);
// }
// }

// // Combine contextual parameters and path field parameters into final arguments
// var arguments = parameters.Concat(pathFieldsParameters).ToList();

tryStatements.Add(ResourceMethodSnippets.CreateHttpMessage(_restClientField, requestMethod.Signature.Name, arguments, out var messageVariable));

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.Collections.Generic;
using Azure.Generator.Management.Models;
using Microsoft.TypeSpec.Generator.Input;
using Microsoft.TypeSpec.Generator.Providers;

namespace Azure.Generator.Management.Providers.OperationMethodProviders
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ private ResourceClientProvider(string resourceName, InputModelType model, IReadO

internal ResourceCollectionClientProvider? ResourceCollection { get; private set; }

public RequestPathPattern ContextualPath => _contextualPath;

protected override string BuildName() => ResourceName.EndsWith("Resource") ? ResourceName : $"{ResourceName}Resource";

protected override FormattableString BuildDescription() => $"A class representing a {ResourceName} along with the instance operations that can be performed on it.\nIf you have a {typeof(ResourceIdentifier):C} you can construct a {Type:C} from an instance of {typeof(ArmClient):C} using the GetResource method.\nOtherwise you can get one from its parent resource {TypeOfParentResource:C} using the {FactoryMethodSignature.Name} method.";
Expand Down Expand Up @@ -177,6 +179,13 @@ private MethodSignature BuildFactoryMethodSignature()
}
}

private List<FieldProvider> BuildPathParameterFields()
{
var fields = new List<FieldProvider>();
// Path parameter fields are only needed for ResourceCollectionClientProvider, not ResourceClientProvider
return fields;
}

protected override FieldProvider[] BuildFields()
{
List<FieldProvider> fields = new();
Expand All @@ -187,6 +196,7 @@ protected override FieldProvider[] BuildFields()
}
fields.Add(_dataField);
fields.Add(_resourceTypeField);
fields.AddRange(BuildPathParameterFields());

return fields.ToArray();
}
Expand Down Expand Up @@ -412,8 +422,8 @@ protected override MethodProvider[] BuildMethods()
if (method is InputPagingServiceMethod pagingMethod)
{
// Use PageableOperationMethodProvider for InputPagingServiceMethod
operationMethods.Add(new PageableOperationMethodProvider(this, _contextualPath, restClientInfo, pagingMethod, true, methodName: ResourceHelpers.GetOperationMethodName(methodKind, true)));
operationMethods.Add(new PageableOperationMethodProvider(this, _contextualPath, restClientInfo, pagingMethod, false, methodName: ResourceHelpers.GetOperationMethodName(methodKind, false)));
operationMethods.Add(new PageableOperationMethodProvider(this, _contextualPath, restClientInfo, pagingMethod, BuildPathParameterFields(), true, methodName: ResourceHelpers.GetOperationMethodName(methodKind, true)));
operationMethods.Add(new PageableOperationMethodProvider(this, _contextualPath, restClientInfo, pagingMethod, BuildPathParameterFields(), false, methodName: ResourceHelpers.GetOperationMethodName(methodKind, false)));

continue;
}
Expand All @@ -432,9 +442,9 @@ protected override MethodProvider[] BuildMethods()
else
{
var asyncMethodName = ResourceHelpers.GetOperationMethodName(methodKind, true);
operationMethods.Add(new ResourceOperationMethodProvider(this, _contextualPath, restClientInfo, method, true, asyncMethodName, forceLro: isFakeLro));
operationMethods.Add(new ResourceOperationMethodProvider(this, _contextualPath, restClientInfo, method, true, methodName: asyncMethodName, forceLro: isFakeLro));
var methodName = ResourceHelpers.GetOperationMethodName(methodKind, false);
operationMethods.Add(new ResourceOperationMethodProvider(this, _contextualPath, restClientInfo, method, false, methodName, forceLro: isFakeLro));
operationMethods.Add(new ResourceOperationMethodProvider(this, _contextualPath, restClientInfo, method, false, methodName: methodName, forceLro: isFakeLro));
}
}

Expand All @@ -457,12 +467,12 @@ protected override MethodProvider[] BuildMethods()
var getRestClientInfo = _clientInfos[getClient];

methods.AddRange([
new AddTagMethodProvider(this, _contextualPath, updateMethodProvider, getMethod, updateRestClientInfo, getRestClientInfo, isPatch, true),
new AddTagMethodProvider(this, _contextualPath, updateMethodProvider, getMethod, updateRestClientInfo, getRestClientInfo, isPatch, false),
new SetTagsMethodProvider(this, _contextualPath, updateMethodProvider, getMethod, updateRestClientInfo, getRestClientInfo, isPatch, true),
new SetTagsMethodProvider(this, _contextualPath, updateMethodProvider, getMethod, updateRestClientInfo, getRestClientInfo, isPatch, false),
new RemoveTagMethodProvider(this, _contextualPath, updateMethodProvider, getMethod, updateRestClientInfo, getRestClientInfo, isPatch, true),
new RemoveTagMethodProvider(this, _contextualPath, updateMethodProvider, getMethod, updateRestClientInfo, getRestClientInfo, isPatch, false)
new AddTagMethodProvider(this, _contextualPath, updateMethodProvider, getMethod, BuildPathParameterFields(), updateRestClientInfo, getRestClientInfo, isPatch, true),
new AddTagMethodProvider(this, _contextualPath, updateMethodProvider, getMethod, BuildPathParameterFields(), updateRestClientInfo, getRestClientInfo, isPatch, false),
new SetTagsMethodProvider(this, _contextualPath, updateMethodProvider, getMethod, BuildPathParameterFields(), updateRestClientInfo, getRestClientInfo, isPatch, true),
new SetTagsMethodProvider(this, _contextualPath, updateMethodProvider, getMethod, BuildPathParameterFields(), updateRestClientInfo, getRestClientInfo, isPatch, false),
new RemoveTagMethodProvider(this, _contextualPath, updateMethodProvider, getMethod, BuildPathParameterFields(), updateRestClientInfo, getRestClientInfo, isPatch, true),
new RemoveTagMethodProvider(this, _contextualPath, updateMethodProvider, getMethod, BuildPathParameterFields(), updateRestClientInfo, getRestClientInfo, isPatch, false)
]);
}
}
Expand Down
Loading