Skip to content

Commit 7abeeb5

Browse files
committed
Fixed: Query serializer with nested Arrays
The ToQueryString() method was not writing nested arrays as expected causing MultipleQueries with nested arrays to return wrong responses. Expected format: query=&facetFilters=[["facet1:true"],["facet2:true"]] query=&facetFilters=[["facet1:true","facet2:true"],["facet3:true"]] query=&facetFilters=[["facet1:true"]]
1 parent 3b6fdba commit 7abeeb5

File tree

2 files changed

+34
-15
lines changed

2 files changed

+34
-15
lines changed

src/Algolia.Search.Test/Serializer/SerializerTest.cs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,29 @@ public void TestQueryWithMultipleObjects()
103103
[Parallelizable]
104104
public void TestQueryWithNestedList()
105105
{
106-
Query query = new Query("") { FacetFilters = new List<List<string>> { new List<string> { "facet1" }, new List<string> { "facet2" } } };
107-
Assert.AreEqual(query.ToQueryString(), "query=&facetFilters=facet1%2Cfacet2");
106+
Query query = new Query("") { FacetFilters = new List<List<string>> { new List<string> { "facet1:true" }, new List<string> { "facet2:true" } } };
107+
// Expected: query=&facetFilters=[["facet1:true"],["facet2:true"]]
108+
Assert.AreEqual(query.ToQueryString(), "query=&facetFilters=%5B%5B%22facet1%3Atrue%22%5D%2C%5B%22facet2%3Atrue%22%5D%5D");
108109

109-
Query query2 = new Query("") { FacetFilters = new List<List<string>> { new List<string> { "facet1", "facet2" } } };
110-
Assert.AreEqual(query2.ToQueryString(), "query=&facetFilters=facet1%2Cfacet2");
110+
Query query2 = new Query("") { FacetFilters = new List<List<string>> { new List<string> { "facet1:true", "facet2:true" } } };
111+
// Expected: query=&facetFilters=[["facet1:true","facet2:true"]]
112+
Assert.AreEqual(query2.ToQueryString(), "query=&facetFilters=%5B%5B%22facet1%3Atrue%22%2C%22facet2%3Atrue%22%5D%5D");
111113

112-
Query query3 = new Query("") { InsideBoundingBox = new List<List<float>> { new List<float> { 10, 35f, 1000, 42f } } };
113-
Assert.AreEqual(query3.ToQueryString(), "query=&insideBoundingBox=10.0%2C35.0%2C1000.0%2C42.0");
114+
Query query3 = new Query("") { FacetFilters = new List<List<string>> { new List<string> { "facet1:true", "facet2:true" }, new List<string> { "facet3:true" } } };
115+
// Expected: query=&facetFilters=[["facet1:true","facet2:true"],["facet3:true"]]
116+
Assert.AreEqual(query3.ToQueryString(), "query=&facetFilters=%5B%5B%22facet1%3Atrue%22%2C%22facet2%3Atrue%22%5D%2C%5B%22facet3%3Atrue%22%5D%5D");
117+
118+
Query query4 = new Query("") { FacetFilters = new List<List<string>> { new List<string> { "facet1:true" } } };
119+
// Expected: query=&facetFilters=[["facet1:true"]]
120+
Assert.AreEqual(query4.ToQueryString(), "query=&facetFilters=%5B%5B%22facet1%3Atrue%22%5D%5D");
121+
122+
Query query5 = new Query("") { InsideBoundingBox = new List<List<float>> { new List<float> { 47.3165f, 4.9665f, 47.3424f, 5.0201f }, new List<float> { 40.9234f, 2.1185f, 38.643f, 1.9916f } } };
123+
// Expected: query=&insideBoundingBox=[[47.3165,4.9665,47.3424,5.0201],[40.9234,2.1185,38.643,1.9916]]
124+
Assert.AreEqual(query5.ToQueryString(), "query=&insideBoundingBox=%5B%5B47.3165%2C4.9665%2C47.3424%2C5.0201%5D%2C%5B40.9234%2C2.1185%2C38.643%2C1.9916%5D%5D");
125+
126+
Query query6 = new Query("") { InsideBoundingBox = new List<List<float>> { new List<float> { 47.3165f, 4.9665f, 47.3424f, 5.0201f } } };
127+
// Expected: query=&insideBoundingBox=[[47.3165,4.9665,47.3424,5.0201]]
128+
Assert.AreEqual(query6.ToQueryString(), "query=&insideBoundingBox=%5B%5B47.3165%2C4.9665%2C47.3424%2C5.0201%5D%5D");
114129
}
115130

116131
[Test]

src/Algolia.Search/Utils/QueryStringHelper.cs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
using System.Collections.Generic;
2929
using System.Globalization;
3030
using System.Linq;
31-
using System.Net;
3231
using System.Reflection;
3332

3433
namespace Algolia.Search.Utils
@@ -92,32 +91,32 @@ public static string ToQueryString<T>(T value, params string[] ignoreList)
9291
p.GetCustomAttribute<JsonPropertyAttribute>() == null)
9392
.Select(p =>
9493
{
95-
string encodedValue = null;
94+
string values = null;
9695
var genericTypeArgument = p.PropertyType.GenericTypeArguments[0];
9796

9897
// In case of nested lists
9998
if (typeof(IEnumerable).GetTypeInfo().IsAssignableFrom(genericTypeArgument.GetTypeInfo()) && genericTypeArgument != typeof(string))
10099
{
101100
if (typeof(IEnumerable<float>).GetTypeInfo().IsAssignableFrom(genericTypeArgument.GetTypeInfo()))
102101
{
103-
IEnumerable<float> flatList = ((IEnumerable)p.GetValue(value, null)).Cast<IEnumerable<float>>().SelectMany(i => i).ToList();
102+
IEnumerable<IEnumerable<float>> nestedParametersLists = ((IEnumerable)p.GetValue(value, null)).Cast<IEnumerable<float>>();
104103
// Culture set to en-US to have floating points separators with "."
105-
encodedValue = Uri.EscapeDataString(string.Join(",", flatList.Select(f => f.ToString("0.0", CultureInfo.InvariantCulture))));
104+
values = WrapValues(string.Join(",", nestedParametersLists.Select(f => WrapValues(string.Join(",", f.Select(x => x.ToString(CultureInfo.InvariantCulture)))))));
106105
}
107106
else
108107
{
109-
IEnumerable<Object> flatList = ((IEnumerable)p.GetValue(value, null)).Cast<IEnumerable<Object>>().SelectMany(i => i).ToList();
110-
encodedValue = Uri.EscapeDataString(string.Join(",", flatList));
108+
IEnumerable<IEnumerable<object>> nestedParametersLists = ((IEnumerable)p.GetValue(value, null)).Cast<IEnumerable<object>>();
109+
values = WrapValues(string.Join(",", nestedParametersLists.Select(x => WrapValues(string.Join(",", x.Select(y => "\"" + y + "\""))))));
111110
}
112111
}
113112
else
114113
{
115114
// One level list
116-
IEnumerable<Object> flatList = ((IEnumerable)p.GetValue(value, null)).Cast<Object>();
117-
encodedValue = Uri.EscapeDataString(string.Join(",", flatList));
115+
IEnumerable<object> parameterList = ((IEnumerable)p.GetValue(value, null)).Cast<object>();
116+
values = string.Join(",", parameterList);
118117
}
119118

120-
return p.Name.ToCamelCase() + "=" + encodedValue;
119+
return p.Name.ToCamelCase() + "=" + Uri.EscapeDataString(values);
121120
});
122121

123122
// Handle properties with JsonPropertyAttribute
@@ -147,5 +146,10 @@ public static string ToQueryString(this Dictionary<string, string> dic)
147146
dic.Select(kvp =>
148147
string.Format($"{kvp.Key}={Uri.EscapeDataString(kvp.Value)}")));
149148
}
149+
150+
private static string WrapValues(string values)
151+
{
152+
return "[" + values + "]";
153+
}
150154
}
151155
}

0 commit comments

Comments
 (0)