Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
64 changes: 62 additions & 2 deletions sources/Valkey.Glide/BaseClient.GenericCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,19 @@ public async Task<long> KeyExistsAsync(ValkeyKey[] keys, CommandFlags flags = Co
return await Command(Request.KeyExistsAsync(keys));
}

public async Task<bool> KeyExpireAsync(ValkeyKey key, TimeSpan? expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None)
public async Task<bool> KeyExpireAsync(ValkeyKey key, TimeSpan? expiry, CommandFlags flags = CommandFlags.None)
=> await KeyExpireAsync(key, expiry, ExpireWhen.Always, flags);

public async Task<bool> KeyExpireAsync(ValkeyKey key, TimeSpan? expiry, ExpireWhen when, CommandFlags flags = CommandFlags.None)
{
Utils.Requires<NotImplementedException>(flags == CommandFlags.None, "Command flags are not supported by GLIDE");
return await Command(Request.KeyExpireAsync(key, expiry, when));
}

public async Task<bool> KeyExpireAsync(ValkeyKey key, DateTime? expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None)
public async Task<bool> KeyExpireAsync(ValkeyKey key, DateTime? expiry, CommandFlags flags = CommandFlags.None)
=> await KeyExpireAsync(key, expiry, ExpireWhen.Always, flags);

public async Task<bool> KeyExpireAsync(ValkeyKey key, DateTime? expiry, ExpireWhen when, CommandFlags flags = CommandFlags.None)
{
Utils.Requires<NotImplementedException>(flags == CommandFlags.None, "Command flags are not supported by GLIDE");
return await Command(Request.KeyExpireAsync(key, expiry, when));
Expand Down Expand Up @@ -116,10 +122,64 @@ public async Task<long> KeyTouchAsync(ValkeyKey[] keys, CommandFlags flags = Com
return await Command(Request.KeyTouchAsync(keys));
}

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

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

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

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

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

public async Task<bool> KeyCopyAsync(ValkeyKey sourceKey, ValkeyKey destinationKey, bool replace = false, CommandFlags flags = CommandFlags.None)
{
Utils.Requires<NotImplementedException>(flags == CommandFlags.None, "Command flags are not supported by GLIDE");
return await Command(Request.KeyCopyAsync(sourceKey, destinationKey, replace));
}

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

public async Task<ValkeyValue[]> SortAsync(ValkeyKey key, long skip = 0, long take = -1, Order order = Order.Ascending, SortType sortType = SortType.Numeric, ValkeyValue by = default, ValkeyValue[]? get = null, CommandFlags flags = CommandFlags.None)
{
Utils.Requires<NotImplementedException>(flags == CommandFlags.None, "Command flags are not supported by GLIDE");
return await Command(Request.SortAsync(key, skip, take, order, sortType, by, get));
}

public async Task<long> SortAndStoreAsync(ValkeyKey destination, ValkeyKey key, long skip = 0, long take = -1, Order order = Order.Ascending, SortType sortType = SortType.Numeric, ValkeyValue by = default, ValkeyValue[]? get = null, CommandFlags flags = CommandFlags.None)
{
Utils.Requires<NotImplementedException>(flags == CommandFlags.None, "Command flags are not supported by GLIDE");
return await Command(Request.SortAndStoreAsync(destination, key, skip, take, order, sortType, by, get));
}

public async Task<long> WaitAsync(long numreplicas, long timeout, CommandFlags flags = CommandFlags.None)
{
Utils.Requires<NotImplementedException>(flags == CommandFlags.None, "Command flags are not supported by GLIDE");
return await Command(Request.WaitAsync(numreplicas, timeout));
}

}
10 changes: 10 additions & 0 deletions sources/Valkey.Glide/Commands/Constants/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,14 @@ public static class Constants
/// The lowest bound in the sorted set for score operations.
/// </summary>
public const string NegativeInfinityScore = "-inf";

/// <summary>
/// Keywords for SORT command.
/// </summary>
public const string AlphaKeyword = "ALPHA";
public const string AscKeyword = "ASC";
public const string DescKeyword = "DESC";
public const string ByKeyword = "BY";
public const string GetKeyword = "GET";
public const string StoreKeyword = "STORE";
}
183 changes: 179 additions & 4 deletions sources/Valkey.Glide/Commands/IGenericBaseCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,26 @@ public interface IGenericBaseCommands
/// </remarks>
Task<long> KeyExistsAsync(ValkeyKey[] keys, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Set a timeout on key. After the timeout has expired, the key will automatically be deleted.<br/>
/// If key already has an existing expire set, the time to live is updated to the new value.
/// If expiry is a non-positive value, the key will be deleted rather than expired.
/// The timeout will only be cleared by commands that delete or overwrite the contents of key.
/// </summary>
/// <seealso href="https://valkey.io/commands/expire"/>
/// <param name="key">The key to expire.</param>
/// <param name="expiry">Duration for the key to expire.</param>
/// <param name="flags">The flags to use for this operation. Currently flags are ignored.</param>
/// <returns><see langword="true"/> if the timeout was set. <see langword="false"/> if key does not exist or the timeout could not be set.</returns>
/// <remarks>
/// <example>
/// <code>
/// bool result = await client.KeyExpireAsync(key, TimeSpan.FromSeconds(10));
/// </code>
/// </example>
/// </remarks>
Task<bool> KeyExpireAsync(ValkeyKey key, TimeSpan? expiry, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Set a timeout on key. After the timeout has expired, the key will automatically be deleted.<br/>
/// If key already has an existing expire set, the time to live is updated to the new value.
Expand All @@ -146,16 +166,34 @@ public interface IGenericBaseCommands
/// </code>
/// </example>
/// </remarks>
Task<bool> KeyExpireAsync(ValkeyKey key, TimeSpan? expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None);
Task<bool> KeyExpireAsync(ValkeyKey key, TimeSpan? expiry, ExpireWhen when, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Sets a timeout on key. It takes an absolute Unix timestamp (seconds since January 1, 1970) instead of
/// specifying the duration. A timestamp in the past will delete the key immediately. After the timeout has
/// expired, the key will automatically be deleted.<br/>
/// If key already has an existing expire set, the time to live is updated to the new value.
/// The timeout will only be cleared by commands that delete or overwrite the contents of key
/// The timeout will only be cleared by commands that delete or overwrite the contents of key.
/// </summary>
/// <seealso href="https://valkey.io/commands/expireat"/>
/// <param name="key">The key to expire.</param>
/// <param name="expiry">The timestamp for expiry.</param>
/// <param name="flags">The flags to use for this operation. Currently flags are ignored.</param>
/// <returns><see langword="true"/> if the timeout was set. <see langword="false"/> if key does not exist or the timeout could not be set.</returns>
/// <remarks>
/// <example>
/// <code>
/// bool result = await client.KeyExpireAsync(key, DateTime.UtcNow.AddMinutes(5));
/// </code>
/// </example>
/// </remarks>
Task<bool> KeyExpireAsync(ValkeyKey key, DateTime? expiry, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Sets a timeout on key. It takes an absolute Unix timestamp (seconds since January 1, 1970) instead of
/// specifying the duration. A timestamp in the past will delete the key immediately. After the timeout has
/// expired, the key will automatically be deleted.<br/>
/// If key already has an existing expire set, the time to live is updated to the new value.
/// If expiry is a non-positive value, the key will be deleted rather than expired.
/// The timeout will only be cleared by commands that delete or overwrite the contents of key.
/// </summary>
/// <seealso href="https://valkey.io/commands/expireat"/>
Expand All @@ -171,7 +209,7 @@ public interface IGenericBaseCommands
/// </code>
/// </example>
/// </remarks>
Task<bool> KeyExpireAsync(ValkeyKey key, DateTime? expiry, ExpireWhen when = ExpireWhen.Always, CommandFlags flags = CommandFlags.None);
Task<bool> KeyExpireAsync(ValkeyKey key, DateTime? expiry, ExpireWhen when, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Returns the remaining time to live of a key that has a timeout.
Expand Down Expand Up @@ -359,6 +397,86 @@ public interface IGenericBaseCommands
/// </remarks>
Task<long> KeyTouchAsync(ValkeyKey[] keys, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Returns the absolute time at which the given key will expire.
/// </summary>
/// <seealso href="https://valkey.io/commands/pexpiretime"/>
/// <param name="key">The key to determine the expiration value of.</param>
/// <param name="flags">The flags to use for this operation. Currently flags are ignored.</param>
/// <returns>The expiration time, or <see langword="null"/> when key does not exist or key exists but has no associated expiration.</returns>
/// <remarks>
/// <example>
/// <code>
/// DateTime? expiration = await client.KeyExpireTimeAsync(key);
/// </code>
/// </example>
/// </remarks>
Task<DateTime?> KeyExpireTimeAsync(ValkeyKey key, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Returns the internal encoding for the object stored at key.
/// </summary>
/// <seealso href="https://valkey.io/commands/object-encoding"/>
/// <param name="key">The key to determine the encoding of.</param>
/// <param name="flags">The flags to use for this operation. Currently flags are ignored.</param>
/// <returns>The encoding of the object, or <see langword="null"/> when key does not exist.</returns>
/// <remarks>
/// <example>
/// <code>
/// string? encoding = await client.KeyEncodingAsync(key);
/// </code>
/// </example>
/// </remarks>
Task<string?> KeyEncodingAsync(ValkeyKey key, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Returns the logarithmic access frequency counter for the object stored at key.
/// </summary>
/// <seealso href="https://valkey.io/commands/object-freq"/>
/// <param name="key">The key to determine the frequency of.</param>
/// <param name="flags">The flags to use for this operation. Currently flags are ignored.</param>
/// <returns>The frequency counter, or <see langword="null"/> when key does not exist.</returns>
/// <remarks>
/// <example>
/// <code>
/// long? frequency = await client.KeyFrequencyAsync(key);
/// </code>
/// </example>
/// </remarks>
Task<long?> KeyFrequencyAsync(ValkeyKey key, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Returns the time in seconds since the object stored at key was last accessed.
/// </summary>
/// <seealso href="https://valkey.io/commands/object-idletime"/>
/// <param name="key">The key to determine the idle time of.</param>
/// <param name="flags">The flags to use for this operation. Currently flags are ignored.</param>
/// <returns>The idle time in seconds, or <see langword="null"/> when key does not exist.</returns>
/// <remarks>
/// <example>
/// <code>
/// long? idleTime = await client.KeyIdleTimeAsync(key);
/// </code>
/// </example>
/// </remarks>
Task<long?> KeyIdleTimeAsync(ValkeyKey key, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Returns the reference count of the object stored at key.
/// </summary>
/// <seealso href="https://valkey.io/commands/object-refcount"/>
/// <param name="key">The key to determine the reference count of.</param>
/// <param name="flags">The flags to use for this operation. Currently flags are ignored.</param>
/// <returns>The reference count, or <see langword="null"/> when key does not exist.</returns>
/// <remarks>
/// <example>
/// <code>
/// long? refCount = await client.KeyRefCountAsync(key);
/// </code>
/// </example>
/// </remarks>
Task<long?> KeyRefCountAsync(ValkeyKey key, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Copies the value stored at the source to the destination key. When
/// replace is true, removes the destination key first if it already
Expand All @@ -380,4 +498,61 @@ public interface IGenericBaseCommands
/// </example>
/// </remarks>
Task<bool> KeyCopyAsync(ValkeyKey sourceKey, ValkeyKey destinationKey, bool replace = false, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Returns a random key from the database.
/// </summary>
/// <seealso href="https://valkey.io/commands/randomkey"/>
/// <param name="flags">The flags to use for this operation. Currently flags are ignored.</param>
/// <returns>A random key, or <see langword="null"/> when the database is empty.</returns>
/// <remarks>
/// <example>
/// <code>
/// string? randomKey = await client.KeyRandomAsync();
/// </code>
/// </example>
/// </remarks>
Task<string?> KeyRandomAsync(CommandFlags flags = CommandFlags.None);

/// <summary>
/// Sorts the elements in the list, set, or sorted set at key and returns the result.
/// </summary>
/// <seealso href="https://valkey.io/commands/sort"/>
/// <param name="key">The key of the list, set, or sorted set to be sorted.</param>
/// <param name="skip">The number of elements to skip.</param>
/// <param name="take">The number of elements to take. -1 means take all.</param>
/// <param name="order">The sort order.</param>
/// <param name="sortType">The sort type.</param>
/// <param name="by">The pattern to sort by external keys.</param>
/// <param name="get">The patterns to retrieve external keys' values.</param>
/// <param name="flags">The flags to use for this operation. Currently flags are ignored.</param>
/// <returns>An array of sorted elements.</returns>
/// <remarks>
/// <example>
/// <code>
/// await client.ListLeftPushAsync("mylist", ["3", "1", "2"]);
/// ValkeyValue[] result = await client.SortAsync("mylist");
/// // result is ["1", "2", "3"]
/// </code>
/// </example>
/// </remarks>
Task<ValkeyValue[]> SortAsync(ValkeyKey key, long skip = 0, long take = -1, Order order = Order.Ascending, SortType sortType = SortType.Numeric, ValkeyValue by = default, ValkeyValue[]? get = null, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Blocks the current client until all the previous write commands are successfully transferred and acknowledged by at least numreplicas replicas.
/// If the timeout is reached, the command returns even if the specified number of replicas were not yet reached.
/// </summary>
/// <seealso href="https://valkey.io/commands/wait"/>
/// <param name="numreplicas">The number of replicas to wait for.</param>
/// <param name="timeout">The timeout in milliseconds.</param>
/// <param name="flags">The flags to use for this operation. Currently flags are ignored.</param>
/// <returns>The number of replicas that acknowledged the write commands.</returns>
/// <remarks>
/// <example>
/// <code>
/// long result = await client.WaitAsync(1, 1000);
/// </code>
/// </example>
/// </remarks>
Task<long> WaitAsync(long numreplicas, long timeout, CommandFlags flags = CommandFlags.None);
}
23 changes: 23 additions & 0 deletions sources/Valkey.Glide/GlideClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,27 @@ public async Task<string> SelectAsync(long index, CommandFlags flags = CommandFl
Utils.Requires<NotImplementedException>(flags == CommandFlags.None, "Command flags are not supported by GLIDE");
return await Command(Request.Select(index));
}

public async IAsyncEnumerable<ValkeyKey> KeysAsync(int database = -1, 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, ValkeyKey[] keys) = await Command(Request.ScanAsync(currentCursor, pattern, pageSize));

IEnumerable<ValkeyKey> keysToYield = currentOffset > 0 ? keys.Skip(currentOffset) : keys;

foreach (ValkeyKey key in keysToYield)
{
yield return key;
}

currentCursor = nextCursor;
currentOffset = 0;
} while (currentCursor != 0);
}
}
14 changes: 13 additions & 1 deletion sources/Valkey.Glide/Internals/Cmd.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,19 @@ public Cmd<object, ClusterValue<T>> ToClusterValue(bool isSingleValue)
/// </summary>
public string[] GetArgs() => Request == RequestType.CustomCommand
? ArgsArray.Args.ToStrings()
: [.. ArgsArray.Args.ToStrings().Prepend(Request.ToString().ToUpper())];
: [.. GetCommandParts(Request).Concat(ArgsArray.Args.ToStrings())];

#pragma warning disable IDE0072 // Populate switch
private static string[] GetCommandParts(RequestType requestType) => requestType switch
{
RequestType.ObjectEncoding => ["OBJECT", "ENCODING"],
RequestType.ObjectFreq => ["OBJECT", "FREQ"],
RequestType.ObjectIdleTime => ["OBJECT", "IDLETIME"],
RequestType.ObjectRefCount => ["OBJECT", "REFCOUNT"],
RequestType.Command_ => ["COMMAND"],
_ => [requestType.ToString().ToUpper()]
};
#pragma warning restore IDE0072 // Populate switch
}

internal record ArgsArray
Expand Down
Loading
Loading