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

Add Lease and non-boxing versions of Execute(Async) #2844

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Prev Previous commit
Next Next commit
tests, and definition fixes
  • Loading branch information
kevin-montrose committed Jan 28, 2025
commit 65cbc796200a6737e1ad6dfbe6ef48c4ddfeddad
17 changes: 17 additions & 0 deletions src/StackExchange.Redis/Interfaces/IServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -263,9 +263,26 @@ public partial interface IServer : IRedis
/// <remarks>This API should be considered an advanced feature; inappropriate use can be harmful.</remarks>
RedisResult Execute(string command, params object[] args);

/// <summary>
/// Execute an arbitrary command against the server; this is primarily intended for
/// executing modules, but may also be used to provide access to new features that lack
/// a direct API.
///
/// Response must be represented as a RESP simple string, bulk string, or integer. Other response will
/// result in an error.
/// </summary>
/// <param name="command">The command to run.</param>
/// <param name="args">The arguments to pass for the command.</param>
/// <returns>A dynamic representation of the command's result.</returns>
/// <remarks>This API should be considered an advanced feature; inappropriate use can be harmful.</remarks>
Lease<byte>? ExecuteLease(string command, params object[] args);

/// <inheritdoc cref="Execute(string, object[])"/>
Task<RedisResult> ExecuteAsync(string command, params object[] args);

/// <inheritdoc cref="ExecuteLease(string, object[])"/>
Task<Lease<byte>?> ExecuteLeaseAsync(string command, params object[] args);

/// <summary>
/// Execute an arbitrary command against the server; this is primarily intended for
/// executing modules, but may also be used to provide access to new features that lack
Expand Down
2 changes: 2 additions & 0 deletions src/StackExchange.Redis/PublicAPI/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@ StackExchange.Redis.IDatabase.ExecuteLease(string! command, params object![]! ar
StackExchange.Redis.IDatabase.ExecuteLease(string! command, System.Collections.Generic.ICollection<object!>! args, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.Lease<byte>?
StackExchange.Redis.IDatabaseAsync.ExecuteLeaseAsync(string! command, params object![]! args) -> System.Threading.Tasks.Task<StackExchange.Redis.Lease<byte>?>!
StackExchange.Redis.IDatabaseAsync.ExecuteLeaseAsync(string! command, System.Collections.Generic.ICollection<object!>? args, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task<StackExchange.Redis.Lease<byte>?>!
StackExchange.Redis.IServer.ExecuteLease(string! command, params object![]! args) -> StackExchange.Redis.Lease<byte>?
StackExchange.Redis.IServer.ExecuteLease(string! command, System.Collections.Generic.ICollection<object!>! args, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.Lease<byte>?
StackExchange.Redis.IServer.ExecuteLeaseAsync(string! command, params object![]! args) -> System.Threading.Tasks.Task<StackExchange.Redis.Lease<byte>?>!
StackExchange.Redis.IServer.ExecuteLeaseAsync(string! command, System.Collections.Generic.ICollection<object!>! args, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task<StackExchange.Redis.Lease<byte>?>!
98 changes: 97 additions & 1 deletion tests/StackExchange.Redis.Tests/ExecuteTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Linq;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;
Expand Down Expand Up @@ -38,4 +40,98 @@ public async Task ServerExecute()
actual = (string?)await server.ExecuteAsync("echo", "some value").ForAwait();
Assert.Equal("some value", actual);
}

[Fact]
public async Task DBExecuteLease()
{
using var conn = Create();

var db = conn.GetDatabase();
var key = Me();

// sync tests
{
db.StringSet(key, "hello world");

using var lease1 = db.ExecuteLease("GET", (RedisKey)key);
Assert.NotNull(lease1);

var value1 = lease1.DecodeString();
Assert.Equal("hello world", value1);

db.StringSet(key, "fizz buzz");

using var lease2 = db.ExecuteLease("GET", new List<object> { (RedisKey)key });
Assert.NotNull(lease2);

var value2 = lease2.DecodeString();
Assert.Equal("fizz buzz", value2);
}

// async tests
{
await db.StringSetAsync(key, "foo bar");

using var lease3 = await db.ExecuteLeaseAsync("GET", (RedisKey)key);
Assert.NotNull(lease3);

var value3 = lease3.DecodeString();
Assert.Equal("foo bar", value3);

await db.StringSetAsync(key, "abc def");

using var lease4 = await db.ExecuteLeaseAsync("GET", new List<object> { (RedisKey)key });
Assert.NotNull(lease4);

var value4 = lease4.DecodeString();
Assert.Equal("abc def", value4);
}
}

[Fact]
public async Task ServerExecuteLease()
{
using var conn = Create();

var server = conn.GetServer(conn.GetEndPoints().First());
var key = Me();

// sync tests
{
server.Execute("SET", key, "hello world");

using var lease1 = server.ExecuteLease("GET", (RedisKey)key);
Assert.NotNull(lease1);

var value1 = lease1.DecodeString();
Assert.Equal("hello world", value1);

server.Execute("SET", key, "fizz buzz");

using var lease2 = server.ExecuteLease("GET", new List<object> { (RedisKey)key });
Assert.NotNull(lease2);

var value2 = lease2.DecodeString();
Assert.Equal("fizz buzz", value2);
}

// async tests
{
await server.ExecuteAsync("SET", key, "foo bar");

using var lease3 = await server.ExecuteLeaseAsync("GET", (RedisKey)key);
Assert.NotNull(lease3);

var value3 = lease3.DecodeString();
Assert.Equal("foo bar", value3);

await server.ExecuteAsync("SET", key, "abc def");

using var lease4 = await server.ExecuteLeaseAsync("GET", new List<object> { (RedisKey)key });
Assert.NotNull(lease4);

var value4 = lease4.DecodeString();
Assert.Equal("abc def", value4);
}
}
}