Repository: microsoft/kiota (csharp)

Issue:
C# - Query Enum Array generated as string[]
Command used:
```
dotnet kiota generate --openapi ./openapi.json -o Generated --language CSharp
```

> dotnet kiota --version
1.11.1+86b3a623dc3fb6b55fed6a49519ec837f0fbc02c

With the following openapi spec:
```json
{
    "openapi": "3.0.2",
    "info": {
        "title": "ContentType",
        "version": "1.0.0"
    },
    "paths": {
        "/test": {
            "get": {
                "parameters": [
                    {
                        "name": "enumValues",
                        "in": "query",
                        "schema": {
                            "type": "array",
                            "items": {
                                "$ref": "#/components/schemas/EnumValue"
                            }
                        }
                    },
                    {
                        "name": "enumValues2",
                        "in": "query",
                        "schema": {
                            "$ref": "#/components/schemas/EnumValue"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "response"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "EnumValue": {
                "type": "string",
                "enum": [
                    "Value1",
                    "Value2",
                    "Value3"
                ]
            }
        }
    }
}
```

The following lines are generated:
```csharp
public class TestRequestBuilderGetQueryParameters {
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
        [QueryParameter("enumValues")]
        public string[]? EnumValues { get; set; }
#nullable restore
#else
        [QueryParameter("enumValues")]
        public string[] EnumValues { get; set; }
#endif
        [Obsolete("This property is deprecated, use enumValues2AsEnumValue instead")]
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
        [QueryParameter("enumValues2")]
        public string? EnumValues2 { get; set; }
#nullable restore
#else
        [QueryParameter("enumValues2")]
        public string EnumValues2 { get; set; }
#endif
        [QueryParameter("enumValues2")]
        public EnumValue? EnumValues2AsEnumValue { get; set; }
}
```

So there is no way to set `EnumValues` as a list of `EnumValue`

Pull request description:
Fixes https://github.com/microsoft/kiota/issues/4225

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 373ca86d2b..c4f3e6ed23 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - Fixed bug where stream responses would generate incorrect partial paging code. [#4207](https://github.com/microsoft/kiota/issues/4207)
 - Sanitize Accept and Content-Type headers during generation. [#4211](https://github.com/microsoft/kiota/issues/4211)
 - Fixed a bug in enum default value generator for TypeScript. [#4216](https://github.com/microsoft/kiota/issues/4216)
+- Generate enum array for query parameters. [#4225](https://github.com/microsoft/kiota/issues/4225)
 
 ## [1.11.1] - 2024-02-05
 
diff --git a/src/Kiota.Builder/KiotaBuilder.cs b/src/Kiota.Builder/KiotaBuilder.cs
index 756afb3228..390d151c69 100644
--- a/src/Kiota.Builder/KiotaBuilder.cs
+++ b/src/Kiota.Builder/KiotaBuilder.cs
@@ -2343,23 +2343,25 @@ private void AddPropertyForQueryParameter(OpenApiUrlTreeNode node, OperationType
     {
         CodeType? resultType = default;
         var addBackwardCompatibleParameter = false;
-        if (parameter.Schema.IsEnum())
+
+        if (parameter.Schema.IsEnum() || (parameter.Schema.IsArray() && parameter.Schema.Items.IsEnum()))
         {
-            var schema = parameter.Schema;
-            var codeNamespace = schema.IsReferencedSchema() switch
+            var enumSchema = parameter.Schema.IsArray() ? parameter.Schema.Items : parameter.Schema;
+            var codeNamespace = enumSchema.IsReferencedSchema() switch
             {
-                true => GetShortestNamespace(parameterClass.GetImmediateParentOfType<CodeNamespace>(), schema), // referenced schema
+                true => GetShortestNamespace(parameterClass.GetImmediateParentOfType<CodeNamespace>(), enumSchema), // referenced schema
                 false => parameterClass.GetImmediateParentOfType<CodeNamespace>(), // Inline schema, i.e. specific to the Operation
             };
-            var shortestNamespace = GetShortestNamespace(codeNamespace, schema);
-            var enumName = schema.GetSchemaName().CleanupSymbolName();
+            var shortestNamespace = GetShortestNamespace(codeNamespace, enumSchema);
+            var enumName = enumSchema.GetSchemaName().CleanupSymbolName();
             if (string.IsNullOrEmpty(enumName))
                 enumName = $"{operationType.ToString().ToFirstCharacterUpperCase()}{parameter.Name.CleanupSymbolName().ToFirstCharacterUpperCase()}QueryParameterType";
-            if (AddEnumDeclarationIfDoesntExist(node, schema, enumName, shortestNamespace) is { } enumDeclaration)
+            if (AddEnumDeclarationIfDoesntExist(node, enumSchema, enumName, shortestNamespace) is { } enumDeclaration)
             {
                 resultType = new CodeType
                 {
                     TypeDefinition = enumDeclaration,
+                    IsNullable = !parameter.Schema.IsArray()
                 };
                 addBackwardCompatibleParameter = true;
             }
diff --git a/src/Kiota.Builder/Writers/Php/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Php/CodeMethodWriter.cs
index 375f986024..13e3ad3734 100644
--- a/src/Kiota.Builder/Writers/Php/CodeMethodWriter.cs
+++ b/src/Kiota.Builder/Writers/Php/CodeMethodWriter.cs
@@ -251,7 +251,8 @@ private static void AssignPropertyFromParameter(CodeClass parentClass, CodeMetho
         {
             for (var i = 0; i < parameters.Count; i++)
             {
-                writer.WriteLine($"$this->{properties[i].Name.ToFirstCharacterLowerCase()} = ${parameters[i].Name.ToFirstCharacterLowerCase()};");
+                var isNonNullableCollection = !parameters[i].Type.IsNullable && parameters[i].Type.CollectionKind != CodeTypeBase.CodeTypeCollectionKind.None;
+                writer.WriteLine($"$this->{properties[i].Name.ToFirstCharacterLowerCase()} = ${parameters[i].Name.ToFirstCharacterLowerCase()}{(isNonNullableCollection ? "?? []" : string.Empty)};");
             }
         }
     }
diff --git a/src/Kiota.Builder/Writers/Python/CodePropertyWriter.cs b/src/Kiota.Builder/Writers/Python/CodePropertyWriter.cs
index 54d775feab..7439f123bf 100644
--- a/src/Kiota.Builder/Writers/Python/CodePropertyWriter.cs
+++ b/src/Kiota.Builder/Writers/Python/CodePropertyWriter.cs
@@ -39,7 +39,8 @@ public override void WriteCodeElement(CodeProperty codeElement, LanguageWriter w
             case CodePropertyKind.Options:
             case CodePropertyKind.QueryParameter:
                 conventions.WriteInLineDescription(codeElement, writer);
-                writer.WriteLine($"{conventions.GetAccessModifier(codeElement.Access)}{codeElement.NamePrefix}{codeElement.Name}: {(codeElement.Type.IsNullable ? "Optional[" : string.Empty)}{returnType}{(codeElement.Type.IsNullable ? "]" : string.Empty)} = None");
+                var isNonNullableCollection = !codeElement.Type.IsNullable && codeElement.Type.CollectionKind != CodeTypeBase.CodeTypeCollectionKind.None;
+                writer.WriteLine($"{conventions.GetAccessModifier(codeElement.Access)}{codeElement.NamePrefix}{codeElement.Name}: {(codeElement.Type.IsNullable ? "Optional[" : string.Empty)}{returnType}{(codeElement.Type.IsNullable ? "]" : string.Empty)} {(isNonNullableCollection ? "= []" : "= None")}");
                 writer.WriteLine();
                 break;
             case CodePropertyKind.ErrorMessageOverride when parentClass.IsErrorDefinition:


Test patch:
diff --git a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs
index 473b2775b4..99ea0c4769 100644
--- a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs
+++ b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs
@@ -12,6 +12,7 @@
 using Kiota.Builder.Extensions;
 
 using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
 using Microsoft.OpenApi.Any;
 using Microsoft.OpenApi.Interfaces;
 using Microsoft.OpenApi.MicrosoftExtensions;
@@ -7493,4 +7494,83 @@ The comment text in [Atlassian Document
         var linkIssueRequestJsonBeanClass = codeModel.FindChildByName<CodeClass>("LinkIssueRequestJsonBean");
         Assert.NotNull(linkIssueRequestJsonBeanClass);
     }
+
+    [Fact]
+    public async Task EnumArrayQueryParameter()
+    {
+        const string schemaDocument = """
+                     openapi: 3.0.2
+                     info:
+                       title: Enum
+                       version: 1.0.0
+                     paths:
+                       /EnumQuery:
+                         get:
+                           parameters:
+                             - name: enumValues
+                               in: query
+                               schema:
+                                 type: array
+                                 items:
+                                   $ref: '#/components/schemas/EnumValue'
+                             - name: enumValues2
+                               in: query
+                               schema:
+                                 $ref: '#/components/schemas/EnumValue'
+                           responses:
+                             '200':
+                               description: response
+                               content:
+                                 application/json:
+                                   schema:
+                                     $ref: '#/components/schemas/EnumObject'
+                     components:
+                       schemas:
+                         EnumValue:
+                           type: string
+                           enum:
+                             - Value1
+                             - Value2
+                             - Value3
+                         EnumObject:
+                           type: object
+                           properties:
+                             enumArray:
+                               type: array
+                               items:
+                                 $ref: '#/components/schemas/EnumValue'
+                     """;
+
+        var tempFilePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName());
+        await using var fs = await GetDocumentStream(schemaDocument);
+
+        var builder = new KiotaBuilder(
+            NullLogger<KiotaBuilder>.Instance,
+            new GenerationConfiguration
+            {
+                ClientClassName = "EnumTest",
+                OpenAPIFilePath = tempFilePath,
+                IncludeAdditionalData = false
+            },
+            _httpClient);
+
+        var document = await builder.CreateOpenApiDocumentAsync(fs);
+        Assert.NotNull(document);
+        var node = builder.CreateUriSpace(document);
+        var codeModel = builder.CreateSourceModel(node);
+        Assert.NotNull(codeModel);
+        var enumRequestBuilder = codeModel.FindChildByName<CodeClass>("EnumQueryRequestBuilder");
+        Assert.NotNull(enumRequestBuilder);
+        var queryParameters = enumRequestBuilder.FindChildByName<CodeClass>("EnumQueryRequestBuilderGetQueryParameters");
+        Assert.NotNull(queryParameters);
+
+        Assert.Contains(queryParameters.Properties, p =>
+            p.Type is
+            {
+                IsCollection: true,
+                IsArray: true,
+                CollectionKind: CodeTypeBase.CodeTypeCollectionKind.Array,
+                Name: "EnumValue"
+            });
+    }
 }