From 28b34e01b8e514c936113ceda2261c0fd9566a91 Mon Sep 17 00:00:00 2001 From: Steve Lorello <42971704+slorello89@users.noreply.github.com> Date: Mon, 15 Jul 2024 16:33:17 -0400 Subject: [PATCH] specifying keys in read/write commands (#463) --- src/Redis.OM/RedisCommands.cs | 39 ++++++++++--------- test/Redis.OM.Unit.Tests/CoreTests.cs | 20 ++++++++++ .../RediSearchTests/SearchTests.cs | 22 +++++------ .../VectorTests/VectorTests.cs | 5 ++- 4 files changed, 54 insertions(+), 32 deletions(-) diff --git a/src/Redis.OM/RedisCommands.cs b/src/Redis.OM/RedisCommands.cs index 8398ca93..96e9ea2a 100644 --- a/src/Redis.OM/RedisCommands.cs +++ b/src/Redis.OM/RedisCommands.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Redis.OM.Contracts; using Redis.OM.Modeling; +using StackExchange.Redis; namespace Redis.OM { @@ -84,7 +85,7 @@ public static async Task SetAsync(this IRedisConnection connection, obje /// How many new fields were created. public static async Task HSetAsync(this IRedisConnection connection, string key, params KeyValuePair[] fieldValues) { - var args = new List { key }; + var args = new List { new RedisKey(key) }; foreach (var kvp in fieldValues) { args.Add(kvp.Key); @@ -104,7 +105,7 @@ public static async Task HSetAsync(this IRedisConnection connection, string /// How many new fields were created. public static async Task HSetAsync(this IRedisConnection connection, string key, TimeSpan timeSpan, params KeyValuePair[] fieldValues) { - var args = new List { key }; + var args = new List { new RedisKey(key) }; foreach (var kvp in fieldValues) { args.Add(kvp.Key); @@ -124,7 +125,7 @@ public static async Task HSetAsync(this IRedisConnection connection, string /// whether the operation succeeded. public static async Task JsonSetAsync(this IRedisConnection connection, string key, string path, string json) { - var result = await connection.ExecuteAsync("JSON.SET", key, path, json); + var result = await connection.ExecuteAsync("JSON.SET", new RedisKey(key), path, json); return result == "OK"; } @@ -139,7 +140,7 @@ public static async Task JsonSetAsync(this IRedisConnection connection, st public static async Task JsonSetAsync(this IRedisConnection connection, string key, string path, object obj) { var json = JsonSerializer.Serialize(obj, RedisSerializationSettings.JsonSerializerOptions); - var result = await connection.ExecuteAsync("JSON.SET", key, path, json); + var result = await connection.ExecuteAsync("JSON.SET", new RedisKey(key), path, json); return result == "OK"; } @@ -154,7 +155,7 @@ public static async Task JsonSetAsync(this IRedisConnection connection, st /// whether the operation succeeded. public static async Task JsonSetAsync(this IRedisConnection connection, string key, string path, string json, TimeSpan timeSpan) { - var args = new[] { key, path, json }; + var args = new object[] { new RedisKey(key), path, json }; return (await connection.SendCommandWithExpiryAsync("JSON.SET", args, key, timeSpan)).First() == "OK"; } @@ -227,7 +228,7 @@ public static async Task JsonSetAsync(this IRedisConnection connection, st public static int HSet(this IRedisConnection connection, string key, TimeSpan timeSpan, params KeyValuePair[] fieldValues) { var args = new List(); - args.Add(key); + args.Add(new RedisKey(key)); foreach (var kvp in fieldValues) { args.Add(kvp.Key); @@ -246,7 +247,7 @@ public static int HSet(this IRedisConnection connection, string key, TimeSpan ti /// How many new fields were created. public static int HSet(this IRedisConnection connection, string key, params KeyValuePair[] fieldValues) { - var args = new List { key }; + var args = new List { new RedisKey(key) }; foreach (var kvp in fieldValues) { args.Add(kvp.Key); @@ -266,7 +267,7 @@ public static int HSet(this IRedisConnection connection, string key, params KeyV /// whether the operation succeeded. public static bool JsonSet(this IRedisConnection connection, string key, string path, string json) { - var result = connection.Execute("JSON.SET", key, path, json); + var result = connection.Execute("JSON.SET", new RedisKey(key), path, json); return result == "OK"; } @@ -281,7 +282,7 @@ public static bool JsonSet(this IRedisConnection connection, string key, string public static bool JsonSet(this IRedisConnection connection, string key, string path, object obj) { var json = JsonSerializer.Serialize(obj, RedisSerializationSettings.JsonSerializerOptions); - var result = connection.Execute("JSON.SET", key, path, json); + var result = connection.Execute("JSON.SET", new RedisKey(key), path, json); return result == "OK"; } @@ -296,7 +297,7 @@ public static bool JsonSet(this IRedisConnection connection, string key, string /// whether the operation succeeded. public static bool JsonSet(this IRedisConnection connection, string key, string path, string json, TimeSpan timeSpan) { - var arr = new[] { key, path, json }; + var arr = new object[] { new RedisKey(key), path, json }; return connection.SendCommandWithExpiry("JSON.SET", arr, key, timeSpan).First() == "OK"; } @@ -570,7 +571,7 @@ public static string Set(this IRedisConnection connection, object obj, TimeSpan /// the object pulled out of redis. public static T? JsonGet(this IRedisConnection connection, string key, params string[] paths) { - var args = new List { key }; + var args = new List { new RedisKey(key) }; args.AddRange(paths); var res = (string)connection.Execute("JSON.GET", args.ToArray()); return !string.IsNullOrEmpty(res) ? JsonSerializer.Deserialize(res, RedisSerializationSettings.JsonSerializerOptions) : default; @@ -586,7 +587,7 @@ public static string Set(this IRedisConnection connection, object obj, TimeSpan /// the object pulled out of redis. public static async Task JsonGetAsync(this IRedisConnection connection, string key, params string[] paths) { - var args = new List { key }; + var args = new List { new RedisKey(key) }; args.AddRange(paths); var res = (string)await connection.ExecuteAsync("JSON.GET", args.ToArray()); return !string.IsNullOrEmpty(res) ? JsonSerializer.Deserialize(res, RedisSerializationSettings.JsonSerializerOptions) : default; @@ -601,7 +602,7 @@ public static string Set(this IRedisConnection connection, object obj, TimeSpan public static IDictionary HGetAll(this IRedisConnection connection, string keyName) { var ret = new Dictionary(); - var res = connection.Execute("HGETALL", keyName).ToArray(); + var res = connection.Execute("HGETALL", new RedisKey(keyName)).ToArray(); for (var i = 0; i < res.Length; i += 2) { ret.Add(res[i], res[i + 1]); @@ -619,7 +620,7 @@ public static IDictionary HGetAll(this IRedisConnection conn public static async Task> HGetAllAsync(this IRedisConnection connection, string keyName) { var ret = new Dictionary(); - var res = (await connection.ExecuteAsync("HGETALL", keyName)).ToArray(); + var res = (await connection.ExecuteAsync("HGETALL", new RedisKey(keyName))).ToArray(); for (var i = 0; i < res.Length; i += 2) { ret.Add(res[i], res[i + 1]); @@ -664,7 +665,7 @@ public static async Task> HGetAllAsync(this IRed sha, keys.Count().ToString(), }; - args.AddRange(keys); + args.AddRange(keys.Select(x => new RedisKey(x)).Cast()); args.AddRange(argv); try { @@ -756,7 +757,7 @@ public static async Task> HGetAllAsync(this IRed /// the connection. /// the key to unlink. /// the status. - public static async Task UnlinkAsync(this IRedisConnection connection, string key) => await connection.ExecuteAsync("UNLINK", key); + public static async Task UnlinkAsync(this IRedisConnection connection, string key) => await connection.ExecuteAsync("UNLINK", new RedisKey(key)); /// /// Unlinks array of keys. @@ -764,7 +765,7 @@ public static async Task> HGetAllAsync(this IRed /// the connection. /// the keys to unlink. /// the status. - public static async Task UnlinkAsync(this IRedisConnection connection, string[] keys) => await connection.ExecuteAsync("UNLINK", keys); + public static async Task UnlinkAsync(this IRedisConnection connection, string[] keys) => await connection.ExecuteAsync("UNLINK", keys.Select(x => new RedisKey(x)).Cast().ToArray()); /// /// Unlinks the key and then adds an updated value of it. @@ -835,7 +836,7 @@ private static RedisReply[] SendCommandWithExpiry( TimeSpan ts) { var commandTuple = Tuple.Create(command, args); - var expireTuple = Tuple.Create("PEXPIRE", new object[] { keyToExpire, ((long)ts.TotalMilliseconds).ToString(CultureInfo.InvariantCulture) }); + var expireTuple = Tuple.Create("PEXPIRE", new object[] { new RedisKey(keyToExpire), ((long)ts.TotalMilliseconds).ToString(CultureInfo.InvariantCulture) }); return connection.ExecuteInTransaction(new[] { commandTuple, expireTuple }); } @@ -847,7 +848,7 @@ private static Task SendCommandWithExpiryAsync( TimeSpan ts) { var commandTuple = Tuple.Create(command, args); - var expireTuple = Tuple.Create("PEXPIRE", new object[] { keyToExpire, ((long)ts.TotalMilliseconds).ToString(CultureInfo.InvariantCulture) }); + var expireTuple = Tuple.Create("PEXPIRE", new object[] { new RedisKey(keyToExpire), ((long)ts.TotalMilliseconds).ToString(CultureInfo.InvariantCulture) }); return connection.ExecuteInTransactionAsync(new[] { commandTuple, expireTuple }); } } diff --git a/test/Redis.OM.Unit.Tests/CoreTests.cs b/test/Redis.OM.Unit.Tests/CoreTests.cs index df927388..12fec419 100644 --- a/test/Redis.OM.Unit.Tests/CoreTests.cs +++ b/test/Redis.OM.Unit.Tests/CoreTests.cs @@ -493,5 +493,25 @@ public void TestUnlink() connection.Execute("SET", key1, "bar"); Assert.Equal(1,connection.Unlink(new []{key1, key2})); } + + [SkipIfMissingEnvVar("CLUSTER_HOST_PORT")] + public async Task TestClusterOperations() + { + var hostInfo = System.Environment.GetEnvironmentVariable("CLUSTER_HOST_PORT"); + Console.WriteLine($"Current host info: {hostInfo}"); + var connectionString = $"redis://{hostInfo}"; + var provider = new RedisConnectionProvider(connectionString); + var connection = provider.Connection; + + var tasks = new List(); + for(var i = 0; i < 10_000; i++) + { + var person = new Person(); + tasks.Add(connection.SetAsync(person)); + } + + await Task.WhenAll(tasks); + } + } } \ No newline at end of file diff --git a/test/Redis.OM.Unit.Tests/RediSearchTests/SearchTests.cs b/test/Redis.OM.Unit.Tests/RediSearchTests/SearchTests.cs index ca203819..4449584f 100644 --- a/test/Redis.OM.Unit.Tests/RediSearchTests/SearchTests.cs +++ b/test/Redis.OM.Unit.Tests/RediSearchTests/SearchTests.cs @@ -992,7 +992,7 @@ public async Task TestUpdateJson() var steve = await collection.FirstAsync(x => x.Name == "Steve"); steve.Age = 33; await collection.UpdateAsync(steve); - await _substitute.Received().ExecuteAsync("EVALSHA", Arg.Any(), "1", "Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N", "SET", "$.Age", "33"); + await _substitute.Received().ExecuteAsync("EVALSHA", Arg.Any(), "1", new RedisKey("Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N"), "SET", "$.Age", "33"); Scripts.ShaCollection.Clear(); } @@ -1010,8 +1010,8 @@ public async Task TestUpdateJsonUnloadedScriptAsync() var steve = await collection.FirstAsync(x => x.Name == "Steve"); steve.Age = 33; await collection.UpdateAsync(steve); - await _substitute.Received().ExecuteAsync("EVALSHA", Arg.Any(), "1", "Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N", "SET", "$.Age", "33"); - await _substitute.Received().ExecuteAsync("EVAL", Scripts.JsonDiffResolution, "1", "Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N", "SET", "$.Age", "33"); + await _substitute.Received().ExecuteAsync("EVALSHA", Arg.Any(), "1", new RedisKey("Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N"), "SET", "$.Age", "33"); + await _substitute.Received().ExecuteAsync("EVAL", Scripts.JsonDiffResolution, "1", new RedisKey("Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N"), "SET", "$.Age", "33"); Scripts.ShaCollection.Clear(); } @@ -1028,8 +1028,8 @@ public void TestUpdateJsonUnloadedScript() var steve = collection.First(x => x.Name == "Steve"); steve.Age = 33; collection.Update(steve); - _substitute.Received().Execute("EVALSHA", Arg.Any(), "1", "Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N", "SET", "$.Age", "33"); - _substitute.Received().Execute("EVAL", Scripts.JsonDiffResolution, "1", "Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N", "SET", "$.Age", "33"); + _substitute.Received().Execute("EVALSHA", Arg.Any(), "1", new RedisKey("Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N"), "SET", "$.Age", "33"); + _substitute.Received().Execute("EVAL", Scripts.JsonDiffResolution, "1", new RedisKey("Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N"), "SET", "$.Age", "33"); Scripts.ShaCollection.Clear(); } @@ -1043,7 +1043,7 @@ public async Task TestUpdateJsonName() var steve = await collection.FirstAsync(x => x.Name == "Steve"); steve.Name = "Bob"; await collection.UpdateAsync(steve); - await _substitute.Received().ExecuteAsync("EVALSHA", Arg.Any(), "1", "Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N", "SET", "$.Name", "\"Bob\""); + await _substitute.Received().ExecuteAsync("EVALSHA", Arg.Any(), "1", new RedisKey("Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N"), "SET", "$.Name", "\"Bob\""); Scripts.ShaCollection.Clear(); } @@ -1058,12 +1058,12 @@ public async Task TestUpdateJsonNestedObject() steve.Address = new Address { State = "Florida" }; await collection.UpdateAsync(steve); var expected = $"{{{Environment.NewLine} \"State\": \"Florida\"{Environment.NewLine}}}"; - await _substitute.Received().ExecuteAsync("EVALSHA", Arg.Any(), "1", "Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N", "SET", "$.Address", expected); + await _substitute.Received().ExecuteAsync("EVALSHA", Arg.Any(), "1", new RedisKey("Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N"), "SET", "$.Address", expected); steve.Address.City = "Satellite Beach"; await collection.UpdateAsync(steve); expected = "\"Satellite Beach\""; - await _substitute.Received().ExecuteAsync("EVALSHA", Arg.Any(), "1", "Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N", "SET", "$.Address.City", expected); + await _substitute.Received().ExecuteAsync("EVALSHA", Arg.Any(), "1", new RedisKey("Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N"), "SET", "$.Address.City", expected); Scripts.ShaCollection.Clear(); } @@ -1079,7 +1079,7 @@ public async Task TestUpdateJsonWithDouble() steve.Age = 33; steve.Height = 71.5; await collection.UpdateAsync(steve); - await _substitute.Received().ExecuteAsync("EVALSHA", Arg.Any(), "1", "Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N", "SET", "$.Age", "33", "SET", "$.Height", "71.5"); + await _substitute.Received().ExecuteAsync("EVALSHA", Arg.Any(), "1", new RedisKey("Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N"), "SET", "$.Age", "33", "SET", "$.Height", "71.5"); Scripts.ShaCollection.Clear(); } @@ -1103,7 +1103,7 @@ public async Task TestDeleteAsync() Assert.True(collection.StateManager.Data.ContainsKey(key)); Assert.True(collection.StateManager.Snapshot.ContainsKey(key)); await collection.DeleteAsync(steve); - await _substitute.Received().ExecuteAsync("UNLINK", key); + await _substitute.Received().ExecuteAsync("UNLINK", new RedisKey(key)); Assert.False(collection.StateManager.Data.ContainsKey(key)); Assert.False(collection.StateManager.Snapshot.ContainsKey(key)); } @@ -1119,7 +1119,7 @@ public void TestDelete() Assert.True(collection.StateManager.Data.ContainsKey(key)); Assert.True(collection.StateManager.Snapshot.ContainsKey(key)); collection.Delete(steve); - _substitute.Received().Execute("UNLINK", key); + _substitute.Received().Execute("UNLINK", new RedisKey(key)); Assert.False(collection.StateManager.Data.ContainsKey(key)); Assert.False(collection.StateManager.Snapshot.ContainsKey(key)); } diff --git a/test/Redis.OM.Unit.Tests/RediSearchTests/VectorTests/VectorTests.cs b/test/Redis.OM.Unit.Tests/RediSearchTests/VectorTests/VectorTests.cs index 66016e60..5c033463 100644 --- a/test/Redis.OM.Unit.Tests/RediSearchTests/VectorTests/VectorTests.cs +++ b/test/Redis.OM.Unit.Tests/RediSearchTests/VectorTests/VectorTests.cs @@ -8,6 +8,7 @@ using Redis.OM.Modeling; using Redis.OM.Modeling.Vectors; using Redis.OM.Searching; +using StackExchange.Redis; using Xunit; namespace Redis.OM.Unit.Tests; @@ -189,9 +190,9 @@ public void InsertVectors() _substitute.Execute("JSON.SET", Arg.Any()).Returns(new RedisReply("OK")); _substitute.Set(hashObj); _substitute.Set(jsonObj); - _substitute.Received().Execute("HSET", "Redis.OM.Unit.Tests.ObjectWithVectorHash:foo", "Id", "foo", "Num", "0", "SimpleHnswVector", + _substitute.Received().Execute("HSET", new RedisKey("Redis.OM.Unit.Tests.ObjectWithVectorHash:foo"), "Id", "foo", "Num", "0", "SimpleHnswVector", Arg.Is(x=>x.SequenceEqual(simpleHnswBytes)), "SimpleVectorizedVector.Vector", Arg.Is(x=>x.SequenceEqual(flatVectorizedBytes)), "SimpleVectorizedVector.Value", "\"foobar\""); - _substitute.Received().Execute("JSON.SET", "Redis.OM.Unit.Tests.ObjectWithVector:foo", ".", json); + _substitute.Received().Execute("JSON.SET", new RedisKey("Redis.OM.Unit.Tests.ObjectWithVector:foo"), ".", json); var deseralized = JsonSerializer.Deserialize(json); Assert.Equal("foobar", deseralized.SimpleVectorizedVector.Value); }