Skip to content

Commit dd11910

Browse files
authored
Fix for 'toList' reducer results empty (#346)
* issue #342- fix for 'toList' reducer results empty * fix collection initializer
1 parent 73e7a6d commit dd11910

File tree

3 files changed

+68
-19
lines changed

3 files changed

+68
-19
lines changed

src/NRedisStack/Search/AggregationResult.cs

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ namespace NRedisStack.Search;
66
public sealed class AggregationResult
77
{
88
public long TotalResults { get; }
9-
private readonly Dictionary<string, RedisValue>[] _results;
9+
private readonly Dictionary<string, object>[] _results;
10+
private Dictionary<string, RedisValue>[] _resultsAsRedisValues;
11+
1012
public long CursorId { get; }
1113

1214

@@ -18,18 +20,23 @@ internal AggregationResult(RedisResult result, long cursorId = -1)
1820
// // the first element is always the number of results
1921
// TotalResults = (long)arr[0];
2022

21-
_results = new Dictionary<string, RedisValue>[arr.Length - 1];
23+
_results = new Dictionary<string, object>[arr.Length - 1];
2224
for (int i = 1; i < arr.Length; i++)
2325
{
2426
var raw = (RedisResult[])arr[i]!;
25-
var cur = new Dictionary<string, RedisValue>();
27+
var cur = new Dictionary<string, object>();
2628
for (int j = 0; j < raw.Length;)
2729
{
2830
var key = (string)raw[j++]!;
2931
var val = raw[j++];
3032
if (val.Type == ResultType.MultiBulk)
31-
continue; // TODO: handle multi-bulk (maybe change to object?)
32-
cur.Add(key, (RedisValue)val);
33+
{
34+
cur.Add(key, ConvertMultiBulkToObject((RedisResult[])val!));
35+
}
36+
else
37+
{
38+
cur.Add(key, (RedisValue)val);
39+
}
3340
}
3441

3542
_results[i - 1] = cur;
@@ -52,17 +59,47 @@ private object ConvertMultiBulkToObject(IEnumerable<RedisResult> multiBulkArray)
5259
{
5360
return multiBulkArray.Select(item => item.Type == ResultType.MultiBulk
5461
? ConvertMultiBulkToObject((RedisResult[])item!)
55-
: item)
62+
: (RedisValue)item)
5663
.ToList();
5764
}
5865

59-
public IReadOnlyList<Dictionary<string, RedisValue>> GetResults() => _results;
66+
/// <summary>
67+
/// Gets the results as a read-only list of dictionaries with string keys and RedisValue values.
68+
/// </summary>
69+
/// <remarks>
70+
/// This method is deprecated and will be removed in future versions.
71+
/// Please use <see cref="GetRow"/> instead.
72+
/// </remarks>
73+
[Obsolete("This method is deprecated and will be removed in future versions. Please use 'GetRow' instead.")]
74+
public IReadOnlyList<Dictionary<string, RedisValue>> GetResults()
75+
{
76+
return getResultsAsRedisValues();
77+
}
6078

79+
/// <summary>
80+
/// Gets the aggregation result at the specified index.
81+
/// </summary>
82+
/// <param name="index">The zero-based index of the aggregation result to retrieve.</param>
83+
/// <returns>
84+
/// A dictionary containing the aggregation result as Redis values if the index is within bounds;
85+
/// otherwise, <c>null</c>.
86+
/// </returns>
87+
[Obsolete("This method is deprecated and will be removed in future versions. Please use 'GetRow' instead.")]
6188
public Dictionary<string, RedisValue>? this[int index]
62-
=> index >= _results.Length ? null : _results[index];
89+
=> index >= getResultsAsRedisValues().Length ? null : getResultsAsRedisValues()[index];
6390

6491
public Row GetRow(int index)
6592
{
6693
return index >= _results.Length ? default : new Row(_results[index]);
6794
}
95+
96+
private Dictionary<string, RedisValue>[] getResultsAsRedisValues()
97+
{
98+
if (_resultsAsRedisValues == null)
99+
_resultsAsRedisValues = _results.Select(dict => dict.ToDictionary(
100+
kvp => kvp.Key,
101+
kvp => kvp.Value is RedisValue value ? value : RedisValue.Null
102+
)).ToArray();
103+
return _resultsAsRedisValues;
104+
}
68105
}

src/NRedisStack/Search/Row.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,19 @@ namespace NRedisStack.Search.Aggregation
44
{
55
public readonly struct Row
66
{
7-
private readonly Dictionary<string, RedisValue> _fields;
7+
private readonly Dictionary<string, object> _fields;
88

9-
internal Row(Dictionary<string, RedisValue> fields)
9+
internal Row(Dictionary<string, object> fields)
1010
{
1111
_fields = fields;
1212
}
1313

1414
public bool ContainsKey(string key) => _fields.ContainsKey(key);
15-
public RedisValue this[string key] => _fields.TryGetValue(key, out var result) ? result : RedisValue.Null;
15+
public RedisValue this[string key] => _fields.TryGetValue(key, out var result) ? (result is RedisValue ? (RedisValue)result : RedisValue.Null) : RedisValue.Null;
16+
public object Get(string key) => _fields.TryGetValue(key, out var result) ? result : RedisValue.Null;
1617

1718
public string? GetString(string key) => _fields.TryGetValue(key, out var result) ? result.ToString() : default;
18-
public long GetLong(string key) => _fields.TryGetValue(key, out var result) ? (long)result : default;
19-
public double GetDouble(string key) => _fields.TryGetValue(key, out var result) ? (double)result : default;
19+
public long GetLong(string key) => _fields.TryGetValue(key, out var result) ? (long)(RedisValue)result : default;
20+
public double GetDouble(string key) => _fields.TryGetValue(key, out var result) ? (double)(RedisValue)result : default;
2021
}
2122
}

tests/NRedisStack.Tests/Search/SearchTests.cs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,7 +1256,9 @@ public void TestAggregationGroupBy()
12561256
res = rawRes.GetRow(0);
12571257
Assert.Equal("redis", res["parent"]);
12581258
// TODO: complete this assert after handling multi bulk reply
1259-
//Assert.Equal((RedisValue[])res["__generated_aliastolisttitle"], { "RediSearch", "RedisAI", "RedisJson"});
1259+
var expected = new List<object> { "RediSearch", "RedisAI", "RedisJson" };
1260+
var actual = (List<object>)res.Get("__generated_aliastolisttitle");
1261+
Assert.True(!expected.Except(actual).Any() && expected.Count == actual.Count);
12601262

12611263
req = new AggregationRequest("redis").GroupBy(
12621264
"@parent", Reducers.FirstValue("@title").As("first"));
@@ -1269,11 +1271,20 @@ public void TestAggregationGroupBy()
12691271
res = ft.Aggregate("idx", req).GetRow(0);
12701272
Assert.Equal("redis", res["parent"]);
12711273
// TODO: complete this assert after handling multi bulk reply
1272-
// Assert.Equal(res[2], "random");
1273-
// Assert.Equal(len(res[3]), 2);
1274-
// Assert.Equal(res[3][0] in ["RediSearch", "RedisAI", "RedisJson"]);
1275-
// req = new AggregationRequest("redis").GroupBy("@parent", redu
1276-
1274+
actual = (List<object>)res.Get("random");
1275+
Assert.Equal(2, actual.Count);
1276+
List<string> possibleValues = new List<string>() { "RediSearch", "RedisAI", "RedisJson" };
1277+
Assert.Contains(actual[0].ToString(), possibleValues);
1278+
Assert.Contains(actual[1].ToString(), possibleValues);
1279+
1280+
req = new AggregationRequest("redis")
1281+
.Load(new FieldName("__key"))
1282+
.GroupBy("@parent", Reducers.ToList("__key").As("docs"));
1283+
1284+
res = db.FT().Aggregate("idx", req).GetRow(0);
1285+
actual = (List<object>)res.Get("docs");
1286+
expected = new List<object> { "ai", "search", "json" };
1287+
Assert.True(!expected.Except(actual).Any() && expected.Count == actual.Count);
12771288
}
12781289

12791290

0 commit comments

Comments
 (0)