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
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ Valkey General Language Independent Driver for the Enterprise (GLIDE) is the off

Valkey GLIDE for C# is API-compatible with the following engine versions:

| Engine Type | 6.2 | 7.0 | 7.1 | 7.2 | 8.0 | 8.1 |
|-----------------------|-------|-------|--------|-------|-------|-------|
| Valkey | - | - | - | V | V | V |
| Redis | V | V | V | V | - | - |
| Engine Type | 6.2 | 7.0 | 7.1 | 7.2 | 8.0 | 8.1 | 9.0 |
|-----------------------|-------|-------|--------|-------|-------|-------|-------|
| Valkey | - | - | - | V | V | V | V |
| Redis | V | V | V | V | - | - | - |

## Installation

Expand Down
77 changes: 77 additions & 0 deletions sources/Valkey.Glide/BaseClient.BitmapCommands.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0

using Valkey.Glide.Commands;
using Valkey.Glide.Commands.Options;
using Valkey.Glide.Internals;

namespace Valkey.Glide;

public abstract partial class BaseClient : IBitmapCommands
{
/// <inheritdoc/>
public async Task<bool> StringGetBitAsync(ValkeyKey key, long offset, CommandFlags flags = CommandFlags.None)
{
Utils.Requires<NotImplementedException>(flags == CommandFlags.None, "Command flags are not supported by GLIDE");
return await Command(Request.GetBitAsync(key, offset));
}

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

/// <inheritdoc/>
public async Task<long> StringBitCountAsync(ValkeyKey key, long start = 0, long end = -1, StringIndexType indexType = StringIndexType.Byte, CommandFlags flags = CommandFlags.None)
{
Utils.Requires<NotImplementedException>(flags == CommandFlags.None, "Command flags are not supported by GLIDE");
return await Command(Request.BitCountAsync(key, start, end, indexType));
}

/// <inheritdoc/>
public async Task<long> StringBitPositionAsync(ValkeyKey key, bool bit, long start = 0, long end = -1, StringIndexType indexType = StringIndexType.Byte, CommandFlags flags = CommandFlags.None)
{
Utils.Requires<NotImplementedException>(flags == CommandFlags.None, "Command flags are not supported by GLIDE");
return await Command(Request.BitPositionAsync(key, bit, start, end, indexType));
}

/// <inheritdoc/>
public async Task<long> StringBitOperationAsync(Bitwise operation, ValkeyKey destination, ValkeyKey first, ValkeyKey second, CommandFlags flags = CommandFlags.None)
{
Utils.Requires<NotImplementedException>(flags == CommandFlags.None, "Command flags are not supported by GLIDE");
return await Command(Request.BitOperationAsync(operation, destination, first, second));
}

/// <inheritdoc/>
public async Task<long> StringBitOperationAsync(Bitwise operation, ValkeyKey destination, ValkeyKey[] keys, CommandFlags flags = CommandFlags.None)
{
Utils.Requires<NotImplementedException>(flags == CommandFlags.None, "Command flags are not supported by GLIDE");
return await Command(Request.BitOperationAsync(operation, destination, keys));
}

/// <inheritdoc/>
public async Task<long[]> StringBitFieldAsync(ValkeyKey key, BitFieldOptions.IBitFieldSubCommand[] subCommands, CommandFlags flags = CommandFlags.None)
{
Utils.Requires<NotImplementedException>(flags == CommandFlags.None, "Command flags are not supported by GLIDE");

// Check if all subcommands are read-only (GET operations)
bool allReadOnly = subCommands.All(cmd => cmd is BitFieldOptions.IBitFieldReadOnlySubCommand);

if (allReadOnly)
{
// Convert to read-only subcommands and use BITFIELD_RO
var readOnlyCommands = subCommands.Cast<BitFieldOptions.IBitFieldReadOnlySubCommand>().ToArray();
return await Command(Request.BitFieldReadOnlyAsync(key, readOnlyCommands));
}

return await Command(Request.BitFieldAsync(key, subCommands));
}

/// <inheritdoc/>
public async Task<long[]> StringBitFieldReadOnlyAsync(ValkeyKey key, BitFieldOptions.IBitFieldReadOnlySubCommand[] subCommands, CommandFlags flags = CommandFlags.None)
{
Utils.Requires<NotImplementedException>(flags == CommandFlags.None, "Command flags are not supported by GLIDE");
return await Command(Request.BitFieldReadOnlyAsync(key, subCommands));
}
}
183 changes: 183 additions & 0 deletions sources/Valkey.Glide/Commands/IBitmapCommands.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
// Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0

namespace Valkey.Glide.Commands;

/// <summary>
/// Supports bitmap commands for standalone and cluster clients.
/// <br/>
/// See more on <see href="https://valkey.io/commands#bitmap">valkey.io</see>.
/// </summary>
public interface IBitmapCommands
{
/// <summary>
/// Returns the bit value at offset in the string value stored at key.
/// </summary>
/// <seealso href="https://valkey.io/commands/getbit"/>
/// <param name="key">The key of the string.</param>
/// <param name="offset">The offset in the string to get the bit at.</param>
/// <param name="flags">The flags to use for this operation. Currently flags are ignored.</param>
/// <returns>The bit value stored at offset. Returns 0 if the key does not exist or if the offset is beyond the string length.</returns>
/// <remarks>
/// <example>
/// <code>
/// await client.StringSetAsync("mykey", "A"); // ASCII 'A' is 01000001
/// bool bit = await client.StringGetBitAsync("mykey", 1);
/// Console.WriteLine(bit); // Output: true (bit 1 is set)
/// </code>
/// </example>
/// </remarks>
Task<bool> StringGetBitAsync(ValkeyKey key, long offset, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Sets or clears the bit at offset in the string value stored at key.
/// </summary>
/// <seealso href="https://valkey.io/commands/setbit"/>
/// <param name="key">The key of the string.</param>
/// <param name="offset">The offset in the string to set the bit at.</param>
/// <param name="value">The bit value to set (true for 1, false for 0).</param>
/// <param name="flags">The flags to use for this operation. Currently flags are ignored.</param>
/// <returns>The original bit value stored at offset. Returns false if the key does not exist or if the offset is beyond the string length.</returns>
/// <remarks>
/// <example>
/// <code>
/// bool oldBit = await client.StringSetBitAsync("mykey", 1, true);
/// Console.WriteLine(oldBit); // Output: false (original bit value)
/// </code>
/// </example>
/// </remarks>
Task<bool> StringSetBitAsync(ValkeyKey key, long offset, bool value, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Count the number of set bits in a string.
/// </summary>
/// <seealso href="https://valkey.io/commands/bitcount"/>
/// <param name="key">The key of the string.</param>
/// <param name="start">The start offset.</param>
/// <param name="end">The end offset.</param>
/// <param name="indexType">The index type (bit or byte).</param>
/// <param name="flags">The flags to use for this operation. Currently flags are ignored.</param>
/// <returns>The number of bits set to 1.</returns>
/// <remarks>
/// <example>
/// <code>
/// await client.StringSetAsync("mykey", "A"); // ASCII 'A' is 01000001
/// long count = await client.StringBitCountAsync("mykey");
/// Console.WriteLine(count); // Output: 2 (two bits set)
/// </code>
/// </example>
/// </remarks>
Task<long> StringBitCountAsync(ValkeyKey key, long start = 0, long end = -1, StringIndexType indexType = StringIndexType.Byte, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Return the position of the first bit set to 1 or 0 in a string.
/// </summary>
/// <seealso href="https://valkey.io/commands/bitpos"/>
/// <param name="key">The key of the string.</param>
/// <param name="bit">The bit value to search for (true for 1, false for 0).</param>
/// <param name="start">The start offset.</param>
/// <param name="end">The end offset.</param>
/// <param name="indexType">The index type (bit or byte).</param>
/// <param name="flags">The flags to use for this operation. Currently flags are ignored.</param>
/// <returns>The position of the first bit with the specified value, or -1 if not found.</returns>
/// <remarks>
/// <example>
/// <code>
/// await client.StringSetAsync("mykey", "A"); // ASCII 'A' is 01000001
/// long pos = await client.StringBitPositionAsync("mykey", true);
/// Console.WriteLine(pos); // Output: 1 (first set bit at position 1)
/// </code>
/// </example>
/// </remarks>
Task<long> StringBitPositionAsync(ValkeyKey key, bool bit, long start = 0, long end = -1, StringIndexType indexType = StringIndexType.Byte, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Perform a bitwise operation between multiple keys and store the result in the destination key.
/// </summary>
/// <seealso href="https://valkey.io/commands/bitop"/>
/// <param name="operation">The bitwise operation to perform.</param>
/// <param name="destination">The key to store the result.</param>
/// <param name="first">The first source key.</param>
/// <param name="second">The second source key.</param>
/// <param name="flags">The flags to use for this operation. Currently flags are ignored.</param>
/// <returns>The size of the string stored in the destination key.</returns>
/// <remarks>
/// <example>
/// <code>
/// await client.StringSetAsync("key1", "A");
/// await client.StringSetAsync("key2", "B");
/// long size = await client.StringBitOperationAsync(Bitwise.And, "result", "key1", "key2");
/// Console.WriteLine(size); // Output: 1 (size of result)
/// </code>
/// </example>
/// </remarks>
Task<long> StringBitOperationAsync(Bitwise operation, ValkeyKey destination, ValkeyKey first, ValkeyKey second, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Perform a bitwise operation between multiple keys and store the result in the destination key.
/// </summary>
/// <seealso href="https://valkey.io/commands/bitop"/>
/// <param name="operation">The bitwise operation to perform.</param>
/// <param name="destination">The key to store the result.</param>
/// <param name="keys">The source keys.</param>
/// <param name="flags">The flags to use for this operation. Currently flags are ignored.</param>
/// <returns>The size of the string stored in the destination key.</returns>
/// <remarks>
/// <example>
/// <code>
/// await client.StringSetAsync("key1", "A");
/// await client.StringSetAsync("key2", "B");
/// await client.StringSetAsync("key3", "C");
/// long size = await client.StringBitOperationAsync(Bitwise.Or, "result", new ValkeyKey[] { "key1", "key2", "key3" });
/// Console.WriteLine(size); // Output: 1 (size of result)
/// </code>
/// </example>
/// </remarks>
Task<long> StringBitOperationAsync(Bitwise operation, ValkeyKey destination, ValkeyKey[] keys, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Reads or modifies the array of bits representing the string stored at key based on the specified subcommands.
/// </summary>
/// <seealso href="https://valkey.io/commands/bitfield"/>
/// <param name="key">The key of the string.</param>
/// <param name="subCommands">The subcommands to execute (GET, SET, INCRBY).</param>
/// <param name="flags">The flags to use for this operation. Currently flags are ignored.</param>
/// <returns>An array of results from the executed subcommands. Null responses from the server are converted to 0.</returns>
/// <remarks>
/// <example>
/// <code>
/// await client.StringSetAsync("mykey", "A"); // ASCII 'A' is 01000001
/// var subCommands = new IBitFieldSubCommand[] {
/// new BitFieldOptions.BitFieldGet(BitFieldOptions.Encoding.Unsigned(8), 0),
/// new BitFieldOptions.BitFieldSet(BitFieldOptions.Encoding.Unsigned(8), 0, 66) // ASCII 'B'
/// };
/// long[] results = await client.StringBitFieldAsync("mykey", subCommands);
/// Console.WriteLine(results[0]); // Output: 65 (ASCII 'A')
/// Console.WriteLine(results[1]); // Output: 65 (old value)
/// </code>
/// </example>
/// </remarks>
Task<long[]> StringBitFieldAsync(ValkeyKey key, Commands.Options.BitFieldOptions.IBitFieldSubCommand[] subCommands, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Reads the array of bits representing the string stored at key based on the specified GET subcommands.
/// This is a read-only variant of BITFIELD.
/// </summary>
/// <seealso href="https://valkey.io/commands/bitfield_ro"/>
/// <param name="key">The key of the string.</param>
/// <param name="subCommands">The GET subcommands to execute.</param>
/// <param name="flags">The flags to use for this operation. Currently flags are ignored.</param>
/// <returns>An array of results from the executed GET subcommands. Null responses from the server are converted to 0.</returns>
/// <remarks>
/// <example>
/// <code>
/// await client.StringSetAsync("mykey", "A"); // ASCII 'A' is 01000001
/// var subCommands = new IBitFieldReadOnlySubCommand[] {
/// new BitFieldOptions.BitFieldGet(BitFieldOptions.Encoding.Unsigned(8), 0)
/// };
/// long[] results = await client.StringBitFieldReadOnlyAsync("mykey", subCommands);
/// Console.WriteLine(results[0]); // Output: 65 (ASCII 'A')
/// </code>
/// </example>
/// </remarks>
Task<long[]> StringBitFieldReadOnlyAsync(ValkeyKey key, Commands.Options.BitFieldOptions.IBitFieldReadOnlySubCommand[] subCommands, CommandFlags flags = CommandFlags.None);
}
Loading
Loading