Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit c6ccaf0

Browse files
committedFeb 15, 2024·
Add support for the BLMOVE and BRPOPLPUSH commands
Issues #235 and #251
1 parent 0512143 commit c6ccaf0

File tree

4 files changed

+150
-0
lines changed

4 files changed

+150
-0
lines changed
 

‎src/NRedisStack/CoreCommands/CoreCommandBuilder.cs

+22
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,28 @@ public static SerializedCommand BRPop(RedisKey[] keys, double timeout)
8787
return BlockingCommandWithKeysAndTimeout(RedisCoreCommands.BRPOP, keys, timeout);
8888
}
8989

90+
public static SerializedCommand BLMove(RedisKey source, RedisKey destination, ListSide sourceSide, ListSide destinationSide, double timeout)
91+
{
92+
List<object> args = new List<object>();
93+
args.Add(source);
94+
args.Add(destination);
95+
args.Add(sourceSide == ListSide.Left ? CoreArgs.LEFT : CoreArgs.RIGHT);
96+
args.Add(destinationSide == ListSide.Left ? CoreArgs.LEFT : CoreArgs.RIGHT);
97+
args.Add(timeout);
98+
99+
return new SerializedCommand(RedisCoreCommands.BLMOVE, args);
100+
}
101+
102+
public static SerializedCommand BRPopLPush(RedisKey source, RedisKey destination, double timeout)
103+
{
104+
List<object> args = new List<object>();
105+
args.Add(source);
106+
args.Add(destination);
107+
args.Add(timeout);
108+
109+
return new SerializedCommand(RedisCoreCommands.BRPOPLPUSH, args);
110+
}
111+
90112
private static SerializedCommand BlockingCommandWithKeysAndTimeout(String command, RedisKey[] keys, double timeout)
91113
{
92114
if (keys.Length == 0)

‎src/NRedisStack/CoreCommands/CoreCommands.cs

+44
Original file line numberDiff line numberDiff line change
@@ -326,5 +326,49 @@ public static bool ClientSetInfo(this IDatabase db, SetInfoAttr attr, string val
326326
{
327327
return BRPop(db, new[] { key }, timeout);
328328
}
329+
330+
/// <summary>
331+
/// The BLMOVE command.
332+
/// <p/>
333+
/// Atomically returns and removes the first or last element of the list stored at <paramref name="source"/>
334+
/// (depending on the value of <paramref name="sourceSide"/>), and pushes the element as the first or last
335+
/// element of the list stored at <paramref name="destination"/> (depending on the value of
336+
/// <paramref name="destinationSide"/>).
337+
/// <p/>
338+
/// This is an extension method added to the <see cref="IDatabase"/> class, for convenience.
339+
/// </summary>
340+
/// <param name="db">The <see cref="IDatabase"/> class where this extension method is applied.</param>
341+
/// <param name="source">The key of the source list.</param>
342+
/// <param name="destination">The key of the destination list.</param>
343+
/// <param name="sourceSide">What side of the <paramref name="source"/> list to remove from.</param>
344+
/// <param name="destinationSide">What side of the <paramref name="destination"/> list to move to.</param>
345+
/// <param name="timeout">Server-side timeout for the wait. A value of <c>0</c> means to wait indefinitely.</param>
346+
/// <returns>The element being popped and pushed, or <c>null</c> if the server timeout expires.</returns>
347+
/// <remarks><seealso href="https://redis.io/commands/blmove"/></remarks>
348+
public static RedisValue? BLMove(this IDatabase db, RedisKey source, RedisKey destination, ListSide sourceSide, ListSide destinationSide, double timeout)
349+
{
350+
var command = CoreCommandBuilder.BLMove(source, destination, sourceSide, destinationSide, timeout);
351+
return db.Execute(command).ToRedisValue();
352+
}
353+
354+
/// <summary>
355+
/// The BRPOPLPUSH command.
356+
/// <p/>
357+
/// Atomically returns and removes the last element (tail) of the list stored at source, and pushes the element
358+
/// at the first element (head) of the list stored at destination.
359+
/// <p/>
360+
/// This is an extension method added to the <see cref="IDatabase"/> class, for convenience.
361+
/// </summary>
362+
/// <param name="db">The <see cref="IDatabase"/> class where this extension method is applied.</param>
363+
/// <param name="source">The key of the source list.</param>
364+
/// <param name="destination">The key of the destination list.</param>
365+
/// <param name="timeout">Server-side timeout for the wait. A value of <c>0</c> means to wait indefinitely.</param>
366+
/// <returns>The element being popped and pushed, or <c>null</c> if the server timeout expires.</returns>
367+
/// <remarks><seealso href="https://redis.io/commands/rpoplpush"/></remarks>
368+
public static RedisValue? BRPopLPush(this IDatabase db, RedisKey source, RedisKey destination, double timeout)
369+
{
370+
var command = CoreCommandBuilder.BRPopLPush(source, destination, timeout);
371+
return db.Execute(command).ToRedisValue();
372+
}
329373
}
330374
}

‎src/NRedisStack/CoreCommands/Literals/Commands.cs

+2
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ namespace NRedisStack.Core.Literals
55
/// </summary>
66
internal static class RedisCoreCommands
77
{
8+
public const string BLMOVE = "BLMOVE";
89
public const string BLMPOP = "BLMPOP";
910
public const string BLPOP = "BLPOP";
1011
public const string BRPOP = "BRPOP";
12+
public const string BRPOPLPUSH = "BRPOPLPUSH";
1113
public const string BZMPOP = "BZMPOP";
1214
public const string BZPOPMAX = "BZPOPMAX";
1315
public const string BZPOPMIN = "BZPOPMIN";

‎tests/NRedisStack.Tests/Core Commands/CoreTests.cs

+82
Original file line numberDiff line numberDiff line change
@@ -620,4 +620,86 @@ public void TestBRPopMultipleLists()
620620
Assert.Equal("list-one", result!.Item1);
621621
Assert.Equal("b", result.Item2.ToString());
622622
}
623+
624+
[SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "6.2.0")]
625+
public void TestBLMove()
626+
{
627+
var redis = ConnectionMultiplexer.Connect("localhost");
628+
629+
var db = redis.GetDatabase(null);
630+
db.Execute("FLUSHALL");
631+
632+
db.ListRightPush("list-one", "a");
633+
db.ListRightPush("list-one", "b");
634+
635+
db.ListRightPush("list-two", "c");
636+
db.ListRightPush("list-two", "d");
637+
638+
var result = db.BLMove("list-one", "list-two", ListSide.Right, ListSide.Left, 0);
639+
Assert.NotNull(result);
640+
Assert.Equal("b", result!);
641+
642+
Assert.Equal(1, db.ListLength("list-one"));
643+
Assert.Equal("a", db.ListGetByIndex("list-one", 0));
644+
Assert.Equal(3, db.ListLength("list-two"));
645+
Assert.Equal("b", db.ListGetByIndex("list-two", 0));
646+
Assert.Equal("c", db.ListGetByIndex("list-two", 1));
647+
Assert.Equal("d", db.ListGetByIndex("list-two", 2));
648+
649+
result = db.BLMove("list-two", "list-one", ListSide.Left, ListSide.Right, 0);
650+
Assert.NotNull(result);
651+
Assert.Equal("b", result!);
652+
653+
Assert.Equal(2, db.ListLength("list-one"));
654+
Assert.Equal("a", db.ListGetByIndex("list-one", 0));
655+
Assert.Equal("b", db.ListGetByIndex("list-one", 1));
656+
Assert.Equal(2, db.ListLength("list-two"));
657+
Assert.Equal("c", db.ListGetByIndex("list-two", 0));
658+
Assert.Equal("d", db.ListGetByIndex("list-two", 1));
659+
660+
result = db.BLMove("list-one", "list-two", ListSide.Left, ListSide.Left, 0);
661+
Assert.NotNull(result);
662+
Assert.Equal("a", result!);
663+
664+
Assert.Equal(1, db.ListLength("list-one"));
665+
Assert.Equal("b", db.ListGetByIndex("list-one", 0));
666+
Assert.Equal(3, db.ListLength("list-two"));
667+
Assert.Equal("a", db.ListGetByIndex("list-two", 0));
668+
Assert.Equal("c", db.ListGetByIndex("list-two", 1));
669+
Assert.Equal("d", db.ListGetByIndex("list-two", 2));
670+
671+
result = db.BLMove("list-two", "list-one", ListSide.Right, ListSide.Right, 0);
672+
Assert.NotNull(result);
673+
Assert.Equal("d", result!);
674+
675+
Assert.Equal(2, db.ListLength("list-one"));
676+
Assert.Equal("b", db.ListGetByIndex("list-one", 0));
677+
Assert.Equal("d", db.ListGetByIndex("list-one", 1));
678+
Assert.Equal(2, db.ListLength("list-two"));
679+
Assert.Equal("a", db.ListGetByIndex("list-two", 0));
680+
Assert.Equal("c", db.ListGetByIndex("list-two", 1));
681+
}
682+
683+
[SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "2.2.0")]
684+
public void TestBRPopLPush()
685+
{
686+
var redis = ConnectionMultiplexer.Connect("localhost");
687+
688+
var db = redis.GetDatabase(null);
689+
db.Execute("FLUSHALL");
690+
691+
db.ListRightPush("list-one", "a");
692+
db.ListRightPush("list-one", "b");
693+
694+
db.ListRightPush("list-two", "c");
695+
db.ListRightPush("list-two", "d");
696+
697+
var result = db.BRPopLPush("list-one", "list-two", 0);
698+
Assert.NotNull(result);
699+
Assert.Equal("b", result!);
700+
701+
Assert.Equal(1, db.ListLength("list-one"));
702+
Assert.Equal(3, db.ListLength("list-two"));
703+
Assert.Equal("b", db.ListLeftPop("list-two"));
704+
}
623705
}

0 commit comments

Comments
 (0)
Please sign in to comment.