Skip to content
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

Support LMOVE #2065

Merged
merged 13 commits into from
Apr 10, 2022
3 changes: 2 additions & 1 deletion docs/ReleaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
29 changes: 29 additions & 0 deletions src/StackExchange.Redis/Enums/ListSide.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System;

namespace StackExchange.Redis
{
/// <summary>
/// Specifies what side of the list to refer to.
/// </summary>
public enum ListSide
{
/// <summary>
/// The head of the list.
/// </summary>
Left,
/// <summary>
/// The tail of the list.
/// </summary>
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))
};
}
}
1 change: 1 addition & 0 deletions src/StackExchange.Redis/Enums/RedisCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ internal enum RedisCommand
LINDEX,
LINSERT,
LLEN,
LMOVE,
LPOP,
LPUSH,
LPUSHX,
Expand Down
13 changes: 13 additions & 0 deletions src/StackExchange.Redis/Interfaces/IDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,19 @@ public interface IDatabase : IRedis, IDatabaseAsync
/// <remarks>https://redis.io/commands/llen</remarks>
long ListLength(RedisKey key, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Returns and removes the first or last element of the list stored at <paramref name="sourceKey"/>, and pushes the element
/// as the first or last element of the list stored at <paramref name="destinationKey"/>.
/// </summary>
/// <param name="sourceKey">The key of the list to remove from.</param>
/// <param name="destinationKey">The key of the list to move to.</param>
/// <param name="sourceSide">What side of the <paramref name="sourceKey"/> list to remove from.</param>
/// <param name="destinationSide">What side of the <paramref name="destinationKey"/> list to move to.</param>
/// <param name="flags">The flags to use for this operation.</param>
/// <returns>The element being popped and pushed or <see cref="RedisValue.Null"/> if there is no element to move.</returns>
/// <remarks>https://redis.io/commands/lmove</remarks>
RedisValue ListMove(RedisKey sourceKey, RedisKey destinationKey, ListSide sourceSide, ListSide destinationSide, CommandFlags flags = CommandFlags.None);

/// <summary>
/// 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.
Expand Down
13 changes: 13 additions & 0 deletions src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,19 @@ public interface IDatabaseAsync : IRedisAsync
/// <remarks>https://redis.io/commands/llen</remarks>
Task<long> ListLengthAsync(RedisKey key, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Returns and removes the first or last element of the list stored at <paramref name="sourceKey"/>, and pushes the element
/// as the first or last element of the list stored at <paramref name="destinationKey"/>.
/// </summary>
/// <param name="sourceKey">The key of the list to remove from.</param>
/// <param name="destinationKey">The key of the list to move to.</param>
/// <param name="sourceSide">What side of the <paramref name="sourceKey"/> list to remove from.</param>
/// <param name="destinationSide">What side of the <paramref name="destinationKey"/> list to move to.</param>
/// <param name="flags">The flags to use for this operation.</param>
/// <returns>The element being popped and pushed or <see cref="RedisValue.Null"/> if there is no element to move.</returns>
/// <remarks>https://redis.io/commands/lmove</remarks>
Avital-Fine marked this conversation as resolved.
Show resolved Hide resolved
Task<RedisValue> ListMoveAsync(RedisKey sourceKey, RedisKey destinationKey, ListSide sourceSide, ListSide destinationSide, CommandFlags flags = CommandFlags.None);

/// <summary>
/// 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.
Expand Down
3 changes: 3 additions & 0 deletions src/StackExchange.Redis/KeyspaceIsolation/DatabaseWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
5 changes: 4 additions & 1 deletion src/StackExchange.Redis/KeyspaceIsolation/WrapperBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,9 @@ public Task<long> ListLeftPushAsync(RedisKey key, RedisValue value, When when =
public Task<long> ListLengthAsync(RedisKey key, CommandFlags flags = CommandFlags.None) =>
Inner.ListLengthAsync(ToInner(key), flags);

public Task<RedisValue> ListMoveAsync(RedisKey sourceKey, RedisKey destinationKey, ListSide sourceSide, ListSide destinationSide, CommandFlags flags = CommandFlags.None) =>
Inner.ListMoveAsync(ToInner(sourceKey), ToInner(destinationKey), sourceSide, destinationSide);

public Task<RedisValue[]> ListRangeAsync(RedisKey key, long start = 0, long stop = -1, CommandFlags flags = CommandFlags.None) =>
Inner.ListRangeAsync(ToInner(key), start, stop, flags);

Expand Down Expand Up @@ -532,7 +535,7 @@ public Task<RedisValue[]> StringGetAsync(RedisKey[] keys, CommandFlags flags = C

public Task<RedisValue> StringGetAsync(RedisKey key, CommandFlags flags = CommandFlags.None) =>
Inner.StringGetAsync(ToInner(key), flags);

public Task<RedisValue> StringGetSetExpiryAsync(RedisKey key, TimeSpan? expiry, CommandFlags flags = CommandFlags.None) =>
Inner.StringGetSetExpiryAsync(ToInner(key), expiry, flags);

Expand Down
5 changes: 5 additions & 0 deletions src/StackExchange.Redis/PublicAPI.Shipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.RedisValue>!
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<long>!
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<long>!
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.RedisValue>!
StackExchange.Redis.IDatabaseAsync.ListLeftPopAsync(StackExchange.Redis.RedisKey key, long count, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task<StackExchange.Redis.RedisValue[]!>!
StackExchange.Redis.IDatabaseAsync.ListLeftPopAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task<StackExchange.Redis.RedisValue>!
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<long>!
Expand Down
12 changes: 12 additions & 0 deletions src/StackExchange.Redis/RedisDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1009,6 +1009,18 @@ public Task<long> 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<RedisValue> 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);
Expand Down
2 changes: 2 additions & 0 deletions src/StackExchange.Redis/RedisLiterals.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public static readonly RedisValue
KEEPTTL = "KEEPTTL",
KILL = "KILL",
LATEST = "LATEST",
LEFT = "LEFT",
LIMIT = "LIMIT",
LIST = "LIST",
LOAD = "LOAD",
Expand All @@ -89,6 +90,7 @@ public static readonly RedisValue
PURGE = "PURGE",
PX = "PX",
PXAT = "PXAT",
RIGHT = "RIGHT",
REPLACE = "REPLACE",
RESET = "RESET",
RESETSTAT = "RESETSTAT",
Expand Down
7 changes: 7 additions & 0 deletions tests/StackExchange.Redis.Tests/DatabaseWrapperTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand Down
Loading