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

Expand arrays when dealing with parameters in RequestInformation #158

Merged
merged 2 commits into from
Dec 4, 2023
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [1.7.3] - 2023-11-30

### Changed

- Fixed an issue where arrays of non-string types passed into the query parameter were not being converted to strings leading to Invalid cast exceptions. [microsoft/kiota#3354](https://github.com/microsoft/kiota/issues/3354)

## [1.7.2] - 2023-11-14

### Added
Expand Down
164 changes: 164 additions & 0 deletions Microsoft.Kiota.Abstractions.Tests/RequestInformationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -502,8 +502,167 @@ public void SetsEnumValuesInPathParameters()
// Assert
Assert.Equal("http://localhost/1,2", testRequest.URI.ToString());
}


[Fact]
public void SetsIntValueInQueryParameters()
{
// Arrange
var testRequest = new RequestInformation()
{
HttpMethod = Method.GET,
UrlTemplate = "http://localhost/me{?item}"
};
// Act
testRequest.AddQueryParameters(new GetQueryParameters { Item = 1 });
// Assert
Assert.Equal("http://localhost/me?item=1", testRequest.URI.ToString());
}
[Fact]
public void SetsIntValuesInQueryParameters()
{
// Arrange
var requestInfo = new RequestInformation()
{
HttpMethod = Method.GET,
UrlTemplate = "http://localhost/me{?items}"
};
// Act
requestInfo.AddQueryParameters(new GetQueryParameters { Items = new object []{1,2}});
// Assert
Assert.Equal("http://localhost/me?items=1,2", requestInfo.URI.ToString());
}

[Fact]
public void SetsBooleanValuesInQueryParameters()
{
// Arrange
var requestInfo = new RequestInformation()
{
HttpMethod = Method.GET,
UrlTemplate = "http://localhost/me{?items}"
};
// Act
requestInfo.AddQueryParameters(new GetQueryParameters { Items = new object [] { true, false } });
// Assert
Assert.Equal("http://localhost/me?items=true,false", requestInfo.URI.ToString());
}

[Fact]
public void SetsDateTimeOffsetValuesInQueryParameters()
{
var requestInfo = new RequestInformation
{
HttpMethod = Method.GET,
UrlTemplate = "http://localhost/me{?items}"
};

// Act
var dateTime1 = new DateTimeOffset(2022, 8, 1, 0, 0, 0, TimeSpan.Zero);
var dateTime2 = new DateTimeOffset(2022, 8, 2, 0, 0, 0, TimeSpan.Zero);

requestInfo.AddQueryParameters(new GetQueryParameters { Items = new object[] { dateTime1, dateTime2 } });

// Assert
Assert.Equal("http://localhost/me?items=2022-08-01T00%3A00%3A00.0000000%2B00%3A00,2022-08-02T00%3A00%3A00.0000000%2B00%3A00", requestInfo.URI.OriginalString);
}
[Fact]
public void SetsDateTimeValuesInQueryParameters()
{
var requestInfo = new RequestInformation
{
HttpMethod = Method.GET,
UrlTemplate = "http://localhost/me{?items}"
};

// Act
var dateTime1 = new DateTime(2022, 8, 1, 0, 0, 0);
var dateTime2 = new DateTime(2022, 8, 2, 0, 0, 0);

requestInfo.AddQueryParameters(new GetQueryParameters { Items = new object[] { dateTime1, dateTime2 } });

// Assert
Assert.Equal("http://localhost/me?items=2022-08-01T00%3A00%3A00.0000000,2022-08-02T00%3A00%3A00.0000000", requestInfo.URI.OriginalString);
}

[Fact]
public void SetsDateValuesInQueryParameters()
{
var requestInfo = new RequestInformation
{
HttpMethod = Method.GET,
UrlTemplate = "http://localhost/me{?items}"
};

// Act
var date1 = new Date(2022, 8, 1);
var date2 = new Date(2022, 8, 2);

requestInfo.AddQueryParameters(new GetQueryParameters { Items = new object[] { date1, date2 } });

// Assert
Assert.Equal("http://localhost/me?items=2022-08-01,2022-08-02", requestInfo.URI.OriginalString);
}

[Fact]
public void SetsTimeValuesInQueryParameters()
{
var requestInfo = new RequestInformation
{
HttpMethod = Method.GET,
UrlTemplate = "http://localhost/me{?items}"
};

// Act
var date1 = new Time(10,0,0);
var date2 = new Time(11, 1, 1);

requestInfo.AddQueryParameters(new GetQueryParameters { Items = new object[] { date1, date2 } });

// Assert
Assert.Equal("http://localhost/me?items=10%3A00%3A00,11%3A01%3A01", requestInfo.URI.OriginalString);
}

[Fact]
public void SetsGuidValuesInQueryParameters()
{
var requestInfo = new RequestInformation
{
HttpMethod = Method.GET,
UrlTemplate = "http://localhost/me{?items}"
};

// Act
var g1 = Guid.Parse("55331110-6817-4A9B-83B2-57617E3E08E5");
var g2 = Guid.Parse("482DFF4F-63D6-47F4-A88B-5CAEC03180D4");

requestInfo.AddQueryParameters(new GetQueryParameters { Items = new object[] { g1, g2 } });

// Assert
Assert.Equal("http://localhost/me?items=55331110-6817-4a9b-83b2-57617e3e08e5,482dff4f-63d6-47f4-a88b-5caec03180d4", requestInfo.URI.OriginalString);
}


[Fact]
public void DoesNotExpandSecondLayerArrays()
{
var requestInfo = new RequestInformation
{
HttpMethod = Method.GET,
UrlTemplate = "http://localhost/me{?items}"
};

// Act
requestInfo.AddQueryParameters(new GetQueryParameters { Items = new object[]{new int[]{1,2,3,4} } });
// Assert
Assert.Equal("http://localhost/me?items=System.Int32%5B%5D", requestInfo.URI.OriginalString);
}


}



/// <summary>The messages in a mailbox or folder. Read-only. Nullable.</summary>
internal class GetQueryParameters
{
Expand Down Expand Up @@ -533,5 +692,10 @@ internal class GetQueryParameters
/// <summary>Which Dataset to use</summary>
[QueryParameter("datasets")]
public TestEnum[] DataSets { get; set; }

[QueryParameter("item")]
public object Item { get; set; }
[QueryParameter("items")]
public object[] Items { get; set; }
}
}
2 changes: 1 addition & 1 deletion src/Microsoft.Kiota.Abstractions.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<PackageProjectUrl>https://aka.ms/kiota/docs</PackageProjectUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<Deterministic>true</Deterministic>
<VersionPrefix>1.7.2</VersionPrefix>
<VersionPrefix>1.7.3</VersionPrefix>
<VersionSuffix></VersionSuffix>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<SignAssembly>false</SignAssembly>
Expand Down
37 changes: 24 additions & 13 deletions src/RequestInformation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using Microsoft.Kiota.Abstractions.Extensions;
using Microsoft.Kiota.Abstractions.Serialization;
Expand Down Expand Up @@ -89,14 +91,14 @@ public Uri URI
var substitutions = new Dictionary<string, object>();
foreach(var urlTemplateParameter in PathParameters)
{
substitutions.Add(urlTemplateParameter.Key, GetSanitizedValue(urlTemplateParameter.Value));
substitutions.Add(urlTemplateParameter.Key, GetSanitizedValues(urlTemplateParameter.Value));
}

foreach(var queryStringParameter in QueryParameters)
{
if(queryStringParameter.Value != null)
{
substitutions.Add(queryStringParameter.Key, GetSanitizedValue(queryStringParameter.Value));
substitutions.Add(queryStringParameter.Key, GetSanitizedValues(queryStringParameter.Value));
}
}

Expand All @@ -105,6 +107,12 @@ public Uri URI
}
}

private static object GetSanitizedValues(object value) => value switch
{
Array array => ExpandArray(array),
_ => GetSanitizedValue(value),
};

/// <summary>
/// Sanitizes objects in order to appear appropiately in the URL
/// </summary>
Expand Down Expand Up @@ -163,25 +171,28 @@ public void AddQueryParameters<T>(T source)
!string.IsNullOrEmpty(x.Value.ToString()) && // no need to add an empty string value
(x.Value is not ICollection collection || collection.Count > 0))) // no need to add empty collection
{
QueryParameters.AddOrReplace(property.Name!, ReplaceEnumValueByStringRepresentation(property.Value!));
QueryParameters.AddOrReplace(property.Name!, property.Value!);
}
}

private static object ExpandArray(Array collection)
{
var passedArray = new string[collection.Length];
for(var i = 0; i < collection.Length; i++)
{
passedArray[i] = GetSanitizedValue(collection.GetValue(i)!).ToString()!;
}
return passedArray;
}

private static object ReplaceEnumValueByStringRepresentation(object source)
{
if(source is Enum enumValue && GetEnumName(enumValue) is string enumValueName)
{
return enumValueName;
}
else if(source is Array collection && collection.Length > 0 && collection.GetValue(0) is Enum)
{
var passedArray = new string[collection.Length];
for(var i = 0; i < collection.Length; i++)
{// this is ugly but necessary due to covariance limitations with pattern matching
passedArray[i] = GetEnumName((Enum)collection.GetValue(i)!)!;
}
return passedArray;
}
else return source;

return source;
}
#if NET5_0_OR_GREATER
private static string? GetEnumName<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(T value) where T : Enum
Expand Down