Skip to content

Commit 592710a

Browse files
committed
fix: support integer-based enums for C#.
1 parent 89e9c09 commit 592710a

4 files changed

Lines changed: 76 additions & 18 deletions

File tree

src/Kiota.Builder/CodeDOM/CodeEnum.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Concurrent;
33
using System.Collections.Generic;
44
using System.Linq;
5+
using Microsoft.OpenApi;
56

67
namespace Kiota.Builder.CodeDOM;
78
#pragma warning disable CA1711
@@ -42,4 +43,9 @@ public CodeConstant? CodeEnumObject
4243
{
4344
get; set;
4445
}
46+
47+
public JsonSchemaType? BackingType
48+
{
49+
get; set;
50+
}
4551
}

src/Kiota.Builder/KiotaBuilder.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2021,6 +2021,7 @@ private CodeElement AddModelDeclarationIfDoesntExist(OpenApiUrlTreeNode currentN
20212021
currentNode.GetPathItemDescription(Constants.DefaultOpenApiLabel),
20222022
},
20232023
Deprecation = schema.GetDeprecationInformation(),
2024+
BackingType = schema.Type,
20242025
};
20252026
SetEnumOptions(schema, newEnum);
20262027
return currentNamespace.AddEnum(newEnum).First();

src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs

Lines changed: 62 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using Kiota.Builder.CodeDOM;
55
using Kiota.Builder.Extensions;
66
using Kiota.Builder.OrderComparers;
7+
using Microsoft.OpenApi;
78

89
namespace Kiota.Builder.Writers.CSharp;
910

@@ -141,10 +142,21 @@ private void WriteFactoryMethodBodyForUnionModel(CodeMethod codeElement, CodeCla
141142
}
142143
else if (propertyType.TypeDefinition is CodeClass && propertyType.IsCollection || propertyType.TypeDefinition is null || propertyType.TypeDefinition is CodeEnum)
143144
{
145+
var readerReference = parseNodeParameter.Name.ToFirstCharacterLowerCase();
146+
var selfReference = $"{ResultVarName}.{property.Name.ToFirstCharacterUpperCase()}";
147+
var deserializationMethodName = GetDeserializationMethodName(propertyType, codeElement);
144148
var typeName = conventions.GetTypeString(propertyType, codeElement, true, (propertyType.TypeDefinition is CodeEnum || conventions.IsPrimitiveType(propertyType.Name)) && propertyType.CollectionKind is not CodeTypeBase.CodeTypeCollectionKind.None);
145149
var valueVarName = $"{property.Name.ToFirstCharacterLowerCase()}Value";
146-
writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)} is {typeName} {valueVarName})");
147-
writer.WriteBlock(lines: $"{ResultVarName}.{property.Name.ToFirstCharacterUpperCase()} = {valueVarName};");
150+
if (propertyType.TypeDefinition is CodeType { TypeDefinition: CodeEnum {BackingType: JsonSchemaType.Integer}})
151+
{
152+
writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({readerReference}.{deserializationMethodName} is int {valueVarName})");
153+
writer.WriteBlock(lines: $"{selfReference} = ({typeName}){valueVarName};");
154+
}
155+
else
156+
{
157+
writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({readerReference}.{deserializationMethodName} is {typeName} {valueVarName})");
158+
writer.WriteBlock(lines: $"{selfReference} = {valueVarName};");
159+
}
148160
}
149161
if (!includeElse)
150162
includeElse = true;
@@ -162,10 +174,21 @@ private void WriteFactoryMethodBodyForIntersectionModel(CodeMethod codeElement,
162174
{
163175
if (property.Type is CodeType propertyType)
164176
{
177+
var readerReference = parseNodeParameter.Name.ToFirstCharacterLowerCase();
178+
var selfReference = $"{ResultVarName}.{property.Name.ToFirstCharacterUpperCase()}";
179+
var deserializationMethodName = GetDeserializationMethodName(propertyType, codeElement);
165180
var typeName = conventions.GetTypeString(propertyType, codeElement, true, propertyType.TypeDefinition is CodeEnum && propertyType.CollectionKind is not CodeTypeBase.CodeTypeCollectionKind.None);
166181
var valueVarName = $"{property.Name.ToFirstCharacterLowerCase()}Value";
167-
writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)} is {typeName} {valueVarName})");
168-
writer.WriteBlock(lines: $"{ResultVarName}.{property.Name.ToFirstCharacterUpperCase()} = {valueVarName};");
182+
if (propertyType.TypeDefinition is CodeType { TypeDefinition: CodeEnum {BackingType: JsonSchemaType.Integer}})
183+
{
184+
writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({readerReference}.{deserializationMethodName} is int {valueVarName})");
185+
writer.WriteBlock(lines: $"{selfReference} = ({typeName}){valueVarName};");
186+
}
187+
else
188+
{
189+
writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({readerReference}.{deserializationMethodName} is {typeName} {valueVarName})");
190+
writer.WriteBlock(lines: $"{selfReference} = {valueVarName};");
191+
}
169192
}
170193
if (!includeElse)
171194
includeElse = true;
@@ -349,7 +372,13 @@ private void WriteDeserializerBodyForInheritedModel(bool shouldHide, CodeMethod
349372
.Where(static x => !x.ExistsInBaseType)
350373
.OrderBy(static x => x.Name, StringComparer.Ordinal))
351374
{
352-
writer.WriteLine($"{{ \"{otherProp.WireName}\", n => {{ {otherProp.Name.ToFirstCharacterUpperCase()} = n.{GetDeserializationMethodName(otherProp.Type, codeElement)}; }} }},");
375+
if (otherProp is {Type: CodeType { TypeDefinition: CodeEnum {BackingType: JsonSchemaType.Integer}} propertyType})
376+
{
377+
var typeName = conventions.GetTypeString(propertyType, codeElement, true, (propertyType.TypeDefinition is CodeEnum || conventions.IsPrimitiveType(propertyType.Name)) && propertyType.CollectionKind is not CodeTypeBase.CodeTypeCollectionKind.None);
378+
writer.WriteLine($"{{ \"{otherProp.WireName}\", n => {{ {otherProp.Name.ToFirstCharacterUpperCase()} = ({typeName}?) n.{GetDeserializationMethodName(otherProp.Type, codeElement)}; }} }},");
379+
}
380+
else
381+
writer.WriteLine($"{{ \"{otherProp.WireName}\", n => {{ {otherProp.Name.ToFirstCharacterUpperCase()} = n.{GetDeserializationMethodName(otherProp.Type, codeElement)}; }} }},");
353382
}
354383
writer.CloseBlock("};");
355384
}
@@ -370,7 +399,10 @@ private string GetDeserializationMethodName(CodeTypeBase propType, CodeMethod me
370399
return $"GetCollectionOfObjectValues<{propertyType}>({propertyType}.CreateFromDiscriminatorValue){collectionMethod}";
371400
}
372401
else if (currentType.TypeDefinition is CodeEnum enumType)
373-
return $"GetEnumValue<{enumType.GetFullName()}>()";
402+
if (enumType.BackingType is JsonSchemaType.Integer)
403+
return $"GetIntValue()";
404+
else
405+
return $"GetEnumValue<{enumType.GetFullName()}>()";
374406
}
375407
return propertyType switch
376408
{
@@ -482,7 +514,10 @@ private void WriteSerializerBodyForInheritedModel(bool shouldHide, CodeMethod me
482514
.OrderBy(static x => x.Name))
483515
{
484516
var serializationMethodName = GetSerializationMethodName(otherProp.Type, method);
485-
writer.WriteLine($"writer.{serializationMethodName}(\"{otherProp.WireName}\", {otherProp.Name.ToFirstCharacterUpperCase()});");
517+
if (otherProp.Type is CodeType{TypeDefinition: CodeEnum {BackingType: JsonSchemaType.Integer}})
518+
writer.WriteLine($"writer.{serializationMethodName}(\"{otherProp.WireName}\", (int?){otherProp.Name.ToFirstCharacterUpperCase()});");
519+
else
520+
writer.WriteLine($"writer.{serializationMethodName}(\"{otherProp.WireName}\", {otherProp.Name.ToFirstCharacterUpperCase()});");
486521
}
487522
}
488523
private void WriteSerializerBodyForUnionModel(CodeMethod method, CodeClass parentClass, LanguageWriter writer)
@@ -494,8 +529,12 @@ private void WriteSerializerBodyForUnionModel(CodeMethod method, CodeClass paren
494529
.OrderBy(static x => x, CodePropertyTypeForwardComparer)
495530
.ThenBy(static x => x.Name))
496531
{
532+
var serializationMethodName = GetSerializationMethodName(otherProp.Type, method);
497533
writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({otherProp.Name.ToFirstCharacterUpperCase()} != null)");
498-
writer.WriteBlock(lines: $"writer.{GetSerializationMethodName(otherProp.Type, method)}(null, {otherProp.Name.ToFirstCharacterUpperCase()});");
534+
if (otherProp.Type is CodeType{TypeDefinition: CodeEnum {BackingType: JsonSchemaType.Integer}})
535+
writer.WriteBlock(lines: $"writer.{serializationMethodName}(\"{otherProp.WireName}\", (int?){otherProp.Name.ToFirstCharacterUpperCase()});");
536+
else
537+
writer.WriteBlock(lines: $"writer.{serializationMethodName}(null, {otherProp.Name.ToFirstCharacterUpperCase()});");
499538
if (!includeElse)
500539
includeElse = true;
501540
}
@@ -510,8 +549,12 @@ private void WriteSerializerBodyForIntersectionModel(CodeMethod method, CodeClas
510549
.OrderBy(static x => x, CodePropertyTypeBackwardComparer)
511550
.ThenBy(static x => x.Name))
512551
{
552+
var serializationMethodName = GetSerializationMethodName(otherProp.Type, method);
513553
writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({otherProp.Name.ToFirstCharacterUpperCase()} != null)");
514-
writer.WriteBlock(lines: $"writer.{GetSerializationMethodName(otherProp.Type, method)}(null, {otherProp.Name.ToFirstCharacterUpperCase()});");
554+
if (otherProp.Type is CodeType{TypeDefinition: CodeEnum {BackingType: JsonSchemaType.Integer}})
555+
writer.WriteBlock(lines: $"writer.{serializationMethodName}(\"{otherProp.WireName}\", (int?){otherProp.Name.ToFirstCharacterUpperCase()});");
556+
else
557+
writer.WriteBlock(lines: $"writer.{serializationMethodName}(null, {otherProp.Name.ToFirstCharacterUpperCase()});");
515558
if (!includeElse)
516559
includeElse = true;
517560
}
@@ -529,7 +572,12 @@ private void WriteSerializerBodyForIntersectionModel(CodeMethod method, CodeClas
529572
.Select(static x => x.Name.ToFirstCharacterUpperCase())
530573
.OrderBy(static x => x)
531574
.Aggregate(static (x, y) => $"{x}, {y}");
532-
writer.WriteLine($"writer.{GetSerializationMethodName(complexProperties.First().Type, method)}(null, {propertiesNames});");
575+
var prop = complexProperties.First();
576+
var serializationMethodName = GetSerializationMethodName(prop.Type, method);
577+
if (prop.Type is CodeType{TypeDefinition: CodeEnum {BackingType: JsonSchemaType.Integer}})
578+
writer.WriteLine($"writer.{serializationMethodName}(\"{prop.WireName}\", (int?){prop.Name.ToFirstCharacterUpperCase()});");
579+
else
580+
writer.WriteLine($"writer.{GetSerializationMethodName(complexProperties.First().Type, method)}(null, {propertiesNames});");
533581
if (includeElse)
534582
{
535583
writer.CloseBlock();
@@ -678,7 +726,10 @@ private string GetSerializationMethodName(CodeTypeBase propType, CodeMethod meth
678726
else
679727
return $"WriteCollectionOfObjectValues<{propertyType}>";
680728
else if (currentType.TypeDefinition is CodeEnum enumType)
681-
return $"WriteEnumValue<{enumType.GetFullName()}>";
729+
if (enumType.BackingType is JsonSchemaType.Integer)
730+
return $"WriteIntValue";
731+
else
732+
return $"WriteEnumValue<{enumType.GetFullName()}>";
682733

683734
}
684735
return propertyType switch

tests/Kiota.Builder.Tests/Writers/CSharp/YamlToCSharpTests.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -353,8 +353,8 @@ public virtual IDictionary<string, Action<IParseNode>> GetFieldDeserializers()
353353
{
354354
return new Dictionary<string, Action<IParseNode>>
355355
{
356-
{ "notNullable", n => { NotNullable = n.GetEnumValue<global::ApiSdk.Models.ESample>(); } },
357-
{ "nullable", n => { Nullable = n.GetEnumValue<global::ApiSdk.Models.ESample>(); } },
356+
{ "notNullable", n => { NotNullable = (global::ApiSdk.Models.ESample?) n.GetIntValue(); } },
357+
{ "nullable", n => { Nullable = (global::ApiSdk.Models.ESample?) n.GetIntValue(); } },
358358
};
359359
}
360360
/// <summary>
@@ -364,8 +364,8 @@ public virtual IDictionary<string, Action<IParseNode>> GetFieldDeserializers()
364364
public virtual void Serialize(ISerializationWriter writer)
365365
{
366366
if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer));
367-
writer.WriteEnumValue<global::ApiSdk.Models.ESample>("notNullable", NotNullable);
368-
writer.WriteEnumValue<global::ApiSdk.Models.ESample>("nullable", Nullable);
367+
writer.WriteIntValue("notNullable", (int?)NotNullable);
368+
writer.WriteIntValue("nullable", (int?)Nullable);
369369
writer.WriteAdditionalData(AdditionalData);
370370
}
371371
}
@@ -376,9 +376,9 @@ public virtual void Serialize(ISerializationWriter writer)
376376

377377

378378
[Theory]
379-
[InlineData(NullableObjectInOpenApi3, new[] {"Models/Sample.cs", NullableObjectInOpenApi3_Models_Sample})]
380-
[InlineData(NullableEnumInOpenApi3, new[] {"Models/SampleEnum.cs", NullableEnumInOpenApi3_Models_SampleEnum})]
381-
public async Task CreateOpenApiDocumentWithResultAsync_ReturnsDiagnostics(string input,
379+
[InlineData("NullableObjectInOpenApi3", NullableObjectInOpenApi3, new[] {"Models/Sample.cs", NullableObjectInOpenApi3_Models_Sample})]
380+
[InlineData("NullableEnumInOpenApi3", NullableEnumInOpenApi3, new[] {"Models/SampleEnum.cs", NullableEnumInOpenApi3_Models_SampleEnum})]
381+
public async Task CreateOpenApiDocumentWithResultAsync_ReturnsDiagnostics(string description, string input,
382382
string[] expectedData)
383383
{
384384
if (expectedData.Length % 2 != 0)

0 commit comments

Comments
 (0)