未验证 提交 eb26a9eb 编写于 作者: S shacharPash 提交者: GitHub

Start addin Tdigest commands (#8)

* Start addin Tdigest commands

* Add Tdigest Commands & Fixing Parsing Warnings
上级 8fe55a6e
......@@ -4,7 +4,7 @@ namespace NRedisStack.Core
{
public static class Auxiliary
{
public static List<object> MergeArgs(RedisKey key, RedisValue[] items)
public static List<object> MergeArgs(RedisKey key, params RedisValue[] items)
{
var args = new List<object> { key };
foreach (var item in items) args.Add(item);
......
......@@ -70,7 +70,7 @@ namespace NRedisStack.Core
/// <param name="key">Name of the key to return information about.</param>
/// <returns>Information of the filter.</returns>
/// <remarks><seealso href="https://redis.io/commands/bf.info"/></remarks>
public BloomInformation? Info(RedisKey key)
public BloomInformation Info(RedisKey key)
{
var info = _db.Execute(BF.INFO, key);
return ResponseParser.ToBloomInfo(info);
......@@ -82,7 +82,7 @@ namespace NRedisStack.Core
/// <param name="key">Name of the key to return information about.</param>
/// <returns>Information of the filter.</returns>
/// <remarks><seealso href="https://redis.io/commands/bf.info"/></remarks>
public async Task<BloomInformation?> InfoAsync(RedisKey key)
public async Task<BloomInformation> InfoAsync(RedisKey key)
{
var info = await _db.ExecuteAsync(BF.INFO, key);
return ResponseParser.ToBloomInfo(info);
......@@ -108,8 +108,8 @@ namespace NRedisStack.Core
double? error = null, int? expansion = null,
bool nocreate = false, bool nonscaling = false)
{
if (items == null)
throw new ArgumentNullException(nameof(items));
if (items.Length < 1)
throw new ArgumentOutOfRangeException(nameof(items));
List<object> args = new List<object> { key };
......@@ -119,6 +119,7 @@ namespace NRedisStack.Core
args.Add(capacity);
}
if (error != null)
{
args.Add(BloomArgs.ERROR);
......@@ -171,8 +172,8 @@ namespace NRedisStack.Core
double? error = null, int? expansion = null,
bool nocreate = false, bool nonscaling = false)
{
if (items == null)
throw new ArgumentNullException(nameof(items));
if (items.Length < 1)
throw new ArgumentOutOfRangeException(nameof(items));
List<object> args = new List<object> { key };
......@@ -221,11 +222,11 @@ namespace NRedisStack.Core
/// <param name="key">Name of the key to restore.</param>
/// <param name="iterator">Iterator value associated with data (returned by SCANDUMP).</param>
/// <param name="data">Current data chunk (returned by SCANDUMP).</param>
/// <returns>Array with information of the filter.</returns>
/// <returns><see langword="true"/> if executed correctly, error otherwise/></returns>
/// <remarks><seealso href="https://redis.io/commands/bf.loadchunk"/></remarks>
public bool LoadChunk(RedisKey key, long iterator, Byte[] data)
{
return ResponseParser.ParseOKtoBoolean(_db.Execute(BF.LOADCHUNK, key, iterator, data));
return ResponseParser.OKtoBoolean(_db.Execute(BF.LOADCHUNK, key, iterator, data));
}
/// <summary>
......@@ -234,12 +235,12 @@ namespace NRedisStack.Core
/// <param name="key">Name of the key to restore.</param>
/// <param name="iterator">Iterator value associated with data (returned by SCANDUMP).</param>
/// <param name="data">Current data chunk (returned by SCANDUMP).</param>
/// <returns>Array with information of the filter.</returns>
/// <returns><see langword="true"/> if executed correctly, error otherwise/></returns>
/// <remarks><seealso href="https://redis.io/commands/bf.loadchunk"/></remarks>
public async Task<bool> LoadChunkAsync(RedisKey key, long iterator, Byte[] data)
{
var result = await _db.ExecuteAsync(BF.LOADCHUNK, key, iterator, data);
return ResponseParser.ParseOKtoBoolean(result);
return ResponseParser.OKtoBoolean(result);
}
/// <summary>
......@@ -250,10 +251,10 @@ namespace NRedisStack.Core
/// <returns>An array of booleans. Each element is either true or false depending on whether the
/// corresponding input element was newly added to the filter or may have previously existed.</returns>
/// <remarks><seealso href="https://redis.io/commands/bf.madd"/></remarks>
public bool[] MAdd(RedisKey key, RedisValue[] items)
public bool[] MAdd(RedisKey key, params RedisValue[] items)
{
if (items == null)
throw new ArgumentNullException(nameof(items));
if (items.Length < 1)
throw new ArgumentOutOfRangeException(nameof(items));
List<object> args = new List<object> { key };
......@@ -273,10 +274,10 @@ namespace NRedisStack.Core
/// <returns>An array of booleans. Each element is either true or false depending on whether the
/// corresponding input element was newly added to the filter or may have previously existed.</returns>
/// <remarks><seealso href="https://redis.io/commands/bf.madd"/></remarks>
public async Task<bool[]> MAddAsync(RedisKey key, RedisValue[] items)
public async Task<bool[]> MAddAsync(RedisKey key, params RedisValue[] items)
{
if (items == null)
throw new ArgumentNullException(nameof(items));
if (items.Length < 1)
throw new ArgumentOutOfRangeException(nameof(items));
List<object> args = new List<object> { key };
......@@ -299,8 +300,8 @@ namespace NRedisStack.Core
/// <remarks><seealso href="https://redis.io/commands/bf.mexists"/></remarks>
public bool[] MExists(RedisKey key, RedisValue[] items)
{
if (items == null)
throw new ArgumentNullException(nameof(items));
if (items.Length < 1)
throw new ArgumentOutOfRangeException(nameof(items));
List<object> args = new List<object> { key };
......@@ -323,8 +324,8 @@ namespace NRedisStack.Core
/// <remarks><seealso href="https://redis.io/commands/bf.mexists"/></remarks>
public async Task<bool[]> MExistsAsync(RedisKey key, RedisValue[] items)
{
if (items == null)
throw new ArgumentNullException(nameof(items));
if (items.Length < 1)
throw new ArgumentOutOfRangeException(nameof(items));
List<object> args = new List<object> { key };
......@@ -348,7 +349,7 @@ namespace NRedisStack.Core
/// created in size of the last sub-filter multiplied by expansion.</param>
/// <param name="nonscaling">(Optional) <see langword="true"/> toprevent the filter
/// from creating additional sub-filters if initial capacity is reached.</param>
/// <returns><see langword="true"/> if executed correctly, <see langword="false"/> otherwise.</returns>
/// <returns><see langword="true"/> if executed correctly, error otherwise/></returns>
/// <remarks><seealso href="https://redis.io/commands/bf.reserve"/></remarks>
public bool Reserve(RedisKey key, double errorRate, long capacity,
int? expansion = null, bool nonscaling = false)
......@@ -365,7 +366,7 @@ namespace NRedisStack.Core
args.Add(BloomArgs.NONSCALING);
}
return ResponseParser.ParseOKtoBoolean(_db.Execute(BF.RESERVE, args));
return ResponseParser.OKtoBoolean(_db.Execute(BF.RESERVE, args));
}
/// <summary>
......@@ -378,7 +379,7 @@ namespace NRedisStack.Core
/// created in size of the last sub-filter multiplied by expansion.</param>
/// <param name="nonscaling">(Optional) <see langword="true"/> toprevent the filter
/// from creating additional sub-filters if initial capacity is reached.</param>
/// <returns><see langword="true"/> if executed correctly, <see langword="false"/> otherwise.</returns>
/// <returns><see langword="true"/> if executed correctly, Error otherwise.</returns>
/// <remarks><seealso href="https://redis.io/commands/bf.reserve"/></remarks>
public async Task<bool> ReserveAsync(RedisKey key, double errorRate, long capacity,
int? expansion = null, bool nonscaling = false)
......@@ -396,7 +397,7 @@ namespace NRedisStack.Core
}
var result = await _db.ExecuteAsync(BF.RESERVE, args);
return ResponseParser.ParseOKtoBoolean(result);
return ResponseParser.OKtoBoolean(result);
}
/// <summary>
......@@ -406,7 +407,7 @@ namespace NRedisStack.Core
/// <param name="iterator">Iterator value; either 0 or the iterator from a previous invocation of this command.</param>
/// <returns>Tuple of iterator and data.</returns>
/// <remarks><seealso href="https://redis.io/commands/bf.scandump"/></remarks>
public Tuple<long,Byte[]>? ScanDump(RedisKey key, long iterator)
public Tuple<long,Byte[]> ScanDump(RedisKey key, long iterator)
{
return ResponseParser.ToScanDumpTuple(_db.Execute(BF.SCANDUMP, key, iterator));
}
......@@ -418,7 +419,7 @@ namespace NRedisStack.Core
/// <param name="iterator">Iterator value; either 0 or the iterator from a previous invocation of this command.</param>
/// <returns>Tuple of iterator and data.</returns>
/// <remarks><seealso href="https://redis.io/commands/bf.scandump"/></remarks>
public async Task<Tuple<long,Byte[]>?> ScanDumpAsync(RedisKey key, long iterator)
public async Task<Tuple<long,Byte[]>> ScanDumpAsync(RedisKey key, long iterator)
{
var result = await _db.ExecuteAsync(BF.SCANDUMP, key, iterator);
return ResponseParser.ToScanDumpTuple(result);
......
......@@ -47,7 +47,7 @@ namespace NRedisStack.Core
/// and the Amount by which the item counter is to be increased.</param>
/// <returns>Count of each item after increment.</returns>
/// <remarks><seealso href="https://redis.io/commands/cms.incrby"/></remarks>
public long[]? IncrBy(RedisKey key, Tuple<RedisValue, long>[] itemIncrements)
public long[] IncrBy(RedisKey key, Tuple<RedisValue, long>[] itemIncrements)
{
if (itemIncrements.Length < 1)
throw new ArgumentException(nameof(itemIncrements));
......@@ -69,7 +69,7 @@ namespace NRedisStack.Core
/// and the Amount by which the item counter is to be increased.</param>
/// <returns>Count of each item after increment.</returns>
/// <remarks><seealso href="https://redis.io/commands/cms.incrby"/></remarks>
public async Task<long[]?> IncrByAsync(RedisKey key, Tuple<RedisValue, long>[] itemIncrements)
public async Task<long[]> IncrByAsync(RedisKey key, Tuple<RedisValue, long>[] itemIncrements)
{
if (itemIncrements.Length < 1)
throw new ArgumentException(nameof(itemIncrements));
......@@ -91,7 +91,7 @@ namespace NRedisStack.Core
/// <param name="key">Name of the key to return information about.</param>
/// <returns>Information of the sketch.</returns>
/// <remarks><seealso href="https://redis.io/commands/cms.info"/></remarks>
public CmsInformation? Info(RedisKey key)
public CmsInformation Info(RedisKey key)
{
var info = _db.Execute(CMS.INFO, key);
return ResponseParser.ToCmsInfo(info);
......@@ -103,13 +103,12 @@ namespace NRedisStack.Core
/// <param name="key">Name of the key to return information about.</param>
/// <returns>Information of the sketch.</returns>
/// <remarks><seealso href="https://redis.io/commands/cms.info"/></remarks>
public async Task<CmsInformation?> InfoAsync(RedisKey key)
public async Task<CmsInformation> InfoAsync(RedisKey key)
{
var info = await _db.ExecuteAsync(CMS.INFO, key);
return ResponseParser.ToCmsInfo(info);
}
//TODO: functions that returns OK cannot return false, they return OK or ERROR. fix this (the Redis functions that can return also false - will return 1 for true ans 0 for false)
/// <summary>
/// Initializes a Count-Min Sketch to dimensions specified by user.
/// </summary>
......@@ -121,7 +120,7 @@ namespace NRedisStack.Core
/// <remarks><seealso href="https://redis.io/commands/cms.initbydim"/></remarks>
public bool InitByDim(RedisKey key, long width, long depth)
{
return ResponseParser.ParseOKtoBoolean(_db.Execute(CMS.INITBYDIM, key, width, depth));
return ResponseParser.OKtoBoolean(_db.Execute(CMS.INITBYDIM, key, width, depth));
}
/// <summary>
......@@ -136,7 +135,7 @@ namespace NRedisStack.Core
public async Task<bool> InitByDimAsync(RedisKey key, long width, long depth)
{
var result = await _db.ExecuteAsync(CMS.INITBYDIM, key, width, depth);
return ResponseParser.ParseOKtoBoolean(result);
return ResponseParser.OKtoBoolean(result);
}
/// <summary>
......@@ -149,7 +148,7 @@ namespace NRedisStack.Core
/// <remarks><seealso href="https://redis.io/commands/cms.initbyprob"/></remarks>
public bool InitByProb(RedisKey key, double error, double probability)
{
return ResponseParser.ParseOKtoBoolean(_db.Execute(CMS.INITBYPROB, key, error, probability));
return ResponseParser.OKtoBoolean(_db.Execute(CMS.INITBYPROB, key, error, probability));
}
/// <summary>
......@@ -163,7 +162,7 @@ namespace NRedisStack.Core
public async Task<bool> InitByProbAsync(RedisKey key, double error, double probability)
{
var result = await _db.ExecuteAsync(CMS.INITBYPROB, key, error, probability);
return ResponseParser.ParseOKtoBoolean(result);
return ResponseParser.OKtoBoolean(result);
}
/// <summary>
......@@ -178,7 +177,7 @@ namespace NRedisStack.Core
public bool Merge(RedisValue destination, long numKeys, RedisValue[] source, long[]? weight = null)
{
if (source.Length < 1)
throw new ArgumentNullException(nameof(source));
throw new ArgumentOutOfRangeException(nameof(source));
List<object> args = new List<object> { destination, numKeys };
......@@ -190,7 +189,7 @@ namespace NRedisStack.Core
foreach (var w in weight) args.Add(w);
}
return ResponseParser.ParseOKtoBoolean(_db.Execute(CMS.MERGE, args));
return ResponseParser.OKtoBoolean(_db.Execute(CMS.MERGE, args));
}
/// <summary>
......@@ -205,7 +204,7 @@ namespace NRedisStack.Core
public async Task<bool> MergeAsync(RedisValue destination, long numKeys, RedisValue[] source, long[]? weight = null)
{
if (source.Length < 1)
throw new ArgumentNullException(nameof(source));
throw new ArgumentOutOfRangeException(nameof(source));
List<object> args = new List<object> { destination, numKeys };
......@@ -218,7 +217,7 @@ namespace NRedisStack.Core
}
var result = await _db.ExecuteAsync(CMS.MERGE, args);
return ResponseParser.ParseOKtoBoolean(result);
return ResponseParser.OKtoBoolean(result);
}
/// <summary>
......@@ -228,10 +227,10 @@ namespace NRedisStack.Core
/// <param name="items">One or more items for which to return the count.</param>
/// <returns>Array with a min-count of each of the items in the sketch</returns>
/// <remarks><seealso href="https://redis.io/commands/cms.query"/></remarks>
public long[]? Query(RedisKey key, RedisValue[] items) //TODO: Create second version of this function using params for items input
public long[] Query(RedisKey key, params RedisValue[] items)
{
if (items.Length < 1)
throw new ArgumentNullException(nameof(items));
throw new ArgumentOutOfRangeException(nameof(items));
List<object> args = new List<object> { key };
foreach (var item in items) args.Add(item);
......@@ -247,10 +246,10 @@ namespace NRedisStack.Core
/// <param name="items">One or more items for which to return the count.</param>
/// <returns>Array with a min-count of each of the items in the sketch</returns>
/// <remarks><seealso href="https://redis.io/commands/cms.query"/></remarks>
public async Task<long[]?> QueryAsync(RedisKey key, RedisValue[] items) //TODO: Create second version of this function using params for items input
public async Task<long[]> QueryAsync(RedisKey key, params RedisValue[] items)
{
if (items.Length < 1)
throw new ArgumentNullException(nameof(items));
throw new ArgumentOutOfRangeException(nameof(items));
List<object> args = new List<object> { key };
foreach (var item in items) args.Add(item);
......
......@@ -145,7 +145,7 @@ namespace NRedisStack.Core
/// <param name="key">Name of the key to return information about.</param>
/// <returns>Information of the filter.</returns>
/// <remarks><seealso href="https://redis.io/commands/cf.info"/></remarks>
public CuckooInformation? Info(RedisKey key)
public CuckooInformation Info(RedisKey key)
{
var info = _db.Execute(CF.INFO, key);
return ResponseParser.ToCuckooInfo(info);
......@@ -157,7 +157,7 @@ namespace NRedisStack.Core
/// <param name="key">Name of the key to return information about.</param>
/// <returns>Information of the filter.</returns>
/// <remarks><seealso href="https://redis.io/commands/cf.info"/></remarks>
public async Task<CuckooInformation?> InfoAsync(RedisKey key)
public async Task<CuckooInformation> InfoAsync(RedisKey key)
{
var info = await _db.ExecuteAsync(CF.INFO, key);
return ResponseParser.ToCuckooInfo(info);
......@@ -174,8 +174,8 @@ namespace NRedisStack.Core
/// <remarks><seealso href="https://redis.io/commands/cf.insert"/></remarks>
public bool[] Insert(RedisKey key, RedisValue[] items, int? capacity = null, bool nocreate = false)
{
if (items == null)
throw new ArgumentNullException(nameof(items));
if (items.Length < 1)
throw new ArgumentOutOfRangeException(nameof(items));
List<object> args = new List<object> { key };
......@@ -210,8 +210,8 @@ namespace NRedisStack.Core
/// <remarks><seealso href="https://redis.io/commands/cf.insert"/></remarks>
public async Task<bool[]> InsertAsync(RedisKey key, RedisValue[] items, int? capacity = null, bool nocreate = false)
{
if (items == null)
throw new ArgumentNullException(nameof(items));
if (items.Length < 1)
throw new ArgumentOutOfRangeException(nameof(items));
List<object> args = new List<object> { key };
......@@ -249,8 +249,8 @@ namespace NRedisStack.Core
/// <remarks><seealso href="https://redis.io/commands/cf.insertnx"/></remarks>
public bool[] InsertNX(RedisKey key, RedisValue[] items, int? capacity = null, bool nocreate = false)
{
if (items == null)
throw new ArgumentNullException(nameof(items));
if (items.Length < 1)
throw new ArgumentOutOfRangeException(nameof(items));
List<object> args = new List<object> { key };
......@@ -287,8 +287,8 @@ namespace NRedisStack.Core
/// <remarks><seealso href="https://redis.io/commands/cf.insertnx"/></remarks>
public async Task<bool[]> InsertNXAsync(RedisKey key, RedisValue[] items, int? capacity = null, bool nocreate = false)
{
if (items == null)
throw new ArgumentNullException(nameof(items));
if (items.Length < 1)
throw new ArgumentOutOfRangeException(nameof(items));
List<object> args = new List<object> { key };
......@@ -323,7 +323,7 @@ namespace NRedisStack.Core
/// <remarks><seealso href="https://redis.io/commands/cf.loadchunk"/></remarks>
public bool LoadChunk(RedisKey key, long iterator, Byte[] data)
{
return ResponseParser.ParseOKtoBoolean(_db.Execute(CF.LOADCHUNK, key, iterator, data));
return ResponseParser.OKtoBoolean(_db.Execute(CF.LOADCHUNK, key, iterator, data));
}
/// <summary>
......@@ -337,7 +337,7 @@ namespace NRedisStack.Core
public async Task<bool> LoadChunkAsync(RedisKey key, long iterator, Byte[] data)
{
var result = await _db.ExecuteAsync(CF.LOADCHUNK, key, iterator, data);
return ResponseParser.ParseOKtoBoolean(result);
return ResponseParser.OKtoBoolean(result);
}
/// <summary>
......@@ -348,10 +348,10 @@ namespace NRedisStack.Core
/// <returns>An array of booleans, for each item <see langword="true"/> means the item may exist in the filter,
/// and <see langword="false"/> means the item may exist in the filter.</returns>
/// <remarks><seealso href="https://redis.io/commands/cf.mexists"/></remarks>
public bool[] MExists(RedisKey key, RedisValue[] items)
public bool[] MExists(RedisKey key, params RedisValue[] items)
{
if (items == null)
throw new ArgumentNullException(nameof(items));
if (items.Length < 1)
throw new ArgumentOutOfRangeException(nameof(items));
List<object> args = new List<object> { key };
......@@ -371,10 +371,10 @@ namespace NRedisStack.Core
/// <returns>An array of booleans, for each item <see langword="true"/> means the item may exist in the filter,
/// and <see langword="false"/> means the item may exist in the filter.</returns>
/// <remarks><seealso href="https://redis.io/commands/cf.mexists"/></remarks>
public async Task<bool[]> MExistsAsync(RedisKey key, RedisValue[] items)
public async Task<bool[]> MExistsAsync(RedisKey key, params RedisValue[] items)
{
if (items == null)
throw new ArgumentNullException(nameof(items));
if (items.Length < 1)
throw new ArgumentOutOfRangeException(nameof(items));
List<object> args = new List<object> { key };
......@@ -397,7 +397,7 @@ namespace NRedisStack.Core
/// declaring filter as full and creating an additional filter.</param>
/// <param name="expansion">(Optional) When capacity is reached, an additional sub-filter is
/// created in size of the last sub-filter multiplied by expansion.</param>
/// <returns><see langword="true"/> if executed correctly, <see langword="false"/> otherwise.</returns>
/// <returns><see langword="true"/> if executed correctly, Error otherwise.</returns>
/// <remarks><seealso href="https://redis.io/commands/cf.reserve"/></remarks>
public bool Reserve(RedisKey key, long capacity,
long? bucketSize = null, int? maxIterations = null, int? expansion = null)
......@@ -422,7 +422,7 @@ namespace NRedisStack.Core
args.Add(expansion);
}
return ResponseParser.ParseOKtoBoolean(_db.Execute(CF.RESERVE, args));
return ResponseParser.OKtoBoolean(_db.Execute(CF.RESERVE, args));
}
/// <summary>
......@@ -435,7 +435,7 @@ namespace NRedisStack.Core
/// declaring filter as full and creating an additional filter.</param>
/// <param name="expansion">(Optional) When capacity is reached, an additional sub-filter is
/// created in size of the last sub-filter multiplied by expansion.</param>
/// <returns><see langword="true"/> if executed correctly, <see langword="false"/> otherwise.</returns>
/// <returns><see langword="true"/> if executed correctly, Error otherwise.</returns>
/// <remarks><seealso href="https://redis.io/commands/cf.reserve"/></remarks>
public async Task<bool> ReserveAsync(RedisKey key, long capacity,
long? bucketSize = null, int? maxIterations = null, int? expansion = null)
......@@ -461,7 +461,7 @@ namespace NRedisStack.Core
}
var result = await _db.ExecuteAsync(CF.RESERVE, args);
return ResponseParser.ParseOKtoBoolean(result);
return ResponseParser.OKtoBoolean(result);
}
/// <summary>
......@@ -471,7 +471,7 @@ namespace NRedisStack.Core
/// <param name="iterator">Iterator value; either 0 or the iterator from a previous invocation of this command.</param>
/// <returns>Tuple of iterator and data.</returns>
/// <remarks><seealso href="https://redis.io/commands/cf.scandump"/></remarks>
public Tuple<long,Byte[]>? ScanDump(RedisKey key, long iterator)
public Tuple<long,Byte[]> ScanDump(RedisKey key, long iterator)
{
return ResponseParser.ToScanDumpTuple(_db.Execute(CF.SCANDUMP, key, iterator));
}
......@@ -483,7 +483,7 @@ namespace NRedisStack.Core
/// <param name="iterator">Iterator value; either 0 or the iterator from a previous invocation of this command.</param>
/// <returns>Tuple of iterator and data.</returns>
/// <remarks><seealso href="https://redis.io/commands/cf.scandump"/></remarks>
public async Task<Tuple<long,Byte[]>?> ScanDumpAsync(RedisKey key, long iterator)
public async Task<Tuple<long,Byte[]>> ScanDumpAsync(RedisKey key, long iterator)
{
var result = await _db.ExecuteAsync(CF.SCANDUMP, key, iterator);
return ResponseParser.ToScanDumpTuple(result);
......
......@@ -8,21 +8,21 @@ using NRedisStack.Core.Bloom.DataTypes;
using NRedisStack.Core.CuckooFilter.DataTypes;
using NRedisStack.Core.CountMinSketch.DataTypes;
using NRedisStack.Core.TopK.DataTypes;
using NRedisStack.Core.Tdigest.DataTypes;
namespace NRedisStack.Core
{
public static class ResponseParser
{
//TODO: See if I can change the code to remove the warnings
public static bool ParseOKtoBoolean(RedisResult result)
public static bool OKtoBoolean(RedisResult result)
{
return result.ToString() == "OK";
}
public static bool[] ToBooleanArray(RedisResult result)
{
RedisResult[] redisResults = (RedisResult[])result;
RedisResult[]? redisResults = ToArray(result);
bool[] boolArr = new bool[redisResults.Length];
for (int i = 0; i < redisResults.Length; i++)
{
......@@ -32,21 +32,50 @@ namespace NRedisStack.Core
return boolArr;
}
public static RedisResult[]? ToArray(RedisResult result)
public static RedisResult[] ToArray(RedisResult result)
{
return (RedisResult[]?)result;
var redisResults = (RedisResult[]?)result;
if(redisResults != null)
return redisResults;
throw new ArgumentNullException(nameof(redisResults));
}
public static long ToLong(RedisResult result)
{
if (result.Type == ResultType.None) return 0;
return (long)result;
if((long?) result == null)
throw new ArgumentNullException(nameof(result));
return (long) result;
}
public static long[]? ToLongArray(RedisResult result)
public static double ToDouble(RedisResult result)
{
if (result.Type == ResultType.None) return null;
return (long[])result;
if((double?) result == null)
throw new ArgumentNullException(nameof(result));
return (double) result;
}
public static double[] ToDoubleArray(RedisResult result)
{
List<double> redisResults = new List<double>();
foreach(var res in ToArray(result))
{
redisResults.Add(ToDouble(res));
}
return redisResults.ToArray();
}
public static long[] ToLongArray(RedisResult result)
{
List<long> redisResults = new List<long>();
foreach(var res in ToArray(result))
{
redisResults.Add(ToLong(res));
}
return redisResults.ToArray();
}
public static TimeStamp ToTimeStamp(RedisResult result)
......@@ -66,35 +95,36 @@ namespace NRedisStack.Core
public static TimeSeriesTuple? ToTimeSeriesTuple(RedisResult result)
{
RedisResult[]? redisResults = (RedisResult[]?)result;
RedisResult[] redisResults = ToArray(result);
if (redisResults.Length == 0) return null;
return new TimeSeriesTuple(ToTimeStamp(redisResults[0]), (double)redisResults[1]);
}
public static Tuple<long, Byte[]>? ToScanDumpTuple(RedisResult result)
public static Tuple<long, Byte[]> ToScanDumpTuple(RedisResult result)
{
RedisResult[]? redisResults = (RedisResult[]?)result;
RedisResult[] redisResults = ToArray(result);
if (redisResults == null || redisResults.Length == 0) return null;
return new Tuple<long, Byte[]>((long)redisResults[0], (Byte[])redisResults[1]);
}
public static HashEntry? ToHashEntry(RedisResult result)
public static HashEntry ToHashEntry(RedisResult result)
{
RedisValue[]? redisResults = (RedisValue[]?)result;
if (redisResults.Length == 0) return null;
return new HashEntry(redisResults[0], redisResults[1]);
RedisResult[] redisResults = ToArray(result);
if (redisResults.Length < 2)
throw new ArgumentOutOfRangeException(nameof(result));
return new HashEntry((RedisValue)(redisResults[0]), ((RedisValue)redisResults[1]));
}
public static HashEntry[]? ToHashEntryArray(RedisResult result)
public static HashEntry[] ToHashEntryArray(RedisResult result)
{
RedisValue[]? redisResults = (RedisValue[]?)result;
RedisResult[] redisResults = ToArray(result);
var hash = new HashEntry[redisResults.Length / 2];
if (redisResults.Length == 0) return hash;
for (int i = 0; i < redisResults.Length - 1; i += 2)
hash[i / 2] = new HashEntry(redisResults[i], redisResults[i + 1]);
hash[i / 2] = new HashEntry(((RedisValue)redisResults[i]), ((RedisValue)redisResults[i + 1]));
return hash;
}
......@@ -181,13 +211,11 @@ namespace NRedisStack.Core
return DuplicatePolicyExtensions.AsPolicy(policyStatus.ToUpper());
}
public static BloomInformation? ToBloomInfo(RedisResult result) //TODO: Think about a different implementation, because if the output of BF.INFO changes or even just the names of the labels then the parsing will not work
public static BloomInformation ToBloomInfo(RedisResult result) //TODO: Think about a different implementation, because if the output of BF.INFO changes or even just the names of the labels then the parsing will not work
{
long capacity, size, numberOfFilters, numberOfItemsInserted, expansionRate;
capacity = size = numberOfFilters = numberOfItemsInserted = expansionRate = -1;
RedisResult[]? redisResults = (RedisResult[]?)result;
if (redisResults == null) return null;
RedisResult[] redisResults = ToArray(result);
for (int i = 0; i < redisResults.Length; ++i)
{
......@@ -215,7 +243,7 @@ namespace NRedisStack.Core
return new BloomInformation(capacity, size, numberOfFilters, numberOfItemsInserted, expansionRate);
}
public static CuckooInformation? ToCuckooInfo(RedisResult result) //TODO: Think about a different implementation, because if the output of BF.INFO changes or even just the names of the labels then the parsing will not work
public static CuckooInformation ToCuckooInfo(RedisResult result) //TODO: Think about a different implementation, because if the output of BF.INFO changes or even just the names of the labels then the parsing will not work
{
long size, numberOfBuckets, numberOfFilter, numberOfItemsInserted,
numberOfItemsDeleted, bucketSize, expansionRate, maxIteration;
......@@ -224,9 +252,7 @@ namespace NRedisStack.Core
numberOfItemsInserted = numberOfItemsDeleted =
bucketSize = expansionRate = maxIteration = -1;
RedisResult[]? redisResults = (RedisResult[]?)result;
if (redisResults == null) return null;
RedisResult[] redisResults = ToArray(result);
for (int i = 0; i < redisResults.Length; ++i)
{
......@@ -265,15 +291,13 @@ namespace NRedisStack.Core
numberOfItemsDeleted, bucketSize, expansionRate, maxIteration);
}
public static CmsInformation? ToCmsInfo(RedisResult result) //TODO: Think about a different implementation, because if the output of CMS.INFO changes or even just the names of the labels then the parsing will not work
public static CmsInformation ToCmsInfo(RedisResult result) //TODO: Think about a different implementation, because if the output of CMS.INFO changes or even just the names of the labels then the parsing will not work
{
long width, depth, count;
width = depth = count = -1;
RedisResult[]? redisResults = (RedisResult[]?)result;
if (redisResults == null) return null;
RedisResult[] redisResults = ToArray(result);
for (int i = 0; i < redisResults.Length; ++i)
{
......@@ -296,7 +320,7 @@ namespace NRedisStack.Core
return new CmsInformation(width, depth, count);
}
public static TopKInformation? ToTopKInfo(RedisResult result) //TODO: Think about a different implementation, because if the output of CMS.INFO changes or even just the names of the labels then the parsing will not work
public static TopKInformation ToTopKInfo(RedisResult result) //TODO: Think about a different implementation, because if the output of CMS.INFO changes or even just the names of the labels then the parsing will not work
{
long k, width, depth;
double decay;
......@@ -304,9 +328,7 @@ namespace NRedisStack.Core
k = width = depth = -1;
decay = -1.0;
RedisResult[]? redisResults = (RedisResult[]?)result;
if (redisResults == null) return null;
RedisResult[] redisResults = ToArray(result);
for (int i = 0; i < redisResults.Length; ++i)
{
......@@ -332,6 +354,50 @@ namespace NRedisStack.Core
return new TopKInformation(k, width, depth, decay);
}
public static TdigestInformation ToTdigestInfo(RedisResult result) //TODO: Think about a different implementation, because if the output of CMS.INFO changes or even just the names of the labels then the parsing will not work
{
long compression, capacity, mergedNodes, unmergedNodes, totalCompressions;
string? mergedWeight, unmergedWeight;
compression = capacity = mergedNodes = unmergedNodes = totalCompressions = -1;
mergedWeight = unmergedWeight = "";
RedisResult[] redisResults = ToArray(result);
for (int i = 0; i < redisResults.Length; ++i)
{
string? label = redisResults[i++].ToString();
switch (label)
{
case "Compression":
compression = (long)redisResults[i];
break;
case "Capacity":
capacity = (long)redisResults[i];
break;
case "Merged nodes":
mergedNodes = (long)redisResults[i];
break;
case "Unmerged nodes":
unmergedNodes = (long)redisResults[i];
break;
case "Merged weight":
mergedWeight = redisResults[i].ToString();
break;
case "Unmerged weight":
unmergedWeight = redisResults[i].ToString();
break;
case "Total compressions":
totalCompressions = (long)redisResults[i];
break;
}
}
return new TdigestInformation(compression, capacity, mergedNodes, unmergedNodes,
mergedWeight, unmergedWeight, totalCompressions);
}
public static TimeSeriesInformation ToTimeSeriesInfo(RedisResult result)
{
long totalSamples = -1, memoryUsage = -1, retentionTime = -1, chunkSize = -1, chunkCount = -1;
......@@ -392,9 +458,10 @@ namespace NRedisStack.Core
lastTimestamp, retentionTime, chunkCount, chunkSize, labels, sourceKey, rules, duplicatePolicy);
}
public static IReadOnlyList<string> ToStringArray(RedisResult result)
public static IReadOnlyList<string>? ToStringArray(RedisResult result)
{
RedisResult[] redisResults = (RedisResult[])result;
RedisResult[] redisResults = ToArray(result);
var list = new List<string>();
if (redisResults.Length == 0) return list;
Array.ForEach(redisResults, str => list.Add((string)str));
......
namespace NRedisStack.Core.Tdigest.DataTypes
{
/// <summary>
/// This class represents the response for TDIGEST.INFO command.
/// This object has Read-only properties and cannot be generated outside a TDIGEST.INFO response.
/// </summary>
public class TdigestInformation
{
public long Compression { get; private set; }
public long Capacity { get; private set; }
public long MergedNodes { get; private set; }
public long UnmergedNodes { get; private set; }
public string MergedWeight { get; private set; }
public string UnmergedWeight { get; private set; }
public long TotalCompressions { get; private set; }
internal TdigestInformation(long compression, long capacity, long mergedNodes,
long unmergedNodes, string mergedWeight,
string unmergedWeight, long totalCompressions)
{
Compression = compression;
Capacity = capacity;
MergedNodes = mergedNodes;
UnmergedNodes = unmergedNodes;
MergedWeight = mergedWeight;
UnmergedWeight = unmergedWeight;
TotalCompressions = totalCompressions;
}
}
}
\ No newline at end of file
namespace NRedisStack.Core.Literals
{
internal class TdigestArgs
{
public static string COMPRESSION => "COMPRESSION";
}
}
\ No newline at end of file
namespace NRedisStack.Core.Literals
{
internal class TDIGEST
{
public static string CREATE => "TDIGEST.CREATE";
public static string RESET => "TDIGEST.RESET";
public static string ADD => "TDIGEST.ADD";
public static string MERGE => "TDIGEST.MERGE";
public static string MERGESTORE => "TDIGEST.MERGESTORE";
public static string MIN => "TDIGEST.MIN";
public static string MAX => "TDIGEST.MAX";
public static string QUANTILE => "TDIGEST.QUANTILE";
public static string CDF => "TDIGEST.CDF";
public static string TRIMMED_MEAN => "TDIGEST.TRIMMED_MEAN";
public static string INFO => "TDIGEST.INFO";
}
}
\ No newline at end of file
using NRedisStack.Core.Tdigest.DataTypes;
using NRedisStack.Core.Literals;
using StackExchange.Redis;
namespace NRedisStack.Core
{
public class TdigestCommands
{
IDatabase _db;
public TdigestCommands(IDatabase db)
{
_db = db;
}
/// <summary>
/// Adds one or more observations to a t-digest sketch.
/// </summary>
/// <param name="key">The name of the sketch.</param>
/// <param name="value">The value of the observation.</param>
/// <param name="weight">The weight of this observation.</param>
/// <returns><see langword="true"/> if executed correctly, error otherwise</returns>
/// <remarks><seealso href="https://redis.io/commands/tdigest.add"/></remarks>
public bool Add(RedisKey key, double item, double weight)
{
if (weight < 0) throw new ArgumentException(nameof(weight));
return ResponseParser.OKtoBoolean(_db.Execute(TDIGEST.ADD, key, item, weight));
}
/// <summary>
/// Adds one or more observations to a t-digest sketch.
/// </summary>
/// <param name="key">The name of the sketch.</param>
/// <param name="value">The value of the observation.</param>
/// <param name="weight">The weight of this observation.</param>
/// <returns><see langword="true"/> if executed correctly, error otherwise</returns>
/// <remarks><seealso href="https://redis.io/commands/tdigest.add"/></remarks>
public async Task<bool> AddAsync(RedisKey key, double item, double weight)
{
if (weight < 0) throw new ArgumentException(nameof(weight));
var result = await _db.ExecuteAsync(TDIGEST.ADD, key, item);
return ResponseParser.OKtoBoolean(result);
}
/// <summary>
/// Adds one or more observations to a t-digest sketch.
/// </summary>
/// <param name="key">The name of the sketch.</param>
/// <param name="valueWeight">Tuple of the value of the observation and The weight of this observation.</param>
/// <returns><see langword="true"/> if executed correctly, error otherwise</returns>
/// <remarks><seealso href="https://redis.io/commands/tdigest.add"/></remarks>
public bool Add(RedisKey key, Tuple<double, double>[] valueWeight)
{
var args = new List<object> { key };
foreach (var pair in valueWeight)
{
if (pair.Item2 < 0) throw new ArgumentException(nameof(pair.Item2));
args.Add(pair.Item1);
args.Add(pair.Item2);
}
return ResponseParser.OKtoBoolean(_db.Execute(TDIGEST.ADD, args));
}
/// <summary>
/// Adds one or more observations to a t-digest sketch.
/// </summary>
/// <param name="key">The name of the sketch.</param>
/// <param name="valueWeight">Tuple of the value of the observation and The weight of this observation.</param>
/// <returns><see langword="true"/> if executed correctly, error otherwise</returns>
/// <remarks><seealso href="https://redis.io/commands/tdigest.add"/></remarks>
public async Task<bool> AddAsync(RedisKey key, Tuple<double, double>[] valueWeight)
{
var args = new List<object> { key };
foreach (var pair in valueWeight)
{
if (pair.Item2 < 0) throw new ArgumentException(nameof(pair.Item2));
args.Add(pair.Item1);
args.Add(pair.Item2);
}
return ResponseParser.OKtoBoolean(await _db.ExecuteAsync(TDIGEST.ADD, args));
}
/// <summary>
/// Estimate the fraction of all observations added which are <= value.
/// </summary>
/// <param name="key">The name of the sketch.</param>
/// <param name="value">upper limit of observation value.</param>
/// <returns>double-reply - estimation of the fraction of all observations added which are <= value</returns>
/// <remarks><seealso href="https://redis.io/commands/tdigest.cdf"/></remarks>
public double CDF(RedisKey key, double item)
{
return ResponseParser.ToDouble(_db.Execute(TDIGEST.ADD, key, item));
}
/// <summary>
/// Estimate the fraction of all observations added which are <= value.
/// </summary>
/// <param name="key">The name of the sketch.</param>
/// <param name="value">upper limit of observation value.</param>
/// <returns>double-reply - estimation of the fraction of all observations added which are <= value</returns>
/// <remarks><seealso href="https://redis.io/commands/tdigest.cdf"/></remarks>
public async Task<double> CDF(RedisKey key, double item, double weight)
{
var result = await _db.ExecuteAsync(TDIGEST.ADD, key, item);
return ResponseParser.ToDouble(result);
}
/// <summary>
/// Allocate memory and initialize a t-digest sketch.
/// </summary>
/// <param name="key">The name of the sketch.</param>
/// <param name="compression">The compression parameter.</param>
/// <returns>double-reply - estimation of the fraction of all observations added which are <= value</returns>
/// <remarks><seealso href="https://redis.io/commands/tdigest.create"/></remarks>
public double Create(RedisKey key, long compression = 100)
{
return ResponseParser.ToDouble(_db.Execute(TDIGEST.CREATE, key, compression));
}
/// <summary>
/// Allocate memory and initialize a t-digest sketch.
/// </summary>
/// <param name="key">The name of the sketch.</param>
/// <param name="compression">The compression parameter.</param>
/// <returns>double-reply - estimation of the fraction of all observations added which are <= value</returns>
/// <remarks><seealso href="https://redis.io/commands/tdigest.create"/></remarks>
public async Task<double> CreateAsync(RedisKey key, long compression = 100)
{
return ResponseParser.ToDouble(await _db.ExecuteAsync(TDIGEST.CREATE, key, compression));
}
/// <summary>
/// Returns information about a sketch.
/// </summary>
/// <param name="key">The name of the sketch.</param>
/// <returns>information about a sketch</returns>
/// <remarks><seealso href="https://redis.io/commands/tdigest.info"/></remarks>
public TdigestInformation Info(RedisKey key)
{
return ResponseParser.ToTdigestInfo(_db.Execute(TDIGEST.INFO, key));
}
/// <summary>
/// Returns information about a sketch.
/// </summary>
/// <param name="key">The name of the sketch.</param>
/// <returns>information about a sketch</returns>
/// <remarks><seealso href="https://redis.io/commands/tdigest.info"/></remarks>
public async Task<TdigestInformation> InfoAsync(RedisKey key)
{
return ResponseParser.ToTdigestInfo(await _db.ExecuteAsync(TDIGEST.INFO, key));
}
/// <summary>
/// Get the maximum observation value from the sketch.
/// </summary>
/// <param name="key">The name of the sketch.</param>
/// <returns>the maximum observation value from the sketch</returns>
/// <remarks><seealso href="https://redis.io/commands/tdigest.max"/></remarks>
public RedisResult Max(RedisKey key)
{
return _db.Execute(TDIGEST.MAX, key);
}
/// <summary>
/// Get the maximum observation value from the sketch.
/// </summary>
/// <param name="key">The name of the sketch.</param>
/// <returns>the maximum observation value from the sketch</returns>
/// <remarks><seealso href="https://redis.io/commands/tdigest.max"/></remarks>
public async Task<RedisResult> MaxAsync(RedisKey key)
{
return await _db.ExecuteAsync(TDIGEST.MAX, key);
}
/// <summary>
/// Get the minimum observation value from the sketch.
/// </summary>
/// <param name="key">The name of the sketch.</param>
/// <returns>the minimum observation value from the sketch</returns>
/// <remarks><seealso href="https://redis.io/commands/tdigest.min"/></remarks>
public RedisResult Min(RedisKey key)
{
return _db.Execute(TDIGEST.MIN, key);
}
/// <summary>
/// Get the minimum observation value from the sketch.
/// </summary>
/// <param name="key">The name of the sketch.</param>
/// <returns>the minimum observation value from the sketch</returns>
/// <remarks><seealso href="https://redis.io/commands/tdigest.min"/></remarks>
public async Task<RedisResult> MinAsync(RedisKey key)
{
return await _db.ExecuteAsync(TDIGEST.MIN, key);
}
/// <summary>
/// Get the minimum observation value from the sketch.
/// </summary>
/// <param name="destinationKey">TSketch to copy observation values to (a t-digest data structure).</param>
/// <param name="sourceKey">Sketch to copy observation values from (a t-digest data structure).</param>
/// <returns><see langword="true"/> if executed correctly, error otherwise</returns>
/// <remarks><seealso href="https://redis.io/commands/tdigest.merge"/></remarks>
public bool Merge(RedisKey destinationKey, RedisKey sourceKey)
{
return ResponseParser.OKtoBoolean(_db.Execute(TDIGEST.MERGE, destinationKey, sourceKey));
}
/// <summary>
/// Get the minimum observation value from the sketch.
/// </summary>
/// <param name="destinationKey">TSketch to copy observation values to (a t-digest data structure).</param>
/// <param name="sourceKey">Sketch to copy observation values from (a t-digest data structure).</param>
/// <returns><see langword="true"/> if executed correctly, error otherwise</returns>
/// <remarks><seealso href="https://redis.io/commands/tdigest.merge"/></remarks>
public async Task<bool> MergeAsync(RedisKey destinationKey, RedisKey sourceKey)
{
var result = await _db.ExecuteAsync(TDIGEST.MERGE, destinationKey, sourceKey);
return ResponseParser.OKtoBoolean(result);
}
/// <summary>
/// Get the minimum observation value from the sketch.
/// </summary>
/// <param name="destinationKey">TSketch to copy observation values to (a t-digest data structure).</param>
/// <param name="sourceKeys">Sketch to copy observation values from (a t-digest data structure).</param>
/// <returns><see langword="true"/> if executed correctly, error otherwise</returns>
/// <remarks><seealso href="https://redis.io/commands/tdigest.merge"/></remarks>
public bool Merge(RedisKey destinationKey, params RedisKey[] sourceKeys)
{
if (sourceKeys.Length < 1) throw new ArgumentException(nameof(sourceKeys));
var args = sourceKeys.ToList();
args.Insert(0, destinationKey);
return ResponseParser.OKtoBoolean(_db.Execute(TDIGEST.MERGE, args));
}
/// <summary>
/// Get the minimum observation value from the sketch.
/// </summary>
/// <param name="destinationKey">TSketch to copy observation values to (a t-digest data structure).</param>
/// <param name="sourceKeys">Sketch to copy observation values from (a t-digest data structure).</param>
/// <returns><see langword="true"/> if executed correctly, error otherwise</returns>
/// <remarks><seealso href="https://redis.io/commands/tdigest.merge"/></remarks>
public async Task<bool> MergeAsync(RedisKey destinationKey, params RedisKey[] sourceKeys)
{
if (sourceKeys.Length < 1) throw new ArgumentException(nameof(sourceKeys));
var args = sourceKeys.ToList();
args.Insert(0, destinationKey);
var result = await _db.ExecuteAsync(TDIGEST.MERGE, args);
return ResponseParser.OKtoBoolean(result);
}
/// <summary>
/// Merges all of the values from 'from' keys to 'destination-key' sketch.
/// </summary>
/// <param name="destinationKey">TSketch to copy observation values to (a t-digest data structure).</param>
/// <param name="numkeys">Number of sketch(es) to copy observation values from.</param>
/// <param name="compression">The compression parameter.</param>
/// <param name="sourceKeys">Sketch to copy observation values from (a t-digest data structure).</param>
/// <returns><see langword="true"/> if executed correctly, error otherwise</returns>
/// <remarks><seealso href="https://redis.io/commands/tdigest.mergestore"/></remarks>
public bool MergeStore(RedisKey destinationKey, long numkeys, long compression = 100, params RedisKey[] sourceKeys)
{
if (sourceKeys.Length < 1) throw new ArgumentException(nameof(sourceKeys));
var args = new List<object> { destinationKey, numkeys };
foreach (var key in sourceKeys) args.Add(key);
args.Add(TdigestArgs.COMPRESSION);
args.Add(compression);
return ResponseParser.OKtoBoolean(_db.Execute(TDIGEST.MERGE, args));
}
/// <summary>
/// Merges all of the values from 'from' keys to 'destination-key' sketch.
/// </summary>
/// <param name="destinationKey">TSketch to copy observation values to (a t-digest data structure).</param>
/// <param name="numkeys">Number of sketch(es) to copy observation values from.</param>
/// <param name="compression">The compression parameter.</param>
/// <param name="sourceKeys">Sketch to copy observation values from (a t-digest data structure).</param>
/// <returns><see langword="true"/> if executed correctly, error otherwise</returns>
/// <remarks><seealso href="https://redis.io/commands/tdigest.mergestore"/></remarks>
public async Task<bool> MergeStoreAsync(RedisKey destinationKey, long numkeys, long compression = 100, params RedisKey[] sourceKeys)
{
if (sourceKeys.Length < 1) throw new ArgumentException(nameof(sourceKeys));
var args = new List<object> { destinationKey, numkeys };
foreach (var key in sourceKeys) args.Add(key);
args.Add(TdigestArgs.COMPRESSION);
args.Add(compression);
var result = await _db.ExecuteAsync(TDIGEST.MERGE, args);
return ResponseParser.OKtoBoolean(result);
}
/// <summary>
/// Returns estimates of one or more cutoffs such that a specified fraction of the observations
///added to this t-digest would be less than or equal to each of the specified cutoffs.
/// </summary>
/// <param name="key">The name of the sketch (a t-digest data structure).</param>
/// <param name="quantile">The desired fraction (between 0 and 1 inclusively).</param>
/// <returns>An array of results populated with quantile_1, cutoff_1, quantile_2, cutoff_2, ..., quantile_N, cutoff_N.</returns>
/// <remarks><seealso href="https://redis.io/commands/tdigest.quantile"/></remarks>
public double[] Quantile(RedisKey key, params double[] quantile)
{
if (quantile.Length < 1) throw new ArgumentException(nameof(quantile));
var args = new List<object> { key };
foreach (var q in quantile) args.Add(q);
return ResponseParser.ToDoubleArray(_db.Execute(TDIGEST.QUANTILE, args));
}
/// <summary>
/// Returns estimates of one or more cutoffs such that a specified fraction of the observations
///added to this t-digest would be less than or equal to each of the specified cutoffs.
/// </summary>
/// <param name="key">The name of the sketch (a t-digest data structure).</param>
/// <param name="quantile">The desired fraction (between 0 and 1 inclusively).</param>
/// <returns>An array of results populated with quantile_1, cutoff_1, quantile_2, cutoff_2, ..., quantile_N, cutoff_N.</returns>
/// <remarks><seealso href="https://redis.io/commands/tdigest.quantile"/></remarks>
public async Task<double[]> QuantileAsync(RedisKey key, params double[] quantile)
{
if (quantile.Length < 1) throw new ArgumentException(nameof(quantile));
var args = new List<object> { key };
foreach (var q in quantile) args.Add(q);
return ResponseParser.ToDoubleArray(await _db.ExecuteAsync(TDIGEST.QUANTILE, args));
}
/// <summary>
/// Reset the sketch - empty the sketch and re-initialize it
/// </summary>
/// <param name="key">The name of the sketch (a t-digest data structure).</param>
/// <returns><see langword="true"/> if executed correctly, error otherwise.</returns>
/// <remarks><seealso href="https://redis.io/commands/tdigest.reset"/></remarks>
public bool Reset(RedisKey key, params double[] quantile)
{
return ResponseParser.OKtoBoolean(_db.Execute(TDIGEST.RESET, key));
}
/// <summary>
/// Reset the sketch - empty the sketch and re-initialize it
/// </summary>
/// <param name="key">The name of the sketch (a t-digest data structure).</param>
/// <returns><see langword="true"/> if executed correctly, error otherwise.</returns>
/// <remarks><seealso href="https://redis.io/commands/tdigest.reset"/></remarks>
public async Task<bool> ResetAsync(RedisKey key, params double[] quantile)
{
return ResponseParser.OKtoBoolean(await _db.ExecuteAsync(TDIGEST.RESET, key));
}
/// <summary>
/// Reset the sketch - empty the sketch and re-initialize it
/// </summary>
/// <param name="key">The name of the sketch (a t-digest data structure).</param>
/// <param name="lowCutQuantile">Exclude observation values lower than this quantile.</param>
/// <param name="highCutQuantile">Exclude observation values higher than this quantile.</param>
/// <returns>estimation of the mean value. Will return DBL_MAX if the sketch is empty.</returns>
/// <remarks><seealso href="https://redis.io/commands/tdigest.reset"/></remarks>
public RedisResult TrimmedMean(RedisKey key, double lowCutQuantile, double highCutQuantile)
{
return _db.Execute(TDIGEST.RESET, key, lowCutQuantile, highCutQuantile);
}
/// <summary>
/// Reset the sketch - empty the sketch and re-initialize it
/// </summary>
/// <param name="key">The name of the sketch (a t-digest data structure).</param>
/// <param name="lowCutQuantile">Exclude observation values lower than this quantile.</param>
/// <param name="highCutQuantile">Exclude observation values higher than this quantile.</param>
/// <returns>estimation of the mean value. Will return DBL_MAX if the sketch is empty.</returns>
/// <remarks><seealso href="https://redis.io/commands/tdigest.reset"/></remarks>
public async Task<RedisResult> TrimmedMeanAsync(RedisKey key, double lowCutQuantile, double highCutQuantile)
{
return await _db.ExecuteAsync(TDIGEST.RESET, key, lowCutQuantile, highCutQuantile);
}
}
}
......@@ -17,7 +17,7 @@ namespace NRedisStack.Core
public bool Create(string key, long? retentionTime = null, IReadOnlyCollection<TimeSeriesLabel> labels = null, bool? uncompressed = null, long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null)
{
var args = TimeSeriesAux.BuildTsCreateArgs(key, retentionTime, labels, uncompressed, chunkSizeBytes, duplicatePolicy);
return ResponseParser.ParseOKtoBoolean(_db.Execute(TS.CREATE, args));
return ResponseParser.OKtoBoolean(_db.Execute(TS.CREATE, args));
}
public TimeSeriesInformation Info(string key)
......@@ -28,7 +28,7 @@ namespace NRedisStack.Core
public bool TimeSeriesAlter(string key, long? retentionTime = null, IReadOnlyCollection<TimeSeriesLabel> labels = null)
{
var args = TimeSeriesAux.BuildTsAlterArgs(key, retentionTime, labels);
return ResponseParser.ParseOKtoBoolean(_db.Execute(TS.ALTER, args));
return ResponseParser.OKtoBoolean(_db.Execute(TS.ALTER, args));
}
}
......
namespace NRedisStack.Core.TopK.DataTypes
{
/// <summary>
/// This class represents the response for CMS.INFO command.
/// This object has Read-only properties and cannot be generated outside a CMS.INFO response.
/// This class represents the response for TOPK.INFO command.
/// This object has Read-only properties and cannot be generated outside a TOPK.INFO response.
/// </summary>
public class TopKInformation
{
......
......@@ -2,6 +2,6 @@ namespace NRedisStack.Core.Literals
{
internal class TopKArgs
{
//TODO: TOPK doesn't have literals to save, consider deleting it, or keep it in case they need it in the future
// TOPK doesn't have literals to save, it's here in case they need it in the future
}
}
\ No newline at end of file
......@@ -4,7 +4,7 @@ using StackExchange.Redis;
namespace NRedisStack.Core
{
public class TopKCommands //TODO: Finish this
public class TopKCommands
{
IDatabase _db;
public TopKCommands(IDatabase db)
......@@ -12,24 +12,24 @@ namespace NRedisStack.Core
_db = db;
}
/// <summary>
/// Increases the count of item by increment.
/// </summary>
/// <param name="key">The name of the sketch.</param>
/// <param name="item">Item to be added.</param>
/// <returns>Array of simple-string-reply - if an element was dropped from the TopK list, null otherwise</returns>
/// <remarks><seealso href="https://redis.io/commands/topk.add"/></remarks>
public RedisResult[]? Add(RedisKey key, RedisValue item)
{
return ResponseParser.ToArray(_db.Execute(TOPK.ADD, key, item));
}
// /// <summary>
// /// Increases the count of item by increment.
// /// </summary>
// /// <param name="key">The name of the sketch.</param>
// /// <param name="item">Item to be added.</param>
// /// <returns>Array of simple-string-reply - if an element was dropped from the TopK list, null otherwise</returns>
// /// <remarks><seealso href="https://redis.io/commands/topk.add"/></remarks>
// public RedisResult[] Add(RedisKey key, RedisValue item)
// {
// return ResponseParser.ToArray(_db.Execute(TOPK.ADD, key, item));
// }
/// <inheritdoc cref="Add(RedisKey, RedisValue)"/>
public async Task<RedisResult[]?> AddAsync(RedisKey key, RedisValue item)
{
var result = await _db.ExecuteAsync(TOPK.ADD, key, item);
return ResponseParser.ToArray(result);
}
// /// <inheritdoc cref="Add(RedisKey, RedisValue)"/>
// public async Task<RedisResult[]> AddAsync(RedisKey key, RedisValue item)
// {
// var result = await _db.ExecuteAsync(TOPK.ADD, key, item);
// return ResponseParser.ToArray(result);
// }
/// <summary>
/// Increases the count of item by increment.
......@@ -40,38 +40,43 @@ namespace NRedisStack.Core
/// <remarks><seealso href="https://redis.io/commands/topk.add"/></remarks>
public RedisResult[]? Add(RedisKey key, params RedisValue[] items)
{
var args = Auxiliary.MergeArgs(key, items);
if (items.Length < 1)
throw new ArgumentOutOfRangeException(nameof(items));
var args = Auxiliary.MergeArgs(key, items);
return (RedisResult[]?)_db.Execute(TOPK.ADD, args);
}
/// <inheritdoc cref="Add(RedisKey, RedisValue[])"/>
public async Task<RedisResult[]?> AddAsync(RedisKey key, params RedisValue[] items)
{
if (items.Length < 1)
throw new ArgumentOutOfRangeException(nameof(items));
var args = Auxiliary.MergeArgs(key, items);
var result = await _db.ExecuteAsync(TOPK.ADD, args);
return (RedisResult[]?)result;
}
/// <summary>
/// Returns count for an item.
/// </summary>
/// <param name="key">Name of sketch where item is counted</param>
/// <param name="item">Item to be counted.</param>
/// <returns>count for responding item.</returns>
/// <remarks><seealso href="https://redis.io/commands/cf.count"/></remarks>
public long Count(RedisKey key, RedisValue item)
{
return ResponseParser.ToLong(_db.Execute(TOPK.COUNT, key, item));
}
// /// <summary>
// /// Returns count for an item.
// /// </summary>
// /// <param name="key">Name of sketch where item is counted</param>
// /// <param name="item">Item to be counted.</param>
// /// <returns>count for responding item.</returns>
// /// <remarks><seealso href="https://redis.io/commands/cf.count"/></remarks>
// public long Count(RedisKey key, RedisValue item)
// {
// return ResponseParser.ToLong(_db.Execute(TOPK.COUNT, key, item));
// }
/// <inheritdoc cref="Count(RedisKey, RedisValue)"/>
public async Task<long> CountAsync(RedisKey key, RedisValue item)
{
var result = await _db.ExecuteAsync(TOPK.COUNT, key, item);
return ResponseParser.ToLong(result);
}
// /// <inheritdoc cref="Count(RedisKey, RedisValue)"/>
// public async Task<long> CountAsync(RedisKey key, RedisValue item)
// {
// var result = await _db.ExecuteAsync(TOPK.COUNT, key, item);
// return ResponseParser.ToLong(result);
// }
/// <summary>
/// Returns count for an items.
......@@ -80,15 +85,21 @@ namespace NRedisStack.Core
/// <param name="item">Items to be counted.</param>
/// <returns>count for responding item.</returns>
/// <remarks><seealso href="https://redis.io/commands/cf.count"/></remarks>
public long[]? Count(RedisKey key, params RedisValue[] items)
public long[] Count(RedisKey key, params RedisValue[] items)
{
if (items.Length < 1)
throw new ArgumentOutOfRangeException(nameof(items));
var args = Auxiliary.MergeArgs(key, items);
return ResponseParser.ToLongArray(_db.Execute(TOPK.COUNT, args));
}
/// <inheritdoc cref="Count(RedisKey, RedisValue[])"/>
public async Task<long[]?> CountAsync(RedisKey key, params RedisValue[] items)
public async Task<long[]> CountAsync(RedisKey key, params RedisValue[] items)
{
if (items.Length < 1)
throw new ArgumentOutOfRangeException(nameof(items));
var args = Auxiliary.MergeArgs(key, items);
var result = await _db.ExecuteAsync(TOPK.COUNT, args);
return ResponseParser.ToLongArray(result);
......@@ -103,7 +114,7 @@ namespace NRedisStack.Core
/// and the Amount by which the item score is to be increased.</param>
/// <returns>Score of each item after increment.</returns>
/// <remarks><seealso href="https://redis.io/commands/topk.incrby"/></remarks>
public RedisResult[]? IncrBy(RedisKey key, params Tuple<RedisValue, long>[] itemIncrements)
public RedisResult[] IncrBy(RedisKey key, params Tuple<RedisValue, long>[] itemIncrements)
{
if (itemIncrements.Length < 1)
throw new ArgumentException(nameof(itemIncrements));
......@@ -125,7 +136,7 @@ namespace NRedisStack.Core
/// and the Amount by which the item score is to be increased.</param>
/// <returns>Score of each item after increment.</returns>
/// <remarks><seealso href="https://redis.io/commands/topk.incrby"/></remarks>
public async Task<RedisResult[]?> IncrByAsync(RedisKey key, params Tuple<RedisValue, long>[] itemIncrements)
public async Task<RedisResult[]> IncrByAsync(RedisKey key, params Tuple<RedisValue, long>[] itemIncrements)
{
if (itemIncrements.Length < 1)
throw new ArgumentException(nameof(itemIncrements));
......@@ -141,27 +152,25 @@ namespace NRedisStack.Core
return ResponseParser.ToArray(result);
}
// //TODO: information about what?
/// <summary>
/// Return TopK information.
/// </summary>
/// <param name="key">Name of the key to return information about.</param>
/// <returns>TopK Information.</returns>
/// <remarks><seealso href="https://redis.io/commands/topk.info"/></remarks>
public TopKInformation? Info(RedisKey key)
public TopKInformation Info(RedisKey key)
{
var info = _db.Execute(TOPK.INFO, key);
return ResponseParser.ToTopKInfo(info);
}
// //TODO: information about what?
/// <summary>
/// Return TopK information.
/// </summary>
/// <param name="key">Name of the key to return information about.</param>
/// <returns>TopK Information.</returns>
/// <remarks><seealso href="https://redis.io/commands/topk.info"/></remarks>
public async Task<TopKInformation?> InfoAsync(RedisKey key)
public async Task<TopKInformation> InfoAsync(RedisKey key)
{
var info = await _db.ExecuteAsync(TOPK.INFO, key);
return ResponseParser.ToTopKInfo(info);
......@@ -174,7 +183,7 @@ namespace NRedisStack.Core
/// <param name="withcount">return Count of each element is returned.</param>
/// <returns>Full list of items in Top K list</returns>
/// <remarks><seealso href="https://redis.io/commands/topk.list"/></remarks>
public RedisResult[]? List(RedisKey key, bool withcount = false)
public RedisResult[] List(RedisKey key, bool withcount = false)
{
var result = (withcount) ? _db.Execute(TOPK.LIST, key, "WITHCOUNT")
: _db.Execute(TOPK.LIST, key);
......@@ -188,7 +197,7 @@ namespace NRedisStack.Core
/// <param name="withcount">return Count of each element is returned.</param>
/// <returns>Full list of items in Top K list</returns>
/// <remarks><seealso href="https://redis.io/commands/topk.list"/></remarks>
public async Task<RedisResult[]?> ListAsync(RedisKey key, bool withcount = false)
public async Task<RedisResult[]> ListAsync(RedisKey key, bool withcount = false)
{
var result = await ((withcount) ? _db.ExecuteAsync(TOPK.LIST, key, "WITHCOUNT")
: _db.ExecuteAsync(TOPK.LIST, key));
......@@ -202,7 +211,7 @@ namespace NRedisStack.Core
/// <param name="item">Item to be queried.</param>
/// <returns><see langword="true"/> if item is in Top-K, <see langword="false"/> otherwise/></returns>
/// <remarks><seealso href="https://redis.io/commands/topk.query"/></remarks>
public bool? Query(RedisKey key, RedisValue item)
public bool Query(RedisKey key, RedisValue item)
{
return _db.Execute(TOPK.QUERY, key, item).ToString() == "1";
}
......@@ -214,7 +223,7 @@ namespace NRedisStack.Core
/// <param name="item">Item to be queried.</param>
/// <returns><see langword="true"/> if item is in Top-K, <see langword="false"/> otherwise/></returns>
/// <remarks><seealso href="https://redis.io/commands/topk.query"/></remarks>
public async Task<bool?> QueryAsync(RedisKey key, RedisValue item)
public async Task<bool> QueryAsync(RedisKey key, RedisValue item)
{
var result = await _db.ExecuteAsync(TOPK.QUERY, key, item);
return result.ToString() == "1";
......@@ -227,10 +236,10 @@ namespace NRedisStack.Core
/// <param name="items">Items to be queried.</param>
/// <returns>Bolean Array where <see langword="true"/> if item is in Top-K, <see langword="false"/> otherwise/></returns>
/// <remarks><seealso href="https://redis.io/commands/topk.query"/></remarks>
public bool[]? Query(RedisKey key, params RedisValue[] items)
public bool[] Query(RedisKey key, params RedisValue[] items)
{
if (items.Length < 1)
throw new ArgumentNullException(nameof(items));
throw new ArgumentOutOfRangeException(nameof(items));
var args = Auxiliary.MergeArgs(key, items);
......@@ -244,10 +253,10 @@ namespace NRedisStack.Core
/// <param name="items">Items to be queried.</param>
/// <returns>Bolean Array where <see langword="true"/> if item is in Top-K, <see langword="false"/> otherwise/></returns>
/// <remarks><seealso href="https://redis.io/commands/topk.query"/></remarks>
public async Task<bool[]?> QueryAsync(RedisKey key, params RedisValue[] items)
public async Task<bool[]> QueryAsync(RedisKey key, params RedisValue[] items)
{
if (items.Length < 1)
throw new ArgumentNullException(nameof(items));
throw new ArgumentOutOfRangeException(nameof(items));
var args = Auxiliary.MergeArgs(key, items);
......@@ -265,9 +274,9 @@ namespace NRedisStack.Core
/// <param name="decay">The probability of reducing a counter in an occupied bucket. (Default 0.9)</param>
/// <returns><see langword="true"/> if executed correctly, error otherwise/></returns>
/// <remarks><seealso href="https://redis.io/commands/topk.reserve"/></remarks>
public bool? Reserve(RedisKey key, long topk, long width = 7, long depth = 8, double decay = 0.9)
public bool Reserve(RedisKey key, long topk, long width = 7, long depth = 8, double decay = 0.9)
{
return ResponseParser.ParseOKtoBoolean(_db.Execute(TOPK.RESERVE, key, topk, width, depth, decay));
return ResponseParser.OKtoBoolean(_db.Execute(TOPK.RESERVE, key, topk, width, depth, decay));
}
/// <summary>
......@@ -280,10 +289,10 @@ namespace NRedisStack.Core
/// <param name="decay">The probability of reducing a counter in an occupied bucket. (Default 0.9)</param>
/// <returns><see langword="true"/> if executed correctly, error otherwise/></returns>
/// <remarks><seealso href="https://redis.io/commands/topk.reserve"/></remarks>
public async Task<bool?> ReserveAsync(RedisKey key, long topk, long width = 7, long depth = 8, double decay = 0.9)
public async Task<bool> ReserveAsync(RedisKey key, long topk, long width = 7, long depth = 8, double decay = 0.9)
{
var result = await _db.ExecuteAsync(TOPK.RESERVE, key, topk, width, depth, decay);
return ResponseParser.ParseOKtoBoolean(result);
return ResponseParser.OKtoBoolean(result);
}
}
}
......@@ -225,7 +225,7 @@ public class BloomTests : AbstractNRedisStackTest, IDisposable
}
[Fact]
public void TestInfo() //TODO: think again about the returned value of BF.INFO, maybe creating a new returned type
public void TestInfo()
{
IDatabase db = redisFixture.Redis.GetDatabase();
db.Execute("FLUSHALL");
......
......@@ -86,7 +86,7 @@ public class CmsTests : AbstractNRedisStackTest, IDisposable
public async void TestKeyAlreadyExistsAsync()
{
IDatabase db = redisFixture.Redis.GetDatabase();
db.Execute("FLUSHALL"); //TODO: Check if I need Execute("FLUSHALL") to be Async in the async test
db.Execute("FLUSHALL");
await db.CMS().InitByDimAsync("dup", 16, 4);
await Assert.ThrowsAsync<RedisServerException>(() => db.CMS().InitByDimAsync("dup", 8, 6));
......
......@@ -169,7 +169,7 @@ public class CuckooTests : AbstractNRedisStackTest, IDisposable
}
[Fact]
public void TestInfo() //TODO: think again about the returned value of CF.INFO, maybe creating a new returned type
public void TestInfo()
{
IDatabase db = redisFixture.Redis.GetDatabase();
db.Execute("FLUSHALL");
......@@ -184,7 +184,7 @@ public class CuckooTests : AbstractNRedisStackTest, IDisposable
}
[Fact]
public async void TestInfoAsync() //TODO: think again about the returned value of CF.INFO, maybe creating a new returned type
public async void TestInfoAsync()
{
IDatabase db = redisFixture.Redis.GetDatabase();
db.Execute("FLUSHALL");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册