Skip to content

Commit 7bde6eb

Browse files
authored
Valkey-9 MultiDB support (#90)
Signed-off-by: Alex Rehnby-Martin <[email protected]>
1 parent 21f0ece commit 7bde6eb

File tree

11 files changed

+172
-92
lines changed

11 files changed

+172
-92
lines changed

sources/Valkey.Glide/BaseClient.GenericCommands.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,17 @@ public async Task<bool> KeyCopyAsync(ValkeyKey sourceKey, ValkeyKey destinationK
158158
return await Command(Request.KeyCopyAsync(sourceKey, destinationKey, replace));
159159
}
160160

161+
public async Task<bool> KeyMoveAsync(ValkeyKey key, int database, CommandFlags flags = CommandFlags.None)
162+
{
163+
Utils.Requires<NotImplementedException>(flags == CommandFlags.None, "Command flags are not supported by GLIDE");
164+
return await Command(Request.KeyMoveAsync(key, database));
165+
}
166+
167+
public async Task<bool> KeyCopyAsync(ValkeyKey sourceKey, ValkeyKey destinationKey, int destinationDatabase, bool replace = false, CommandFlags flags = CommandFlags.None)
168+
{
169+
Utils.Requires<NotImplementedException>(flags == CommandFlags.None, "Command flags are not supported by GLIDE");
170+
return await Command(Request.KeyCopyAsync(sourceKey, destinationKey, destinationDatabase, replace));
171+
}
161172
public async Task<string?> KeyRandomAsync(CommandFlags flags = CommandFlags.None)
162173
{
163174
Utils.Requires<NotImplementedException>(flags == CommandFlags.None, "Command flags are not supported by GLIDE");

sources/Valkey.Glide/Commands/IGenericBaseCommands.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,46 @@ public interface IGenericBaseCommands
499499
/// </remarks>
500500
Task<bool> KeyCopyAsync(ValkeyKey sourceKey, ValkeyKey destinationKey, bool replace = false, CommandFlags flags = CommandFlags.None);
501501

502+
/// <summary>
503+
/// Moves key from the currently selected database to the specified destination database.
504+
/// When key already exists in the destination database, or it does not exist in the source database, it does nothing.
505+
/// It is possible to use MOVE as a locking primitive because of this.
506+
/// </summary>
507+
/// <seealso href="https://valkey.io/commands/move"/>
508+
/// <param name="key">The key to move.</param>
509+
/// <param name="database">The database to move the key to.</param>
510+
/// <param name="flags">The flags to use for this operation. Currently flags are ignored.</param>
511+
/// <returns><see langword="true"/> if key was moved. <see langword="false"/> if key was not moved.</returns>
512+
/// <remarks>
513+
/// <example>
514+
/// <code>
515+
/// bool result = await client.KeyMoveAsync(key, 2);
516+
/// </code>
517+
/// </example>
518+
/// </remarks>
519+
Task<bool> KeyMoveAsync(ValkeyKey key, int database, CommandFlags flags = CommandFlags.None);
520+
521+
/// <summary>
522+
/// Copies the value stored at the source to the destination key in the specified database. When
523+
/// replace is true, removes the destination key first if it already
524+
/// exists, otherwise performs no action.
525+
/// </summary>
526+
/// <seealso href="https://valkey.io/commands/copy"/>
527+
/// <note>Since Valkey 6.2.0 and above.</note>
528+
/// <param name="sourceKey">The key to the source value.</param>
529+
/// <param name="destinationKey">The key where the value should be copied to.</param>
530+
/// <param name="destinationDatabase">The database ID to store destinationKey in.</param>
531+
/// <param name="replace">Whether to overwrite an existing values at destinationKey.</param>
532+
/// <param name="flags">The flags to use for this operation. Currently flags are ignored.</param>
533+
/// <returns><see langword="true"/> if sourceKey was copied. <see langword="false"/> if sourceKey was not copied.</returns>
534+
/// <remarks>
535+
/// <example>
536+
/// <code>
537+
/// bool result = await client.KeyCopyAsync(sourceKey, destKey, 1, replace: true);
538+
/// </code>
539+
/// </example>
540+
/// </remarks>
541+
Task<bool> KeyCopyAsync(ValkeyKey sourceKey, ValkeyKey destinationKey, int destinationDatabase, bool replace = false, CommandFlags flags = CommandFlags.None);
502542
/// <summary>
503543
/// Returns a random key from the database.
504544
/// </summary>

sources/Valkey.Glide/Commands/IGenericCommands.cs

Lines changed: 2 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -167,45 +167,7 @@ public interface IGenericCommands
167167
/// </returns>
168168
Task<object?[]?> Exec(Batch batch, bool raiseOnError, BatchOptions options);
169169

170-
/// <summary>
171-
/// Move key from the currently selected database to the database specified by database.
172-
/// </summary>
173-
/// <seealso href="https://valkey.io/commands/move"/>
174-
/// <param name="key">The key to move.</param>
175-
/// <param name="database">The index of the database to move key to.</param>
176-
/// <param name="flags">The flags to use for this operation. Currently flags are ignored.</param>
177-
/// <returns>
178-
/// <see langword="true"/> if key was moved. <see langword="false"/> if the key already exists in the destination
179-
/// database or does not exist in the source database.
180-
/// </returns>
181-
/// <remarks>
182-
/// <example>
183-
/// <code>
184-
/// bool result = await client.KeyMoveAsync(key, 2);
185-
/// </code>
186-
/// </example>
187-
/// </remarks>
188-
Task<bool> KeyMoveAsync(ValkeyKey key, int database, CommandFlags flags = CommandFlags.None);
189170

190-
/// <summary>
191-
/// Copies the value stored at the source to the destination key. When
192-
/// replace is true, removes the destination key first if it already
193-
/// exists, otherwise performs no action.
194-
/// </summary>
195-
/// <seealso href="https://valkey.io/commands/copy"/>
196-
/// <note>Since Valkey 6.2.0 and above.</note>
197-
/// <param name="sourceKey">The key to the source value.</param>
198-
/// <param name="destinationKey">The key where the value should be copied to.</param>
199-
/// <param name="destinationDatabase">The database ID to store destinationKey in.</param>
200-
/// <param name="replace">Whether to overwrite an existing values at destinationKey.</param>
201-
/// <param name="flags">The flags to use for this operation. Currently flags are ignored.</param>
202-
/// <returns><see langword="true"/> if souceKey was copied. <see langword="false"/> if sourceKey was not copied.</returns>
203-
/// <remarks>
204-
/// <example>
205-
/// <code>
206-
/// bool result = await client.KeyCopyAsync(sourceKey, destKey, replace: true);
207-
/// </code>
208-
/// </example>
209-
/// </remarks>
210-
Task<bool> KeyCopyAsync(ValkeyKey sourceKey, ValkeyKey destinationKey, int destinationDatabase, bool replace = false, CommandFlags flags = CommandFlags.None);
171+
172+
211173
}

sources/Valkey.Glide/ConnectionConfiguration.cs

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ internal StandaloneClientConfiguration() { }
187187
/// <param name="connectionTimeout"><inheritdoc cref="ClientConfigurationBuilder{T}.ConnectionTimeout" path="/summary" /></param>
188188
/// <param name="readFrom"><inheritdoc cref="ClientConfigurationBuilder{T}.ReadFrom" path="/summary" /></param>
189189
/// <param name="retryStrategy"><inheritdoc cref="ClientConfigurationBuilder{T}.ConnectionRetryStrategy" path="/summary" /></param>
190-
/// <param name="databaseId"><inheritdoc cref="StandaloneClientConfigurationBuilder.DataBaseId" path="/summary" /></param>
190+
/// <param name="databaseId"><inheritdoc cref="ClientConfigurationBuilder{T}.DataBaseId" path="/summary" /></param>
191191
/// <param name="protocol"><inheritdoc cref="ClientConfigurationBuilder{T}.ProtocolVersion" path="/summary" /></param>
192192
/// <param name="clientName"><inheritdoc cref="ClientConfigurationBuilder{T}.ClientName" path="/summary" /></param>
193193
public StandaloneClientConfiguration(
@@ -220,8 +220,7 @@ public StandaloneClientConfiguration(
220220
}
221221

222222
/// <summary>
223-
/// Configuration for a cluster client. Use <see cref="ClusterClientConfigurationBuilder" /> or
224-
/// <see cref="ClusterClientConfiguration(List{ValueTuple{string?, ushort?}}, bool?, TimeSpan?, TimeSpan?, ReadFrom?, RetryStrategy?, string?, string?, Protocol?, string?)" /> to create an instance.
223+
/// Configuration for a cluster client. Use <see cref="ClusterClientConfigurationBuilder" /> to create an instance.
225224
/// </summary>
226225
public sealed class ClusterClientConfiguration : BaseClientConfiguration
227226
{
@@ -237,6 +236,7 @@ internal ClusterClientConfiguration() { }
237236
/// <param name="connectionTimeout"><inheritdoc cref="ClientConfigurationBuilder{T}.ConnectionTimeout" path="/summary" /></param>
238237
/// <param name="readFrom"><inheritdoc cref="ClientConfigurationBuilder{T}.ReadFrom" path="/summary" /></param>
239238
/// <param name="retryStrategy"><inheritdoc cref="ClientConfigurationBuilder{T}.ConnectionRetryStrategy" path="/summary" /></param>
239+
/// <param name="databaseId"><inheritdoc cref="ClientConfigurationBuilder{T}.DataBaseId" path="/summary" /></param>
240240
/// <param name="protocol"><inheritdoc cref="ClientConfigurationBuilder{T}.ProtocolVersion" path="/summary" /></param>
241241
/// <param name="clientName"><inheritdoc cref="ClientConfigurationBuilder{T}.ClientName" path="/summary" /></param>
242242
public ClusterClientConfiguration(
@@ -248,6 +248,7 @@ public ClusterClientConfiguration(
248248
RetryStrategy? retryStrategy = null,
249249
string? username = null,
250250
string? password = null,
251+
uint? databaseId = null,
251252
Protocol? protocol = null,
252253
string? clientName = null
253254
)
@@ -260,6 +261,7 @@ public ClusterClientConfiguration(
260261
_ = readFrom.HasValue ? builder.ReadFrom = readFrom.Value : new();
261262
_ = retryStrategy.HasValue ? builder.ConnectionRetryStrategy = retryStrategy.Value : new();
262263
_ = (username ?? password) is not null ? builder.Authentication = (username, password!) : new();
264+
_ = databaseId.HasValue ? builder.DataBaseId = databaseId.Value : new();
263265
_ = protocol.HasValue ? builder.ProtocolVersion = protocol.Value : new();
264266
_ = clientName is not null ? builder.ClientName = clientName : "";
265267
Request = builder.Build().Request;
@@ -515,6 +517,23 @@ public T WithConnectionRetryStrategy(RetryStrategy connectionRetryStrategy)
515517
public T WithConnectionRetryStrategy(uint numberOfRetries, uint factor, uint exponentBase, uint? jitterPercent = null)
516518
=> WithConnectionRetryStrategy(new RetryStrategy(numberOfRetries, factor, exponentBase, jitterPercent));
517519
#endregion
520+
#region DataBase ID
521+
/// <summary>
522+
/// Index of the logical database to connect to. Must be non-negative and within the range
523+
/// supported by the server configuration. If not specified, defaults to database 0.
524+
/// For cluster mode, requires Valkey 9.0+ with cluster-databases configuration enabled.
525+
/// </summary>
526+
public uint DataBaseId
527+
{
528+
set => Config.DatabaseId = value;
529+
}
530+
/// <inheritdoc cref="DataBaseId" />
531+
public T WithDataBaseId(uint dataBaseId)
532+
{
533+
DataBaseId = dataBaseId;
534+
return (T)this;
535+
}
536+
#endregion
518537

519538
internal ConnectionConfig Build() => Config;
520539
}
@@ -530,22 +549,6 @@ public StandaloneClientConfigurationBuilder() : base(false) { }
530549
/// Complete the configuration with given settings.
531550
/// </summary>
532551
public new StandaloneClientConfiguration Build() => new() { Request = base.Build() };
533-
534-
#region DataBase ID
535-
/// <summary>
536-
/// Index of the logical database to connect to.
537-
/// </summary>
538-
public uint DataBaseId
539-
{
540-
set => Config.DatabaseId = value;
541-
}
542-
/// <inheritdoc cref="DataBaseId" />
543-
public StandaloneClientConfigurationBuilder WithDataBaseId(uint dataBaseId)
544-
{
545-
DataBaseId = dataBaseId;
546-
return this;
547-
}
548-
#endregion
549552
}
550553

551554
/// <summary>

sources/Valkey.Glide/GlideClient.cs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -91,17 +91,9 @@ public async Task<TimeSpan> PingAsync(ValkeyValue message, CommandFlags flags =
9191
return await Command(Request.Ping(message));
9292
}
9393

94-
public async Task<bool> KeyMoveAsync(ValkeyKey key, int database, CommandFlags flags = CommandFlags.None)
95-
{
96-
Utils.Requires<NotImplementedException>(flags == CommandFlags.None, "Command flags are not supported by GLIDE");
97-
return await Command(Request.KeyMoveAsync(key, database));
98-
}
9994

100-
public async Task<bool> KeyCopyAsync(ValkeyKey sourceKey, ValkeyKey destinationKey, int destinationDatabase, bool replace = false, CommandFlags flags = CommandFlags.None)
101-
{
102-
Utils.Requires<NotImplementedException>(flags == CommandFlags.None, "Command flags are not supported by GLIDE");
103-
return await Command(Request.KeyCopyAsync(sourceKey, destinationKey, destinationDatabase, replace));
104-
}
95+
96+
10597

10698
public async Task<KeyValuePair<string, string>[]> ConfigGetAsync(ValkeyValue pattern = default, CommandFlags flags = CommandFlags.None)
10799
{

sources/Valkey.Glide/Pipeline/BaseBatch.GenericCommands.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ public abstract partial class BaseBatch<T>
8989
/// <inheritdoc cref="IBatchGenericCommands.KeyCopy(ValkeyKey, ValkeyKey, bool)" />
9090
public T KeyCopy(ValkeyKey sourceKey, ValkeyKey destinationKey, bool replace = false) => AddCmd(KeyCopyAsync(sourceKey, destinationKey, replace));
9191

92+
/// <inheritdoc cref="IBatchGenericCommands.KeyMove(ValkeyKey, int)" />
93+
public T KeyMove(ValkeyKey key, int database) => AddCmd(KeyMoveAsync(key, database));
94+
95+
/// <inheritdoc cref="IBatchGenericCommands.KeyCopy(ValkeyKey, ValkeyKey, int, bool)" />
96+
public T KeyCopy(ValkeyKey sourceKey, ValkeyKey destinationKey, int destinationDatabase, bool replace = false) => AddCmd(KeyCopyAsync(sourceKey, destinationKey, destinationDatabase, replace));
9297
/// <inheritdoc cref="IBatchGenericCommands.KeyRandom()" />
9398
public T KeyRandom() => AddCmd(KeyRandomAsync());
9499

@@ -125,6 +130,8 @@ public abstract partial class BaseBatch<T>
125130
IBatch IBatchGenericCommands.KeyIdleTime(ValkeyKey key) => KeyIdleTime(key);
126131
IBatch IBatchGenericCommands.KeyRefCount(ValkeyKey key) => KeyRefCount(key);
127132
IBatch IBatchGenericCommands.KeyCopy(ValkeyKey sourceKey, ValkeyKey destinationKey, bool replace) => KeyCopy(sourceKey, destinationKey, replace);
133+
IBatch IBatchGenericCommands.KeyMove(ValkeyKey key, int database) => KeyMove(key, database);
134+
IBatch IBatchGenericCommands.KeyCopy(ValkeyKey sourceKey, ValkeyKey destinationKey, int destinationDatabase, bool replace) => KeyCopy(sourceKey, destinationKey, destinationDatabase, replace);
128135
IBatch IBatchGenericCommands.KeyRandom() => KeyRandom();
129136
IBatch IBatchGenericCommands.Sort(ValkeyKey key, long skip, long take, Order order, SortType sortType, ValkeyValue by, ValkeyValue[]? get) => Sort(key, skip, take, order, sortType, by, get);
130137
IBatch IBatchGenericCommands.Wait(long numreplicas, long timeout) => Wait(numreplicas, timeout);

sources/Valkey.Glide/Pipeline/Batch.cs

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
// Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0
22

3-
using Valkey.Glide.Internals;
4-
53
namespace Valkey.Glide.Pipeline;
64

75
/// <summary>
@@ -25,15 +23,6 @@ namespace Valkey.Glide.Pipeline;
2523
/// </param>
2624
public sealed class Batch(bool isAtomic) : BaseBatch<Batch>(isAtomic), IBatchStandalone
2725
{
28-
// Standalone commands: select, move, copy, scan
29-
30-
/// <inheritdoc cref="IBatchStandalone.KeyCopy(ValkeyKey, ValkeyKey, int, bool)" />
31-
public Batch KeyCopy(ValkeyKey sourceKey, ValkeyKey destinationKey, int destinationDatabase, bool replace = false) => AddCmd(Request.KeyCopyAsync(sourceKey, destinationKey, destinationDatabase, replace));
32-
33-
/// <inheritdoc cref="IBatchStandalone.KeyMove(ValkeyKey, int)" />
34-
public Batch KeyMove(ValkeyKey key, int database) => AddCmd(Request.KeyMoveAsync(key, database));
35-
3626
// Explicit interface implementations for IBatchStandalone
37-
IBatchStandalone IBatchStandalone.KeyCopy(ValkeyKey sourceKey, ValkeyKey destinationKey, int destinationDatabase, bool replace) => KeyCopy(sourceKey, destinationKey, destinationDatabase, replace);
38-
IBatchStandalone IBatchStandalone.KeyMove(ValkeyKey key, int database) => KeyMove(key, database);
27+
IBatch IBatchStandalone.SelectAsync(long index) => SelectAsync(index);
3928
}

sources/Valkey.Glide/Pipeline/IBatchGenericCommands.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,13 @@ internal interface IBatchGenericCommands
111111
/// <returns>Command Response - <inheritdoc cref="IGenericBaseCommands.KeyCopyAsync(ValkeyKey, ValkeyKey, bool, CommandFlags)" /></returns>
112112
IBatch KeyCopy(ValkeyKey sourceKey, ValkeyKey destinationKey, bool replace = false);
113113

114+
/// <inheritdoc cref="IGenericBaseCommands.KeyMoveAsync(ValkeyKey, int, CommandFlags)" path="/*[not(self::remarks) and not(self::returns)]" />
115+
/// <returns>Command Response - <inheritdoc cref="IGenericBaseCommands.KeyMoveAsync(ValkeyKey, int, CommandFlags)" /></returns>
116+
IBatch KeyMove(ValkeyKey key, int database);
117+
118+
/// <inheritdoc cref="IGenericBaseCommands.KeyCopyAsync(ValkeyKey, ValkeyKey, int, bool, CommandFlags)" path="/*[not(self::remarks) and not(self::returns)]" />
119+
/// <returns>Command Response - <inheritdoc cref="IGenericBaseCommands.KeyCopyAsync(ValkeyKey, ValkeyKey, int, bool, CommandFlags)" /></returns>
120+
IBatch KeyCopy(ValkeyKey sourceKey, ValkeyKey destinationKey, int destinationDatabase, bool replace = false);
114121
/// <inheritdoc cref="IGenericBaseCommands.KeyRandomAsync(CommandFlags)" path="/*[not(self::remarks) and not(self::returns)]" />
115122
/// <returns>Command Response - <inheritdoc cref="IGenericBaseCommands.KeyRandomAsync(CommandFlags)" /></returns>
116123
IBatch KeyRandom();
Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,13 @@
11
// Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0
22

3-
using Valkey.Glide.Commands;
4-
53
namespace Valkey.Glide.Pipeline;
64

75
/// <summary>
86
/// Interface for standalone-specific batch operations that are not available in cluster mode.
97
/// </summary>
108
internal interface IBatchStandalone
119
{
12-
/// <inheritdoc cref="IGenericCommands.KeyCopyAsync(ValkeyKey, ValkeyKey, int, bool, CommandFlags)" path="/*[not(self::remarks) and not(self::returns)]" />
13-
/// <returns>Command Response - <inheritdoc cref="IGenericCommands.KeyCopyAsync(ValkeyKey, ValkeyKey, int, bool, CommandFlags)" /></returns>
14-
IBatchStandalone KeyCopy(ValkeyKey sourceKey, ValkeyKey destinationKey, int destinationDatabase, bool replace = false);
15-
16-
/// <inheritdoc cref="IGenericCommands.KeyMoveAsync(ValkeyKey, int, CommandFlags)" path="/*[not(self::remarks) and not(self::returns)]" />
17-
/// <returns>Command Response - <inheritdoc cref="IGenericCommands.KeyMoveAsync(ValkeyKey, int, CommandFlags)" /></returns>
18-
IBatchStandalone KeyMove(ValkeyKey key, int database);
10+
/// <inheritdoc cref="Commands.IServerManagementCommands.SelectAsync(long, CommandFlags)" path="/*[not(self::remarks) and not(self::returns)]" />
11+
/// <returns>Command Response - <inheritdoc cref="Commands.IServerManagementCommands.SelectAsync(long, CommandFlags)" /></returns>
12+
IBatch SelectAsync(long index);
1913
}

0 commit comments

Comments
 (0)