Repository: microsoft/kiota (csharp)

Issue:
[TypeScript] Add support for nested arrays (array of string arrays)
Hey there. Running into an issue with the generated client. I have a schema where one of the properties is an array of string arrays. It is returned in an API response and it looks like the following:

```json
      "Foo": {
        "type": "object",
        "properties": {
          "sortBy": {
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        }
      },
```

When I make an API call using the generated client, I get this error: 

```
Error: encountered an unknown type during deserialization object
```

The stacktrace points to the generated models. When I inspect the generated model, I see that the a few things are off.

The code fails during deserialization in this function. Looks like the wrong function is invoked `getCollectionOfPrimitiveValues`

```ts
export function deserializeIntoFoo(foo: Partial<Foo> | undefined = {}) : Record<string, (node: ParseNode) => void> {
    return {
        "sortBy": n => { foo.sortBy = n.getCollectionOfPrimitiveValues<string>(); },
    }
}
```

The schema is typed incorrectly. It should be `string[][]`

```ts
export interface Foo extends Parsable {
    /**
     * The sortBy property
     */
    sortBy?: string[];
}
```

Also I changed the OpenAPI spec a few different ways and here are my findings.

1. Untyped the nested array. Same error. The property is typed as `UntypedNode[]`
2. Changed the nested array to object type. No error, but in the response the array value is parsed as an object `{ "0": "updatedAt", "1": "DESC" }`
3. Removed properties from Foo. No error, but Foo is no longer typed correctly.

Pull request description:
Fixes https://github.com/microsoft/kiota/issues/4549

Updates the Kiota Builder to not call `CreateCollectionModelDeclaration` when the array schema is a multi dimensional collection(array of arrays) so that this is handled as a instance of `UntypedNode` as the current functionality will recusively unwrap the schema to incorrectly represent it as a single dimensional collection of the nested type.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5d5b2b6b61..df485049c4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 - Aligns naming of sliced OpenAPI description generated by `plugin add` should be named `<plugin-name>-openapi.json|yml`
 - Fixed RPC server to respect the `KIOTA_CONFIG_PREVIEW` flag.
+- Fixed handling of nested arrays to be handled as `UntypedNode` instances [#4549](https://github.com/microsoft/kiota/issues/4549)
 
 ## [1.14.0] - 2024-05-02
 
diff --git a/src/Kiota.Builder/KiotaBuilder.cs b/src/Kiota.Builder/KiotaBuilder.cs
index 5bcbcf7881..ef2920287b 100644
--- a/src/Kiota.Builder/KiotaBuilder.cs
+++ b/src/Kiota.Builder/KiotaBuilder.cs
@@ -1693,7 +1693,8 @@ private CodeTypeBase CreateModelDeclarations(OpenApiUrlTreeNode currentNode, Ope
             return CreateModelDeclarationAndType(currentNode, schema, operation, codeNamespace, suffix, response: responseValue, typeNameForInlineSchema: typeNameForInlineSchema, isRequestBody);
         }
 
-        if (schema.IsArray())
+        if (schema.IsArray() &&
+            !schema.Items.IsArray()) // Only handle collections of primitives and complex types. Otherwise, multi-dimensional arrays would be recursively unwrapped undesirably to lead to incorrect serialization types. 
         {
             // collections at root
             return CreateCollectionModelDeclaration(currentNode, schema, operation, codeNamespace, typeNameForInlineSchema, isRequestBody);


Test patch:
diff --git a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs
index 66c5469c5a..82dabd2d6a 100644
--- a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs
+++ b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs
@@ -1273,6 +1273,74 @@ public void OData_doubles_as_any_of()
         Assert.Equal("double", progressProp.Type.Name);
     }
     [Fact]
+    public void MultiNestedArraysSupportedAsUntypedNodes()
+    {
+        var fooSchema = new OpenApiSchema
+        {
+            Type = "object",
+            Properties = new Dictionary<string, OpenApiSchema> {
+                {
+                    "sortBy", new OpenApiSchema {
+                        Type = "array",
+                        Items = new OpenApiSchema {
+                            Type = "array",
+                            Items = new OpenApiSchema {
+                                Type = "string"
+                            }
+                        }
+                    }
+                },
+            },
+            Reference = new OpenApiReference
+            {
+                Id = "#/components/schemas/bar.foo"
+            },
+            UnresolvedReference = false
+        };
+        var document = new OpenApiDocument
+        {
+            Paths = new OpenApiPaths
+            {
+                ["foos/{id}"] = new OpenApiPathItem
+                {
+                    Operations = {
+                        [OperationType.Get] = new OpenApiOperation
+                        {
+                            Responses = new OpenApiResponses {
+                                ["200"] = new OpenApiResponse
+                                {
+                                    Content = {
+                                        ["application/json"] = new OpenApiMediaType
+                                        {
+                                            Schema = fooSchema
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                },
+            },
+            Components = new OpenApiComponents
+            {
+                Schemas = new Dictionary<string, OpenApiSchema> {
+                    {
+                        "bar.foo", fooSchema
+                    }
+                }
+            }
+        };
+        var mockLogger = new CountLogger<KiotaBuilder>();
+        var builder = new KiotaBuilder(mockLogger, new GenerationConfiguration { ClientClassName = "Graph", ApiRootUrl = "https://localhost" }, _httpClient);
+        var node = builder.CreateUriSpace(document);
+        var codeModel = builder.CreateSourceModel(node);
+        var fooClass = codeModel.FindNamespaceByName("ApiSdk.models").FindChildByName<CodeClass>("foo");
+        Assert.NotNull(fooClass);
+        var sortByProp = fooClass.FindChildByName<CodeProperty>("sortBy", false);
+        Assert.NotNull(sortByProp);
+        Assert.Equal(KiotaBuilder.UntypedNodeName, sortByProp.Type.Name);// nested array property an UntypedNode
+    }
+    [Fact]
     public void Object_Arrays_are_supported()
     {
         var userSchema = new OpenApiSchema