diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index 4b7a77c9e..56c31a1a1 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -7,7 +7,8 @@ - Fixes a few internal edge cases that will now throw proper errors (rather than a downstream null reference) - Fixes inconsistencies with `null` vs. empty array returns (preferring an not-null empty array in those edge cases) - Note: does *not* increment a major version (as these are warnings to consumers), because: they're warnings (errors are opt-in), removing obsolete types with a 3.0 rev _would_ be binary breaking (this isn't), and reving to 3.0 would cause binding redirect pain for consumers. Bumping from 2.5 to 2.6 only for this change. -- Adds: Support for `COPY` ([#2064 by Avital-Fine](https://github.com/StackExchange/StackExchange.Redis/pull/2064)) +- Adds: Support for `COPY` with `.KeyCopy()`/`.KeyCopyAsync()` ([#2064 by Avital-Fine](https://github.com/StackExchange/StackExchange.Redis/pull/2064)) +- Adds: Support for `LMOVE` with `.ListMove()`/`.ListMoveAsync()` ([#2065 by Avital-Fine](https://github.com/StackExchange/StackExchange.Redis/pull/2065)) ## 2.5.61 diff --git a/src/StackExchange.Redis/Enums/ListSide.cs b/src/StackExchange.Redis/Enums/ListSide.cs new file mode 100644 index 000000000..0e71f91e8 --- /dev/null +++ b/src/StackExchange.Redis/Enums/ListSide.cs @@ -0,0 +1,29 @@ +using System; + +namespace StackExchange.Redis +{ + /// + /// Specifies what side of the list to refer to. + /// + public enum ListSide + { + /// + /// The head of the list. + /// + Left, + /// + /// The tail of the list. + /// + Right, + } + + internal static class ListSideExtensions + { + public static RedisValue ToLiteral(this ListSide side) => side switch + { + ListSide.Left => RedisLiterals.LEFT, + ListSide.Right => RedisLiterals.RIGHT, + _ => throw new ArgumentOutOfRangeException(nameof(side)) + }; + } +} diff --git a/src/StackExchange.Redis/Enums/RedisCommand.cs b/src/StackExchange.Redis/Enums/RedisCommand.cs index 09d067184..5e7de00c1 100644 --- a/src/StackExchange.Redis/Enums/RedisCommand.cs +++ b/src/StackExchange.Redis/Enums/RedisCommand.cs @@ -83,6 +83,7 @@ internal enum RedisCommand LINDEX, LINSERT, LLEN, + LMOVE, LPOP, LPUSH, LPUSHX, diff --git a/src/StackExchange.Redis/Interfaces/IDatabase.cs b/src/StackExchange.Redis/Interfaces/IDatabase.cs index 0c4c4acce..92853a20c 100644 --- a/src/StackExchange.Redis/Interfaces/IDatabase.cs +++ b/src/StackExchange.Redis/Interfaces/IDatabase.cs @@ -769,6 +769,19 @@ public interface IDatabase : IRedis, IDatabaseAsync /// https://redis.io/commands/llen long ListLength(RedisKey key, CommandFlags flags = CommandFlags.None); + /// + /// Returns and removes the first or last element of the list stored at , and pushes the element + /// as the first or last element of the list stored at . + /// + /// The key of the list to remove from. + /// The key of the list to move to. + /// What side of the list to remove from. + /// What side of the list to move to. + /// The flags to use for this operation. + /// The element being popped and pushed or if there is no element to move. + /// https://redis.io/commands/lmove + RedisValue ListMove(RedisKey sourceKey, RedisKey destinationKey, ListSide sourceSide, ListSide destinationSide, CommandFlags flags = CommandFlags.None); + /// /// Returns the specified elements of the list stored at key. /// The offsets start and stop are zero-based indexes, with 0 being the first element of the list (the head of the list), 1 being the next element and so on. diff --git a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs index 81d4d55af..7bb26ed1b 100644 --- a/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs +++ b/src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs @@ -745,6 +745,19 @@ public interface IDatabaseAsync : IRedisAsync /// https://redis.io/commands/llen Task ListLengthAsync(RedisKey key, CommandFlags flags = CommandFlags.None); + /// + /// Returns and removes the first or last element of the list stored at , and pushes the element + /// as the first or last element of the list stored at . + /// + /// The key of the list to remove from. + /// The key of the list to move to. + /// What side of the list to remove from. + /// What side of the list to move to. + /// The flags to use for this operation. + /// The element being popped and pushed or if there is no element to move. + /// https://redis.io/commands/lmove + Task ListMoveAsync(RedisKey sourceKey, RedisKey destinationKey, ListSide sourceSide, ListSide destinationSide, CommandFlags flags = CommandFlags.None); + /// /// Returns the specified elements of the list stored at key. /// The offsets start and stop are zero-based indexes, with 0 being the first element of the list (the head of the list), 1 being the next element and so on. diff --git a/src/StackExchange.Redis/KeyspaceIsolation/DatabaseWrapper.cs b/src/StackExchange.Redis/KeyspaceIsolation/DatabaseWrapper.cs index e755c2d34..a669cee57 100644 --- a/src/StackExchange.Redis/KeyspaceIsolation/DatabaseWrapper.cs +++ b/src/StackExchange.Redis/KeyspaceIsolation/DatabaseWrapper.cs @@ -203,6 +203,9 @@ public long ListLeftPush(RedisKey key, RedisValue value, When when = When.Always public long ListLength(RedisKey key, CommandFlags flags = CommandFlags.None) => Inner.ListLength(ToInner(key), flags); + public RedisValue ListMove(RedisKey sourceKey, RedisKey destinationKey, ListSide sourceSide, ListSide destinationSide, CommandFlags flags = CommandFlags.None) => + Inner.ListMove(ToInner(sourceKey), ToInner(destinationKey), sourceSide, destinationSide); + public RedisValue[] ListRange(RedisKey key, long start = 0, long stop = -1, CommandFlags flags = CommandFlags.None) => Inner.ListRange(ToInner(key), start, stop, flags); diff --git a/src/StackExchange.Redis/KeyspaceIsolation/WrapperBase.cs b/src/StackExchange.Redis/KeyspaceIsolation/WrapperBase.cs index 2da36d504..694087e75 100644 --- a/src/StackExchange.Redis/KeyspaceIsolation/WrapperBase.cs +++ b/src/StackExchange.Redis/KeyspaceIsolation/WrapperBase.cs @@ -213,6 +213,9 @@ public Task ListLeftPushAsync(RedisKey key, RedisValue value, When when = public Task ListLengthAsync(RedisKey key, CommandFlags flags = CommandFlags.None) => Inner.ListLengthAsync(ToInner(key), flags); + public Task ListMoveAsync(RedisKey sourceKey, RedisKey destinationKey, ListSide sourceSide, ListSide destinationSide, CommandFlags flags = CommandFlags.None) => + Inner.ListMoveAsync(ToInner(sourceKey), ToInner(destinationKey), sourceSide, destinationSide); + public Task ListRangeAsync(RedisKey key, long start = 0, long stop = -1, CommandFlags flags = CommandFlags.None) => Inner.ListRangeAsync(ToInner(key), start, stop, flags); @@ -532,7 +535,7 @@ public Task StringGetAsync(RedisKey[] keys, CommandFlags flags = C public Task StringGetAsync(RedisKey key, CommandFlags flags = CommandFlags.None) => Inner.StringGetAsync(ToInner(key), flags); - + public Task StringGetSetExpiryAsync(RedisKey key, TimeSpan? expiry, CommandFlags flags = CommandFlags.None) => Inner.StringGetSetExpiryAsync(ToInner(key), expiry, flags); diff --git a/src/StackExchange.Redis/PublicAPI.Shipped.txt b/src/StackExchange.Redis/PublicAPI.Shipped.txt index 008027d61..da09e4044 100644 --- a/src/StackExchange.Redis/PublicAPI.Shipped.txt +++ b/src/StackExchange.Redis/PublicAPI.Shipped.txt @@ -411,6 +411,9 @@ StackExchange.Redis.GeoUnit.Feet = 3 -> StackExchange.Redis.GeoUnit StackExchange.Redis.GeoUnit.Kilometers = 1 -> StackExchange.Redis.GeoUnit StackExchange.Redis.GeoUnit.Meters = 0 -> StackExchange.Redis.GeoUnit StackExchange.Redis.GeoUnit.Miles = 2 -> StackExchange.Redis.GeoUnit +StackExchange.Redis.ListSide +StackExchange.Redis.ListSide.Left = 0 -> StackExchange.Redis.ListSide +StackExchange.Redis.ListSide.Right = 1 -> StackExchange.Redis.ListSide StackExchange.Redis.HashEntry StackExchange.Redis.HashEntry.Equals(StackExchange.Redis.HashEntry other) -> bool StackExchange.Redis.HashEntry.HashEntry() -> void @@ -537,6 +540,7 @@ StackExchange.Redis.IDatabase.KeyType(StackExchange.Redis.RedisKey key, StackExc StackExchange.Redis.IDatabase.ListGetByIndex(StackExchange.Redis.RedisKey key, long index, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue StackExchange.Redis.IDatabase.ListInsertAfter(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue pivot, StackExchange.Redis.RedisValue value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long StackExchange.Redis.IDatabase.ListInsertBefore(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue pivot, StackExchange.Redis.RedisValue value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long +StackExchange.Redis.IDatabase.ListMove(StackExchange.Redis.RedisKey sourceKey, StackExchange.Redis.RedisKey destinationKey, StackExchange.Redis.ListSide sourceSide, StackExchange.Redis.ListSide destinationSide, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue StackExchange.Redis.IDatabase.ListLeftPop(StackExchange.Redis.RedisKey key, long count, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue[]! StackExchange.Redis.IDatabase.ListLeftPop(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisValue StackExchange.Redis.IDatabase.ListLeftPush(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue value, StackExchange.Redis.When when = StackExchange.Redis.When.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long @@ -726,6 +730,7 @@ StackExchange.Redis.IDatabaseAsync.KeyTypeAsync(StackExchange.Redis.RedisKey key StackExchange.Redis.IDatabaseAsync.ListGetByIndexAsync(StackExchange.Redis.RedisKey key, long index, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.ListInsertAfterAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue pivot, StackExchange.Redis.RedisValue value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.ListInsertBeforeAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue pivot, StackExchange.Redis.RedisValue value, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! +StackExchange.Redis.IDatabaseAsync.ListMoveAsync(StackExchange.Redis.RedisKey sourceKey, StackExchange.Redis.RedisKey destinationKey, StackExchange.Redis.ListSide sourceSide, StackExchange.Redis.ListSide destinationSide, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.ListLeftPopAsync(StackExchange.Redis.RedisKey key, long count, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.ListLeftPopAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! StackExchange.Redis.IDatabaseAsync.ListLeftPushAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisValue value, StackExchange.Redis.When when = StackExchange.Redis.When.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task! diff --git a/src/StackExchange.Redis/RedisDatabase.cs b/src/StackExchange.Redis/RedisDatabase.cs index 6eb4ed0bf..cc8fa6acd 100644 --- a/src/StackExchange.Redis/RedisDatabase.cs +++ b/src/StackExchange.Redis/RedisDatabase.cs @@ -1009,6 +1009,18 @@ public Task ListLengthAsync(RedisKey key, CommandFlags flags = CommandFlag return ExecuteAsync(msg, ResultProcessor.Int64); } + public RedisValue ListMove(RedisKey sourceKey, RedisKey destinationKey, ListSide sourceSide, ListSide destinationSide, CommandFlags flags = CommandFlags.None) + { + var msg = Message.Create(Database, flags, RedisCommand.LMOVE, sourceKey, destinationKey, sourceSide.ToLiteral(), destinationSide.ToLiteral()); + return ExecuteSync(msg, ResultProcessor.RedisValue); + } + + public Task ListMoveAsync(RedisKey sourceKey, RedisKey destinationKey, ListSide sourceSide, ListSide destinationSide, CommandFlags flags = CommandFlags.None) + { + var msg = Message.Create(Database, flags, RedisCommand.LMOVE, sourceKey, destinationKey, sourceSide.ToLiteral(), destinationSide.ToLiteral()); + return ExecuteAsync(msg, ResultProcessor.RedisValue); + } + public RedisValue[] ListRange(RedisKey key, long start = 0, long stop = -1, CommandFlags flags = CommandFlags.None) { var msg = Message.Create(Database, flags, RedisCommand.LRANGE, key, start, stop); diff --git a/src/StackExchange.Redis/RedisLiterals.cs b/src/StackExchange.Redis/RedisLiterals.cs index a31fbdf25..ca3a79357 100644 --- a/src/StackExchange.Redis/RedisLiterals.cs +++ b/src/StackExchange.Redis/RedisLiterals.cs @@ -68,6 +68,7 @@ public static readonly RedisValue KEEPTTL = "KEEPTTL", KILL = "KILL", LATEST = "LATEST", + LEFT = "LEFT", LIMIT = "LIMIT", LIST = "LIST", LOAD = "LOAD", @@ -89,6 +90,7 @@ public static readonly RedisValue PURGE = "PURGE", PX = "PX", PXAT = "PXAT", + RIGHT = "RIGHT", REPLACE = "REPLACE", RESET = "RESET", RESETSTAT = "RESETSTAT", diff --git a/tests/StackExchange.Redis.Tests/DatabaseWrapperTests.cs b/tests/StackExchange.Redis.Tests/DatabaseWrapperTests.cs index 0ddd9981b..53a7437f6 100644 --- a/tests/StackExchange.Redis.Tests/DatabaseWrapperTests.cs +++ b/tests/StackExchange.Redis.Tests/DatabaseWrapperTests.cs @@ -412,6 +412,13 @@ public void ListLength() mock.Verify(_ => _.ListLength("prefix:key", CommandFlags.None)); } + [Fact] + public void ListMove() + { + wrapper.ListMove("key", "destination", ListSide.Left, ListSide.Right, CommandFlags.None); + mock.Verify(_ => _.ListMove("prefix:key", "prefix:destination", ListSide.Left, ListSide.Right, CommandFlags.None)); + } + [Fact] public void ListRange() { diff --git a/tests/StackExchange.Redis.Tests/Lists.cs b/tests/StackExchange.Redis.Tests/Lists.cs index 0667b6266..a3daeb9a5 100644 --- a/tests/StackExchange.Redis.Tests/Lists.cs +++ b/tests/StackExchange.Redis.Tests/Lists.cs @@ -40,7 +40,7 @@ public void ListLeftPushEmptyValues() using (var conn = Create()) { var db = conn.GetDatabase(); - RedisKey key = "testlist"; + RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); var result = db.ListLeftPush(key, Array.Empty(), When.Always, CommandFlags.None); Assert.Equal(0, result); @@ -53,7 +53,7 @@ public void ListLeftPushKeyDoesNotExists() using (var conn = Create()) { var db = conn.GetDatabase(); - RedisKey key = "testlist"; + RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); var result = db.ListLeftPush(key, new RedisValue[] { "testvalue" }, When.Exists, CommandFlags.None); Assert.Equal(0, result); @@ -66,7 +66,7 @@ public void ListLeftPushToExisitingKey() using (var conn = Create()) { var db = conn.GetDatabase(); - RedisKey key = "testlist"; + RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); var pushResult = db.ListLeftPush(key, new RedisValue[] { "testvalue1" }, CommandFlags.None); @@ -88,7 +88,7 @@ public void ListLeftPushMultipleToExisitingKey() { Skip.IfBelow(conn, RedisFeatures.v4_0_0); var db = conn.GetDatabase(); - RedisKey key = "testlist"; + RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); var pushResult = db.ListLeftPush(key, new RedisValue[] { "testvalue1" }, CommandFlags.None); @@ -110,7 +110,7 @@ public async Task ListLeftPushAsyncEmptyValues() using (var conn = Create()) { var db = conn.GetDatabase(); - RedisKey key = "testlist"; + RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); var result = await db.ListLeftPushAsync(key, Array.Empty(), When.Always, CommandFlags.None); Assert.Equal(0, result); @@ -123,7 +123,7 @@ public async Task ListLeftPushAsyncKeyDoesNotExists() using (var conn = Create()) { var db = conn.GetDatabase(); - RedisKey key = "testlist"; + RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); var result = await db.ListLeftPushAsync(key, new RedisValue[] { "testvalue" }, When.Exists, CommandFlags.None); Assert.Equal(0, result); @@ -136,7 +136,7 @@ public async Task ListLeftPushAsyncToExisitingKey() using (var conn = Create()) { var db = conn.GetDatabase(); - RedisKey key = "testlist"; + RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); var pushResult = await db.ListLeftPushAsync(key, new RedisValue[] { "testvalue1" }, CommandFlags.None); @@ -158,7 +158,7 @@ public async Task ListLeftPushAsyncMultipleToExisitingKey() { Skip.IfBelow(conn, RedisFeatures.v4_0_0); var db = conn.GetDatabase(); - RedisKey key = "testlist"; + RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); var pushResult = await db.ListLeftPushAsync(key, new RedisValue[] { "testvalue1" }, CommandFlags.None); @@ -180,7 +180,7 @@ public void ListRightPushEmptyValues() using (var conn = Create()) { var db = conn.GetDatabase(); - RedisKey key = "testlist"; + RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); var result = db.ListRightPush(key, Array.Empty(), When.Always, CommandFlags.None); Assert.Equal(0, result); @@ -193,7 +193,7 @@ public void ListRightPushKeyDoesNotExists() using (var conn = Create()) { var db = conn.GetDatabase(); - RedisKey key = "testlist"; + RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); var result = db.ListRightPush(key, new RedisValue[] { "testvalue" }, When.Exists, CommandFlags.None); Assert.Equal(0, result); @@ -206,7 +206,7 @@ public void ListRightPushToExisitingKey() using (var conn = Create()) { var db = conn.GetDatabase(); - RedisKey key = "testlist"; + RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); var pushResult = db.ListRightPush(key, new RedisValue[] { "testvalue1" }, CommandFlags.None); @@ -228,7 +228,7 @@ public void ListRightPushMultipleToExisitingKey() { Skip.IfBelow(conn, RedisFeatures.v4_0_0); var db = conn.GetDatabase(); - RedisKey key = "testlist"; + RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); var pushResult = db.ListRightPush(key, new RedisValue[] { "testvalue1" }, CommandFlags.None); @@ -250,7 +250,7 @@ public async Task ListRightPushAsyncEmptyValues() using (var conn = Create()) { var db = conn.GetDatabase(); - RedisKey key = "testlist"; + RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); var result = await db.ListRightPushAsync(key, Array.Empty(), When.Always, CommandFlags.None); Assert.Equal(0, result); @@ -263,7 +263,7 @@ public async Task ListRightPushAsyncKeyDoesNotExists() using (var conn = Create()) { var db = conn.GetDatabase(); - RedisKey key = "testlist"; + RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); var result = await db.ListRightPushAsync(key, new RedisValue[] { "testvalue" }, When.Exists, CommandFlags.None); Assert.Equal(0, result); @@ -276,7 +276,7 @@ public async Task ListRightPushAsyncToExisitingKey() using (var conn = Create()) { var db = conn.GetDatabase(); - RedisKey key = "testlist"; + RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); var pushResult = await db.ListRightPushAsync(key, new RedisValue[] { "testvalue1" }, CommandFlags.None); @@ -298,7 +298,7 @@ public async Task ListRightPushAsyncMultipleToExisitingKey() { Skip.IfBelow(conn, RedisFeatures.v4_0_0); var db = conn.GetDatabase(); - RedisKey key = "testlist"; + RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); var pushResult = await db.ListRightPushAsync(key, new RedisValue[] { "testvalue1" }, CommandFlags.None); @@ -313,5 +313,44 @@ public async Task ListRightPushAsyncMultipleToExisitingKey() Assert.Equal("testvalue3", rangeResult[2]); } } + + [Fact] + public async Task ListMove() + { + using var conn = Create(); + Skip.IfBelow(conn, RedisFeatures.v6_2_0); + + var db = conn.GetDatabase(); + RedisKey src = Me(); + RedisKey dest = Me() + "dest"; + db.KeyDelete(src, CommandFlags.FireAndForget); + + var pushResult = await db.ListRightPushAsync(src, new RedisValue[] { "testvalue1", "testvalue2" }); + Assert.Equal(2, pushResult); + + var rangeResult1 = db.ListMove(src, dest, ListSide.Left, ListSide.Right); + var rangeResult2 = db.ListMove(src, dest, ListSide.Left, ListSide.Left); + var rangeResult3 = db.ListMove(dest, src, ListSide.Right, ListSide.Right); + var rangeResult4 = db.ListMove(dest, src, ListSide.Right, ListSide.Left); + Assert.Equal("testvalue1", rangeResult1); + Assert.Equal("testvalue2", rangeResult2); + Assert.Equal("testvalue1", rangeResult3); + Assert.Equal("testvalue2", rangeResult4); + } + + [Fact] + public void ListMoveKeyDoesNotExist() + { + using var conn = Create(); + Skip.IfBelow(conn, RedisFeatures.v6_2_0); + + var db = conn.GetDatabase(); + RedisKey src = Me(); + RedisKey dest = Me() + "dest"; + db.KeyDelete(src, CommandFlags.FireAndForget); + + var rangeResult1 = db.ListMove(src, dest, ListSide.Left, ListSide.Right); + Assert.True(rangeResult1.IsNull); + } } } diff --git a/tests/StackExchange.Redis.Tests/WrapperBaseTests.cs b/tests/StackExchange.Redis.Tests/WrapperBaseTests.cs index 13b5fd8cd..1197a636d 100644 --- a/tests/StackExchange.Redis.Tests/WrapperBaseTests.cs +++ b/tests/StackExchange.Redis.Tests/WrapperBaseTests.cs @@ -372,6 +372,13 @@ public void ListLengthAsync() mock.Verify(_ => _.ListLengthAsync("prefix:key", CommandFlags.None)); } + [Fact] + public void ListMoveAsync() + { + wrapper.ListMoveAsync("key", "destination", ListSide.Left, ListSide.Right, CommandFlags.None); + mock.Verify(_ => _.ListMoveAsync("prefix:key", "prefix:destination", ListSide.Left, ListSide.Right, CommandFlags.None)); + } + [Fact] public void ListRangeAsync() {