Skip to content

Add bloom (BF) commands #3

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

Merged
merged 12 commits into from
Aug 4, 2022
159 changes: 147 additions & 12 deletions src/NRedisStack.Core/Bloom/BloomCommands.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using NRedisStack.Core.Bloom.DataTypes;
using NRedisStack.Core.Literals;
using StackExchange.Redis;
namespace NRedisStack.Core
Expand All @@ -11,24 +12,62 @@ public BloomCommands(IDatabase db)
_db = db;
}

public RedisResult Add(RedisKey key, string item)
/// <summary>
/// Adds an item to a Bloom Filter.
/// </summary>
/// <param name="key">The key under which the filter is found.</param>
/// <param name="item">The item to add.</param>
/// <returns><see langword="true"/> if the item did not exist in the filter, <see langword="false"/> otherwise.</returns>
/// <remarks><seealso href="https://redis.io/commands/bf.add"/></remarks>
public bool Add(RedisKey key, RedisValue item)
{
return _db.Execute(BF.ADD, key, item);
return _db.Execute(BF.ADD, key, item).ToString() == "1";
}

public bool Exists(RedisKey key, string item)
/// <summary>
/// Checks whether an item exist in the Bloom Filter or not.
/// </summary>
/// <param name="key">The name of the filter.</param>
/// <param name="item">The item to check for.</param>
/// <returns><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/bf.exists"/></remarks>
public bool Exists(RedisKey key, RedisValue item)
{
return _db.Execute(BF.EXISTS, key, item).ToString() == "1";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens when this fails and an exception is raised (if the module isn't present, for example).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will return false.
What would you expect to happen?

}

public RedisResult Info(RedisKey key)
/// <summary>
/// Return information about a bloom filter.
/// </summary>
/// <param name="key">Name of the key to return information about.</param>
/// <returns>Array with information of the filter.</returns>
/// <remarks><seealso href="https://redis.io/commands/bf.info"/></remarks>
public BloomInformation? Info(RedisKey key)
{
return _db.Execute(BF.INFO, key);
var info = _db.Execute(BF.INFO, key);
return ResponseParser.ToBloomInfo(info);
}

public RedisResult Insert(RedisKey key, RedisValue[] items, int? capacity = null,
/// <summary>
/// Adds one or more items to a Bloom Filter. A filter will be created if it does not exist.
/// </summary>
/// <param name="key">The name of the filter.</param>
/// <param name="items">One or more items to add.</param>
/// <param name="capacity">(Optional) Specifies the desired capacity for the filter to be created.</param>
/// <param name="error">(Optional) Specifies the error ratio of the newly created filter if it does not yet exist.</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>
/// <param name="nocreate">(Optional) <see langword="true"/> to indicates that the
/// filter should not be created if it does not already exist.</param>
/// <param name="nonscaling">(Optional) <see langword="true"/> toprevent the filter
/// from creating additional sub-filters if initial capacity is reached.</param>
/// <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.insert"/></remarks>
public bool[] Insert(RedisKey key, RedisValue[] items, int? capacity = null,
double? error = null, int? expansion = null,
bool nocreate = false, bool nonscaling = false) //NOT DONE
bool nocreate = false, bool nonscaling = false)
{
if (items == null)
throw new ArgumentNullException(nameof(items));
Expand All @@ -54,29 +93,125 @@ public RedisResult Insert(RedisKey key, RedisValue[] items, int? capacity = null
}

if (nocreate)
{
args.Add(BloomArgs.NOCREATE);

}

if (nonscaling)
{
args.Add(BloomArgs.NONSCALING);
}

args.Add(BloomArgs.ITEMS);
foreach (var item in items)
{
args.Add(item);
}

return _db.Execute(BF.INSERT, args);
return ResponseParser.ToBooleanArray(_db.Execute(BF.INSERT, args));
}

public RedisResult ScanDump(RedisKey key, int iterator)
/// <summary>
/// Restores a filter previosly saved using SCANDUMP.
/// </summary>
/// <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>
/// <remarks><seealso href="https://redis.io/commands/bf.loadchunk"/></remarks>
public bool LoadChunk(RedisKey key, long iterator, Byte[] data)
{
return _db.Execute(BF.SCANDUMP, key, iterator);
return ResponseParser.ParseOKtoBoolean(_db.Execute(BF.LOADCHUNK, key, iterator, data));
}

public RedisResult LoadChunk(RedisKey key, int iterator, RedisValue data)
/// <summary>
/// Adds one or more items to the Bloom Filter. A filter will be created if it does not exist yet.
/// </summary>
/// <param name="key">The name of the filter.</param>
/// <param name="items">One or more items to add.</param>
/// <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)
{
return _db.Execute(BF.LOADCHUNK, key, iterator, data);
if (items == null)
throw new ArgumentNullException(nameof(items));

List<object> args = new List<object> { key };

foreach (var item in items)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason you can't concat these two types of lists, rather than loop? Is it possible to do a:

args.Concat(items).ToList

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Concat" and "AddRange" only works for Enumerable, and RedisValue[] is not Enumerable (it's also not working for input of type List<RedisValue>).

I haven't found a more elegant way than this..
I can Change it to:items.ForEach(item => args.Add(item));
Tell me if it's better in your opinion

{
args.Add(item);
}

return ResponseParser.ToBooleanArray(_db.Execute(BF.MADD, args));
}

/// <summary>
/// Checks whether one or more items may exist in the filter or not.
/// </summary>
/// <param name="key">The name of the filter.</param>
/// <param name="items">One or more items to check.</param>
/// <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/bf.mexists"/></remarks>
public bool[] MExists(RedisKey key, RedisValue[] items)
{
if (items == null)
throw new ArgumentNullException(nameof(items));

List<object> args = new List<object> { key };

foreach (var item in items)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question re: concat

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same answer re: concat ;)

{
args.Add(item);
}

return ResponseParser.ToBooleanArray(_db.Execute(BF.MEXISTS, args));

}

/// <summary>
/// Creates a new Bloom Filter.
/// </summary>
/// <param name="key">The key under which the filter is found.</param>
/// <param name="errorRate">The desired probability for false positives (value between 0 to 1).</param>
/// <param name="capacity">The number of entries intended to be added to the 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>
/// <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>
/// <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)
{
List<object> args = new List<object> { key, errorRate, capacity };

if (expansion != null)
{
args.Add(expansion);
}

if (nonscaling)
{
args.Add(BloomArgs.NONSCALING);
}

return ResponseParser.ParseOKtoBoolean(_db.Execute(BF.RESERVE, args));
}

/// <summary>
/// Restores a filter previosly saved using SCANDUMP.
/// </summary>
/// <param name="key">Name of the filter.</param>
/// <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)
{
return ResponseParser.ToScanDumpTuple(_db.Execute(BF.SCANDUMP, key, iterator));
}
}
}
24 changes: 24 additions & 0 deletions src/NRedisStack.Core/Bloom/DataTypes/BloomInformation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace NRedisStack.Core.Bloom.DataTypes
{
/// <summary>
/// This class represents the response for BF.INFO command.
/// This object has Read-only properties and cannot be generated outside a BF.INFO response.
/// </summary>
public class BloomInformation
{
public long Capacity { get; private set; }
public long Size { get; private set; }
public long NumberOfFilters { get; private set; }
public long NumberOfItemsInserted { get; private set; }
public long ExpansionRate { get; private set; }

internal BloomInformation(long capacity, long size, long numberOfFilters, long numberOfItemsInserted, long expansionRate)
{
Capacity = capacity;
Size = size;
NumberOfFilters = numberOfFilters;
NumberOfItemsInserted = numberOfItemsInserted;
ExpansionRate = expansionRate;
}
}
}
12 changes: 8 additions & 4 deletions src/NRedisStack.Core/Json/JsonCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,15 @@ public RedisResult Set(RedisKey key, RedisValue path, RedisValue json, When when
}
}

public RedisResult Get(RedisKey key, RedisValue? indent = null,
RedisValue? newLine = null, RedisValue? space = null, RedisValue? path = null)
public RedisResult Get(RedisKey key,
RedisValue? indent = null,
RedisValue? newLine = null,
RedisValue? space = null,
RedisValue? path = null)
{
List<object> args = new List<object>();
args.Add(key);

List<object> args = new List<object>(){key};

if (indent != null)
{
args.Add(JsonArgs.INDENT);
Expand Down
Loading