Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Response abstraction #4438

Merged
merged 45 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
40ecf45
init
live1206 Sep 13, 2024
7da2225
Merge branch 'main' into response-abstraction
live1206 Sep 13, 2024
d170d95
cleanup
live1206 Sep 13, 2024
88a4620
clean up
live1206 Sep 13, 2024
0c8c172
Merge branch 'main' into response-abstraction
live1206 Sep 14, 2024
634c06a
wip
live1206 Sep 18, 2024
5bbcd8a
update FromValue expression
live1206 Sep 18, 2024
93932af
rename
live1206 Sep 19, 2024
f1a9a3d
restructure
live1206 Sep 19, 2024
1169baf
revert type change
live1206 Sep 19, 2024
9752376
Merge branch 'main' into response-abstraction
live1206 Sep 19, 2024
f062d77
make static methods abstract
live1206 Sep 23, 2024
d1889c2
Merge branch 'response-abstraction' of https://github.com/live1206/ty…
live1206 Sep 23, 2024
9eb3b66
update Type to CSharpType
live1206 Sep 23, 2024
56e0f8a
make ErrorResultDefinition public
live1206 Sep 25, 2024
8f6e642
update
live1206 Sep 26, 2024
47a6427
Merge branch 'main' into response-abstraction
live1206 Sep 26, 2024
4a94206
Add more abstraction to make Azure plugin work
live1206 Sep 30, 2024
37295c0
regen tests
live1206 Sep 30, 2024
49ee47d
Merge branch 'main' into response-abstraction
live1206 Sep 30, 2024
eb32597
fix typo
live1206 Sep 30, 2024
c29e8c0
update
live1206 Sep 30, 2024
eb98948
Merge branch 'main' into response-abstraction
live1206 Oct 8, 2024
fcf7ee5
add interfaces
live1206 Oct 9, 2024
109e93e
revert changes for serialization
live1206 Oct 9, 2024
f8c7bbb
revert test change
live1206 Oct 9, 2024
b0d4fca
Merge branch 'main' into response-abstraction
live1206 Oct 9, 2024
a038db4
fix
live1206 Oct 9, 2024
f83dd0b
cleanup
live1206 Oct 9, 2024
a5a379f
make test pass
live1206 Oct 9, 2024
aa27a8d
Merge branch 'main' into response-abstraction
live1206 Oct 10, 2024
100328f
minor
live1206 Oct 10, 2024
14f87d0
Merge branch 'main' into response-abstraction
live1206 Oct 10, 2024
48449f4
Merge branch 'main' into response-abstraction
live1206 Oct 11, 2024
456f13a
resolve comments
live1206 Oct 11, 2024
71bf272
Merge branch 'main' into response-abstraction
live1206 Oct 11, 2024
0cfe54f
Add IExpressionApi<T>
live1206 Oct 14, 2024
1189b18
add constraint
live1206 Oct 14, 2024
cb6c50e
Add ParameterName to IHttpRequestOptionsApi
live1206 Oct 16, 2024
486104c
Add tests for abstraction and simplify the implementation
live1206 Oct 17, 2024
aba79be
Merge branch 'main' into response-abstraction
live1206 Oct 17, 2024
c8a8735
fix typo
live1206 Oct 17, 2024
e3c067a
more typo
live1206 Oct 17, 2024
55637ee
fix typo in test data file name
live1206 Oct 17, 2024
5f192fb
Merge branch 'main' into response-abstraction
live1206 Oct 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ protected override MethodProvider[] BuildMethods()
private MethodProvider ProcessHeadAsBoolMessage()
{
MethodSignature signature = GetProcessHeadAsBoolMessageSignature(false);
var responseVariable = new VariableExpression(typeof(PipelineResponse), "response");
var response = responseVariable.As<PipelineResponse>();
var responseVariable = new VariableExpression(ClientModelPlugin.Instance.TypeFactory.HttpResponseType, "response");
var response = responseVariable.ToApi<HttpResponseApi>();
return new MethodProvider(signature, new MethodBodyStatement[]
{
new DeclarationExpression(responseVariable, false).Assign(_pipeline.ProcessMessage(_message, _options, false)).Terminate(),
Expand All @@ -75,34 +75,34 @@ private MethodProvider ProcessHeadAsBoolMessage()
private MethodProvider ProcessHeadAsBoolMessageAsync()
{
MethodSignature signature = GetProcessHeadAsBoolMessageSignature(true);
var responseVariable = new VariableExpression(typeof(PipelineResponse), "response");
var response = responseVariable.As<PipelineResponse>();
var responseVariable = new VariableExpression(ClientModelPlugin.Instance.TypeFactory.HttpResponseType, "response");
var response = responseVariable.ToApi<HttpResponseApi>();
return new MethodProvider(signature, new MethodBodyStatement[]
{
new DeclarationExpression(responseVariable, false).Assign(_pipeline.ProcessMessage(_message, _options, true)).Terminate(),
GetProcessHeadAsBoolMessageBody(response)
}, this);
}

private MethodBodyStatement GetProcessHeadAsBoolMessageBody(ScopedApi<PipelineResponse> response)
private MethodBodyStatement GetProcessHeadAsBoolMessageBody(HttpResponseApi response)
{
return new MethodBodyStatement[]
{
new SwitchStatement(new MemberExpression(response, "Status"), new SwitchCaseStatement[]
{
new SwitchStatement(new MemberExpression(response, "Status"),
[
new SwitchCaseStatement(ValueExpression.Empty.GreaterThanOrEqual(Literal(200)).AndExpr(ValueExpression.Empty.LessThan(Literal(300))), new MethodBodyStatement[]
{
Return(ClientResultSnippets.FromValue(typeof(bool), True, response))
Return(Static(ClientModelPlugin.Instance.TypeFactory.ClientResponseType).Invoke("FromValue", [True, response], [typeof(bool)], false).ToApi<ClientResponseApi>())
}),
new SwitchCaseStatement(ValueExpression.Empty.GreaterThanOrEqual(Literal(400)).AndExpr(ValueExpression.Empty.LessThan(Literal(500))), new MethodBodyStatement[]
{
Return(ClientResultSnippets.FromValue(typeof(bool), False, response))
Return(Static(ClientModelPlugin.Instance.TypeFactory.ClientResponseType).Invoke("FromValue", [False, response], [typeof(bool)], false).ToApi<ClientResponseApi>())
}),
new SwitchCaseStatement(Array.Empty<ValueExpression>(), new MethodBodyStatement[]
{
Return(new NewInstanceExpression(ErrorResultSnippets.ErrorResultType.MakeGenericType([typeof(bool)]), [response, new NewInstanceExpression(typeof(ClientResultException), [response])]))
Return(new NewInstanceExpression(ErrorResultSnippets.ErrorResultType.MakeGenericType([typeof(bool)]), [response, new NewInstanceExpression(ClientModelPlugin.Instance.TypeFactory.ClientResponseExceptionType, [response])]))
})
}),
]),
};
}

Expand All @@ -117,7 +117,7 @@ private MethodSignature GetProcessHeadAsBoolMessageSignature(bool isAsync)
isAsync ? "ProcessHeadAsBoolMessageAsync" : "ProcessHeadAsBoolMessage",
null,
modifiers,
isAsync ? typeof(ValueTask<ClientResult<bool>>) : typeof(ClientResult<bool>),
isAsync ? new CSharpType(typeof(ValueTask<>), new CSharpType(ClientModelPlugin.Instance.TypeFactory.ClientResponseOfTType, typeof(bool))) : new CSharpType(ClientModelPlugin.Instance.TypeFactory.ClientResponseOfTType, typeof(bool)),
null,
[_pipelineParam, _messageParam, _requestOptionsParam]);
}
Expand All @@ -133,10 +133,10 @@ private MethodProvider BuildProcessMessage()
MethodBodyStatement.EmptyLine,
new IfStatement(_message.Response().IsError().And(new BinaryOperatorExpression("&", _options.NullConditional().Property("ErrorOptions"), clientErrorNoThrow).NotEqual(clientErrorNoThrow)))
{
Throw(New.Instance(typeof(ClientResultException), _message.Response()))
Throw(New.Instance(ClientModelPlugin.Instance.TypeFactory.ClientResponseExceptionType, _message.Response()))
},
MethodBodyStatement.EmptyLine,
Declare("response", typeof(PipelineResponse), new TernaryConditionalExpression(_message.BufferResponse(), _message.Response(), _message.ExtractResponse()), out var response),
Declare("response", ClientModelPlugin.Instance.TypeFactory.HttpResponseType, new TernaryConditionalExpression(_message.BufferResponse(), _message.Response(), _message.ExtractResponse()), out var response),
Return(response)
}, this);
}
Expand All @@ -152,7 +152,7 @@ private MethodSignature GetProcessMessageSignature(bool isAsync)
isAsync ? "ProcessMessageAsync" : "ProcessMessage",
null,
modifiers,
isAsync ? typeof(ValueTask<PipelineResponse>) : typeof(PipelineResponse),
isAsync ? new CSharpType(typeof(ValueTask<>), ClientModelPlugin.Instance.TypeFactory.HttpResponseType) : ClientModelPlugin.Instance.TypeFactory.HttpResponseType,
null,
[_pipelineParam, _messageParam, _requestOptionsParam]);
}
Expand All @@ -168,7 +168,7 @@ private MethodProvider BuildProcessMessageAsync()
MethodBodyStatement.EmptyLine,
new IfStatement(_message.Response().IsError().And(new BinaryOperatorExpression("&", _options.NullConditional().Property("ErrorOptions"), clientErrorNoThrow).NotEqual(clientErrorNoThrow)))
{
Throw(Static<ClientResultException>().Invoke(nameof(ClientResultException.CreateAsync), [_message.Response()], true))
Throw(Static(ClientModelPlugin.Instance.TypeFactory.ClientResponseExceptionType).Invoke("CreateAsync", [_message.Response()], true))
},
MethodBodyStatement.EmptyLine,
Declare("response", typeof(PipelineResponse), new TernaryConditionalExpression(_message.BufferResponse(), _message.Response(), _message.ExtractResponse()), out var response),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using Microsoft.Generator.CSharp.Expressions;
using Microsoft.Generator.CSharp.Snippets;

namespace Microsoft.Generator.CSharp.ClientModel.Providers
{
public abstract record ClientResponseApi : ScopedApi
{
protected ClientResponseApi(Type type, ValueExpression original) : base(type, original)
{
}

public abstract HttpResponseApi GetRawResponse();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.ClientModel.Primitives;
using System.ClientModel;
using Microsoft.Generator.CSharp.Expressions;
using Microsoft.Generator.CSharp.Snippets;

namespace Microsoft.Generator.CSharp.ClientModel.Providers
{
internal record ClientResultProvider : ClientResponseApi
{
public ClientResultProvider(ValueExpression clientResult) : base(typeof(ClientResult), clientResult)
{
}

public override HttpResponseApi GetRawResponse()
=> new PipelineResponseProvider(GetRawResponseExpression());

private ScopedApi<PipelineResponse> GetRawResponseExpression()
=> Original.Invoke(nameof(ClientResponseApi.GetRawResponse)).As<PipelineResponse>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ private class ErrorResultTemplate<T> { }

public ErrorResultDefinition()
{
_responseField = new FieldProvider(FieldModifiers.Private | FieldModifiers.ReadOnly, typeof(PipelineResponse), "_response", this);
_exceptionField = new FieldProvider(FieldModifiers.Private | FieldModifiers.ReadOnly, typeof(ClientResultException), "_exception", this);
_responseField = new FieldProvider(FieldModifiers.Private | FieldModifiers.ReadOnly, ClientModelPlugin.Instance.TypeFactory.HttpResponseType, "_response", this);
_exceptionField = new FieldProvider(FieldModifiers.Private | FieldModifiers.ReadOnly, ClientModelPlugin.Instance.TypeFactory.ClientResponseExceptionType, "_exception", this);
_response = new VariableExpression(_responseField.Type, _responseField.Declaration);
_exception = new VariableExpression(_exceptionField.Type, _exceptionField.Declaration);
}
Expand All @@ -47,7 +47,7 @@ protected override CSharpType[] GetTypeArguments()

protected override CSharpType[] BuildImplements()
{
return [new CSharpType(typeof(ClientResult<>), _t)];
return [new CSharpType(ClientModelPlugin.Instance.TypeFactory.ClientResponseOfTType, _t)];
}

protected override FieldProvider[] BuildFields()
Expand All @@ -62,8 +62,8 @@ protected override ConstructorProvider[] BuildConstructors()

private ConstructorProvider BuildCtor()
{
var response = new ParameterProvider("response", FormattableStringHelpers.Empty, typeof(PipelineResponse));
var exception = new ParameterProvider("exception", FormattableStringHelpers.Empty, typeof(ClientResultException));
var response = new ParameterProvider("response", FormattableStringHelpers.Empty, ClientModelPlugin.Instance.TypeFactory.HttpResponseType);
var exception = new ParameterProvider("exception", FormattableStringHelpers.Empty, ClientModelPlugin.Instance.TypeFactory.ClientResponseExceptionType);
var baseInitializer = new ConstructorInitializer(true, new List<ValueExpression> { Default, response });
var signature = new ConstructorSignature(Type, null, MethodSignatureModifiers.Public, [response, exception], Initializer: baseInitializer);
return new ConstructorProvider(signature, new MethodBodyStatement[]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.IO;
using Microsoft.Generator.CSharp.Expressions;
using Microsoft.Generator.CSharp.Snippets;

namespace Microsoft.Generator.CSharp.ClientModel.Providers
{
public abstract record HttpResponseApi : ScopedApi
{
protected HttpResponseApi(Type type, ValueExpression original) : base(type, original)
{
}

public abstract ScopedApi<Stream> ContentStream();

public abstract ScopedApi<BinaryData> Content();

public abstract ScopedApi<bool> IsError();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ protected override MethodProvider[] BuildMethods()
{
//cast operators
methods.Add(BuildImplicitToBinaryContent());
methods.Add(BuildExplicitFromClientResult());
methods.Add(BuildExplicitFromClientResponse());
}

if (_isStruct)
Expand All @@ -166,17 +166,17 @@ protected override MethodProvider[] BuildMethods()
return [.. methods];
}

private MethodProvider BuildExplicitFromClientResult()
private MethodProvider BuildExplicitFromClientResponse()
{
var result = new ParameterProvider("result", $"The {typeof(ClientResult):C} to deserialize the {Type:C} from.", typeof(ClientResult));
var result = new ParameterProvider("result", $"The {ClientModelPlugin.Instance.TypeFactory.ClientResponseType:C} to deserialize the {Type:C} from.", ClientModelPlugin.Instance.TypeFactory.ClientResponseType);
var modifiers = MethodSignatureModifiers.Public | MethodSignatureModifiers.Static | MethodSignatureModifiers.Explicit | MethodSignatureModifiers.Operator;
// using PipelineResponse response = result.GetRawResponse();
var responseDeclaration = UsingDeclare("response", typeof(PipelineResponse), result.Invoke(nameof(ClientResult.GetRawResponse)), out var response);
var responseDeclaration = UsingDeclare<HttpResponseApi>("response", ClientModelPlugin.Instance.TypeFactory.HttpResponseType, result.AsExpression.ToApi<ClientResponseApi>().GetRawResponse(), out var response);
// using JsonDocument document = JsonDocument.Parse(response.Content);
var document = UsingDeclare(
"document",
typeof(JsonDocument),
JsonDocumentSnippets.Parse(response.Property(nameof(PipelineResponse.Content)).As<BinaryData>()),
JsonDocumentSnippets.Parse(response.Property(nameof(HttpResponseApi.Content)).As<BinaryData>()),
out var docVariable);
// return DeserializeT(doc.RootElement, ModelSerializationExtensions.WireOptions);
var deserialize = Return(_model.Type.Deserialize(docVariable.As<JsonDocument>().RootElement(), ModelSerializationExtensionsSnippets.Wire));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.ClientModel.Primitives;
using System.IO;
using Microsoft.Generator.CSharp.Expressions;
using Microsoft.Generator.CSharp.Snippets;

namespace Microsoft.Generator.CSharp.ClientModel.Providers
{
internal record PipelineResponseProvider : HttpResponseApi
{
public PipelineResponseProvider(ValueExpression pipelineResponse) : base(typeof(PipelineResponse), pipelineResponse)
{
}

public override ScopedApi<Stream> ContentStream()
=> Original.Property(nameof(PipelineResponse.ContentStream)).As<Stream>();

public override ScopedApi<BinaryData> Content()
=> Original.Property(nameof(PipelineResponse.Content)).As<BinaryData>();

public override ScopedApi<bool> IsError()
=> Original.Property(nameof(PipelineResponse.IsError)).As<bool>();
}
}
Loading
Loading