Skip to content

Commit 5c6109e

Browse files
authored
Merge branch 'master' into ali/tba-int
2 parents a186a37 + 15fd7d2 commit 5c6109e

File tree

7 files changed

+289
-23
lines changed

7 files changed

+289
-23
lines changed

src/NRedisStack/NRedisStack.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
<Owners>Redis OSS</Owners>
1111
<Description>.Net Client for Redis Stack</Description>
1212
<PackageReadmeFile>README.md</PackageReadmeFile>
13-
<Version>0.13.0</Version>
14-
<ReleaseVersion>0.13.0</ReleaseVersion>
15-
<PackageVersion>0.13.0</PackageVersion>
13+
<Version>0.13.1</Version>
14+
<ReleaseVersion>0.13.1</ReleaseVersion>
15+
<PackageVersion>0.13.1</PackageVersion>
1616
</PropertyGroup>
1717

1818
<ItemGroup>

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
}

src/NRedisStack/TimeSeries/Extensions/ReduceExtensions.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ internal static class ReduceExtensions
99
TsReduce.Sum => "SUM",
1010
TsReduce.Min => "MIN",
1111
TsReduce.Max => "MAX",
12+
TsReduce.Avg => "AVG",
13+
TsReduce.Range => "RANGE",
14+
TsReduce.Count => "COUNT",
15+
TsReduce.StdP => "STD.P",
16+
TsReduce.StdS => "STD.S",
17+
TsReduce.VarP => "VAR.P",
18+
TsReduce.VarS => "VAR.S",
1219
_ => throw new ArgumentOutOfRangeException(nameof(reduce), "Invalid Reduce type"),
1320
};
1421
}

src/NRedisStack/TimeSeries/Literals/Enums/Reduce.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,40 @@ public enum TsReduce
1919
/// A maximum sample of all samples in the group
2020
/// </summary>
2121
Max,
22+
23+
/// <summary>
24+
/// Arithmetic mean of all non-NaN values (since RedisTimeSeries v1.8)
25+
/// </summary>
26+
Avg,
27+
28+
/// <summary>
29+
/// Difference between maximum non-NaN value and minimum non-NaN value (since RedisTimeSeries v1.8)
30+
/// </summary>
31+
Range,
32+
33+
/// <summary>
34+
/// Number of non-NaN values (since RedisTimeSeries v1.8)
35+
/// </summary>
36+
Count,
37+
38+
/// <summary>
39+
/// Population standard deviation of all non-NaN values (since RedisTimeSeries v1.8)
40+
/// </summary>
41+
StdP,
42+
43+
/// <summary>
44+
/// Sample standard deviation of all non-NaN values (since RedisTimeSeries v1.8)
45+
/// </summary>
46+
StdS,
47+
48+
/// <summary>
49+
/// Population variance of all non-NaN values (since RedisTimeSeries v1.8)
50+
/// </summary>
51+
VarP,
52+
53+
/// <summary>
54+
/// Sample variance of all non-NaN values (since RedisTimeSeries v1.8)
55+
/// </summary>
56+
VarS
2257
}
2358
}

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)