Skip to content

New operations of BITOP command in Redis Community Edition 8.2 #2900

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

Open
wants to merge 1 commit into
base: main
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
25 changes: 25 additions & 0 deletions src/StackExchange.Redis/Enums/Bitwise.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,30 @@ public enum Bitwise
/// <a href="https://en.wikipedia.org/wiki/Bitwise_operation#NOT">Not</a>
/// </summary>
Not,

/// <summary>
/// DIFF operation: members of X that are not members of any of Y1, Y2, ...
/// Equivalent to X ∧ ¬(Y1 ∨ Y2 ∨ ...)
/// </summary>
Diff,

/// <summary>
/// DIFF1 operation: members of one or more of Y1, Y2, ... that are not members of X
/// Equivalent to ¬X ∧ (Y1 ∨ Y2 ∨ ...)
/// </summary>
Diff1,

/// <summary>
/// ANDOR operation: members of X that are also members of one or more of Y1, Y2, ...
/// Equivalent to X ∧ (Y1 ∨ Y2 ∨ ...)
/// </summary>
AndOr,

/// <summary>
/// ONE operation: members of exactly one of X1, X2, ...
/// For two bitmaps this is equivalent to XOR. For more than two bitmaps,
/// this returns bits that are set in exactly one of the input bitmaps.
/// </summary>
One,
}
}
4 changes: 4 additions & 0 deletions src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1899,3 +1899,7 @@ static StackExchange.Redis.RedisChannel.Sharded(byte[]? value) -> StackExchange.
static StackExchange.Redis.RedisChannel.Sharded(string! value) -> StackExchange.Redis.RedisChannel
StackExchange.Redis.ClientInfo.ShardedSubscriptionCount.get -> int
StackExchange.Redis.ConfigurationOptions.SetUserPfxCertificate(string! userCertificatePath, string? password = null) -> void
StackExchange.Redis.Bitwise.AndOr = 6 -> StackExchange.Redis.Bitwise
StackExchange.Redis.Bitwise.Diff = 4 -> StackExchange.Redis.Bitwise
StackExchange.Redis.Bitwise.Diff1 = 5 -> StackExchange.Redis.Bitwise
StackExchange.Redis.Bitwise.One = 7 -> StackExchange.Redis.Bitwise
3 changes: 2 additions & 1 deletion src/StackExchange.Redis/RedisFeatures.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ namespace StackExchange.Redis
v7_0_0_rc1 = new Version(6, 9, 240), // 7.0 RC1 is version 6.9.240
v7_2_0_rc1 = new Version(7, 1, 240), // 7.2 RC1 is version 7.1.240
v7_4_0_rc1 = new Version(7, 3, 240), // 7.4 RC1 is version 7.3.240
v7_4_0_rc2 = new Version(7, 3, 241); // 7.4 RC2 is version 7.3.241
v7_4_0_rc2 = new Version(7, 3, 241), // 7.4 RC2 is version 7.3.241
v8_2_0_rc1 = new Version(8, 1, 240); // 8.2 RC1 is version 8.1.240
#pragma warning restore SA1310 // Field names should not contain underscore
#pragma warning restore SA1311 // Static readonly fields should begin with upper-case letter

Expand Down
8 changes: 8 additions & 0 deletions src/StackExchange.Redis/RedisLiterals.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public static readonly RedisValue
AGGREGATE = "AGGREGATE",
ALPHA = "ALPHA",
AND = "AND",
ANDOR = "ANDOR",
ANY = "ANY",
ASC = "ASC",
AUTH = "AUTH",
Expand All @@ -73,6 +74,8 @@ public static readonly RedisValue
DB = "DB",
@default = "default",
DESC = "DESC",
DIFF = "DIFF",
DIFF1 = "DIFF1",
DOCTOR = "DOCTOR",
ENCODING = "ENCODING",
EX = "EX",
Expand Down Expand Up @@ -118,6 +121,7 @@ public static readonly RedisValue
NUMSUB = "NUMSUB",
NX = "NX",
OBJECT = "OBJECT",
ONE = "ONE",
OR = "OR",
PATTERN = "PATTERN",
PAUSE = "PAUSE",
Expand Down Expand Up @@ -216,6 +220,10 @@ public static readonly RedisValue
Bitwise.Or => OR,
Bitwise.Xor => XOR,
Bitwise.Not => NOT,
Bitwise.Diff => DIFF,
Bitwise.Diff1 => DIFF1,
Bitwise.AndOr => ANDOR,
Bitwise.One => ONE,
_ => throw new ArgumentOutOfRangeException(nameof(operation)),
};
}
Expand Down
36 changes: 36 additions & 0 deletions tests/StackExchange.Redis.Tests/KeyPrefixedDatabaseTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1239,6 +1239,42 @@ public void StringBitOperation_2()
mock.Received().StringBitOperation(Bitwise.Xor, "prefix:destination", Arg.Is(valid), CommandFlags.None);
}

[Fact]
public void StringBitOperation_Diff()
{
RedisKey[] keys = new RedisKey[] { "x", "y1", "y2" };
Expression<Predicate<RedisKey[]>> valid = _ => _.Length == 3 && _[0] == "prefix:x" && _[1] == "prefix:y1" && _[2] == "prefix:y2";
prefixed.StringBitOperation(Bitwise.Diff, "destination", keys, CommandFlags.None);
mock.Received().StringBitOperation(Bitwise.Diff, "prefix:destination", Arg.Is(valid), CommandFlags.None);
}

[Fact]
public void StringBitOperation_Diff1()
{
RedisKey[] keys = new RedisKey[] { "x", "y1", "y2" };
Expression<Predicate<RedisKey[]>> valid = _ => _.Length == 3 && _[0] == "prefix:x" && _[1] == "prefix:y1" && _[2] == "prefix:y2";
prefixed.StringBitOperation(Bitwise.Diff1, "destination", keys, CommandFlags.None);
mock.Received().StringBitOperation(Bitwise.Diff1, "prefix:destination", Arg.Is(valid), CommandFlags.None);
}

[Fact]
public void StringBitOperation_AndOr()
{
RedisKey[] keys = new RedisKey[] { "x", "y1", "y2" };
Expression<Predicate<RedisKey[]>> valid = _ => _.Length == 3 && _[0] == "prefix:x" && _[1] == "prefix:y1" && _[2] == "prefix:y2";
prefixed.StringBitOperation(Bitwise.AndOr, "destination", keys, CommandFlags.None);
mock.Received().StringBitOperation(Bitwise.AndOr, "prefix:destination", Arg.Is(valid), CommandFlags.None);
}

[Fact]
public void StringBitOperation_One()
{
RedisKey[] keys = new RedisKey[] { "a", "b", "c" };
Expression<Predicate<RedisKey[]>> valid = _ => _.Length == 3 && _[0] == "prefix:a" && _[1] == "prefix:b" && _[2] == "prefix:c";
prefixed.StringBitOperation(Bitwise.One, "destination", keys, CommandFlags.None);
mock.Received().StringBitOperation(Bitwise.One, "prefix:destination", Arg.Is(valid), CommandFlags.None);
}

[Fact]
public void StringBitPosition()
{
Expand Down
36 changes: 36 additions & 0 deletions tests/StackExchange.Redis.Tests/KeyPrefixedTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1155,6 +1155,42 @@ public async Task StringBitOperationAsync_2()
await mock.Received().StringBitOperationAsync(Bitwise.Xor, "prefix:destination", Arg.Is(valid), CommandFlags.None);
}

[Fact]
public async Task StringBitOperationAsync_Diff()
{
RedisKey[] keys = new RedisKey[] { "x", "y1", "y2" };
Expression<Predicate<RedisKey[]>> valid = _ => _.Length == 3 && _[0] == "prefix:x" && _[1] == "prefix:y1" && _[2] == "prefix:y2";
await prefixed.StringBitOperationAsync(Bitwise.Diff, "destination", keys, CommandFlags.None);
await mock.Received().StringBitOperationAsync(Bitwise.Diff, "prefix:destination", Arg.Is(valid), CommandFlags.None);
}

[Fact]
public async Task StringBitOperationAsync_Diff1()
{
RedisKey[] keys = new RedisKey[] { "x", "y1", "y2" };
Expression<Predicate<RedisKey[]>> valid = _ => _.Length == 3 && _[0] == "prefix:x" && _[1] == "prefix:y1" && _[2] == "prefix:y2";
await prefixed.StringBitOperationAsync(Bitwise.Diff1, "destination", keys, CommandFlags.None);
await mock.Received().StringBitOperationAsync(Bitwise.Diff1, "prefix:destination", Arg.Is(valid), CommandFlags.None);
}

[Fact]
public async Task StringBitOperationAsync_AndOr()
{
RedisKey[] keys = new RedisKey[] { "x", "y1", "y2" };
Expression<Predicate<RedisKey[]>> valid = _ => _.Length == 3 && _[0] == "prefix:x" && _[1] == "prefix:y1" && _[2] == "prefix:y2";
await prefixed.StringBitOperationAsync(Bitwise.AndOr, "destination", keys, CommandFlags.None);
await mock.Received().StringBitOperationAsync(Bitwise.AndOr, "prefix:destination", Arg.Is(valid), CommandFlags.None);
}

[Fact]
public async Task StringBitOperationAsync_One()
{
RedisKey[] keys = new RedisKey[] { "a", "b", "c" };
Expression<Predicate<RedisKey[]>> valid = _ => _.Length == 3 && _[0] == "prefix:a" && _[1] == "prefix:b" && _[2] == "prefix:c";
await prefixed.StringBitOperationAsync(Bitwise.One, "destination", keys, CommandFlags.None);
await mock.Received().StringBitOperationAsync(Bitwise.One, "prefix:destination", Arg.Is(valid), CommandFlags.None);
}

[Fact]
public async Task StringBitPositionAsync()
{
Expand Down
Loading
Loading