Skip to content
Merged
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
52 changes: 52 additions & 0 deletions sources/Valkey.Glide/BaseClient.SetCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,56 @@ public async Task<long> SetDifferenceStoreAsync(ValkeyKey destination, ValkeyKey
Utils.Requires<NotImplementedException>(flags == CommandFlags.None, "Command flags are not supported by GLIDE");
return await Command(Request.SetDifferenceStoreAsync(destination, keys));
}

public async Task<bool> SetContainsAsync(ValkeyKey key, ValkeyValue value, CommandFlags flags = CommandFlags.None)
{
Utils.Requires<NotImplementedException>(flags == CommandFlags.None, "Command flags are not supported by GLIDE");
return await Command(Request.SetContainsAsync(key, value));
}

public async Task<bool[]> SetContainsAsync(ValkeyKey key, ValkeyValue[] values, CommandFlags flags = CommandFlags.None)
{
Utils.Requires<NotImplementedException>(flags == CommandFlags.None, "Command flags are not supported by GLIDE");
return await Command(Request.SetContainsAsync(key, values));
}

public async Task<ValkeyValue> SetRandomMemberAsync(ValkeyKey key, CommandFlags flags = CommandFlags.None)
{
Utils.Requires<NotImplementedException>(flags == CommandFlags.None, "Command flags are not supported by GLIDE");
return await Command(Request.SetRandomMemberAsync(key));
}

public async Task<ValkeyValue[]> SetRandomMembersAsync(ValkeyKey key, long count, CommandFlags flags = CommandFlags.None)
{
Utils.Requires<NotImplementedException>(flags == CommandFlags.None, "Command flags are not supported by GLIDE");
return await Command(Request.SetRandomMembersAsync(key, count));
}

public async Task<bool> SetMoveAsync(ValkeyKey source, ValkeyKey destination, ValkeyValue value, CommandFlags flags = CommandFlags.None)
{
Utils.Requires<NotImplementedException>(flags == CommandFlags.None, "Command flags are not supported by GLIDE");
return await Command(Request.SetMoveAsync(source, destination, value));
}

public async IAsyncEnumerable<ValkeyValue> SetScanAsync(ValkeyKey key, ValkeyValue pattern = default, int pageSize = 250, long cursor = 0, int pageOffset = 0, CommandFlags flags = CommandFlags.None)
{
Utils.Requires<NotImplementedException>(flags == CommandFlags.None, "Command flags are not supported by GLIDE");

long currentCursor = cursor;
int currentOffset = pageOffset;

do
{
(long nextCursor, ValkeyValue[] elements) = await Command(Request.SetScanAsync(key, currentCursor, pattern, pageSize));

IEnumerable<ValkeyValue> elementsToYield = currentOffset > 0 ? elements.Skip(currentOffset) : elements;

foreach (ValkeyValue element in elementsToYield)
{
yield return element;
}

currentCursor = nextCursor;
} while (currentCursor != 0);
}
}
2 changes: 2 additions & 0 deletions sources/Valkey.Glide/Commands/Constants/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ public static class Constants
public const string ReverseKeyword = "REV";
public const string ByLexKeyword = "BYLEX";
public const string ByScoreKeyword = "BYSCORE";
public const string MatchKeyword = "MATCH";
public const string CountKeyword = "COUNT";

/// <summary>
/// Expiry keywords.
Expand Down
134 changes: 126 additions & 8 deletions sources/Valkey.Glide/Commands/ISetCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Valkey.Glide.Commands;
public interface ISetCommands
{
/// <summary>
/// SAdd adds specified members to the set stored at key.
/// Adds specified members to the set stored at key.
/// Specified members that are already a member of this set are ignored.
/// </summary>
/// <seealso href="https://valkey.io/commands/sadd"/>
Expand All @@ -28,7 +28,7 @@ public interface ISetCommands
Task<bool> SetAddAsync(ValkeyKey key, ValkeyValue value, CommandFlags flags = CommandFlags.None);

/// <summary>
/// SAdd adds specified members to the set stored at key.
/// Adds specified members to the set stored at key.
/// Specified members that are already a member of this set are ignored.
/// </summary>
/// <seealso href="https://valkey.io/commands/sadd"/>
Expand All @@ -46,7 +46,7 @@ public interface ISetCommands
Task<long> SetAddAsync(ValkeyKey key, ValkeyValue[] values, CommandFlags flags = CommandFlags.None);

/// <summary>
/// SetRemove removes specified members from the set stored at key.
/// Removes specified members from the set stored at key.
/// Specified members that are not a member of this set are ignored.
/// </summary>
/// <seealso href="https://valkey.io/commands/srem"/>
Expand All @@ -64,7 +64,7 @@ public interface ISetCommands
Task<bool> SetRemoveAsync(ValkeyKey key, ValkeyValue value, CommandFlags flags = CommandFlags.None);

/// <summary>
/// SetRemove removes specified members from the set stored at key.
/// Removes specified members from the set stored at key.
/// Specified members that are not a member of this set are ignored.
/// </summary>
/// <seealso href="https://valkey.io/commands/srem"/>
Expand All @@ -82,7 +82,7 @@ public interface ISetCommands
Task<long> SetRemoveAsync(ValkeyKey key, ValkeyValue[] values, CommandFlags flags = CommandFlags.None);

/// <summary>
/// SetMembers retrieves all the members of the set value stored at key.
/// Retrieves all the members of the set value stored at key.
/// </summary>
/// <seealso href="https://valkey.io/commands/smembers"/>
/// <param name="key">The key from which to retrieve the set members.</param>
Expand All @@ -98,7 +98,7 @@ public interface ISetCommands
Task<ValkeyValue[]> SetMembersAsync(ValkeyKey key, CommandFlags flags = CommandFlags.None);

/// <summary>
/// SetLength retrieves the set cardinality (number of elements) of the set stored at key.
/// Retrieves the set cardinality (number of elements) of the set stored at key.
/// </summary>
/// <seealso href="https://valkey.io/commands/scard"/>
/// <param name="key">The key from which to retrieve the number of set members.</param>
Expand All @@ -114,7 +114,7 @@ public interface ISetCommands
Task<long> SetLengthAsync(ValkeyKey key, CommandFlags flags = CommandFlags.None);

/// <summary>
/// SetIntersectionLength gets the cardinality of the intersection of all the given sets.
/// Gets the cardinality of the intersection of all the given sets.
/// </summary>
/// <seealso href="https://valkey.io/commands/sintercard"/>
/// <note>Since Valkey 7.0 and above.</note>
Expand All @@ -137,7 +137,7 @@ public interface ISetCommands
Task<long> SetIntersectionLengthAsync(ValkeyKey[] keys, long limit = 0, CommandFlags flags = CommandFlags.None);

/// <summary>
/// SetPop removes and returns one random member from the set stored at key.
/// Removes and returns one random member from the set stored at key.
/// </summary>
/// <seealso href="https://valkey.io/commands/spop"/>
/// <param name="key">The key of the set.</param>
Expand Down Expand Up @@ -394,4 +394,122 @@ public interface ISetCommands
/// </example>
/// </remarks>
Task<long> SetDifferenceStoreAsync(ValkeyKey destination, ValkeyKey[] keys, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Returns whether value is a member of the set stored at key.
/// </summary>
/// <seealso href="https://valkey.io/commands/sismember"/>
/// <param name="key">The key of the set.</param>
/// <param name="value">The member to check for existence in the set.</param>
/// <param name="flags">The flags to use for this operation. Currently flags are ignored.</param>
/// <returns><see langword="true"/> if the element exists in the set, <see langword="false"/> if the element is not a member of the set, or if key does not exist (treated as an empty set).</returns>
/// <remarks>
/// <example>
/// <code>
/// bool result = await client.SetContainsAsync(key, value);
/// </code>
/// </example>
/// </remarks>
Task<bool> SetContainsAsync(ValkeyKey key, ValkeyValue value, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Returns whether each value is a member of the set stored at key.
/// </summary>
/// <seealso href="https://valkey.io/commands/smismember"/>
/// <param name="key">The key of the set.</param>
/// <param name="values">The members to check.</param>
/// <param name="flags">The flags to use for this operation. Currently flags are ignored.</param>
/// <returns>An array of <see langword="bool"/> values, each indicating whether the corresponding element is a member of the set.</returns>
/// <remarks>
/// <example>
/// <code>
/// bool[] result = await client.SetContainsAsync(key, [value1, value2]);
/// </code>
/// </example>
/// </remarks>
Task<bool[]> SetContainsAsync(ValkeyKey key, ValkeyValue[] values, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Returns a random element from the set value stored at key.
/// </summary>
/// <seealso href="https://valkey.io/commands/srandmember"/>
/// <param name="key">The key from which to retrieve the set member.</param>
/// <param name="flags">The flags to use for this operation. Currently flags are ignored.</param>
/// <returns>The randomly selected element, or <see cref="ValkeyValue.Null"/> when key does not exist.</returns>
/// <remarks>
/// <example>
/// <code>
/// ValkeyValue result = await client.SetRandomMemberAsync(key);
/// </code>
/// </example>
/// </remarks>
Task<ValkeyValue> SetRandomMemberAsync(ValkeyKey key, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Returns multiple random members from the set value stored at key.
/// If <paramref name="count"/> is positive, returns unique elements (no repetition) up to count or the set size, whichever is smaller.
/// If <paramref name="count"/> is negative, returns elements with possible repetition (the same element may be returned multiple times),
/// and the number of returned elements is the absolute value of count.
/// </summary>
/// <seealso href="https://valkey.io/commands/srandmember"/>
/// <param name="key">The key from which to retrieve the set members.</param>
/// <param name="count">The number of members to return.</param>
/// <param name="flags">The flags to use for this operation. Currently flags are ignored.</param>
/// <returns>
/// An array of random elements from the set.
/// When count is positive, the returned elements are unique (no repetitions).
/// When count is negative, the returned elements may contain duplicates.
/// If the set does not exist or is empty, an empty array is returned.
/// </returns>
/// <remarks>
/// <example>
/// <code>
/// ValkeyValue[] result = await client.SetRandomMembersAsync(key, 3);
/// </code>
/// </example>
/// </remarks>
Task<ValkeyValue[]> SetRandomMembersAsync(ValkeyKey key, long count, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Moves <paramref name="value"/> from the set at <paramref name="source"/>` to the set at <paramref name="destination"/>, removing it from the source set.
/// Creates a new destination set if needed. The operation is atomic.
/// </summary>
/// <seealso href="https://valkey.io/commands/smove"/>
/// <note>When in cluster mode, <paramref name="source"/> and <paramref name="destination"/> must map to the same hash slot.</note>
/// <param name="source">The key of the set to remove the element from.</param>
/// <param name="destination">The key of the set to add the element to.</param>
/// <param name="value">The set element to move.</param>
/// <param name="flags">The flags to use for this operation. Currently flags are ignored.</param>
/// <returns><see langword="true"/> if the element is moved, <see langword="false"/> if the source set does not exist or the element is not a member of the source set.</returns>
/// <remarks>
/// <example>
/// <code>
/// bool result = await client.SetMoveAsync(sourceKey, destKey, value);
/// </code>
/// </example>
/// </remarks>
Task<bool> SetMoveAsync(ValkeyKey source, ValkeyKey destination, ValkeyValue value, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Iterates elements over a set.
/// </summary>
/// <seealso href="https://valkey.io/commands/sscan"/>
/// <param name="key">The key of the set.</param>
/// <param name="pattern">The pattern to match.</param>
/// <param name="pageSize">The page size to iterate by.</param>
/// <param name="cursor">The cursor position to start at.</param>
/// <param name="pageOffset">The page offset to start at.</param>
/// <param name="flags">The flags to use for this operation. Currently flags are ignored.</param>
/// <returns>An <see cref="IAsyncEnumerable{T}"/> that yields all matching elements of the set.</returns>
/// <remarks>
/// <example>
/// <code>
/// await foreach (ValkeyValue value in client.SetScanAsync(key, "*pattern*"))
/// {
/// // Process each value
/// }
/// </code>
/// </example>
/// </remarks>
IAsyncEnumerable<ValkeyValue> SetScanAsync(ValkeyKey key, ValkeyValue pattern = default, int pageSize = 250, long cursor = 0, int pageOffset = 0, CommandFlags flags = CommandFlags.None);
}
38 changes: 38 additions & 0 deletions sources/Valkey.Glide/Internals/Request.SetCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,42 @@ public static Cmd<long, long> SetIntersectStoreAsync(ValkeyKey destination, Valk

public static Cmd<long, long> SetDifferenceStoreAsync(ValkeyKey destination, ValkeyKey[] keys)
=> Simple<long>(RequestType.SDiffStore, [destination.ToGlideString(), .. keys.ToGlideStrings()]);

public static Cmd<bool, bool> SetContainsAsync(ValkeyKey key, ValkeyValue value)
=> Simple<bool>(RequestType.SIsMember, [key.ToGlideString(), value.ToGlideString()]);

public static Cmd<object[], bool[]> SetContainsAsync(ValkeyKey key, ValkeyValue[] values)
=> new(RequestType.SMIsMember, [key.ToGlideString(), .. values.ToGlideStrings()], false, arr => [.. arr.Cast<bool>()]);

public static Cmd<GlideString, ValkeyValue> SetRandomMemberAsync(ValkeyKey key)
=> new(RequestType.SRandMember, [key.ToGlideString()], true, response => response is null ? ValkeyValue.Null : (ValkeyValue)response);

public static Cmd<object[], ValkeyValue[]> SetRandomMembersAsync(ValkeyKey key, long count)
=> new(RequestType.SRandMember, [key.ToGlideString(), count.ToGlideString()], false, arr => [.. arr.Cast<GlideString>().Select(gs => (ValkeyValue)gs)]);

public static Cmd<bool, bool> SetMoveAsync(ValkeyKey source, ValkeyKey destination, ValkeyValue value)
=> Simple<bool>(RequestType.SMove, [source.ToGlideString(), destination.ToGlideString(), value.ToGlideString()]);

public static Cmd<object[], (long, ValkeyValue[])> SetScanAsync(ValkeyKey key, long cursor, ValkeyValue pattern = default, long count = 0)
{
List<GlideString> args = [key.ToGlideString(), cursor.ToGlideString()];

if (!pattern.IsNull)
{
args.AddRange([Constants.MatchKeyword.ToGlideString(), pattern.ToGlideString()]);
}

if (count > 0)
{
args.AddRange([Constants.CountKeyword.ToGlideString(), count.ToGlideString()]);
}

return new(RequestType.SScan, [.. args], false, arr =>
{
object[] scanArray = arr;
long nextCursor = long.Parse(((GlideString)scanArray[0]).ToString());
ValkeyValue[] elements = [.. ((object[])scanArray[1]).Cast<GlideString>().Select(gs => (ValkeyValue)gs)];
return (nextCursor, elements);
});
}
}
24 changes: 24 additions & 0 deletions sources/Valkey.Glide/Pipeline/BaseBatch.SetCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,24 @@ public abstract partial class BaseBatch<T>
/// <inheritdoc cref="IBatchSetCommands.SetDifferenceStore(ValkeyKey, ValkeyKey[])" />
public T SetDifferenceStore(ValkeyKey destination, ValkeyKey[] keys) => AddCmd(SetDifferenceStoreAsync(destination, keys));

/// <inheritdoc cref="IBatchSetCommands.SetContains(ValkeyKey, ValkeyValue)" />
public T SetContains(ValkeyKey key, ValkeyValue value) => AddCmd(SetContainsAsync(key, value));

/// <inheritdoc cref="IBatchSetCommands.SetContains(ValkeyKey, ValkeyValue[])" />
public T SetContains(ValkeyKey key, ValkeyValue[] values) => AddCmd(SetContainsAsync(key, values));

/// <inheritdoc cref="IBatchSetCommands.SetRandomMember(ValkeyKey)" />
public T SetRandomMember(ValkeyKey key) => AddCmd(SetRandomMemberAsync(key));

/// <inheritdoc cref="IBatchSetCommands.SetRandomMembers(ValkeyKey, long)" />
public T SetRandomMembers(ValkeyKey key, long count) => AddCmd(SetRandomMembersAsync(key, count));

/// <inheritdoc cref="IBatchSetCommands.SetMove(ValkeyKey, ValkeyKey, ValkeyValue)" />
public T SetMove(ValkeyKey source, ValkeyKey destination, ValkeyValue value) => AddCmd(SetMoveAsync(source, destination, value));

/// <inheritdoc cref="IBatchSetCommands.SetScan(ValkeyKey, long, ValkeyValue, long)" />
public T SetScan(ValkeyKey key, long cursor, ValkeyValue pattern = default, long count = 0) => AddCmd(SetScanAsync(key, cursor, pattern, count));

// Explicit interface implementations for IBatchSetCommands
IBatch IBatchSetCommands.SetAdd(ValkeyKey key, ValkeyValue value) => SetAdd(key, value);
IBatch IBatchSetCommands.SetAdd(ValkeyKey key, ValkeyValue[] values) => SetAdd(key, values);
Expand All @@ -94,4 +112,10 @@ public abstract partial class BaseBatch<T>
IBatch IBatchSetCommands.SetIntersectStore(ValkeyKey destination, ValkeyKey[] keys) => SetIntersectStore(destination, keys);
IBatch IBatchSetCommands.SetDifferenceStore(ValkeyKey destination, ValkeyKey first, ValkeyKey second) => SetDifferenceStore(destination, first, second);
IBatch IBatchSetCommands.SetDifferenceStore(ValkeyKey destination, ValkeyKey[] keys) => SetDifferenceStore(destination, keys);
IBatch IBatchSetCommands.SetContains(ValkeyKey key, ValkeyValue value) => SetContains(key, value);
IBatch IBatchSetCommands.SetContains(ValkeyKey key, ValkeyValue[] values) => SetContains(key, values);
IBatch IBatchSetCommands.SetRandomMember(ValkeyKey key) => SetRandomMember(key);
IBatch IBatchSetCommands.SetRandomMembers(ValkeyKey key, long count) => SetRandomMembers(key, count);
IBatch IBatchSetCommands.SetMove(ValkeyKey source, ValkeyKey destination, ValkeyValue value) => SetMove(source, destination, value);
IBatch IBatchSetCommands.SetScan(ValkeyKey key, long cursor, ValkeyValue pattern, long count) => SetScan(key, cursor, pattern, count);
}
Loading