Skip to content

Commit

Permalink
fix(dpg): duplicated result retrieval methods when polling operation …
Browse files Browse the repository at this point in the history
…is referenced multiple times (#5116)

- when writing result retrieval methods, avoid duplicated instances
- add test case which should be added into cadl-ranch later

fix #5113
  • Loading branch information
archerzz authored Oct 17, 2024
1 parent ab56c7d commit ad47bb7
Show file tree
Hide file tree
Showing 12 changed files with 2,264 additions and 545 deletions.
2 changes: 1 addition & 1 deletion src/AutoRest.CSharp/LowLevel/Generation/DpgClientWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ public void WriteClient()

private void WriteLongRunningResultRetrievalMethods()
{
foreach (var method in _client.ClientMethods.Select(c => c.LongRunningResultRetrievalMethod).WhereNotNull())
foreach (var method in _client.ClientMethods.Select(c => c.LongRunningResultRetrievalMethod).WhereNotNull().Distinct())
{
_writer.Line();
WriteLroResultRetrievalMethod(method);
Expand Down
37 changes: 37 additions & 0 deletions test/TestProjects/FirstTest-TypeSpec/FirstTest-TypeSpec.tsp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ using TypeSpec.Versioning;
using Azure.Core;
using Azure.ClientGenerator.Core;
using Azure.ResourceManager;
using Azure.Core.Traits;

@versioned(Versions)
@service({
Expand Down Expand Up @@ -569,3 +570,39 @@ model AzureLocationModel
@put
@convenientAPI(true)
op azureLocationOp(@query location: azureLocation, @header regenLocation: azureLocation, @body body?: AzureLocationModel): void;

// TODO: remove below after duplicated polling operation case is added into cadl-ranch
@resource("resources")
model Resource {
@visibility("read")
id: string;

@key
@visibility("read")
name: string;

type: string;
}

model ExportedResource {
id: string;
name: string;
}

model ExportParams {
@query
projectFileVersion?: string;
}
interface ResourceOperations
extends Azure.Core.ResourceOperations<NoRepeatableRequests &
NoConditionalRequests &
NoClientRequestId> {}

@route("/lro")
interface VersioningOp {
@pollingOperation(ResourceOperations.GetResourceOperationStatus<Resource, ExportedResource>)
export is ResourceOperations.LongRunningResourceAction<Resource, ExportParams, ExportedResource>;

@pollingOperation(ResourceOperations.GetResourceOperationStatus<Resource, ExportedResource>)
exportW is ResourceOperations.LongRunningResourceAction<Resource, ExportParams, ExportedResource>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<?xml version="1.0" encoding="utf-8"?>
<doc>
<members>
<member name="ExportAsync(WaitUntil,string,string,RequestContext)">
<example>
This sample shows how to call ExportAsync and parse the result.
<code><![CDATA[
Uri endpoint = new Uri("<https://my-service.azure.com>");
VersioningOp client = new FirstTestTypeSpecClient(endpoint).GetVersioningOpClient(apiVersion: "2022-05-15-preview");
Operation<BinaryData> operation = await client.ExportAsync(WaitUntil.Completed, "<name>", null, null);
BinaryData responseData = operation.Value;
JsonElement result = JsonDocument.Parse(responseData.ToStream()).RootElement;
Console.WriteLine(result.GetProperty("id").ToString());
Console.WriteLine(result.GetProperty("name").ToString());
]]></code>
This sample shows how to call ExportAsync with all parameters and parse the result.
<code><![CDATA[
Uri endpoint = new Uri("<https://my-service.azure.com>");
VersioningOp client = new FirstTestTypeSpecClient(endpoint).GetVersioningOpClient(apiVersion: "2022-05-15-preview");
Operation<BinaryData> operation = await client.ExportAsync(WaitUntil.Completed, "<name>", "<projectFileVersion>", null);
BinaryData responseData = operation.Value;
JsonElement result = JsonDocument.Parse(responseData.ToStream()).RootElement;
Console.WriteLine(result.GetProperty("id").ToString());
Console.WriteLine(result.GetProperty("name").ToString());
]]></code></example>
</member>
<member name="Export(WaitUntil,string,string,RequestContext)">
<example>
This sample shows how to call Export and parse the result.
<code><![CDATA[
Uri endpoint = new Uri("<https://my-service.azure.com>");
VersioningOp client = new FirstTestTypeSpecClient(endpoint).GetVersioningOpClient(apiVersion: "2022-05-15-preview");
Operation<BinaryData> operation = client.Export(WaitUntil.Completed, "<name>", null, null);
BinaryData responseData = operation.Value;
JsonElement result = JsonDocument.Parse(responseData.ToStream()).RootElement;
Console.WriteLine(result.GetProperty("id").ToString());
Console.WriteLine(result.GetProperty("name").ToString());
]]></code>
This sample shows how to call Export with all parameters and parse the result.
<code><![CDATA[
Uri endpoint = new Uri("<https://my-service.azure.com>");
VersioningOp client = new FirstTestTypeSpecClient(endpoint).GetVersioningOpClient(apiVersion: "2022-05-15-preview");
Operation<BinaryData> operation = client.Export(WaitUntil.Completed, "<name>", "<projectFileVersion>", null);
BinaryData responseData = operation.Value;
JsonElement result = JsonDocument.Parse(responseData.ToStream()).RootElement;
Console.WriteLine(result.GetProperty("id").ToString());
Console.WriteLine(result.GetProperty("name").ToString());
]]></code></example>
</member>
<member name="ExportWAsync(WaitUntil,string,string,RequestContext)">
<example>
This sample shows how to call ExportWAsync and parse the result.
<code><![CDATA[
Uri endpoint = new Uri("<https://my-service.azure.com>");
VersioningOp client = new FirstTestTypeSpecClient(endpoint).GetVersioningOpClient(apiVersion: "2022-05-15-preview");
Operation<BinaryData> operation = await client.ExportWAsync(WaitUntil.Completed, "<name>", null, null);
BinaryData responseData = operation.Value;
JsonElement result = JsonDocument.Parse(responseData.ToStream()).RootElement;
Console.WriteLine(result.GetProperty("id").ToString());
Console.WriteLine(result.GetProperty("name").ToString());
]]></code>
This sample shows how to call ExportWAsync with all parameters and parse the result.
<code><![CDATA[
Uri endpoint = new Uri("<https://my-service.azure.com>");
VersioningOp client = new FirstTestTypeSpecClient(endpoint).GetVersioningOpClient(apiVersion: "2022-05-15-preview");
Operation<BinaryData> operation = await client.ExportWAsync(WaitUntil.Completed, "<name>", "<projectFileVersion>", null);
BinaryData responseData = operation.Value;
JsonElement result = JsonDocument.Parse(responseData.ToStream()).RootElement;
Console.WriteLine(result.GetProperty("id").ToString());
Console.WriteLine(result.GetProperty("name").ToString());
]]></code></example>
</member>
<member name="ExportW(WaitUntil,string,string,RequestContext)">
<example>
This sample shows how to call ExportW and parse the result.
<code><![CDATA[
Uri endpoint = new Uri("<https://my-service.azure.com>");
VersioningOp client = new FirstTestTypeSpecClient(endpoint).GetVersioningOpClient(apiVersion: "2022-05-15-preview");
Operation<BinaryData> operation = client.ExportW(WaitUntil.Completed, "<name>", null, null);
BinaryData responseData = operation.Value;
JsonElement result = JsonDocument.Parse(responseData.ToStream()).RootElement;
Console.WriteLine(result.GetProperty("id").ToString());
Console.WriteLine(result.GetProperty("name").ToString());
]]></code>
This sample shows how to call ExportW with all parameters and parse the result.
<code><![CDATA[
Uri endpoint = new Uri("<https://my-service.azure.com>");
VersioningOp client = new FirstTestTypeSpecClient(endpoint).GetVersioningOpClient(apiVersion: "2022-05-15-preview");
Operation<BinaryData> operation = client.ExportW(WaitUntil.Completed, "<name>", "<projectFileVersion>", null);
BinaryData responseData = operation.Value;
JsonElement result = JsonDocument.Parse(responseData.ToStream()).RootElement;
Console.WriteLine(result.GetProperty("id").ToString());
Console.WriteLine(result.GetProperty("name").ToString());
]]></code></example>
</member>
</members>
</doc>

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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

// <auto-generated/>

#nullable disable

using System;
using System.ClientModel.Primitives;
using System.Collections.Generic;
using System.Text.Json;
using Azure;
using Azure.Core;

namespace FirstTestTypeSpec.Models
{
internal partial class ExportedResource : IUtf8JsonSerializable, IJsonModel<ExportedResource>
{
void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) => ((IJsonModel<ExportedResource>)this).Write(writer, ModelSerializationExtensions.WireOptions);

void IJsonModel<ExportedResource>.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options)
{
var format = options.Format == "W" ? ((IPersistableModel<ExportedResource>)this).GetFormatFromOptions(options) : options.Format;
if (format != "J")
{
throw new FormatException($"The model {nameof(ExportedResource)} does not support writing '{format}' format.");
}

writer.WriteStartObject();
writer.WritePropertyName("id"u8);
writer.WriteStringValue(Id);
writer.WritePropertyName("name"u8);
writer.WriteStringValue(Name);
if (options.Format != "W" && _serializedAdditionalRawData != null)
{
foreach (var item in _serializedAdditionalRawData)
{
writer.WritePropertyName(item.Key);
#if NET6_0_OR_GREATER
writer.WriteRawValue(item.Value);
#else
using (JsonDocument document = JsonDocument.Parse(item.Value))
{
JsonSerializer.Serialize(writer, document.RootElement);
}
#endif
}
}
writer.WriteEndObject();
}

ExportedResource IJsonModel<ExportedResource>.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options)
{
var format = options.Format == "W" ? ((IPersistableModel<ExportedResource>)this).GetFormatFromOptions(options) : options.Format;
if (format != "J")
{
throw new FormatException($"The model {nameof(ExportedResource)} does not support reading '{format}' format.");
}

using JsonDocument document = JsonDocument.ParseValue(ref reader);
return DeserializeExportedResource(document.RootElement, options);
}

internal static ExportedResource DeserializeExportedResource(JsonElement element, ModelReaderWriterOptions options = null)
{
options ??= ModelSerializationExtensions.WireOptions;

if (element.ValueKind == JsonValueKind.Null)
{
return null;
}
string id = default;
string name = default;
IDictionary<string, BinaryData> serializedAdditionalRawData = default;
Dictionary<string, BinaryData> rawDataDictionary = new Dictionary<string, BinaryData>();
foreach (var property in element.EnumerateObject())
{
if (property.NameEquals("id"u8))
{
id = property.Value.GetString();
continue;
}
if (property.NameEquals("name"u8))
{
name = property.Value.GetString();
continue;
}
if (options.Format != "W")
{
rawDataDictionary.Add(property.Name, BinaryData.FromString(property.Value.GetRawText()));
}
}
serializedAdditionalRawData = rawDataDictionary;
return new ExportedResource(id, name, serializedAdditionalRawData);
}

BinaryData IPersistableModel<ExportedResource>.Write(ModelReaderWriterOptions options)
{
var format = options.Format == "W" ? ((IPersistableModel<ExportedResource>)this).GetFormatFromOptions(options) : options.Format;

switch (format)
{
case "J":
return ModelReaderWriter.Write(this, options);
default:
throw new FormatException($"The model {nameof(ExportedResource)} does not support writing '{options.Format}' format.");
}
}

ExportedResource IPersistableModel<ExportedResource>.Create(BinaryData data, ModelReaderWriterOptions options)
{
var format = options.Format == "W" ? ((IPersistableModel<ExportedResource>)this).GetFormatFromOptions(options) : options.Format;

switch (format)
{
case "J":
{
using JsonDocument document = JsonDocument.Parse(data);
return DeserializeExportedResource(document.RootElement, options);
}
default:
throw new FormatException($"The model {nameof(ExportedResource)} does not support reading '{options.Format}' format.");
}
}

string IPersistableModel<ExportedResource>.GetFormatFromOptions(ModelReaderWriterOptions options) => "J";

/// <summary> Deserializes the model from a raw response. </summary>
/// <param name="response"> The response to deserialize the model from. </param>
internal static ExportedResource FromResponse(Response response)
{
using var document = JsonDocument.Parse(response.Content);
return DeserializeExportedResource(document.RootElement);
}

/// <summary> Convert into a <see cref="RequestContent"/>. </summary>
internal virtual RequestContent ToRequestContent()
{
var content = new Utf8JsonRequestContent();
content.JsonWriter.WriteObjectValue(this, ModelSerializationExtensions.WireOptions);
return content;
}
}
}
Loading

0 comments on commit ad47bb7

Please sign in to comment.