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

Fix for 'toList' reducer results empty #346

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
53 changes: 45 additions & 8 deletions src/NRedisStack/Search/AggregationResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ namespace NRedisStack.Search;
public sealed class AggregationResult
{
public long TotalResults { get; }
private readonly Dictionary<string, RedisValue>[] _results;
private readonly Dictionary<string, object>[] _results;
private Dictionary<string, RedisValue>[] _resultsAsRedisValues;

public long CursorId { get; }


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

_results = new Dictionary<string, RedisValue>[arr.Length - 1];
_results = new Dictionary<string, object>[arr.Length - 1];
for (int i = 1; i < arr.Length; i++)
{
var raw = (RedisResult[])arr[i]!;
var cur = new Dictionary<string, RedisValue>();
var cur = new Dictionary<string, object>();
for (int j = 0; j < raw.Length;)
{
var key = (string)raw[j++]!;
var val = raw[j++];
if (val.Type == ResultType.MultiBulk)
continue; // TODO: handle multi-bulk (maybe change to object?)
cur.Add(key, (RedisValue)val);
{
cur.Add(key, ConvertMultiBulkToObject((RedisResult[])val!));
}
else
{
cur.Add(key, (RedisValue)val);
}
}

_results[i - 1] = cur;
Expand All @@ -52,17 +59,47 @@ private object ConvertMultiBulkToObject(IEnumerable<RedisResult> multiBulkArray)
{
return multiBulkArray.Select(item => item.Type == ResultType.MultiBulk
? ConvertMultiBulkToObject((RedisResult[])item!)
: item)
: (RedisValue)item)
.ToList();
}

public IReadOnlyList<Dictionary<string, RedisValue>> GetResults() => _results;
/// <summary>
/// Gets the results as a read-only list of dictionaries with string keys and RedisValue values.
/// </summary>
/// <remarks>
/// This method is deprecated and will be removed in future versions.
/// Please use <see cref="GetRow"/> instead.
/// </remarks>
[Obsolete("This method is deprecated and will be removed in future versions. Please use 'GetRow' instead.")]
public IReadOnlyList<Dictionary<string, RedisValue>> GetResults()
{
return getResultsAsRedisValues();
}

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

public Row GetRow(int index)
{
return index >= _results.Length ? default : new Row(_results[index]);
}

private Dictionary<string, RedisValue>[] getResultsAsRedisValues()
{
if (_resultsAsRedisValues == null)
_resultsAsRedisValues = _results.Select(dict => dict.ToDictionary(
kvp => kvp.Key,
kvp => kvp.Value is RedisValue value ? value : RedisValue.Null
)).ToArray();
return _resultsAsRedisValues;
}
}
11 changes: 6 additions & 5 deletions src/NRedisStack/Search/Row.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,19 @@ namespace NRedisStack.Search.Aggregation
{
public readonly struct Row
{
private readonly Dictionary<string, RedisValue> _fields;
private readonly Dictionary<string, object> _fields;

internal Row(Dictionary<string, RedisValue> fields)
internal Row(Dictionary<string, object> fields)
{
_fields = fields;
}

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

public string? GetString(string key) => _fields.TryGetValue(key, out var result) ? result.ToString() : default;
public long GetLong(string key) => _fields.TryGetValue(key, out var result) ? (long)result : default;
public double GetDouble(string key) => _fields.TryGetValue(key, out var result) ? (double)result : default;
public long GetLong(string key) => _fields.TryGetValue(key, out var result) ? (long)(RedisValue)result : default;
public double GetDouble(string key) => _fields.TryGetValue(key, out var result) ? (double)(RedisValue)result : default;
}
}
23 changes: 17 additions & 6 deletions tests/NRedisStack.Tests/Search/SearchTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1256,7 +1256,9 @@ public void TestAggregationGroupBy()
res = rawRes.GetRow(0);
Assert.Equal("redis", res["parent"]);
// TODO: complete this assert after handling multi bulk reply
//Assert.Equal((RedisValue[])res["__generated_aliastolisttitle"], { "RediSearch", "RedisAI", "RedisJson"});
var expected = new List<object> { "RediSearch", "RedisAI", "RedisJson" };
var actual = (List<object>)res.Get("__generated_aliastolisttitle");
Assert.True(!expected.Except(actual).Any() && expected.Count == actual.Count);

req = new AggregationRequest("redis").GroupBy(
"@parent", Reducers.FirstValue("@title").As("first"));
Expand All @@ -1269,11 +1271,20 @@ public void TestAggregationGroupBy()
res = ft.Aggregate("idx", req).GetRow(0);
Assert.Equal("redis", res["parent"]);
// TODO: complete this assert after handling multi bulk reply
// Assert.Equal(res[2], "random");
// Assert.Equal(len(res[3]), 2);
// Assert.Equal(res[3][0] in ["RediSearch", "RedisAI", "RedisJson"]);
// req = new AggregationRequest("redis").GroupBy("@parent", redu

actual = (List<object>)res.Get("random");
Assert.Equal(2, actual.Count);
List<string> possibleValues = new List<string>() { "RediSearch", "RedisAI", "RedisJson" };
Assert.Contains(actual[0].ToString(), possibleValues);
Assert.Contains(actual[1].ToString(), possibleValues);

req = new AggregationRequest("redis")
.Load(new FieldName("__key"))
.GroupBy("@parent", Reducers.ToList("__key").As("docs"));

res = db.FT().Aggregate("idx", req).GetRow(0);
actual = (List<object>)res.Get("docs");
expected = new List<object> { "ai", "search", "json" };
Assert.True(!expected.Except(actual).Any() && expected.Count == actual.Count);
}


Expand Down
Loading