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

fixes a bug where collections types would generate invalid return types in CSharp #1733

Merged
merged 1 commit into from
Jul 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- Fixed a bug where collections types would generate invalid return types in CSharp.

## [0.3.0] - 2022-07-08

### Added
Expand Down
33 changes: 21 additions & 12 deletions src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,6 @@ protected void WriteRequestExecutorBody(CodeMethod codeElement, RequestParams re
{
if (codeElement.HttpMethod == null) throw new InvalidOperationException("http method cannot be null");

var isStream = conventions.StreamTypeName.Equals(returnType, StringComparison.OrdinalIgnoreCase);
var generatorMethodName = (codeElement.Parent as CodeClass)
.Methods
.FirstOrDefault(x => x.IsOfKind(CodeMethodKind.RequestGenerator) && x.HttpMethod == codeElement.HttpMethod)
Expand All @@ -239,8 +238,14 @@ protected void WriteRequestExecutorBody(CodeMethod codeElement, RequestParams re
var returnTypeFactory = returnTypeCodeType?.TypeDefinition is CodeClass returnTypeClass
? $", {returnTypeWithoutCollectionInformation}.CreateFromDiscriminatorValue"
: null;
var isEnum = returnTypeCodeType?.TypeDefinition is CodeEnum;
writer.WriteLine($"{(isVoid ? string.Empty : "return ")}await RequestAdapter.{GetSendRequestMethodName(isVoid, isStream, codeElement.ReturnType.IsCollection, returnType, isEnum)}(requestInfo{returnTypeFactory}, responseHandler, {errorMappingVarName}, cancellationToken);");
var prefix = (isVoid, codeElement.ReturnType.IsCollection) switch {
(true, _) => string.Empty,
(_, true) => "var collectionResult = ",
(_, _ ) => "return ",
};
writer.WriteLine($"{prefix}await RequestAdapter.{GetSendRequestMethodName(isVoid, codeElement.Parent, codeElement.ReturnType)}(requestInfo{returnTypeFactory}, responseHandler, {errorMappingVarName}, cancellationToken);");
if (codeElement.ReturnType.IsCollection)
writer.WriteLine("return collectionResult.ToList();");
}
private const string RequestInfoVarName = "requestInfo";
private const string RequestConfigVarName = "requestConfig";
Expand All @@ -263,12 +268,13 @@ private void WriteRequestGeneratorBody(CodeMethod codeElement, RequestParams req
writer.WriteLine($"{RequestInfoVarName}.Headers.Add(\"Accept\", \"{string.Join(", ", codeElement.AcceptedResponseTypes)}\");");
if (requestParams.requestBody != null)
{
var suffix = requestParams.requestBody.Type.IsCollection ? ".ToArray()" : string.Empty;
if (requestParams.requestBody.Type.Name.Equals(conventions.StreamTypeName, StringComparison.OrdinalIgnoreCase))
writer.WriteLine($"{RequestInfoVarName}.SetStreamContent({requestParams.requestBody.Name});");
else if (requestParams.requestBody.Type is CodeType bodyType && bodyType.TypeDefinition is CodeClass)
writer.WriteLine($"{RequestInfoVarName}.SetContentFromParsable({requestAdapterProperty.Name.ToFirstCharacterUpperCase()}, \"{codeElement.RequestBodyContentType}\", {requestParams.requestBody.Name});");
writer.WriteLine($"{RequestInfoVarName}.SetContentFromParsable({requestAdapterProperty.Name.ToFirstCharacterUpperCase()}, \"{codeElement.RequestBodyContentType}\", {requestParams.requestBody.Name}{suffix});");
else
writer.WriteLine($"{RequestInfoVarName}.SetContentFromScalar({requestAdapterProperty.Name.ToFirstCharacterUpperCase()}, \"{codeElement.RequestBodyContentType}\", {requestParams.requestBody.Name});");
writer.WriteLine($"{RequestInfoVarName}.SetContentFromScalar({requestAdapterProperty.Name.ToFirstCharacterUpperCase()}, \"{codeElement.RequestBodyContentType}\", {requestParams.requestBody.Name}{suffix});");
}

if (requestParams.requestConfiguration != null)
Expand Down Expand Up @@ -313,16 +319,19 @@ protected virtual void WriteCommandBuilderBody(CodeMethod codeElement, RequestPa
throw new InvalidOperationException("CommandBuilder methods are not implemented in this SDK. They're currently only supported in the shell language.");
}

protected string GetSendRequestMethodName(bool isVoid, bool isStream, bool isCollection, string returnType, bool isEnum)
protected string GetSendRequestMethodName(bool isVoid, CodeElement currentElement, CodeTypeBase returnType)
{
var returnTypeName = conventions.GetTypeString(returnType, currentElement, false);
var isStream = conventions.StreamTypeName.Equals(returnTypeName, StringComparison.OrdinalIgnoreCase);
var isEnum = returnType is CodeType codeType && codeType.TypeDefinition is CodeEnum;
if (isVoid) return "SendNoContentAsync";
else if (isStream || conventions.IsPrimitiveType(returnType) || isEnum)
if (isCollection)
return $"SendPrimitiveCollectionAsync<{returnType.StripArraySuffix()}>";
else if (isStream || conventions.IsPrimitiveType(returnTypeName) || isEnum)
if (returnType.IsCollection)
return $"SendPrimitiveCollectionAsync<{returnTypeName}>";
else
return $"SendPrimitiveAsync<{returnType}>";
else if (isCollection) return $"SendCollectionAsync<{returnType.StripArraySuffix()}>";
else return $"SendAsync<{returnType}>";
return $"SendPrimitiveAsync<{returnTypeName}>";
else if (returnType.IsCollection) return $"SendCollectionAsync<{returnTypeName}>";
else return $"SendAsync<{returnTypeName}>";
}
private void WriteMethodDocumentation(CodeMethod code, LanguageWriter writer)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,28 @@ public void WritesRequestExecutorBody() {
AssertExtensions.CurlyBracesAreClosed(result);
}
[Fact]
public void WritesRequestExecutorBodyForCollection() {
method.Kind = CodeMethodKind.RequestExecutor;
method.HttpMethod = HttpMethod.Get;
var error4XX = root.AddClass(new CodeClass{
Name = "Error4XX",
}).First();
method.AddErrorMapping("4XX", new CodeType {Name = "Error4XX", TypeDefinition = error4XX});
AddRequestBodyParameters();
var bodyParameter = method.Parameters.OfKind(CodeParameterKind.RequestBody);
bodyParameter.Type.CollectionKind = CodeTypeBase.CodeTypeCollectionKind.Complex;
method.ReturnType.CollectionKind = CodeTypeBase.CodeTypeCollectionKind.Complex;
writer.Write(method);
var result = tw.ToString();
Assert.Contains("var requestInfo", result);
Assert.Contains("var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>", result);
Assert.Contains("{\"4XX\", Error4XX.CreateFromDiscriminatorValue},", result);
Assert.Contains("SendCollectionAsync", result);
Assert.Contains("return collectionResult.ToList()", result);
Assert.Contains($"{ReturnTypeName}.CreateFromDiscriminatorValue", result);
AssertExtensions.CurlyBracesAreClosed(result);
}
[Fact]
public void DoesntCreateDictionaryOnEmptyErrorMapping() {
method.Kind = CodeMethodKind.RequestExecutor;
method.HttpMethod = HttpMethod.Get;
Expand Down Expand Up @@ -452,6 +474,21 @@ public void WritesRequestGeneratorBodyForParsable() {
AssertExtensions.CurlyBracesAreClosed(result);
}
[Fact]
public void WritesRequestGeneratorBodyForCollection() {
method.Kind = CodeMethodKind.RequestGenerator;
method.HttpMethod = HttpMethod.Get;
AddRequestProperties();
AddRequestBodyParameters(true);
method.AcceptedResponseTypes.Add("application/json");
var bodyParameter = method.Parameters.OfKind(CodeParameterKind.RequestBody);
bodyParameter.Type.CollectionKind = CodeTypeBase.CodeTypeCollectionKind.Complex;
writer.Write(method);
var result = tw.ToString();
Assert.Contains(".ToArray()", result);
Assert.Contains("SetContentFromParsable", result);
AssertExtensions.CurlyBracesAreClosed(result);
}
[Fact]
public void WritesInheritedDeSerializerBody() {
method.Kind = CodeMethodKind.Deserializer;
AddSerializationProperties();
Expand Down