From 9ddec7fde93dee442c8405a110bccc3281de4d7d Mon Sep 17 00:00:00 2001 From: Shachar Pashchur Date: Sun, 25 Dec 2022 17:09:00 +0200 Subject: [PATCH 01/21] add pipeline class & test --- src/NRedisStack/Pipeline.cs | 50 +++++++++++++++++++++++ tests/NRedisStack.Tests/Json/JsonTests.cs | 15 +++++++ 2 files changed, 65 insertions(+) create mode 100644 src/NRedisStack/Pipeline.cs diff --git a/src/NRedisStack/Pipeline.cs b/src/NRedisStack/Pipeline.cs new file mode 100644 index 00000000..dd833fd6 --- /dev/null +++ b/src/NRedisStack/Pipeline.cs @@ -0,0 +1,50 @@ +using NRedisStack.RedisStackCommands; +using StackExchange.Redis; + +namespace NRedisStack +{ + public class Pipeline + { + private readonly IDatabase _db; + private readonly List _commands = new List(); + + public Pipeline(IDatabase db) + { + _db = db; + } + + public void AddCommand(SerializedCommand command) + { + _commands.Add(command); + } + + public RedisResult[] Execute() + { + var transaction = _db.CreateTransaction(); + var tasks = new List>(); + foreach (var command in _commands) + { + tasks.Add(transaction.ExecuteAsync(command.Command, command.Args)); + } + + transaction.Execute(); + Task.WhenAll(tasks).Wait(); + return tasks.Select(x => x.Result).ToArray(); + } + + public async Task ExecuteAsync() + { + var transaction = _db.CreateTransaction(); + var tasks = new List>(); + foreach (var command in _commands) + { + tasks.Add(transaction.ExecuteAsync(command.Command, command.Args)); + } + + transaction.Execute(); + await Task.WhenAll(tasks); + return tasks.Select(x => x.Result).ToArray(); + } + + } +} \ No newline at end of file diff --git a/tests/NRedisStack.Tests/Json/JsonTests.cs b/tests/NRedisStack.Tests/Json/JsonTests.cs index 1396881c..c0b9b2e1 100644 --- a/tests/NRedisStack.Tests/Json/JsonTests.cs +++ b/tests/NRedisStack.Tests/Json/JsonTests.cs @@ -20,6 +20,21 @@ public void Dispose() redisFixture.Redis.GetDatabase().KeyDelete(_testName); } + [Fact] + public void TestPipeline() + { + var conn = redisFixture.Redis; + var db = conn.GetDatabase(); + IJsonCommands json = new JsonCommands(db); + var pipeline = new Pipeline(db); + pipeline.AddCommand(JsonCommandBuilder.Set("key", "$", new Person { Name = "Shachar", Age = 23 })); + pipeline.AddCommand(JsonCommandBuilder.Get("key")); + var results = pipeline.Execute(); + Assert.Equal(2, results.Length); + Assert.Equal("OK", results[0].ToString()); + Assert.Equal("{\"Name\":\"Shachar\",\"Age\":23}", results[1].ToString()); + } + [Fact] public void TestSetFromFile() { From 4f1369914500348514ed2fa9beec6256b0b6a805 Mon Sep 17 00:00:00 2001 From: Shachar Pashchur Date: Tue, 27 Dec 2022 17:16:56 +0200 Subject: [PATCH 02/21] Update StackExchange version to 2.6.86 --- tests/NRedisStack.Tests/NRedisStack.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/NRedisStack.Tests/NRedisStack.Tests.csproj b/tests/NRedisStack.Tests/NRedisStack.Tests.csproj index 0f9f5deb..0321d62e 100644 --- a/tests/NRedisStack.Tests/NRedisStack.Tests.csproj +++ b/tests/NRedisStack.Tests/NRedisStack.Tests.csproj @@ -20,7 +20,7 @@ - + From aabc398a7c957d623abb9060eb6ea40d572c9530 Mon Sep 17 00:00:00 2001 From: Shachar Pashchur Date: Tue, 17 Jan 2023 11:58:14 +0200 Subject: [PATCH 03/21] Fix Pipeline test --- tests/NRedisStack.Tests/Json/JsonTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/NRedisStack.Tests/Json/JsonTests.cs b/tests/NRedisStack.Tests/Json/JsonTests.cs index 6d05973b..80b06a3a 100644 --- a/tests/NRedisStack.Tests/Json/JsonTests.cs +++ b/tests/NRedisStack.Tests/Json/JsonTests.cs @@ -27,7 +27,8 @@ public void TestPipeline() var db = conn.GetDatabase(); IJsonCommands json = new JsonCommands(db); var pipeline = new Pipeline(db); - pipeline.AddCommand(JsonCommandBuilder.Set("key", "$", new Person { Name = "Shachar", Age = 23 })); + string jsonPerson = JsonSerializer.Serialize(new Person { Name = "Shachar", Age = 23 }); + pipeline.AddCommand(JsonCommandBuilder.Set("key", "$", jsonPerson)); pipeline.AddCommand(JsonCommandBuilder.Get("key")); var results = pipeline.Execute(); Assert.Equal(2, results.Length); From fea722fe81b7bafb5aef6f79e06c6098f3e8ee50 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Fri, 20 Jan 2023 00:15:56 +0200 Subject: [PATCH 04/21] fix conflicts --- .github/workflows/integration.yml | 2 +- tests/NRedisStack.Tests/NRedisStack.Tests.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index ec7a3ce0..edbac4fc 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -30,7 +30,7 @@ jobs: with: dotnet-version: '7.0.x' - name: run redis-stack-server docker - run: docker run -p 6379:6379 -d redislabs/redismod:edge + run: docker run -p 6379:6379 -d redis/redis-stack-server:edge - name: Restore dependencies run: dotnet restore - name: Build diff --git a/tests/NRedisStack.Tests/NRedisStack.Tests.csproj b/tests/NRedisStack.Tests/NRedisStack.Tests.csproj index 0321d62e..01c824f8 100644 --- a/tests/NRedisStack.Tests/NRedisStack.Tests.csproj +++ b/tests/NRedisStack.Tests/NRedisStack.Tests.csproj @@ -20,7 +20,7 @@ - + From 04ef5c65e0be6c121ad4f8543e01251469b18b5e Mon Sep 17 00:00:00 2001 From: shacharPash Date: Wed, 25 Jan 2023 00:09:58 +0200 Subject: [PATCH 05/21] support pipelines with batch --- src/NRedisStack/Auxiliary.cs | 2 +- src/NRedisStack/Json/IJsonCommands.cs | 257 ------------------- src/NRedisStack/Json/IJsonCommandsAsync.cs | 273 +++++++++++++++++++++ src/NRedisStack/Json/JsonCommandBuilder.cs | 52 ++-- src/NRedisStack/Json/JsonCommands.cs | 253 ++----------------- src/NRedisStack/Json/JsonCommandsAsync.cs | 228 +++++++++++++++++ src/NRedisStack/Pipeline.cs | 54 +--- tests/NRedisStack.Tests/Json/JsonTests.cs | 79 +++--- 8 files changed, 608 insertions(+), 590 deletions(-) create mode 100644 src/NRedisStack/Json/IJsonCommandsAsync.cs create mode 100644 src/NRedisStack/Json/JsonCommandsAsync.cs diff --git a/src/NRedisStack/Auxiliary.cs b/src/NRedisStack/Auxiliary.cs index edc1abde..2dcde416 100644 --- a/src/NRedisStack/Auxiliary.cs +++ b/src/NRedisStack/Auxiliary.cs @@ -31,7 +31,7 @@ public static RedisResult Execute(this IDatabase db, SerializedCommand command) return db.Execute(command.Command, command.Args); } - public async static Task ExecuteAsync(this IDatabase db, SerializedCommand command) + public async static Task ExecuteAsync(this IDatabaseAsync db, SerializedCommand command) { return await db.ExecuteAsync(command.Command, command.Args); } diff --git a/src/NRedisStack/Json/IJsonCommands.cs b/src/NRedisStack/Json/IJsonCommands.cs index 80b2af7e..d022cab6 100644 --- a/src/NRedisStack/Json/IJsonCommands.cs +++ b/src/NRedisStack/Json/IJsonCommands.cs @@ -270,261 +270,4 @@ public interface IJsonCommands /// The path within the object. /// the value's size in bytes. long DebugMemory(string key, string? path = null); - - /// - /// Appends the provided items to the array at the provided path. - /// - /// The key to append to - /// The path to append to - /// the values to append - /// The new array sizes for the appended paths - /// - Task ArrAppendAsync(RedisKey key, string? path = null, params object[] values); - - /// - /// Finds the index of the provided item within the provided range - /// - /// The key to look up. - /// The json path. - /// The value to find the index of. - /// The starting index within the array. Inclusive. - /// The ending index within the array. Exclusive - /// The index of the value for each array the path resolved to. - /// - Task ArrIndexAsync(RedisKey key, string path, object value, long? start = null, long? stop = null); - - /// - /// Inserts the provided items at the provided index within a json array. - /// - /// The key to insert into. - /// The path of the array(s) within the key to insert into. - /// The index to insert at. - /// The values to insert - /// The new size of each array the item was inserted into. - /// - Task ArrInsertAsync(RedisKey key, string path, long index, params object[] values); - - /// - /// Gets the length of the arrays resolved by the provided path. - /// - /// The key of the json object. - /// The path to the array(s) - /// The length of each array resolved by the json path. - /// - Task ArrLenAsync(RedisKey key, string? path = null); - - /// - /// Pops an item from the array(s) at the provided index. Or the last element if no index is provided. - /// - /// The json key to use. - /// The path of the array(s). - /// The index to pop from - /// The items popped from the array - /// - Task ArrPopAsync(RedisKey key, string? path = null, long? index = null); - - /// - /// Trims the array(s) at the provided path, leaving the range between the specified indexes (inclusive). - /// - /// The key to trim from. - /// The path of the array(s) within the json object to trim. - /// the starting index to retain. - /// The ending index to retain. - /// The new length of the array(s) after they're trimmed. - /// - Task ArrTrimAsync(RedisKey key, string path, long start, long stop); - - /// - /// Clear's container values(arrays/objects), and sets numeric values to 0. - /// - /// The key to clear. - /// The path to clear. - /// number of values cleared - /// - Task ClearAsync(RedisKey key, string? path = null); - - /// - /// Deletes a json value. - /// - /// The key to delete from. - /// The path to delete. - /// number of path's deleted - /// - Task DelAsync(RedisKey key, string? path = null); - - /// - /// Deletes a json value. - /// - /// The key to delete from. - /// The path to delete. - /// number of path's deleted - /// - Task ForgetAsync(RedisKey key, string? path = null); - - /// - /// Gets the value stored at the key and path in redis. - /// - /// The key to retrieve. - /// the indentation string for nested levels - /// sets the string that's printed at the end of each line - /// sets the string that's put between a key and a value - /// the path to get. - /// The requested Items - /// - Task GetAsync(RedisKey key, RedisValue? indent = null, RedisValue? newLine = null, RedisValue? space = null, RedisValue? path = null); - - /// - /// Gets the values stored at the provided paths in redis. - /// - /// The key to pull from. - /// The paths within the key to pull. - /// the indentation string for nested levels - /// sets the string that's printed at the end of each line - /// sets the string that's put between a key and a value - /// - Task GetAsync(RedisKey key, string[] paths, RedisValue? indent = null, RedisValue? newLine = null, RedisValue? space = null); - - /// - /// Generically gets an Item stored in Redis. - /// - /// The key to retrieve - /// The path to retrieve - /// The type retrieved - /// The object requested - /// - Task GetAsync(RedisKey key, string path = "$"); - - /// - /// Gets the provided path from multiple keys - /// - /// The keys to retrieve from. - /// The path to retrieve - /// An array of RedisResults with the requested data. - /// - Task MGetAsync(RedisKey[] keys, string path); - - /// - /// Increments the fields at the provided path by the provided number. - /// - /// The key. - /// The path to increment. - /// The value to increment by. - /// The new values after being incremented, or null if the path resolved a non-numeric. - /// - Task NumIncrbyAsync(RedisKey key, string path, double value); - - /// - /// Gets the keys of the object at the provided path. - /// - /// the key of the json object. - /// The path of the object(s) - /// the keys of the resolved object(s) - /// - Task>> ObjKeysAsync(RedisKey key, string? path = null); - - /// - /// returns the number of keys in the object(s) at the provided path. - /// - /// The key of the json object. - /// The path of the object(s) to resolve. - /// The length of the object(s) keyspace. - /// - Task ObjLenAsync(RedisKey key, string? path = null); - - /// - /// Gets the key in RESP(Redis Serialization Protocol) form. - /// - /// The key to get. - /// Path within the key to get. - /// the resultant resp - /// - Task RespAsync(RedisKey key, string? path = null); - - /// - /// Set's the key/path to the provided value. - /// - /// The key. - /// The path to set within the key. - /// The value to set. - /// When to set the value. - /// The disposition of the command - /// - Task SetAsync(RedisKey key, RedisValue path, object obj, When when = When.Always); - - /// - /// Set's the key/path to the provided value. - /// - /// The key. - /// The path to set within the key. - /// The value to set. - /// When to set the value. - /// The disposition of the command - /// - Task SetAsync(RedisKey key, RedisValue path, RedisValue json, When when = When.Always); - - /// - /// Set json file from the provided file Path. - /// - /// The key. - /// The path to set within the key. - /// The path of the file to set. - /// When to set the value. - /// The disposition of the command - /// - Task SetFromFileAsync(RedisKey key, RedisValue path, string filePath, When when = When.Always); - - /// - /// Set all json files in the provided file Path. - /// - /// The path to set within the file name as key. - /// The path of the file to set. - /// When to set the value. - /// The number of files that have been set - /// - Task SetFromDirectoryAsync(RedisValue path, string filesPath, When when = When.Always); - - /// - /// Appends the provided string to the string(s) at the provided path. - /// - /// The key to append to. - /// The path of the string(s) to append to. - /// The value to append. - /// The new length of the string(s) appended to, those lengths will be null if the path did not resolve ot a string. - /// - Task StrAppendAsync(RedisKey key, string value, string? path = null); - - /// - /// Check's the length of the string(s) at the provided path. - /// - /// The key of the json object. - /// The path of the string(s) within the json object. - /// The length of the string(s) appended to, those lengths will be null if the path did not resolve ot a string. - /// - Task StrLenAsync(RedisKey key, string? path = null); - - /// - /// Toggles the boolean value(s) at the provided path. - /// - /// The key of the json object. - /// The path of the value(s) to toggle. - /// the new value(s). Which will be null if the path did not resolve to a boolean. - /// - Task ToggleAsync(RedisKey key, string? path = null); - - /// - /// Gets the type(s) of the item(s) at the provided json path. - /// - /// The key of the JSON object. - /// The path to resolve. - /// An array of types. - /// - Task TypeAsync(RedisKey key, string? path = null); - - /// - /// Report a value's memory usage in bytes. path defaults to root if not provided. - /// - /// The object's key - /// The path within the object. - /// the value's size in bytes. - Task DebugMemoryAsync(string key, string? path = null); } \ No newline at end of file diff --git a/src/NRedisStack/Json/IJsonCommandsAsync.cs b/src/NRedisStack/Json/IJsonCommandsAsync.cs new file mode 100644 index 00000000..2d038ae3 --- /dev/null +++ b/src/NRedisStack/Json/IJsonCommandsAsync.cs @@ -0,0 +1,273 @@ +using StackExchange.Redis; + +namespace NRedisStack; + +public interface IJsonCommandsAsync +{ + /// + /// Appends the provided items to the array at the provided path. + /// + /// The key to append to + /// The path to append to + /// the values to append + /// The new array sizes for the appended paths + /// + Task ArrAppendAsync(RedisKey key, string? path = null, params object[] values); + + /// + /// Finds the index of the provided item within the provided range + /// + /// The key to look up. + /// The json path. + /// The value to find the index of. + /// The starting index within the array. Inclusive. + /// The ending index within the array. Exclusive + /// The index of the value for each array the path resolved to. + /// + Task ArrIndexAsync(RedisKey key, string path, object value, long? start = null, long? stop = null); + + /// + /// Inserts the provided items at the provided index within a json array. + /// + /// The key to insert into. + /// The path of the array(s) within the key to insert into. + /// The index to insert at. + /// The values to insert + /// The new size of each array the item was inserted into. + /// + Task ArrInsertAsync(RedisKey key, string path, long index, params object[] values); + + /// + /// Gets the length of the arrays resolved by the provided path. + /// + /// The key of the json object. + /// The path to the array(s) + /// The length of each array resolved by the json path. + /// + Task ArrLenAsync(RedisKey key, string? path = null); + + /// + /// Pops an item from the array(s) at the provided index. Or the last element if no index is provided. + /// + /// The json key to use. + /// The path of the array(s). + /// The index to pop from + /// The items popped from the array + /// + Task ArrPopAsync(RedisKey key, string? path = null, long? index = null); + + /// + /// Trims the array(s) at the provided path, leaving the range between the specified indexes (inclusive). + /// + /// The key to trim from. + /// The path of the array(s) within the json object to trim. + /// the starting index to retain. + /// The ending index to retain. + /// The new length of the array(s) after they're trimmed. + /// + Task ArrTrimAsync(RedisKey key, string path, long start, long stop); + + /// + /// Clear's container values(arrays/objects), and sets numeric values to 0. + /// + /// The key to clear. + /// The path to clear. + /// number of values cleared + /// + Task ClearAsync(RedisKey key, string? path = null); + + /// + /// Deletes a json value. + /// + /// The key to delete from. + /// The path to delete. + /// number of path's deleted + /// + Task DelAsync(RedisKey key, string? path = null); + + /// + /// Deletes a json value. + /// + /// The key to delete from. + /// The path to delete. + /// number of path's deleted + /// + Task ForgetAsync(RedisKey key, string? path = null); + + /// + /// Gets the value stored at the key and path in redis. + /// + /// The key to retrieve. + /// the indentation string for nested levels + /// sets the string that's printed at the end of each line + /// sets the string that's put between a key and a value + /// the path to get. + /// The requested Items + /// + Task GetAsync(RedisKey key, RedisValue? indent = null, RedisValue? newLine = null, RedisValue? space = null, RedisValue? path = null); + + /// + /// Gets the values stored at the provided paths in redis. + /// + /// The key to pull from. + /// The paths within the key to pull. + /// the indentation string for nested levels + /// sets the string that's printed at the end of each line + /// sets the string that's put between a key and a value + /// + Task GetAsync(RedisKey key, string[] paths, RedisValue? indent = null, RedisValue? newLine = null, RedisValue? space = null); + + /// + /// Generically gets an Item stored in Redis. + /// + /// The key to retrieve + /// The path to retrieve + /// The type retrieved + /// The object requested + /// + Task GetAsync(RedisKey key, string path = "$"); + + /// + /// retrieves a group of items stored in redis, appropriate if the path will resolve to multiple records. + /// + /// The key to pull from. + /// The path to pull. + /// The type. + /// An enumerable of the requested tyep + /// + Task> GetEnumerableAsync(RedisKey key, string path = "$"); + + /// + /// Gets the provided path from multiple keys + /// + /// The keys to retrieve from. + /// The path to retrieve + /// An array of RedisResults with the requested data. + /// + Task MGetAsync(RedisKey[] keys, string path); + + /// + /// Increments the fields at the provided path by the provided number. + /// + /// The key. + /// The path to increment. + /// The value to increment by. + /// The new values after being incremented, or null if the path resolved a non-numeric. + /// + Task NumIncrbyAsync(RedisKey key, string path, double value); + + /// + /// Gets the keys of the object at the provided path. + /// + /// the key of the json object. + /// The path of the object(s) + /// the keys of the resolved object(s) + /// + Task>> ObjKeysAsync(RedisKey key, string? path = null); + + /// + /// returns the number of keys in the object(s) at the provided path. + /// + /// The key of the json object. + /// The path of the object(s) to resolve. + /// The length of the object(s) keyspace. + /// + Task ObjLenAsync(RedisKey key, string? path = null); + + /// + /// Gets the key in RESP(Redis Serialization Protocol) form. + /// + /// The key to get. + /// Path within the key to get. + /// the resultant resp + /// + Task RespAsync(RedisKey key, string? path = null); + + /// + /// Set's the key/path to the provided value. + /// + /// The key. + /// The path to set within the key. + /// The value to set. + /// When to set the value. + /// The disposition of the command + /// + Task SetAsync(RedisKey key, RedisValue path, object obj, When when = When.Always); + + /// + /// Set's the key/path to the provided value. + /// + /// The key. + /// The path to set within the key. + /// The value to set. + /// When to set the value. + /// The disposition of the command + /// + Task SetAsync(RedisKey key, RedisValue path, RedisValue json, When when = When.Always); + + /// + /// Set json file from the provided file Path. + /// + /// The key. + /// The path to set within the key. + /// The path of the file to set. + /// When to set the value. + /// The disposition of the command + /// + Task SetFromFileAsync(RedisKey key, RedisValue path, string filePath, When when = When.Always); + + /// + /// Set all json files in the provided file Path. + /// + /// The path to set within the file name as key. + /// The path of the file to set. + /// When to set the value. + /// The number of files that have been set + /// + Task SetFromDirectoryAsync(RedisValue path, string filesPath, When when = When.Always); + + /// + /// Appends the provided string to the string(s) at the provided path. + /// + /// The key to append to. + /// The path of the string(s) to append to. + /// The value to append. + /// The new length of the string(s) appended to, those lengths will be null if the path did not resolve ot a string. + /// + Task StrAppendAsync(RedisKey key, string value, string? path = null); + + /// + /// Check's the length of the string(s) at the provided path. + /// + /// The key of the json object. + /// The path of the string(s) within the json object. + /// The length of the string(s) appended to, those lengths will be null if the path did not resolve ot a string. + /// + Task StrLenAsync(RedisKey key, string? path = null); + + /// + /// Toggles the boolean value(s) at the provided path. + /// + /// The key of the json object. + /// The path of the value(s) to toggle. + /// the new value(s). Which will be null if the path did not resolve to a boolean. + /// + Task ToggleAsync(RedisKey key, string? path = null); + + /// + /// Gets the type(s) of the item(s) at the provided json path. + /// + /// The key of the JSON object. + /// The path to resolve. + /// An array of types. + /// + Task TypeAsync(RedisKey key, string? path = null); + + /// + /// Report a value's memory usage in bytes. path defaults to root if not provided. + /// + /// The object's key + /// The path within the object. + /// the value's size in bytes. + Task DebugMemoryAsync(string key, string? path = null); +} \ No newline at end of file diff --git a/src/NRedisStack/Json/JsonCommandBuilder.cs b/src/NRedisStack/Json/JsonCommandBuilder.cs index 4924a346..29474345 100644 --- a/src/NRedisStack/Json/JsonCommandBuilder.cs +++ b/src/NRedisStack/Json/JsonCommandBuilder.cs @@ -2,14 +2,18 @@ using NRedisStack.RedisStackCommands; using StackExchange.Redis; using System.Text.Json; -using System.Text.Json.Nodes; using static NRedisStack.Auxiliary; namespace NRedisStack; -public static class JsonCommandBuilder +public sealed class JsonCommandBuilder { - public static SerializedCommand Resp(RedisKey key, string? path = null) + private static readonly JsonCommandBuilder _instance = new JsonCommandBuilder(); + public static JsonCommandBuilder Instance { get { return _instance; } } + + private JsonCommandBuilder() { } + + public SerializedCommand Resp(RedisKey key, string? path = null) { if (string.IsNullOrEmpty(path)) { @@ -19,7 +23,7 @@ public static SerializedCommand Resp(RedisKey key, string? path = null) return new SerializedCommand(JSON.RESP, key, path); } - public static SerializedCommand Set(RedisKey key, RedisValue path, RedisValue json, When when = When.Always) + public SerializedCommand Set(RedisKey key, RedisValue path, RedisValue json, When when = When.Always) { return when switch { @@ -29,7 +33,7 @@ public static SerializedCommand Set(RedisKey key, RedisValue path, RedisValue js }; } - public static SerializedCommand StrAppend(RedisKey key, string value, string? path = null) + public SerializedCommand StrAppend(RedisKey key, string value, string? path = null) { if (path == null) { @@ -39,31 +43,31 @@ public static SerializedCommand StrAppend(RedisKey key, string value, string? pa return new SerializedCommand(JSON.STRAPPEND, key, path, JsonSerializer.Serialize(value)); } - public static SerializedCommand StrLen(RedisKey key, string? path = null) + public SerializedCommand StrLen(RedisKey key, string? path = null) { return (path != null) ? new SerializedCommand(JSON.STRLEN, key, path) : new SerializedCommand(JSON.STRLEN, key); } - public static SerializedCommand Toggle(RedisKey key, string? path = null) + public SerializedCommand Toggle(RedisKey key, string? path = null) { return (path != null) ? new SerializedCommand(JSON.TOGGLE, key, path) : new SerializedCommand(JSON.TOGGLE, key, "$"); } - public static SerializedCommand Type(RedisKey key, string? path = null) + public SerializedCommand Type(RedisKey key, string? path = null) { return (path != null) ? new SerializedCommand(JSON.TYPE, key, path) : new SerializedCommand(JSON.TYPE, key); } - public static SerializedCommand DebugMemory(string key, string? path = null) + public SerializedCommand DebugMemory(string key, string? path = null) { return (path != null) ? new SerializedCommand(JSON.DEBUG, JSON.MEMORY, key, path) : new SerializedCommand(JSON.DEBUG, JSON.MEMORY, key); } - public static SerializedCommand ArrAppend(RedisKey key, string? path = null, params object[] values) + public SerializedCommand ArrAppend(RedisKey key, string? path = null, params object[] values) { if (values.Length < 1) throw new ArgumentOutOfRangeException(nameof(values)); @@ -79,7 +83,7 @@ public static SerializedCommand ArrAppend(RedisKey key, string? path = null, par return new SerializedCommand(JSON.ARRAPPEND, args.ToArray()); } - public static SerializedCommand ArrIndex(RedisKey key, string path, object value, long? start = null, long? stop = null) + public SerializedCommand ArrIndex(RedisKey key, string path, object value, long? start = null, long? stop = null) { if (start == null && stop != null) throw new ArgumentException("stop cannot be defined without start"); @@ -88,7 +92,7 @@ public static SerializedCommand ArrIndex(RedisKey key, string path, object value return new SerializedCommand(JSON.ARRINDEX, args); } - public static SerializedCommand ArrInsert(RedisKey key, string path, long index, params object[] values) + public SerializedCommand ArrInsert(RedisKey key, string path, long index, params object[] values) { if (values.Length < 1) throw new ArgumentOutOfRangeException(nameof(values)); @@ -101,13 +105,13 @@ public static SerializedCommand ArrInsert(RedisKey key, string path, long index, return new SerializedCommand(JSON.ARRINSERT, args); } - public static SerializedCommand ArrLen(RedisKey key, string? path = null) + public SerializedCommand ArrLen(RedisKey key, string? path = null) { var args = AssembleNonNullArguments(key, path); return new SerializedCommand(JSON.ARRLEN, args); } - public static SerializedCommand ArrPop(RedisKey key, string? path = null, long? index = null) + public SerializedCommand ArrPop(RedisKey key, string? path = null, long? index = null) { if (path == null && index != null) throw new ArgumentException("index cannot be defined without path"); @@ -116,22 +120,22 @@ public static SerializedCommand ArrPop(RedisKey key, string? path = null, long? return new SerializedCommand(JSON.ARRPOP, args)!; } - public static SerializedCommand ArrTrim(RedisKey key, string path, long start, long stop) => + public SerializedCommand ArrTrim(RedisKey key, string path, long start, long stop) => new SerializedCommand(JSON.ARRTRIM, key, path, start, stop); - public static SerializedCommand Clear(RedisKey key, string? path = null) + public SerializedCommand Clear(RedisKey key, string? path = null) { var args = AssembleNonNullArguments(key, path); return new SerializedCommand(JSON.CLEAR, args); } - public static SerializedCommand Del(RedisKey key, string? path = null) + public SerializedCommand Del(RedisKey key, string? path = null) { var args = AssembleNonNullArguments(key, path); return new SerializedCommand(JSON.DEL, args); } - public static SerializedCommand Get(RedisKey key, RedisValue? indent = null, RedisValue? newLine = null, RedisValue? space = null, RedisValue? path = null) + public SerializedCommand Get(RedisKey key, RedisValue? indent = null, RedisValue? newLine = null, RedisValue? space = null, RedisValue? path = null) { List args = new List() { key }; @@ -161,7 +165,7 @@ public static SerializedCommand Get(RedisKey key, RedisValue? indent = null, Red return new SerializedCommand(JSON.GET, args); } - public static SerializedCommand Get(RedisKey key, string[] paths, RedisValue? indent = null, RedisValue? newLine = null, RedisValue? space = null) + public SerializedCommand Get(RedisKey key, string[] paths, RedisValue? indent = null, RedisValue? newLine = null, RedisValue? space = null) { List args = new List() { key }; @@ -191,13 +195,13 @@ public static SerializedCommand Get(RedisKey key, string[] paths, RedisValue? in return new SerializedCommand(JSON.GET, args); } - public static SerializedCommand Get(RedisKey key, string path = "$") + public SerializedCommand Get(RedisKey key, string path = "$") { return new SerializedCommand(JSON.GET, key, path); } - public static SerializedCommand MGet(RedisKey[] keys, string path) + public SerializedCommand MGet(RedisKey[] keys, string path) { var args = new List(); foreach (var key in keys) @@ -209,18 +213,18 @@ public static SerializedCommand MGet(RedisKey[] keys, string path) return new SerializedCommand(JSON.MGET, args); } - public static SerializedCommand NumIncrby(RedisKey key, string path, double value) + public SerializedCommand NumIncrby(RedisKey key, string path, double value) { return new SerializedCommand(JSON.NUMINCRBY, key, path, value); } - public static SerializedCommand ObjKeys(RedisKey key, string? path = null) + public SerializedCommand ObjKeys(RedisKey key, string? path = null) { var args = AssembleNonNullArguments(key, path); return new SerializedCommand(JSON.OBJKEYS, args); } - public static SerializedCommand ObjLen(RedisKey key, string? path = null) + public SerializedCommand ObjLen(RedisKey key, string? path = null) { var args = AssembleNonNullArguments(key, path); return new SerializedCommand(JSON.OBJLEN, args); diff --git a/src/NRedisStack/Json/JsonCommands.cs b/src/NRedisStack/Json/JsonCommands.cs index a1ec708f..16daff94 100644 --- a/src/NRedisStack/Json/JsonCommands.cs +++ b/src/NRedisStack/Json/JsonCommands.cs @@ -7,6 +7,8 @@ namespace NRedisStack; public class JsonCommands : IJsonCommands { IDatabase _db; + JsonCommandBuilder jsonBuilder = JsonCommandBuilder.Instance; + public JsonCommands(IDatabase db) { _db = db; @@ -15,7 +17,7 @@ public JsonCommands(IDatabase db) /// public RedisResult[] Resp(RedisKey key, string? path = null) { - RedisResult result = _db.Execute(JsonCommandBuilder.Resp(key, path)); + RedisResult result = _db.Execute(jsonBuilder.Resp(key, path)); if (result.IsNull) { @@ -35,7 +37,7 @@ public bool Set(RedisKey key, RedisValue path, object obj, When when = When.Alwa /// public bool Set(RedisKey key, RedisValue path, RedisValue json, When when = When.Always) { - return _db.Execute(JsonCommandBuilder.Set(key, path, json, when)).OKtoBoolean(); + return _db.Execute(jsonBuilder.Set(key, path, json, when)).OKtoBoolean(); } /// @@ -76,19 +78,19 @@ public int SetFromDirectory(RedisValue path, string filesPath, When when = When. /// public long?[] StrAppend(RedisKey key, string value, string? path = null) { - return _db.Execute(JsonCommandBuilder.StrAppend(key, value, path)).ToNullableLongArray(); + return _db.Execute(jsonBuilder.StrAppend(key, value, path)).ToNullableLongArray(); } /// public long?[] StrLen(RedisKey key, string? path = null) { - return _db.Execute(JsonCommandBuilder.StrLen(key, path)).ToNullableLongArray(); + return _db.Execute(jsonBuilder.StrLen(key, path)).ToNullableLongArray(); } /// public bool?[] Toggle(RedisKey key, string? path = null) { - RedisResult result = _db.Execute(JsonCommandBuilder.Toggle(key, path)); + RedisResult result = _db.Execute(jsonBuilder.Toggle(key, path)); if (result.IsNull) { @@ -106,7 +108,7 @@ public int SetFromDirectory(RedisValue path, string filesPath, When when = When. /// public JsonType[] Type(RedisKey key, string? path = null) { - RedisResult result = _db.Execute(JsonCommandBuilder.Type(key, path)); + RedisResult result = _db.Execute(jsonBuilder.Type(key, path)); if (result.Type == ResultType.MultiBulk) { @@ -124,242 +126,37 @@ public JsonType[] Type(RedisKey key, string? path = null) public long DebugMemory(string key, string? path = null) { - return _db.Execute(JsonCommandBuilder.DebugMemory(key, path)).ToLong(); - } - - public async Task ArrAppendAsync(RedisKey key, string? path = null, params object[] values) - { - return (await _db.ExecuteAsync(JsonCommandBuilder.ArrAppend(key, path, values))).ToNullableLongArray(); - } - - public async Task ArrIndexAsync(RedisKey key, string path, object value, long? start = null, long? stop = null) - { - return (await _db.ExecuteAsync(JsonCommandBuilder.ArrIndex(key, path, value, start, stop))).ToNullableLongArray(); - } - - public async Task ArrInsertAsync(RedisKey key, string path, long index, params object[] values) - { - return (await _db.ExecuteAsync(JsonCommandBuilder.ArrInsert(key, path, index, values))).ToNullableLongArray(); - } - - public async Task ArrLenAsync(RedisKey key, string? path = null) - { - return (await _db.ExecuteAsync(JsonCommandBuilder.ArrLen(key, path))).ToNullableLongArray(); - } - - public async Task ArrPopAsync(RedisKey key, string? path = null, long? index = null) - { - RedisResult result = await _db.ExecuteAsync(JsonCommandBuilder.ArrPop(key, path, index)); - - if (result.Type == ResultType.MultiBulk) - { - return (RedisResult[])result!; - } - - if (result.Type == ResultType.BulkString) - { - return new[] { result }; - } - - return Array.Empty(); - } - - public async Task ArrTrimAsync(RedisKey key, string path, long start, long stop) => - (await _db.ExecuteAsync(JsonCommandBuilder.ArrTrim(key, path, start, stop))).ToNullableLongArray(); - - public async Task ClearAsync(RedisKey key, string? path = null) - { - return (await _db.ExecuteAsync(JsonCommandBuilder.Clear(key, path))).ToLong(); - } - - public async Task DelAsync(RedisKey key, string? path = null) - { - return (await _db.ExecuteAsync(JsonCommandBuilder.Del(key, path))).ToLong(); - } - - public Task ForgetAsync(RedisKey key, string? path = null) => DelAsync(key, path); - - public async Task GetAsync(RedisKey key, RedisValue? indent = null, RedisValue? newLine = null, RedisValue? space = null, - RedisValue? path = null) - { - return await _db.ExecuteAsync(JsonCommandBuilder.Get(key, indent, newLine, space, path)); - } - - public async Task GetAsync(RedisKey key, string[] paths, RedisValue? indent = null, RedisValue? newLine = null, - RedisValue? space = null) - { - return await _db.ExecuteAsync(JsonCommandBuilder.Get(key, paths, indent, newLine, space)); - } - - public async Task GetAsync(RedisKey key, string path = "$") - { - var res = await _db.ExecuteAsync(JsonCommandBuilder.Get(key, path)); - if (res.Type == ResultType.BulkString) - { - var arr = JsonSerializer.Deserialize(res.ToString()!); - if (arr?.Count > 0) - { - return JsonSerializer.Deserialize(JsonSerializer.Serialize(arr[0])); - } - } - - return default; - } - - public async Task MGetAsync(RedisKey[] keys, string path) - { - return (await _db.ExecuteAsync(JsonCommandBuilder.MGet(keys, path))).ToArray(); - } - - public async Task NumIncrbyAsync(RedisKey key, string path, double value) - { - var res = await _db.ExecuteAsync(JsonCommandBuilder.NumIncrby(key, path, value)); - return JsonSerializer.Deserialize(res.ToString()); - } - - public async Task>> ObjKeysAsync(RedisKey key, string? path = null) - { - return (await _db.ExecuteAsync(JsonCommandBuilder.ObjKeys(key, path))).ToHashSets(); - } - - public async Task ObjLenAsync(RedisKey key, string? path = null) - { - return (await _db.ExecuteAsync(JsonCommandBuilder.ObjLen(key, path))).ToNullableLongArray(); - } - - public async Task RespAsync(RedisKey key, string? path = null) - { - RedisResult result = await _db.ExecuteAsync(JsonCommandBuilder.Resp(key, path)); - - if (result.IsNull) - { - return Array.Empty(); - } - - return (RedisResult[])result!; - } - - public Task SetAsync(RedisKey key, RedisValue path, object obj, When when = When.Always) - { - string json = JsonSerializer.Serialize(obj); - return SetAsync(key, path, json, when); - } - - public async Task SetAsync(RedisKey key, RedisValue path, RedisValue json, When when = When.Always) - { - return (await _db.ExecuteAsync(JsonCommandBuilder.Set(key, path, json, when))).OKtoBoolean(); - } - - public async Task SetFromFileAsync(RedisKey key, RedisValue path, string filePath, When when = When.Always) - { - if (!File.Exists(filePath)) - { - throw new FileNotFoundException($"File {filePath} not found."); - } - - string fileContent = File.ReadAllText(filePath); - return await SetAsync(key, path, fileContent, when); - } - - public async Task SetFromDirectoryAsync(RedisValue path, string filesPath, When when = When.Always) - { - int inserted = 0; - string key; - var files = Directory.EnumerateFiles(filesPath, "*.json"); - foreach (var filePath in files) - { - key = filePath.Substring(0, filePath.IndexOf(".")); - if(await SetFromFileAsync(key, path, filePath, when)) - { - inserted++; - } - } - - foreach (var dirPath in Directory.EnumerateDirectories(filesPath)) - { - inserted += await SetFromDirectoryAsync(path, dirPath, when); - } - - return inserted; - } - - public async Task StrAppendAsync(RedisKey key, string value, string? path = null) - { - return (await _db.ExecuteAsync(JsonCommandBuilder.StrAppend(key, value, path))).ToNullableLongArray(); - } - - public async Task StrLenAsync(RedisKey key, string? path = null) - { - return (await _db.ExecuteAsync(JsonCommandBuilder.StrLen(key, path))).ToNullableLongArray(); - } - - public async Task ToggleAsync(RedisKey key, string? path = null) - { - RedisResult result = await _db.ExecuteAsync(JsonCommandBuilder.Toggle(key, path)); - - if (result.IsNull) - { - return Array.Empty(); - } - - if (result.Type == ResultType.Integer) - { - return new bool?[] { (long)result == 1 }; - } - - return ((RedisResult[])result!).Select(x => (bool?)((long)x == 1)).ToArray(); - } - - public async Task TypeAsync(RedisKey key, string? path = null) - { - RedisResult result = await _db.ExecuteAsync(JsonCommandBuilder.Type(key, path)); - - if (result.Type == ResultType.MultiBulk) - { - return ((RedisResult[])result!).Select(x => Enum.Parse(x.ToString()!.ToUpper())).ToArray(); - } - - if (result.Type == ResultType.BulkString) - { - return new[] { Enum.Parse(result.ToString()!.ToUpper()) }; - } - - return Array.Empty(); - } - - public async Task DebugMemoryAsync(string key, string? path = null) - { - return (await _db.ExecuteAsync(JsonCommandBuilder.DebugMemory(key, path))).ToLong(); + return _db.Execute(jsonBuilder.DebugMemory(key, path)).ToLong(); } /// public long?[] ArrAppend(RedisKey key, string? path = null, params object[] values) { - return _db.Execute(JsonCommandBuilder.ArrAppend(key, path, values)).ToNullableLongArray(); + return _db.Execute(jsonBuilder.ArrAppend(key, path, values)).ToNullableLongArray(); } /// public long?[] ArrIndex(RedisKey key, string path, object value, long? start = null, long? stop = null) { - return _db.Execute(JsonCommandBuilder.ArrIndex(key, path, value, start, stop)).ToNullableLongArray(); + return _db.Execute(jsonBuilder.ArrIndex(key, path, value, start, stop)).ToNullableLongArray(); } /// public long?[] ArrInsert(RedisKey key, string path, long index, params object[] values) { - return _db.Execute(JsonCommandBuilder.ArrInsert(key, path, index, values)).ToNullableLongArray(); + return _db.Execute(jsonBuilder.ArrInsert(key, path, index, values)).ToNullableLongArray(); } /// public long?[] ArrLen(RedisKey key, string? path = null) { - return _db.Execute(JsonCommandBuilder.ArrLen(key, path)).ToNullableLongArray(); + return _db.Execute(jsonBuilder.ArrLen(key, path)).ToNullableLongArray(); } /// public RedisResult[] ArrPop(RedisKey key, string? path = null, long? index = null) { - RedisResult result = _db.Execute(JsonCommandBuilder.ArrPop(key, path, index)); + RedisResult result = _db.Execute(jsonBuilder.ArrPop(key, path, index)); if (result.Type == ResultType.MultiBulk) { @@ -376,18 +173,18 @@ public RedisResult[] ArrPop(RedisKey key, string? path = null, long? index = nul /// public long?[] ArrTrim(RedisKey key, string path, long start, long stop) => - _db.Execute(JsonCommandBuilder.ArrTrim(key, path, start, stop)).ToNullableLongArray(); + _db.Execute(jsonBuilder.ArrTrim(key, path, start, stop)).ToNullableLongArray(); /// public long Clear(RedisKey key, string? path = null) { - return _db.Execute(JsonCommandBuilder.Clear(key, path)).ToLong(); + return _db.Execute(jsonBuilder.Clear(key, path)).ToLong(); } /// public long Del(RedisKey key, string? path = null) { - return _db.Execute(JsonCommandBuilder.Del(key, path)).ToLong(); + return _db.Execute(jsonBuilder.Del(key, path)).ToLong(); } /// @@ -396,19 +193,19 @@ public long Del(RedisKey key, string? path = null) /// public RedisResult Get(RedisKey key, RedisValue? indent = null, RedisValue? newLine = null, RedisValue? space = null, RedisValue? path = null) { - return _db.Execute(JsonCommandBuilder.Get(key, indent, newLine, space, path)); + return _db.Execute(jsonBuilder.Get(key, indent, newLine, space, path)); } /// public RedisResult Get(RedisKey key, string[] paths, RedisValue? indent = null, RedisValue? newLine = null, RedisValue? space = null) { - return _db.Execute(JsonCommandBuilder.Get(key, paths, indent, newLine, space)); + return _db.Execute(jsonBuilder.Get(key, paths, indent, newLine, space)); } /// public T? Get(RedisKey key, string path = "$") { - var res = _db.Execute(JsonCommandBuilder.Get(key, path)); + var res = _db.Execute(jsonBuilder.Get(key, path)); if (res.Type == ResultType.BulkString) { var arr = JsonSerializer.Deserialize(res.ToString()!); @@ -424,32 +221,32 @@ public RedisResult Get(RedisKey key, string[] paths, RedisValue? indent = null, /// public IEnumerable GetEnumerable(RedisKey key, string path = "$") { - RedisResult res = _db.Execute(JsonCommandBuilder.Get(key, path)); + RedisResult res = _db.Execute(jsonBuilder.Get(key, path)); return JsonSerializer.Deserialize>(res.ToString()); } /// public RedisResult[] MGet(RedisKey[] keys, string path) { - return _db.Execute(JsonCommandBuilder.MGet(keys, path)).ToArray(); + return _db.Execute(jsonBuilder.MGet(keys, path)).ToArray(); } /// public double?[] NumIncrby(RedisKey key, string path, double value) { - var res = _db.Execute(JsonCommandBuilder.NumIncrby(key, path, value)); + var res = _db.Execute(jsonBuilder.NumIncrby(key, path, value)); return JsonSerializer.Deserialize(res.ToString()); } /// public IEnumerable> ObjKeys(RedisKey key, string? path = null) { - return _db.Execute(JsonCommandBuilder.ObjKeys(key, path)).ToHashSets(); + return _db.Execute(jsonBuilder.ObjKeys(key, path)).ToHashSets(); } /// public long?[] ObjLen(RedisKey key, string? path = null) { - return _db.Execute(JsonCommandBuilder.ObjLen(key, path)).ToNullableLongArray(); + return _db.Execute(jsonBuilder.ObjLen(key, path)).ToNullableLongArray(); } } \ No newline at end of file diff --git a/src/NRedisStack/Json/JsonCommandsAsync.cs b/src/NRedisStack/Json/JsonCommandsAsync.cs new file mode 100644 index 00000000..05b60074 --- /dev/null +++ b/src/NRedisStack/Json/JsonCommandsAsync.cs @@ -0,0 +1,228 @@ +using StackExchange.Redis; +using System.Text.Json; +using System.Text.Json.Nodes; + +namespace NRedisStack; + +public class JsonCommandsAsync : IJsonCommandsAsync +{ + IDatabaseAsync _db; + JsonCommandBuilder jsonBuilder = JsonCommandBuilder.Instance; + + public JsonCommandsAsync(IDatabaseAsync db) + { + _db = db; + } + + public async Task ArrAppendAsync(RedisKey key, string? path = null, params object[] values) + { + return (await _db.ExecuteAsync(jsonBuilder.ArrAppend(key, path, values))).ToNullableLongArray(); + } + + public async Task ArrIndexAsync(RedisKey key, string path, object value, long? start = null, long? stop = null) + { + return (await _db.ExecuteAsync(jsonBuilder.ArrIndex(key, path, value, start, stop))).ToNullableLongArray(); + } + + public async Task ArrInsertAsync(RedisKey key, string path, long index, params object[] values) + { + return (await _db.ExecuteAsync(jsonBuilder.ArrInsert(key, path, index, values))).ToNullableLongArray(); + } + + public async Task ArrLenAsync(RedisKey key, string? path = null) + { + return (await _db.ExecuteAsync(jsonBuilder.ArrLen(key, path))).ToNullableLongArray(); + } + + public async Task ArrPopAsync(RedisKey key, string? path = null, long? index = null) + { + RedisResult result = await _db.ExecuteAsync(jsonBuilder.ArrPop(key, path, index)); + + if (result.Type == ResultType.MultiBulk) + { + return (RedisResult[])result!; + } + + if (result.Type == ResultType.BulkString) + { + return new[] { result }; + } + + return Array.Empty(); + } + + public async Task ArrTrimAsync(RedisKey key, string path, long start, long stop) => + (await _db.ExecuteAsync(jsonBuilder.ArrTrim(key, path, start, stop))).ToNullableLongArray(); + + public async Task ClearAsync(RedisKey key, string? path = null) + { + return (await _db.ExecuteAsync(jsonBuilder.Clear(key, path))).ToLong(); + } + + public async Task DelAsync(RedisKey key, string? path = null) + { + return (await _db.ExecuteAsync(jsonBuilder.Del(key, path))).ToLong(); + } + + public Task ForgetAsync(RedisKey key, string? path = null) => DelAsync(key, path); + + public async Task GetAsync(RedisKey key, RedisValue? indent = null, RedisValue? newLine = null, RedisValue? space = null, + RedisValue? path = null) + { + return await _db.ExecuteAsync(jsonBuilder.Get(key, indent, newLine, space, path)); + } + + public async Task GetAsync(RedisKey key, string[] paths, RedisValue? indent = null, RedisValue? newLine = null, + RedisValue? space = null) + { + return await _db.ExecuteAsync(jsonBuilder.Get(key, paths, indent, newLine, space)); + } + + public async Task GetAsync(RedisKey key, string path = "$") + { + var res = await _db.ExecuteAsync(jsonBuilder.Get(key, path)); + if (res.Type == ResultType.BulkString) + { + var arr = JsonSerializer.Deserialize(res.ToString()!); + if (arr?.Count > 0) + { + return JsonSerializer.Deserialize(JsonSerializer.Serialize(arr[0])); + } + } + + return default; + } + + /// + public async Task> GetEnumerableAsync(RedisKey key, string path = "$") + { + RedisResult res = await _db.ExecuteAsync(jsonBuilder.Get(key, path)); + return JsonSerializer.Deserialize>(res.ToString()); + } + + public async Task MGetAsync(RedisKey[] keys, string path) + { + return (await _db.ExecuteAsync(jsonBuilder.MGet(keys, path))).ToArray(); + } + + public async Task NumIncrbyAsync(RedisKey key, string path, double value) + { + var res = await _db.ExecuteAsync(jsonBuilder.NumIncrby(key, path, value)); + return JsonSerializer.Deserialize(res.ToString()); + } + + public async Task>> ObjKeysAsync(RedisKey key, string? path = null) + { + return (await _db.ExecuteAsync(jsonBuilder.ObjKeys(key, path))).ToHashSets(); + } + + public async Task ObjLenAsync(RedisKey key, string? path = null) + { + return (await _db.ExecuteAsync(jsonBuilder.ObjLen(key, path))).ToNullableLongArray(); + } + + public async Task RespAsync(RedisKey key, string? path = null) + { + RedisResult result = await _db.ExecuteAsync(jsonBuilder.Resp(key, path)); + + if (result.IsNull) + { + return Array.Empty(); + } + + return (RedisResult[])result!; + } + + public Task SetAsync(RedisKey key, RedisValue path, object obj, When when = When.Always) + { + string json = JsonSerializer.Serialize(obj); + return SetAsync(key, path, json, when); + } + + public async Task SetAsync(RedisKey key, RedisValue path, RedisValue json, When when = When.Always) + { + return (await _db.ExecuteAsync(jsonBuilder.Set(key, path, json, when))).OKtoBoolean(); + } + + public async Task SetFromFileAsync(RedisKey key, RedisValue path, string filePath, When when = When.Always) + { + if (!File.Exists(filePath)) + { + throw new FileNotFoundException($"File {filePath} not found."); + } + + string fileContent = File.ReadAllText(filePath); + return await SetAsync(key, path, fileContent, when); + } + + public async Task SetFromDirectoryAsync(RedisValue path, string filesPath, When when = When.Always) + { + int inserted = 0; + string key; + var files = Directory.EnumerateFiles(filesPath, "*.json"); + foreach (var filePath in files) + { + key = filePath.Substring(0, filePath.IndexOf(".")); + if(await SetFromFileAsync(key, path, filePath, when)) + { + inserted++; + } + } + + foreach (var dirPath in Directory.EnumerateDirectories(filesPath)) + { + inserted += await SetFromDirectoryAsync(path, dirPath, when); + } + + return inserted; + } + + public async Task StrAppendAsync(RedisKey key, string value, string? path = null) + { + return (await _db.ExecuteAsync(jsonBuilder.StrAppend(key, value, path))).ToNullableLongArray(); + } + + public async Task StrLenAsync(RedisKey key, string? path = null) + { + return (await _db.ExecuteAsync(jsonBuilder.StrLen(key, path))).ToNullableLongArray(); + } + + public async Task ToggleAsync(RedisKey key, string? path = null) + { + RedisResult result = await _db.ExecuteAsync(jsonBuilder.Toggle(key, path)); + + if (result.IsNull) + { + return Array.Empty(); + } + + if (result.Type == ResultType.Integer) + { + return new bool?[] { (long)result == 1 }; + } + + return ((RedisResult[])result!).Select(x => (bool?)((long)x == 1)).ToArray(); + } + + public async Task TypeAsync(RedisKey key, string? path = null) + { + RedisResult result = await _db.ExecuteAsync(jsonBuilder.Type(key, path)); + + if (result.Type == ResultType.MultiBulk) + { + return ((RedisResult[])result!).Select(x => Enum.Parse(x.ToString()!.ToUpper())).ToArray(); + } + + if (result.Type == ResultType.BulkString) + { + return new[] { Enum.Parse(result.ToString()!.ToUpper()) }; + } + + return Array.Empty(); + } + + public async Task DebugMemoryAsync(string key, string? path = null) + { + return (await _db.ExecuteAsync(jsonBuilder.DebugMemory(key, path))).ToLong(); + } +} \ No newline at end of file diff --git a/src/NRedisStack/Pipeline.cs b/src/NRedisStack/Pipeline.cs index dd833fd6..e5c80946 100644 --- a/src/NRedisStack/Pipeline.cs +++ b/src/NRedisStack/Pipeline.cs @@ -1,50 +1,22 @@ -using NRedisStack.RedisStackCommands; using StackExchange.Redis; -namespace NRedisStack +namespace NRedisStack; + +public class Pipeline { - public class Pipeline + public Pipeline(IConnectionMultiplexer muxer) { - private readonly IDatabase _db; - private readonly List _commands = new List(); - - public Pipeline(IDatabase db) - { - _db = db; - } - - public void AddCommand(SerializedCommand command) - { - _commands.Add(command); - } - - public RedisResult[] Execute() - { - var transaction = _db.CreateTransaction(); - var tasks = new List>(); - foreach (var command in _commands) - { - tasks.Add(transaction.ExecuteAsync(command.Command, command.Args)); - } + _batch = muxer.GetDatabase().CreateBatch(); + } - transaction.Execute(); - Task.WhenAll(tasks).Wait(); - return tasks.Select(x => x.Result).ToArray(); - } + private IBatch _batch; - public async Task ExecuteAsync() - { - var transaction = _db.CreateTransaction(); - var tasks = new List>(); - foreach (var command in _commands) - { - tasks.Add(transaction.ExecuteAsync(command.Command, command.Args)); - } + public void Execute() + { + _batch.Execute(); + } - transaction.Execute(); - await Task.WhenAll(tasks); - return tasks.Select(x => x.Result).ToArray(); - } + public IJsonCommandsAsync Json => new JsonCommandsAsync(_batch); - } + public IDatabaseAsync Db => _batch; } \ No newline at end of file diff --git a/tests/NRedisStack.Tests/Json/JsonTests.cs b/tests/NRedisStack.Tests/Json/JsonTests.cs index 80b06a3a..5d9c1a7e 100644 --- a/tests/NRedisStack.Tests/Json/JsonTests.cs +++ b/tests/NRedisStack.Tests/Json/JsonTests.cs @@ -21,19 +21,19 @@ public void Dispose() } [Fact] - public void TestPipeline() + public async Task TestJsonPipeline() { - var conn = redisFixture.Redis; - var db = conn.GetDatabase(); - IJsonCommands json = new JsonCommands(db); - var pipeline = new Pipeline(db); + var pipeline = new Pipeline(ConnectionMultiplexer.Connect("localhost")); + await pipeline.Db.ExecuteAsync("FLUSHALL"); + string jsonPerson = JsonSerializer.Serialize(new Person { Name = "Shachar", Age = 23 }); - pipeline.AddCommand(JsonCommandBuilder.Set("key", "$", jsonPerson)); - pipeline.AddCommand(JsonCommandBuilder.Get("key")); - var results = pipeline.Execute(); - Assert.Equal(2, results.Length); - Assert.Equal("OK", results[0].ToString()); - Assert.Equal("{\"Name\":\"Shachar\",\"Age\":23}", results[1].ToString()); + var setResponse = pipeline.Json.SetAsync("key", "$", jsonPerson); + var getResponse = pipeline.Json.GetAsync("key"); + + pipeline.Execute(); + + Assert.Equal("True", setResponse.Result.ToString()); + Assert.Equal("{\"Name\":\"Shachar\",\"Age\":23}", getResponse.Result.ToString()); } [Fact] @@ -191,7 +191,7 @@ public async Task TestRespAsync() //arrange var conn = redisFixture.Redis; var db = conn.GetDatabase(); - IJsonCommands commands = new JsonCommands(db); + IJsonCommandsAsync commands = new JsonCommandsAsync(db); var keys = CreateKeyNames(1); var key = keys[0]; @@ -244,7 +244,7 @@ public async Task TestStringAppendAsync() //arrange var conn = redisFixture.Redis; var db = conn.GetDatabase(); - IJsonCommands commands = new JsonCommands(db); + IJsonCommandsAsync commands = new JsonCommandsAsync(db); var keys = CreateKeyNames(2); var key = keys[0]; @@ -297,7 +297,7 @@ public async Task StringLengthAsync() //arrange var conn = redisFixture.Redis; var db = conn.GetDatabase(); - IJsonCommands commands = new JsonCommands(db); + IJsonCommandsAsync commands = new JsonCommandsAsync(db); var keys = CreateKeyNames(2); var key = keys[0]; var simpleStringKey = keys[1]; @@ -344,7 +344,7 @@ public async Task ToggleAsync() //arrange var conn = redisFixture.Redis; var db = conn.GetDatabase(); - IJsonCommands commands = new JsonCommands(db); + IJsonCommandsAsync commands = new JsonCommandsAsync(db); var keys = CreateKeyNames(2); var key = keys[0]; var simpleKey = keys[1]; @@ -390,7 +390,7 @@ public async Task TypeAsync() //arrange var conn = redisFixture.Redis; var db = conn.GetDatabase(); - IJsonCommands commands = new JsonCommands(db); + IJsonCommandsAsync commands = new JsonCommandsAsync(db); var keys = CreateKeyNames(2); var key = keys[0]; var simpleKey = keys[1]; @@ -431,7 +431,7 @@ public async Task ArrayAppendAsync() { var conn = redisFixture.Redis; var db = conn.GetDatabase(); - IJsonCommands commands = new JsonCommands(db); + IJsonCommandsAsync commands = new JsonCommandsAsync(db); var keys = CreateKeyNames(2); var key = keys[0]; var complexKey = keys[1]; @@ -463,7 +463,7 @@ public async Task ArrayIndexAsync() { var conn = redisFixture.Redis; var db = conn.GetDatabase(); - IJsonCommands commands = new JsonCommands(db); + IJsonCommandsAsync commands = new JsonCommandsAsync(db); var keys = CreateKeyNames(1); var key = keys[0]; await commands.SetAsync(key, "$", new { name = "Elizabeth", nicknames = new[] { "Beth", "Betty", "Liz" }, sibling = new { name = "Johnathan", nicknames = new[] { "Jon", "Johnny" } } }); @@ -492,7 +492,7 @@ public void ArrayInsert() [Fact] public async Task ArrayInsertAsync() { - IJsonCommands commands = new JsonCommands(redisFixture.Redis.GetDatabase()); + IJsonCommandsAsync commands = new JsonCommandsAsync(redisFixture.Redis.GetDatabase()); var keys = CreateKeyNames(2); var key = keys[0]; var simpleKey = keys[1]; @@ -525,7 +525,7 @@ public void ArrayLength() [Fact] public async Task ArrayLengthAsync() { - IJsonCommands commands = new JsonCommands(redisFixture.Redis.GetDatabase()); + IJsonCommandsAsync commands = new JsonCommandsAsync(redisFixture.Redis.GetDatabase()); var keys = CreateKeyNames(2); var key = keys[0]; var simpleKey = keys[1]; @@ -559,7 +559,7 @@ public void ArrayPop() [Fact] public async Task ArrayPopAsync() { - IJsonCommands commands = new JsonCommands(redisFixture.Redis.GetDatabase()); + IJsonCommandsAsync commands = new JsonCommandsAsync(redisFixture.Redis.GetDatabase()); var keys = CreateKeyNames(2); var key = keys[0]; var simpleKey = keys[1]; @@ -593,7 +593,7 @@ public void ArrayTrim() [Fact] public async Task ArrayTrimAsync() { - IJsonCommands commands = new JsonCommands(redisFixture.Redis.GetDatabase()); + IJsonCommandsAsync commands = new JsonCommandsAsync(redisFixture.Redis.GetDatabase()); var keys = CreateKeyNames(2); var key = keys[0]; var simpleKey = keys[1]; @@ -625,7 +625,7 @@ public void Clear() [Fact] public async Task ClearAsync() { - IJsonCommands commands = new JsonCommands(redisFixture.Redis.GetDatabase()); + IJsonCommandsAsync commands = new JsonCommandsAsync(redisFixture.Redis.GetDatabase()); var keys = CreateKeyNames(2); var key = keys[0]; var simpleKey = keys[1]; @@ -657,7 +657,7 @@ public void Del() [Fact] public async Task DelAsync() { - IJsonCommands commands = new JsonCommands(redisFixture.Redis.GetDatabase()); + IJsonCommandsAsync commands = new JsonCommandsAsync(redisFixture.Redis.GetDatabase()); var keys = CreateKeyNames(2); var key = keys[0]; var simpleKey = keys[1]; @@ -689,7 +689,7 @@ public void Forget() [Fact] public async Task ForgetAsync() { - IJsonCommands commands = new JsonCommands(redisFixture.Redis.GetDatabase()); + IJsonCommandsAsync commands = new JsonCommandsAsync(redisFixture.Redis.GetDatabase()); var keys = CreateKeyNames(2); var key = keys[0]; var simpleKey = keys[1]; @@ -725,7 +725,7 @@ public void Get() [Fact] public async Task GetAsync() { - IJsonCommands commands = new JsonCommands(redisFixture.Redis.GetDatabase()); + IJsonCommandsAsync commands = new JsonCommandsAsync(redisFixture.Redis.GetDatabase()); var keys = CreateKeyNames(2); var key = keys[0]; var complexKey = keys[1]; @@ -734,7 +734,7 @@ public async Task GetAsync() var result = await commands.GetAsync(key); Assert.Equal("Alice", result!.Name); Assert.Equal(35, result.Age); - var people = (commands.GetEnumerable(complexKey, "$..a")).ToArray(); + var people = (await commands.GetEnumerableAsync(complexKey, "$..a")).ToArray(); Assert.Equal(2, people.Length); Assert.Equal("Alice", people[0]!.Name); Assert.Equal(35, people[0]!.Age); @@ -760,7 +760,7 @@ public void MGet() [Fact] public async Task MGetAsync() { - IJsonCommands commands = new JsonCommands(redisFixture.Redis.GetDatabase()); + IJsonCommandsAsync commands = new JsonCommandsAsync(redisFixture.Redis.GetDatabase()); var keys = CreateKeyNames(2); var key1 = keys[0]; var key2 = keys[1]; @@ -788,7 +788,7 @@ public void NumIncrby() [Fact] public async Task NumIncrbyAsync() { - IJsonCommands commands = new JsonCommands(redisFixture.Redis.GetDatabase()); + IJsonCommandsAsync commands = new JsonCommandsAsync(redisFixture.Redis.GetDatabase()); var keys = CreateKeyNames(1); var key = keys[0]; await commands.SetAsync(key, "$", new { age = 33, a = new { age = 34 }, b = new { age = "cat" } }); @@ -819,7 +819,7 @@ public void ObjectKeys() [Fact] public async Task ObjectKeysAsync() { - IJsonCommands commands = new JsonCommands(redisFixture.Redis.GetDatabase()); + IJsonCommandsAsync commands = new JsonCommandsAsync(redisFixture.Redis.GetDatabase()); var keys = CreateKeyNames(3); var key = keys[0]; await commands.SetAsync(key, "$", new { a = 5, b = 10, c = "hello", d = new { a = new { a = 6, b = "hello" }, b = 7 } }); @@ -853,7 +853,7 @@ public void ObjectLength() [Fact] public async Task ObjectLengthAsync() { - IJsonCommands commands = new JsonCommands(redisFixture.Redis.GetDatabase()); + IJsonCommandsAsync commands = new JsonCommandsAsync(redisFixture.Redis.GetDatabase()); var keys = CreateKeyNames(3); var key = keys[0]; await commands.SetAsync(key, "$", new { a = 5, b = 10, c = "hello", d = new { a = new { a = 6, b = "hello" }, b = 7 } }); @@ -893,7 +893,7 @@ public void TestMultiPathGet() [Fact] public async Task TestMultiPathGetAsync() { - IJsonCommands commands = new JsonCommands(redisFixture.Redis.GetDatabase()); + IJsonCommandsAsync commands = new JsonCommandsAsync(redisFixture.Redis.GetDatabase()); var keys = CreateKeyNames(1); var key = keys[0]; await commands.SetAsync(key, "$", new { a = "hello", b = new { a = "world" } }); @@ -931,7 +931,7 @@ public void Memory() [Fact] public async Task MemoryAsync() { - IJsonCommands commands = new JsonCommands(redisFixture.Redis.GetDatabase()); + IJsonCommandsAsync commands = new JsonCommandsAsync(redisFixture.Redis.GetDatabase()); var keys = CreateKeyNames(1); var key = keys[0]; @@ -948,7 +948,7 @@ public async Task TestSetFromFileAsync() //arrange var conn = redisFixture.Redis; var db = conn.GetDatabase(); - IJsonCommands commands = new JsonCommands(db); + IJsonCommandsAsync commands = new JsonCommandsAsync(db); var keys = CreateKeyNames(1); //creating json string: @@ -961,7 +961,7 @@ public async Task TestSetFromFileAsync() File.WriteAllText(file, json); Assert.True(await commands.SetFromFileAsync(keys[0], "$", file)); - var actual = commands.Get(keys[0]); + var actual = await commands.GetAsync(keys[0]); Assert.Equal(json, actual.ToString()); File.Delete(file); @@ -976,7 +976,7 @@ public async Task TestSetFromDirectoryAsync() //arrange var conn = redisFixture.Redis; var db = conn.GetDatabase(); - IJsonCommands commands = new JsonCommands(db); + IJsonCommandsAsync commands = new JsonCommandsAsync(db); //creating json string: object[] persons = new object[10]; @@ -1018,7 +1018,7 @@ public async Task TestSetFromDirectoryAsync() Assert.Equal(10, await commands.SetFromDirectoryAsync("$", "BaseDir")); - var actual = commands.Get(Path.Combine("BaseDir", "DirNumber2", "DirNumber3", $"jsonFile7")); + var actual = await commands.GetAsync(Path.Combine("BaseDir", "DirNumber2", "DirNumber3", $"jsonFile7")); Assert.Equal(jsons[6], actual.ToString()); Directory.Delete("BaseDir", true); } @@ -1026,8 +1026,9 @@ public async Task TestSetFromDirectoryAsync() [Fact] public void TestJsonCommandBuilder() { - var getBuild1 = JsonCommandBuilder.Get("key", "indent", "newline", "space", "path"); - var getBuild2 = JsonCommandBuilder.Get("key",new string[]{"path1", "path2", "path3"}, "indent", "newline", "space"); + var jsonBuilder = JsonCommandBuilder.Instance; + var getBuild1 = jsonBuilder.Get("key", "indent", "newline", "space", "path"); + var getBuild2 = jsonBuilder.Get("key",new string[]{"path1", "path2", "path3"}, "indent", "newline", "space"); var expectedArgs1 = new object[] { "key", "INDENT", "indent", "NEWLINE","newline", "SPACE", "space", "path" }; var expectedArgs2 = new object[] { "key", "INDENT", "indent", "NEWLINE", "newline", "SPACE", "space", "path1", "path2", "path3" }; From 822acafef2184bba087eb8e7ce1b94e5d052e733 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Wed, 25 Jan 2023 00:20:49 +0200 Subject: [PATCH 06/21] Update JsonTests.cs --- tests/NRedisStack.Tests/Json/JsonTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/NRedisStack.Tests/Json/JsonTests.cs b/tests/NRedisStack.Tests/Json/JsonTests.cs index 5d9c1a7e..ffac3231 100644 --- a/tests/NRedisStack.Tests/Json/JsonTests.cs +++ b/tests/NRedisStack.Tests/Json/JsonTests.cs @@ -31,7 +31,7 @@ public async Task TestJsonPipeline() var getResponse = pipeline.Json.GetAsync("key"); pipeline.Execute(); - + Assert.Equal("True", setResponse.Result.ToString()); Assert.Equal("{\"Name\":\"Shachar\",\"Age\":23}", getResponse.Result.ToString()); } From d00b9d149e5754570cf0a67dc9aadfcdac3e6e19 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Wed, 25 Jan 2023 00:31:12 +0200 Subject: [PATCH 07/21] mark pipline test in comment --- tests/NRedisStack.Tests/Json/JsonTests.cs | 24 +++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/NRedisStack.Tests/Json/JsonTests.cs b/tests/NRedisStack.Tests/Json/JsonTests.cs index ffac3231..909f9401 100644 --- a/tests/NRedisStack.Tests/Json/JsonTests.cs +++ b/tests/NRedisStack.Tests/Json/JsonTests.cs @@ -20,21 +20,21 @@ public void Dispose() redisFixture.Redis.GetDatabase().KeyDelete(_testName); } - [Fact] - public async Task TestJsonPipeline() - { - var pipeline = new Pipeline(ConnectionMultiplexer.Connect("localhost")); - await pipeline.Db.ExecuteAsync("FLUSHALL"); + // [Fact] + // public async Task TestJsonPipeline() + // { + // var pipeline = new Pipeline(ConnectionMultiplexer.Connect("localhost")); + // await pipeline.Db.ExecuteAsync("FLUSHALL"); - string jsonPerson = JsonSerializer.Serialize(new Person { Name = "Shachar", Age = 23 }); - var setResponse = pipeline.Json.SetAsync("key", "$", jsonPerson); - var getResponse = pipeline.Json.GetAsync("key"); + // string jsonPerson = JsonSerializer.Serialize(new Person { Name = "Shachar", Age = 23 }); + // var setResponse = pipeline.Json.SetAsync("key", "$", jsonPerson); + // var getResponse = pipeline.Json.GetAsync("key"); - pipeline.Execute(); + // pipeline.Execute(); - Assert.Equal("True", setResponse.Result.ToString()); - Assert.Equal("{\"Name\":\"Shachar\",\"Age\":23}", getResponse.Result.ToString()); - } + // Assert.Equal("True", setResponse.Result.ToString()); + // Assert.Equal("{\"Name\":\"Shachar\",\"Age\":23}", getResponse.Result.ToString()); + // } [Fact] public void TestSetFromFile() From aec8c05d8590ddad48f8c9d3ff3e628fe72cecc2 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Wed, 25 Jan 2023 10:45:05 +0200 Subject: [PATCH 08/21] fix pipline test --- tests/NRedisStack.Tests/Json/JsonTests.cs | 24 +++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/NRedisStack.Tests/Json/JsonTests.cs b/tests/NRedisStack.Tests/Json/JsonTests.cs index 909f9401..f1accd3b 100644 --- a/tests/NRedisStack.Tests/Json/JsonTests.cs +++ b/tests/NRedisStack.Tests/Json/JsonTests.cs @@ -20,21 +20,21 @@ public void Dispose() redisFixture.Redis.GetDatabase().KeyDelete(_testName); } - // [Fact] - // public async Task TestJsonPipeline() - // { - // var pipeline = new Pipeline(ConnectionMultiplexer.Connect("localhost")); - // await pipeline.Db.ExecuteAsync("FLUSHALL"); + [Fact] + public async Task TestJsonPipeline() + { + var pipeline = new Pipeline(ConnectionMultiplexer.Connect("localhost")); + pipeline.Db.ExecuteAsync("FLUSHALL"); - // string jsonPerson = JsonSerializer.Serialize(new Person { Name = "Shachar", Age = 23 }); - // var setResponse = pipeline.Json.SetAsync("key", "$", jsonPerson); - // var getResponse = pipeline.Json.GetAsync("key"); + string jsonPerson = JsonSerializer.Serialize(new Person { Name = "Shachar", Age = 23 }); + var setResponse = pipeline.Json.SetAsync("key", "$", jsonPerson); + var getResponse = pipeline.Json.GetAsync("key"); - // pipeline.Execute(); + pipeline.Execute(); - // Assert.Equal("True", setResponse.Result.ToString()); - // Assert.Equal("{\"Name\":\"Shachar\",\"Age\":23}", getResponse.Result.ToString()); - // } + Assert.Equal("True", setResponse.Result.ToString()); + Assert.Equal("{\"Name\":\"Shachar\",\"Age\":23}", getResponse.Result.ToString()); + } [Fact] public void TestSetFromFile() From 7446570c517d16c4282b4101f48e1a05e4e86e49 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Wed, 25 Jan 2023 15:08:24 +0200 Subject: [PATCH 09/21] make JsonCommandBuilder static --- src/NRedisStack/Json/JsonCommandBuilder.cs | 51 ++++++++++------------ src/NRedisStack/Json/JsonCommands.cs | 47 ++++++++++---------- src/NRedisStack/Json/JsonCommandsAsync.cs | 47 ++++++++++---------- tests/NRedisStack.Tests/Json/JsonTests.cs | 5 +-- 4 files changed, 71 insertions(+), 79 deletions(-) diff --git a/src/NRedisStack/Json/JsonCommandBuilder.cs b/src/NRedisStack/Json/JsonCommandBuilder.cs index 29474345..c387832a 100644 --- a/src/NRedisStack/Json/JsonCommandBuilder.cs +++ b/src/NRedisStack/Json/JsonCommandBuilder.cs @@ -6,14 +6,9 @@ namespace NRedisStack; -public sealed class JsonCommandBuilder +public static class JsonCommandBuilder { - private static readonly JsonCommandBuilder _instance = new JsonCommandBuilder(); - public static JsonCommandBuilder Instance { get { return _instance; } } - - private JsonCommandBuilder() { } - - public SerializedCommand Resp(RedisKey key, string? path = null) + public static SerializedCommand Resp(RedisKey key, string? path = null) { if (string.IsNullOrEmpty(path)) { @@ -23,7 +18,7 @@ public SerializedCommand Resp(RedisKey key, string? path = null) return new SerializedCommand(JSON.RESP, key, path); } - public SerializedCommand Set(RedisKey key, RedisValue path, RedisValue json, When when = When.Always) + public static SerializedCommand Set(RedisKey key, RedisValue path, RedisValue json, When when = When.Always) { return when switch { @@ -33,7 +28,7 @@ public SerializedCommand Set(RedisKey key, RedisValue path, RedisValue json, Whe }; } - public SerializedCommand StrAppend(RedisKey key, string value, string? path = null) + public static SerializedCommand StrAppend(RedisKey key, string value, string? path = null) { if (path == null) { @@ -43,31 +38,31 @@ public SerializedCommand StrAppend(RedisKey key, string value, string? path = nu return new SerializedCommand(JSON.STRAPPEND, key, path, JsonSerializer.Serialize(value)); } - public SerializedCommand StrLen(RedisKey key, string? path = null) + public static SerializedCommand StrLen(RedisKey key, string? path = null) { return (path != null) ? new SerializedCommand(JSON.STRLEN, key, path) : new SerializedCommand(JSON.STRLEN, key); } - public SerializedCommand Toggle(RedisKey key, string? path = null) + public static SerializedCommand Toggle(RedisKey key, string? path = null) { return (path != null) ? new SerializedCommand(JSON.TOGGLE, key, path) : new SerializedCommand(JSON.TOGGLE, key, "$"); } - public SerializedCommand Type(RedisKey key, string? path = null) + public static SerializedCommand Type(RedisKey key, string? path = null) { return (path != null) ? new SerializedCommand(JSON.TYPE, key, path) : new SerializedCommand(JSON.TYPE, key); } - public SerializedCommand DebugMemory(string key, string? path = null) + public static SerializedCommand DebugMemory(string key, string? path = null) { return (path != null) ? new SerializedCommand(JSON.DEBUG, JSON.MEMORY, key, path) : new SerializedCommand(JSON.DEBUG, JSON.MEMORY, key); } - public SerializedCommand ArrAppend(RedisKey key, string? path = null, params object[] values) + public static SerializedCommand ArrAppend(RedisKey key, string? path = null, params object[] values) { if (values.Length < 1) throw new ArgumentOutOfRangeException(nameof(values)); @@ -83,7 +78,7 @@ public SerializedCommand ArrAppend(RedisKey key, string? path = null, params obj return new SerializedCommand(JSON.ARRAPPEND, args.ToArray()); } - public SerializedCommand ArrIndex(RedisKey key, string path, object value, long? start = null, long? stop = null) + public static SerializedCommand ArrIndex(RedisKey key, string path, object value, long? start = null, long? stop = null) { if (start == null && stop != null) throw new ArgumentException("stop cannot be defined without start"); @@ -92,7 +87,7 @@ public SerializedCommand ArrIndex(RedisKey key, string path, object value, long? return new SerializedCommand(JSON.ARRINDEX, args); } - public SerializedCommand ArrInsert(RedisKey key, string path, long index, params object[] values) + public static SerializedCommand ArrInsert(RedisKey key, string path, long index, params object[] values) { if (values.Length < 1) throw new ArgumentOutOfRangeException(nameof(values)); @@ -105,13 +100,13 @@ public SerializedCommand ArrInsert(RedisKey key, string path, long index, params return new SerializedCommand(JSON.ARRINSERT, args); } - public SerializedCommand ArrLen(RedisKey key, string? path = null) + public static SerializedCommand ArrLen(RedisKey key, string? path = null) { var args = AssembleNonNullArguments(key, path); return new SerializedCommand(JSON.ARRLEN, args); } - public SerializedCommand ArrPop(RedisKey key, string? path = null, long? index = null) + public static SerializedCommand ArrPop(RedisKey key, string? path = null, long? index = null) { if (path == null && index != null) throw new ArgumentException("index cannot be defined without path"); @@ -120,22 +115,22 @@ public SerializedCommand ArrPop(RedisKey key, string? path = null, long? index = return new SerializedCommand(JSON.ARRPOP, args)!; } - public SerializedCommand ArrTrim(RedisKey key, string path, long start, long stop) => + public static SerializedCommand ArrTrim(RedisKey key, string path, long start, long stop) => new SerializedCommand(JSON.ARRTRIM, key, path, start, stop); - public SerializedCommand Clear(RedisKey key, string? path = null) + public static SerializedCommand Clear(RedisKey key, string? path = null) { var args = AssembleNonNullArguments(key, path); return new SerializedCommand(JSON.CLEAR, args); } - public SerializedCommand Del(RedisKey key, string? path = null) + public static SerializedCommand Del(RedisKey key, string? path = null) { var args = AssembleNonNullArguments(key, path); return new SerializedCommand(JSON.DEL, args); } - public SerializedCommand Get(RedisKey key, RedisValue? indent = null, RedisValue? newLine = null, RedisValue? space = null, RedisValue? path = null) + public static SerializedCommand Get(RedisKey key, RedisValue? indent = null, RedisValue? newLine = null, RedisValue? space = null, RedisValue? path = null) { List args = new List() { key }; @@ -165,7 +160,7 @@ public SerializedCommand Get(RedisKey key, RedisValue? indent = null, RedisValue return new SerializedCommand(JSON.GET, args); } - public SerializedCommand Get(RedisKey key, string[] paths, RedisValue? indent = null, RedisValue? newLine = null, RedisValue? space = null) + public static SerializedCommand Get(RedisKey key, string[] paths, RedisValue? indent = null, RedisValue? newLine = null, RedisValue? space = null) { List args = new List() { key }; @@ -195,13 +190,13 @@ public SerializedCommand Get(RedisKey key, string[] paths, RedisValue? indent = return new SerializedCommand(JSON.GET, args); } - public SerializedCommand Get(RedisKey key, string path = "$") + public static SerializedCommand Get(RedisKey key, string path = "$") { return new SerializedCommand(JSON.GET, key, path); } - public SerializedCommand MGet(RedisKey[] keys, string path) + public static SerializedCommand MGet(RedisKey[] keys, string path) { var args = new List(); foreach (var key in keys) @@ -213,18 +208,18 @@ public SerializedCommand MGet(RedisKey[] keys, string path) return new SerializedCommand(JSON.MGET, args); } - public SerializedCommand NumIncrby(RedisKey key, string path, double value) + public static SerializedCommand NumIncrby(RedisKey key, string path, double value) { return new SerializedCommand(JSON.NUMINCRBY, key, path, value); } - public SerializedCommand ObjKeys(RedisKey key, string? path = null) + public static SerializedCommand ObjKeys(RedisKey key, string? path = null) { var args = AssembleNonNullArguments(key, path); return new SerializedCommand(JSON.OBJKEYS, args); } - public SerializedCommand ObjLen(RedisKey key, string? path = null) + public static SerializedCommand ObjLen(RedisKey key, string? path = null) { var args = AssembleNonNullArguments(key, path); return new SerializedCommand(JSON.OBJLEN, args); diff --git a/src/NRedisStack/Json/JsonCommands.cs b/src/NRedisStack/Json/JsonCommands.cs index 16daff94..5a40160d 100644 --- a/src/NRedisStack/Json/JsonCommands.cs +++ b/src/NRedisStack/Json/JsonCommands.cs @@ -7,7 +7,6 @@ namespace NRedisStack; public class JsonCommands : IJsonCommands { IDatabase _db; - JsonCommandBuilder jsonBuilder = JsonCommandBuilder.Instance; public JsonCommands(IDatabase db) { @@ -17,7 +16,7 @@ public JsonCommands(IDatabase db) /// public RedisResult[] Resp(RedisKey key, string? path = null) { - RedisResult result = _db.Execute(jsonBuilder.Resp(key, path)); + RedisResult result = _db.Execute(JsonCommandBuilder.Resp(key, path)); if (result.IsNull) { @@ -37,7 +36,7 @@ public bool Set(RedisKey key, RedisValue path, object obj, When when = When.Alwa /// public bool Set(RedisKey key, RedisValue path, RedisValue json, When when = When.Always) { - return _db.Execute(jsonBuilder.Set(key, path, json, when)).OKtoBoolean(); + return _db.Execute(JsonCommandBuilder.Set(key, path, json, when)).OKtoBoolean(); } /// @@ -78,19 +77,19 @@ public int SetFromDirectory(RedisValue path, string filesPath, When when = When. /// public long?[] StrAppend(RedisKey key, string value, string? path = null) { - return _db.Execute(jsonBuilder.StrAppend(key, value, path)).ToNullableLongArray(); + return _db.Execute(JsonCommandBuilder.StrAppend(key, value, path)).ToNullableLongArray(); } /// public long?[] StrLen(RedisKey key, string? path = null) { - return _db.Execute(jsonBuilder.StrLen(key, path)).ToNullableLongArray(); + return _db.Execute(JsonCommandBuilder.StrLen(key, path)).ToNullableLongArray(); } /// public bool?[] Toggle(RedisKey key, string? path = null) { - RedisResult result = _db.Execute(jsonBuilder.Toggle(key, path)); + RedisResult result = _db.Execute(JsonCommandBuilder.Toggle(key, path)); if (result.IsNull) { @@ -108,7 +107,7 @@ public int SetFromDirectory(RedisValue path, string filesPath, When when = When. /// public JsonType[] Type(RedisKey key, string? path = null) { - RedisResult result = _db.Execute(jsonBuilder.Type(key, path)); + RedisResult result = _db.Execute(JsonCommandBuilder.Type(key, path)); if (result.Type == ResultType.MultiBulk) { @@ -126,37 +125,37 @@ public JsonType[] Type(RedisKey key, string? path = null) public long DebugMemory(string key, string? path = null) { - return _db.Execute(jsonBuilder.DebugMemory(key, path)).ToLong(); + return _db.Execute(JsonCommandBuilder.DebugMemory(key, path)).ToLong(); } /// public long?[] ArrAppend(RedisKey key, string? path = null, params object[] values) { - return _db.Execute(jsonBuilder.ArrAppend(key, path, values)).ToNullableLongArray(); + return _db.Execute(JsonCommandBuilder.ArrAppend(key, path, values)).ToNullableLongArray(); } /// public long?[] ArrIndex(RedisKey key, string path, object value, long? start = null, long? stop = null) { - return _db.Execute(jsonBuilder.ArrIndex(key, path, value, start, stop)).ToNullableLongArray(); + return _db.Execute(JsonCommandBuilder.ArrIndex(key, path, value, start, stop)).ToNullableLongArray(); } /// public long?[] ArrInsert(RedisKey key, string path, long index, params object[] values) { - return _db.Execute(jsonBuilder.ArrInsert(key, path, index, values)).ToNullableLongArray(); + return _db.Execute(JsonCommandBuilder.ArrInsert(key, path, index, values)).ToNullableLongArray(); } /// public long?[] ArrLen(RedisKey key, string? path = null) { - return _db.Execute(jsonBuilder.ArrLen(key, path)).ToNullableLongArray(); + return _db.Execute(JsonCommandBuilder.ArrLen(key, path)).ToNullableLongArray(); } /// public RedisResult[] ArrPop(RedisKey key, string? path = null, long? index = null) { - RedisResult result = _db.Execute(jsonBuilder.ArrPop(key, path, index)); + RedisResult result = _db.Execute(JsonCommandBuilder.ArrPop(key, path, index)); if (result.Type == ResultType.MultiBulk) { @@ -173,18 +172,18 @@ public RedisResult[] ArrPop(RedisKey key, string? path = null, long? index = nul /// public long?[] ArrTrim(RedisKey key, string path, long start, long stop) => - _db.Execute(jsonBuilder.ArrTrim(key, path, start, stop)).ToNullableLongArray(); + _db.Execute(JsonCommandBuilder.ArrTrim(key, path, start, stop)).ToNullableLongArray(); /// public long Clear(RedisKey key, string? path = null) { - return _db.Execute(jsonBuilder.Clear(key, path)).ToLong(); + return _db.Execute(JsonCommandBuilder.Clear(key, path)).ToLong(); } /// public long Del(RedisKey key, string? path = null) { - return _db.Execute(jsonBuilder.Del(key, path)).ToLong(); + return _db.Execute(JsonCommandBuilder.Del(key, path)).ToLong(); } /// @@ -193,19 +192,19 @@ public long Del(RedisKey key, string? path = null) /// public RedisResult Get(RedisKey key, RedisValue? indent = null, RedisValue? newLine = null, RedisValue? space = null, RedisValue? path = null) { - return _db.Execute(jsonBuilder.Get(key, indent, newLine, space, path)); + return _db.Execute(JsonCommandBuilder.Get(key, indent, newLine, space, path)); } /// public RedisResult Get(RedisKey key, string[] paths, RedisValue? indent = null, RedisValue? newLine = null, RedisValue? space = null) { - return _db.Execute(jsonBuilder.Get(key, paths, indent, newLine, space)); + return _db.Execute(JsonCommandBuilder.Get(key, paths, indent, newLine, space)); } /// public T? Get(RedisKey key, string path = "$") { - var res = _db.Execute(jsonBuilder.Get(key, path)); + var res = _db.Execute(JsonCommandBuilder.Get(key, path)); if (res.Type == ResultType.BulkString) { var arr = JsonSerializer.Deserialize(res.ToString()!); @@ -221,32 +220,32 @@ public RedisResult Get(RedisKey key, string[] paths, RedisValue? indent = null, /// public IEnumerable GetEnumerable(RedisKey key, string path = "$") { - RedisResult res = _db.Execute(jsonBuilder.Get(key, path)); + RedisResult res = _db.Execute(JsonCommandBuilder.Get(key, path)); return JsonSerializer.Deserialize>(res.ToString()); } /// public RedisResult[] MGet(RedisKey[] keys, string path) { - return _db.Execute(jsonBuilder.MGet(keys, path)).ToArray(); + return _db.Execute(JsonCommandBuilder.MGet(keys, path)).ToArray(); } /// public double?[] NumIncrby(RedisKey key, string path, double value) { - var res = _db.Execute(jsonBuilder.NumIncrby(key, path, value)); + var res = _db.Execute(JsonCommandBuilder.NumIncrby(key, path, value)); return JsonSerializer.Deserialize(res.ToString()); } /// public IEnumerable> ObjKeys(RedisKey key, string? path = null) { - return _db.Execute(jsonBuilder.ObjKeys(key, path)).ToHashSets(); + return _db.Execute(JsonCommandBuilder.ObjKeys(key, path)).ToHashSets(); } /// public long?[] ObjLen(RedisKey key, string? path = null) { - return _db.Execute(jsonBuilder.ObjLen(key, path)).ToNullableLongArray(); + return _db.Execute(JsonCommandBuilder.ObjLen(key, path)).ToNullableLongArray(); } } \ No newline at end of file diff --git a/src/NRedisStack/Json/JsonCommandsAsync.cs b/src/NRedisStack/Json/JsonCommandsAsync.cs index 05b60074..d20c993c 100644 --- a/src/NRedisStack/Json/JsonCommandsAsync.cs +++ b/src/NRedisStack/Json/JsonCommandsAsync.cs @@ -7,7 +7,6 @@ namespace NRedisStack; public class JsonCommandsAsync : IJsonCommandsAsync { IDatabaseAsync _db; - JsonCommandBuilder jsonBuilder = JsonCommandBuilder.Instance; public JsonCommandsAsync(IDatabaseAsync db) { @@ -16,27 +15,27 @@ public JsonCommandsAsync(IDatabaseAsync db) public async Task ArrAppendAsync(RedisKey key, string? path = null, params object[] values) { - return (await _db.ExecuteAsync(jsonBuilder.ArrAppend(key, path, values))).ToNullableLongArray(); + return (await _db.ExecuteAsync(JsonCommandBuilder.ArrAppend(key, path, values))).ToNullableLongArray(); } public async Task ArrIndexAsync(RedisKey key, string path, object value, long? start = null, long? stop = null) { - return (await _db.ExecuteAsync(jsonBuilder.ArrIndex(key, path, value, start, stop))).ToNullableLongArray(); + return (await _db.ExecuteAsync(JsonCommandBuilder.ArrIndex(key, path, value, start, stop))).ToNullableLongArray(); } public async Task ArrInsertAsync(RedisKey key, string path, long index, params object[] values) { - return (await _db.ExecuteAsync(jsonBuilder.ArrInsert(key, path, index, values))).ToNullableLongArray(); + return (await _db.ExecuteAsync(JsonCommandBuilder.ArrInsert(key, path, index, values))).ToNullableLongArray(); } public async Task ArrLenAsync(RedisKey key, string? path = null) { - return (await _db.ExecuteAsync(jsonBuilder.ArrLen(key, path))).ToNullableLongArray(); + return (await _db.ExecuteAsync(JsonCommandBuilder.ArrLen(key, path))).ToNullableLongArray(); } public async Task ArrPopAsync(RedisKey key, string? path = null, long? index = null) { - RedisResult result = await _db.ExecuteAsync(jsonBuilder.ArrPop(key, path, index)); + RedisResult result = await _db.ExecuteAsync(JsonCommandBuilder.ArrPop(key, path, index)); if (result.Type == ResultType.MultiBulk) { @@ -52,16 +51,16 @@ public async Task ArrPopAsync(RedisKey key, string? path = null, } public async Task ArrTrimAsync(RedisKey key, string path, long start, long stop) => - (await _db.ExecuteAsync(jsonBuilder.ArrTrim(key, path, start, stop))).ToNullableLongArray(); + (await _db.ExecuteAsync(JsonCommandBuilder.ArrTrim(key, path, start, stop))).ToNullableLongArray(); public async Task ClearAsync(RedisKey key, string? path = null) { - return (await _db.ExecuteAsync(jsonBuilder.Clear(key, path))).ToLong(); + return (await _db.ExecuteAsync(JsonCommandBuilder.Clear(key, path))).ToLong(); } public async Task DelAsync(RedisKey key, string? path = null) { - return (await _db.ExecuteAsync(jsonBuilder.Del(key, path))).ToLong(); + return (await _db.ExecuteAsync(JsonCommandBuilder.Del(key, path))).ToLong(); } public Task ForgetAsync(RedisKey key, string? path = null) => DelAsync(key, path); @@ -69,18 +68,18 @@ public async Task DelAsync(RedisKey key, string? path = null) public async Task GetAsync(RedisKey key, RedisValue? indent = null, RedisValue? newLine = null, RedisValue? space = null, RedisValue? path = null) { - return await _db.ExecuteAsync(jsonBuilder.Get(key, indent, newLine, space, path)); + return await _db.ExecuteAsync(JsonCommandBuilder.Get(key, indent, newLine, space, path)); } public async Task GetAsync(RedisKey key, string[] paths, RedisValue? indent = null, RedisValue? newLine = null, RedisValue? space = null) { - return await _db.ExecuteAsync(jsonBuilder.Get(key, paths, indent, newLine, space)); + return await _db.ExecuteAsync(JsonCommandBuilder.Get(key, paths, indent, newLine, space)); } public async Task GetAsync(RedisKey key, string path = "$") { - var res = await _db.ExecuteAsync(jsonBuilder.Get(key, path)); + var res = await _db.ExecuteAsync(JsonCommandBuilder.Get(key, path)); if (res.Type == ResultType.BulkString) { var arr = JsonSerializer.Deserialize(res.ToString()!); @@ -96,34 +95,34 @@ public async Task GetAsync(RedisKey key, string[] paths, RedisValue /// public async Task> GetEnumerableAsync(RedisKey key, string path = "$") { - RedisResult res = await _db.ExecuteAsync(jsonBuilder.Get(key, path)); + RedisResult res = await _db.ExecuteAsync(JsonCommandBuilder.Get(key, path)); return JsonSerializer.Deserialize>(res.ToString()); } public async Task MGetAsync(RedisKey[] keys, string path) { - return (await _db.ExecuteAsync(jsonBuilder.MGet(keys, path))).ToArray(); + return (await _db.ExecuteAsync(JsonCommandBuilder.MGet(keys, path))).ToArray(); } public async Task NumIncrbyAsync(RedisKey key, string path, double value) { - var res = await _db.ExecuteAsync(jsonBuilder.NumIncrby(key, path, value)); + var res = await _db.ExecuteAsync(JsonCommandBuilder.NumIncrby(key, path, value)); return JsonSerializer.Deserialize(res.ToString()); } public async Task>> ObjKeysAsync(RedisKey key, string? path = null) { - return (await _db.ExecuteAsync(jsonBuilder.ObjKeys(key, path))).ToHashSets(); + return (await _db.ExecuteAsync(JsonCommandBuilder.ObjKeys(key, path))).ToHashSets(); } public async Task ObjLenAsync(RedisKey key, string? path = null) { - return (await _db.ExecuteAsync(jsonBuilder.ObjLen(key, path))).ToNullableLongArray(); + return (await _db.ExecuteAsync(JsonCommandBuilder.ObjLen(key, path))).ToNullableLongArray(); } public async Task RespAsync(RedisKey key, string? path = null) { - RedisResult result = await _db.ExecuteAsync(jsonBuilder.Resp(key, path)); + RedisResult result = await _db.ExecuteAsync(JsonCommandBuilder.Resp(key, path)); if (result.IsNull) { @@ -141,7 +140,7 @@ public Task SetAsync(RedisKey key, RedisValue path, object obj, When when public async Task SetAsync(RedisKey key, RedisValue path, RedisValue json, When when = When.Always) { - return (await _db.ExecuteAsync(jsonBuilder.Set(key, path, json, when))).OKtoBoolean(); + return (await _db.ExecuteAsync(JsonCommandBuilder.Set(key, path, json, when))).OKtoBoolean(); } public async Task SetFromFileAsync(RedisKey key, RedisValue path, string filePath, When when = When.Always) @@ -179,17 +178,17 @@ public async Task SetFromDirectoryAsync(RedisValue path, string filesPath, public async Task StrAppendAsync(RedisKey key, string value, string? path = null) { - return (await _db.ExecuteAsync(jsonBuilder.StrAppend(key, value, path))).ToNullableLongArray(); + return (await _db.ExecuteAsync(JsonCommandBuilder.StrAppend(key, value, path))).ToNullableLongArray(); } public async Task StrLenAsync(RedisKey key, string? path = null) { - return (await _db.ExecuteAsync(jsonBuilder.StrLen(key, path))).ToNullableLongArray(); + return (await _db.ExecuteAsync(JsonCommandBuilder.StrLen(key, path))).ToNullableLongArray(); } public async Task ToggleAsync(RedisKey key, string? path = null) { - RedisResult result = await _db.ExecuteAsync(jsonBuilder.Toggle(key, path)); + RedisResult result = await _db.ExecuteAsync(JsonCommandBuilder.Toggle(key, path)); if (result.IsNull) { @@ -206,7 +205,7 @@ public async Task SetFromDirectoryAsync(RedisValue path, string filesPath, public async Task TypeAsync(RedisKey key, string? path = null) { - RedisResult result = await _db.ExecuteAsync(jsonBuilder.Type(key, path)); + RedisResult result = await _db.ExecuteAsync(JsonCommandBuilder.Type(key, path)); if (result.Type == ResultType.MultiBulk) { @@ -223,6 +222,6 @@ public async Task TypeAsync(RedisKey key, string? path = null) public async Task DebugMemoryAsync(string key, string? path = null) { - return (await _db.ExecuteAsync(jsonBuilder.DebugMemory(key, path))).ToLong(); + return (await _db.ExecuteAsync(JsonCommandBuilder.DebugMemory(key, path))).ToLong(); } } \ No newline at end of file diff --git a/tests/NRedisStack.Tests/Json/JsonTests.cs b/tests/NRedisStack.Tests/Json/JsonTests.cs index f1accd3b..cdc7c497 100644 --- a/tests/NRedisStack.Tests/Json/JsonTests.cs +++ b/tests/NRedisStack.Tests/Json/JsonTests.cs @@ -1026,9 +1026,8 @@ public async Task TestSetFromDirectoryAsync() [Fact] public void TestJsonCommandBuilder() { - var jsonBuilder = JsonCommandBuilder.Instance; - var getBuild1 = jsonBuilder.Get("key", "indent", "newline", "space", "path"); - var getBuild2 = jsonBuilder.Get("key",new string[]{"path1", "path2", "path3"}, "indent", "newline", "space"); + var getBuild1 = JsonCommandBuilder.Get("key", "indent", "newline", "space", "path"); + var getBuild2 = JsonCommandBuilder.Get("key",new string[]{"path1", "path2", "path3"}, "indent", "newline", "space"); var expectedArgs1 = new object[] { "key", "INDENT", "indent", "NEWLINE","newline", "SPACE", "space", "path" }; var expectedArgs2 = new object[] { "key", "INDENT", "indent", "NEWLINE", "newline", "SPACE", "space", "path1", "path2", "path3" }; From f3c0c14ef6ff5c41d48df52529e4812059ad240f Mon Sep 17 00:00:00 2001 From: shacharPash Date: Wed, 25 Jan 2023 16:59:35 +0200 Subject: [PATCH 10/21] split bloom commands to sync and async --- src/NRedisStack/Bloom/BloomCommands.cs | 68 +---------- src/NRedisStack/Bloom/BloomCommandsAsync.cs | 79 +++++++++++++ src/NRedisStack/Bloom/IBloomCommands.cs | 109 ----------------- src/NRedisStack/Bloom/IBloomCommandsAsync.cs | 118 +++++++++++++++++++ src/NRedisStack/Json/JsonCommands.cs | 4 +- src/NRedisStack/ModulPrefixes.cs | 18 +-- tests/NRedisStack.Tests/Bloom/BloomTests.cs | 2 + 7 files changed, 212 insertions(+), 186 deletions(-) create mode 100644 src/NRedisStack/Bloom/BloomCommandsAsync.cs create mode 100644 src/NRedisStack/Bloom/IBloomCommandsAsync.cs diff --git a/src/NRedisStack/Bloom/BloomCommands.cs b/src/NRedisStack/Bloom/BloomCommands.cs index 041b1406..d4f3acb9 100644 --- a/src/NRedisStack/Bloom/BloomCommands.cs +++ b/src/NRedisStack/Bloom/BloomCommands.cs @@ -3,10 +3,10 @@ namespace NRedisStack { - public class BloomCommands : IBloomCommands + public class BloomCommands : BloomCommandsAsync, IBloomCommands { IDatabase _db; - public BloomCommands(IDatabase db) + public BloomCommands(IDatabase db) : base(db) { _db = db; } @@ -17,49 +17,24 @@ public bool Add(RedisKey key, RedisValue item) return _db.Execute(BloomCommandBuilder.Add(key, item)).ToString() == "1"; } - /// - public async Task AddAsync(RedisKey key, RedisValue item) - { - return (await _db.ExecuteAsync(BloomCommandBuilder.Add(key, item))).ToString() == "1"; - } - /// public long Card(RedisKey key) { return _db.Execute(BloomCommandBuilder.Card(key)).ToLong(); } - /// - public async Task CardAsync(RedisKey key) - { - return (await _db.ExecuteAsync(BloomCommandBuilder.Card(key))).ToLong(); - } - /// public bool Exists(RedisKey key, RedisValue item) { return _db.Execute(BloomCommandBuilder.Exists(key, item)).ToString() == "1"; } - /// - public async Task ExistsAsync(RedisKey key, RedisValue item) - { - return (await _db.ExecuteAsync(BloomCommandBuilder.Exists(key, item))).ToString() == "1"; - } - /// public BloomInformation Info(RedisKey key) { return _db.Execute(BloomCommandBuilder.Info(key)).ToBloomInfo(); } - /// - public async Task InfoAsync(RedisKey key) - { - var info = (await _db.ExecuteAsync(BloomCommandBuilder.Info(key))); - return info.ToBloomInfo(); - } - /// public bool[] Insert(RedisKey key, RedisValue[] items, int? capacity = null, double? error = null, int? expansion = null, @@ -68,50 +43,24 @@ public bool[] Insert(RedisKey key, RedisValue[] items, int? capacity = null, return _db.Execute(BloomCommandBuilder.Insert(key, items, capacity, error, expansion, nocreate, nonscaling)).ToBooleanArray(); } - /// - public async Task InsertAsync(RedisKey key, RedisValue[] items, int? capacity = null, - double? error = null, int? expansion = null, - bool nocreate = false, bool nonscaling = false) - { - return (await _db.ExecuteAsync(BloomCommandBuilder.Insert(key, items, capacity, error, expansion, nocreate, nonscaling))).ToBooleanArray(); - } - /// public bool LoadChunk(RedisKey key, long iterator, Byte[] data) { return _db.Execute(BloomCommandBuilder.LoadChunk(key, iterator, data)).OKtoBoolean(); } - /// - public async Task LoadChunkAsync(RedisKey key, long iterator, Byte[] data) - { - return (await _db.ExecuteAsync(BloomCommandBuilder.LoadChunk(key, iterator, data))).OKtoBoolean(); - } - /// public bool[] MAdd(RedisKey key, params RedisValue[] items) { return _db.Execute(BloomCommandBuilder.MAdd(key, items)).ToBooleanArray(); } - /// - public async Task MAddAsync(RedisKey key, params RedisValue[] items) - { - return (await _db.ExecuteAsync(BloomCommandBuilder.MAdd(key, items))).ToBooleanArray(); - } - /// public bool[] MExists(RedisKey key, RedisValue[] items) { return _db.Execute(BloomCommandBuilder.MExists(key, items)).ToBooleanArray(); } - /// - public async Task MExistsAsync(RedisKey key, RedisValue[] items) - { - return (await _db.ExecuteAsync(BloomCommandBuilder.MExists(key, items))).ToBooleanArray(); - } - /// public bool Reserve(RedisKey key, double errorRate, long capacity, int? expansion = null, bool nonscaling = false) @@ -119,23 +68,10 @@ public bool Reserve(RedisKey key, double errorRate, long capacity, return _db.Execute(BloomCommandBuilder.Reserve(key, errorRate, capacity, expansion, nonscaling)).OKtoBoolean(); } - /// - public async Task ReserveAsync(RedisKey key, double errorRate, long capacity, - int? expansion = null, bool nonscaling = false) - { - return (await _db.ExecuteAsync(BloomCommandBuilder.Reserve(key, errorRate, capacity, expansion, nonscaling))).OKtoBoolean(); - } - /// public Tuple ScanDump(RedisKey key, long iterator) { return _db.Execute(BloomCommandBuilder.ScanDump(key, iterator)).ToScanDumpTuple(); } - - /// - public async Task> ScanDumpAsync(RedisKey key, long iterator) - { - return (await _db.ExecuteAsync(BloomCommandBuilder.ScanDump(key, iterator))).ToScanDumpTuple(); - } } } diff --git a/src/NRedisStack/Bloom/BloomCommandsAsync.cs b/src/NRedisStack/Bloom/BloomCommandsAsync.cs new file mode 100644 index 00000000..fabb1dad --- /dev/null +++ b/src/NRedisStack/Bloom/BloomCommandsAsync.cs @@ -0,0 +1,79 @@ +using NRedisStack.Bloom.DataTypes; +using StackExchange.Redis; +namespace NRedisStack +{ + + public class BloomCommandsAsync : IBloomCommandsAsync + { + IDatabase _db; + public BloomCommandsAsync(IDatabase db) + { + _db = db; + } + + /// + public async Task AddAsync(RedisKey key, RedisValue item) + { + return (await _db.ExecuteAsync(BloomCommandBuilder.Add(key, item))).ToString() == "1"; + } + + + /// + public async Task CardAsync(RedisKey key) + { + return (await _db.ExecuteAsync(BloomCommandBuilder.Card(key))).ToLong(); + } + + /// + public async Task ExistsAsync(RedisKey key, RedisValue item) + { + return (await _db.ExecuteAsync(BloomCommandBuilder.Exists(key, item))).ToString() == "1"; + } + + /// + public async Task InfoAsync(RedisKey key) + { + var info = (await _db.ExecuteAsync(BloomCommandBuilder.Info(key))); + return info.ToBloomInfo(); + } + + /// + public async Task InsertAsync(RedisKey key, RedisValue[] items, int? capacity = null, + double? error = null, int? expansion = null, + bool nocreate = false, bool nonscaling = false) + { + return (await _db.ExecuteAsync(BloomCommandBuilder.Insert(key, items, capacity, error, expansion, nocreate, nonscaling))).ToBooleanArray(); + } + + /// + public async Task LoadChunkAsync(RedisKey key, long iterator, Byte[] data) + { + return (await _db.ExecuteAsync(BloomCommandBuilder.LoadChunk(key, iterator, data))).OKtoBoolean(); + } + + /// + public async Task MAddAsync(RedisKey key, params RedisValue[] items) + { + return (await _db.ExecuteAsync(BloomCommandBuilder.MAdd(key, items))).ToBooleanArray(); + } + + /// + public async Task MExistsAsync(RedisKey key, RedisValue[] items) + { + return (await _db.ExecuteAsync(BloomCommandBuilder.MExists(key, items))).ToBooleanArray(); + } + + /// + public async Task ReserveAsync(RedisKey key, double errorRate, long capacity, + int? expansion = null, bool nonscaling = false) + { + return (await _db.ExecuteAsync(BloomCommandBuilder.Reserve(key, errorRate, capacity, expansion, nonscaling))).OKtoBoolean(); + } + + /// + public async Task> ScanDumpAsync(RedisKey key, long iterator) + { + return (await _db.ExecuteAsync(BloomCommandBuilder.ScanDump(key, iterator))).ToScanDumpTuple(); + } + } +} \ No newline at end of file diff --git a/src/NRedisStack/Bloom/IBloomCommands.cs b/src/NRedisStack/Bloom/IBloomCommands.cs index 14f96481..5afb16d7 100644 --- a/src/NRedisStack/Bloom/IBloomCommands.cs +++ b/src/NRedisStack/Bloom/IBloomCommands.cs @@ -14,15 +14,6 @@ public interface IBloomCommands /// bool Add(RedisKey key, RedisValue item); - /// - /// Adds an item to a Bloom Filter. - /// - /// The key under which the filter is found. - /// The item to add. - /// if the item did not exist in the filter, otherwise. - /// - Task AddAsync(RedisKey key, RedisValue item); - /// /// Returns the cardinality of a Bloom filter. /// @@ -31,14 +22,6 @@ public interface IBloomCommands /// long Card(RedisKey key); - /// - /// Returns the cardinality of a Bloom filter. - /// - /// The name of the filter. - /// number of items that were added to a Bloom filter and detected as unique. - /// - Task CardAsync(RedisKey key); - /// /// Checks whether an item exist in the Bloom Filter or not. /// @@ -49,16 +32,6 @@ public interface IBloomCommands /// bool Exists(RedisKey key, RedisValue item); - /// - /// Checks whether an item exist in the Bloom Filter or not. - /// - /// The name of the filter. - /// The item to check for. - /// means the item may exist in the filter, - /// and means it does not exist in the filter. - /// - Task ExistsAsync(RedisKey key, RedisValue item); - /// /// Return information about a bloom filter. /// @@ -67,14 +40,6 @@ public interface IBloomCommands /// BloomInformation Info(RedisKey key); - /// - /// Return information about a bloom filter. - /// - /// Name of the key to return information about. - /// Information of the filter. - /// - Task InfoAsync(RedisKey key); - /// /// Adds one or more items to a Bloom Filter. A filter will be created if it does not exist. /// @@ -95,26 +60,6 @@ bool[] Insert(RedisKey key, RedisValue[] items, int? capacity = null, double? error = null, int? expansion = null, bool nocreate = false, bool nonscaling = false); - /// - /// Adds one or more items to a Bloom Filter. A filter will be created if it does not exist. - /// - /// The name of the filter. - /// One or more items to add. - /// (Optional) Specifies the desired capacity for the filter to be created. - /// (Optional) Specifies the error ratio of the newly created filter if it does not yet exist. - /// (Optional) When capacity is reached, an additional sub-filter is - /// created in size of the last sub-filter multiplied by expansion. - /// (Optional) to indicates that the - /// filter should not be created if it does not already exist. - /// (Optional) toprevent the filter - /// from creating additional sub-filters if initial capacity is reached. - /// An array of booleans. Each element is either true or false depending on whether the - /// corresponding input element was newly added to the filter or may have previously existed. - /// - Task InsertAsync(RedisKey key, RedisValue[] items, int? capacity = null, - double? error = null, int? expansion = null, - bool nocreate = false, bool nonscaling = false); - /// /// Restores a filter previosly saved using SCANDUMP. /// @@ -125,16 +70,6 @@ Task InsertAsync(RedisKey key, RedisValue[] items, int? capacity = null, /// bool LoadChunk(RedisKey key, long iterator, Byte[] data); - /// - /// Restores a filter previosly saved using SCANDUMP. - /// - /// Name of the key to restore. - /// Iterator value associated with data (returned by SCANDUMP). - /// Current data chunk (returned by SCANDUMP). - /// if executed correctly, error otherwise/> - /// - Task LoadChunkAsync(RedisKey key, long iterator, Byte[] data); - /// /// Adds one or more items to the Bloom Filter. A filter will be created if it does not exist yet. /// @@ -145,16 +80,6 @@ Task InsertAsync(RedisKey key, RedisValue[] items, int? capacity = null, /// bool[] MAdd(RedisKey key, params RedisValue[] items); - /// - /// Adds one or more items to the Bloom Filter. A filter will be created if it does not exist yet. - /// - /// The name of the filter. - /// One or more items to add. - /// An array of booleans. Each element is either true or false depending on whether the - /// corresponding input element was newly added to the filter or may have previously existed. - /// - Task MAddAsync(RedisKey key, params RedisValue[] items); - /// /// Checks whether one or more items may exist in the filter or not. /// @@ -165,16 +90,6 @@ Task InsertAsync(RedisKey key, RedisValue[] items, int? capacity = null, /// bool[] MExists(RedisKey key, RedisValue[] items); - /// - /// Checks whether one or more items may exist in the filter or not. - /// - /// The name of the filter. - /// One or more items to check. - /// An array of booleans, for each item means the item may exist in the filter, - /// and means the item may exist in the filter. - /// - Task MExistsAsync(RedisKey key, RedisValue[] items); - /// /// Creates a new Bloom Filter. /// @@ -190,21 +105,6 @@ Task InsertAsync(RedisKey key, RedisValue[] items, int? capacity = null, bool Reserve(RedisKey key, double errorRate, long capacity, int? expansion = null, bool nonscaling = false); - /// - /// Creates a new Bloom Filter. - /// - /// The key under which the filter is found. - /// The desired probability for false positives (value between 0 to 1). - /// The number of entries intended to be added to the filter. - /// (Optional) When capacity is reached, an additional sub-filter is - /// created in size of the last sub-filter multiplied by expansion. - /// (Optional) toprevent the filter - /// from creating additional sub-filters if initial capacity is reached. - /// if executed correctly, Error otherwise. - /// - Task ReserveAsync(RedisKey key, double errorRate, long capacity, - int? expansion = null, bool nonscaling = false); - /// /// Restores a filter previosly saved using SCANDUMP. /// @@ -213,14 +113,5 @@ Task ReserveAsync(RedisKey key, double errorRate, long capacity, /// Tuple of iterator and data. /// Tuple ScanDump(RedisKey key, long iterator); - - /// - /// Restores a filter previosly saved using SCANDUMP. - /// - /// Name of the filter. - /// Iterator value; either 0 or the iterator from a previous invocation of this command. - /// Tuple of iterator and data. - /// - Task> ScanDumpAsync(RedisKey key, long iterator); } } diff --git a/src/NRedisStack/Bloom/IBloomCommandsAsync.cs b/src/NRedisStack/Bloom/IBloomCommandsAsync.cs new file mode 100644 index 00000000..ca7f832d --- /dev/null +++ b/src/NRedisStack/Bloom/IBloomCommandsAsync.cs @@ -0,0 +1,118 @@ +using NRedisStack.Bloom.DataTypes; +using StackExchange.Redis; + +namespace NRedisStack +{ + public interface IBloomCommandsAsync + { + /// + /// Adds an item to a Bloom Filter. + /// + /// The key under which the filter is found. + /// The item to add. + /// if the item did not exist in the filter, otherwise. + /// + Task AddAsync(RedisKey key, RedisValue item); + + /// + /// Returns the cardinality of a Bloom filter. + /// + /// The name of the filter. + /// number of items that were added to a Bloom filter and detected as unique. + /// + Task CardAsync(RedisKey key); + + /// + /// Checks whether an item exist in the Bloom Filter or not. + /// + /// The name of the filter. + /// The item to check for. + /// means the item may exist in the filter, + /// and means it does not exist in the filter. + /// + Task ExistsAsync(RedisKey key, RedisValue item); + + /// + /// Return information about a bloom filter. + /// + /// Name of the key to return information about. + /// Information of the filter. + /// + Task InfoAsync(RedisKey key); + + + /// + /// Adds one or more items to a Bloom Filter. A filter will be created if it does not exist. + /// + /// The name of the filter. + /// One or more items to add. + /// (Optional) Specifies the desired capacity for the filter to be created. + /// (Optional) Specifies the error ratio of the newly created filter if it does not yet exist. + /// (Optional) When capacity is reached, an additional sub-filter is + /// created in size of the last sub-filter multiplied by expansion. + /// (Optional) to indicates that the + /// filter should not be created if it does not already exist. + /// (Optional) toprevent the filter + /// from creating additional sub-filters if initial capacity is reached. + /// An array of booleans. Each element is either true or false depending on whether the + /// corresponding input element was newly added to the filter or may have previously existed. + /// + Task InsertAsync(RedisKey key, RedisValue[] items, int? capacity = null, + double? error = null, int? expansion = null, + bool nocreate = false, bool nonscaling = false); + + /// + /// Restores a filter previosly saved using SCANDUMP. + /// + /// Name of the key to restore. + /// Iterator value associated with data (returned by SCANDUMP). + /// Current data chunk (returned by SCANDUMP). + /// if executed correctly, error otherwise/> + /// + Task LoadChunkAsync(RedisKey key, long iterator, Byte[] data); + + /// + /// Adds one or more items to the Bloom Filter. A filter will be created if it does not exist yet. + /// + /// The name of the filter. + /// One or more items to add. + /// An array of booleans. Each element is either true or false depending on whether the + /// corresponding input element was newly added to the filter or may have previously existed. + /// + Task MAddAsync(RedisKey key, params RedisValue[] items); + + /// + /// Checks whether one or more items may exist in the filter or not. + /// + /// The name of the filter. + /// One or more items to check. + /// An array of booleans, for each item means the item may exist in the filter, + /// and means the item may exist in the filter. + /// + Task MExistsAsync(RedisKey key, RedisValue[] items); + + /// + /// Creates a new Bloom Filter. + /// + /// The key under which the filter is found. + /// The desired probability for false positives (value between 0 to 1). + /// The number of entries intended to be added to the filter. + /// (Optional) When capacity is reached, an additional sub-filter is + /// created in size of the last sub-filter multiplied by expansion. + /// (Optional) toprevent the filter + /// from creating additional sub-filters if initial capacity is reached. + /// if executed correctly, Error otherwise. + /// + Task ReserveAsync(RedisKey key, double errorRate, long capacity, + int? expansion = null, bool nonscaling = false); + + /// + /// Restores a filter previosly saved using SCANDUMP. + /// + /// Name of the filter. + /// Iterator value; either 0 or the iterator from a previous invocation of this command. + /// Tuple of iterator and data. + /// + Task> ScanDumpAsync(RedisKey key, long iterator); + } +} \ No newline at end of file diff --git a/src/NRedisStack/Json/JsonCommands.cs b/src/NRedisStack/Json/JsonCommands.cs index 5a40160d..6e309be2 100644 --- a/src/NRedisStack/Json/JsonCommands.cs +++ b/src/NRedisStack/Json/JsonCommands.cs @@ -4,11 +4,11 @@ namespace NRedisStack; -public class JsonCommands : IJsonCommands +public class JsonCommands : JsonCommandsAsync, IJsonCommands { IDatabase _db; - public JsonCommands(IDatabase db) + public JsonCommands(IDatabase db) : base(db) { _db = db; } diff --git a/src/NRedisStack/ModulPrefixes.cs b/src/NRedisStack/ModulPrefixes.cs index c9db8358..5fcc0b75 100644 --- a/src/NRedisStack/ModulPrefixes.cs +++ b/src/NRedisStack/ModulPrefixes.cs @@ -4,22 +4,22 @@ namespace NRedisStack.RedisStackCommands { public static class ModulPrefixes { - static public IBloomCommands BF(this IDatabase db) => new BloomCommands(db); + static public BloomCommands BF(this IDatabase db) => new BloomCommands(db); - static public ICuckooCommands CF(this IDatabase db) => new CuckooCommands(db); + static public CuckooCommands CF(this IDatabase db) => new CuckooCommands(db); - static public ICmsCommands CMS(this IDatabase db) => new CmsCommands(db); + static public CmsCommands CMS(this IDatabase db) => new CmsCommands(db); - static public IGraphCommands GRAPH(this IDatabase db) => new GraphCommands(db); + static public GraphCommands GRAPH(this IDatabase db) => new GraphCommands(db); - static public ITopKCommands TOPK(this IDatabase db) => new TopKCommands(db); + static public TopKCommands TOPK(this IDatabase db) => new TopKCommands(db); - static public ITdigestCommands TDIGEST(this IDatabase db) => new TdigestCommands(db); + static public TdigestCommands TDIGEST(this IDatabase db) => new TdigestCommands(db); - static public ISearchCommands FT(this IDatabase db) => new SearchCommands(db); + static public SearchCommands FT(this IDatabase db) => new SearchCommands(db); - static public IJsonCommands JSON(this IDatabase db) => new JsonCommands(db); + static public JsonCommands JSON(this IDatabase db) => new JsonCommands(db); - static public ITimeSeriesCommands TS(this IDatabase db) => new TimeSeriesCommands(db); + static public TimeSeriesCommands TS(this IDatabase db) => new TimeSeriesCommands(db); } } \ No newline at end of file diff --git a/tests/NRedisStack.Tests/Bloom/BloomTests.cs b/tests/NRedisStack.Tests/Bloom/BloomTests.cs index a57a5314..c8107481 100644 --- a/tests/NRedisStack.Tests/Bloom/BloomTests.cs +++ b/tests/NRedisStack.Tests/Bloom/BloomTests.cs @@ -16,6 +16,8 @@ public void Dispose() redisFixture.Redis.GetDatabase().KeyDelete(key); } + // TODO: Add test for bloom pipeline + [Fact] public void TestReserveBasic() { From f9538beac43767f5476cdc7f578cc0c5c79f427b Mon Sep 17 00:00:00 2001 From: shacharPash Date: Wed, 25 Jan 2023 17:56:23 +0200 Subject: [PATCH 11/21] chagne to public static --- src/NRedisStack/ModulPrefixes.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/NRedisStack/ModulPrefixes.cs b/src/NRedisStack/ModulPrefixes.cs index 5fcc0b75..3af7cb49 100644 --- a/src/NRedisStack/ModulPrefixes.cs +++ b/src/NRedisStack/ModulPrefixes.cs @@ -4,22 +4,22 @@ namespace NRedisStack.RedisStackCommands { public static class ModulPrefixes { - static public BloomCommands BF(this IDatabase db) => new BloomCommands(db); + public static BloomCommands BF(this IDatabase db) => new BloomCommands(db); - static public CuckooCommands CF(this IDatabase db) => new CuckooCommands(db); + public static CuckooCommands CF(this IDatabase db) => new CuckooCommands(db); - static public CmsCommands CMS(this IDatabase db) => new CmsCommands(db); + public static CmsCommands CMS(this IDatabase db) => new CmsCommands(db); - static public GraphCommands GRAPH(this IDatabase db) => new GraphCommands(db); + public static GraphCommands GRAPH(this IDatabase db) => new GraphCommands(db); - static public TopKCommands TOPK(this IDatabase db) => new TopKCommands(db); + public static TopKCommands TOPK(this IDatabase db) => new TopKCommands(db); - static public TdigestCommands TDIGEST(this IDatabase db) => new TdigestCommands(db); + public static TdigestCommands TDIGEST(this IDatabase db) => new TdigestCommands(db); - static public SearchCommands FT(this IDatabase db) => new SearchCommands(db); + public static SearchCommands FT(this IDatabase db) => new SearchCommands(db); - static public JsonCommands JSON(this IDatabase db) => new JsonCommands(db); + public static JsonCommands JSON(this IDatabase db) => new JsonCommands(db); - static public TimeSeriesCommands TS(this IDatabase db) => new TimeSeriesCommands(db); + public static TimeSeriesCommands TS(this IDatabase db) => new TimeSeriesCommands(db); } } \ No newline at end of file From 81db098d0697d7b896fd3b01add9c807817bd1a6 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Thu, 26 Jan 2023 10:32:51 +0200 Subject: [PATCH 12/21] split cms to async and sync --- src/NRedisStack/Bloom/BloomCommandsAsync.cs | 4 +- src/NRedisStack/CountMinSketch/CmsCommands.cs | 48 +----------- .../CountMinSketch/CmsCommandsAsync.cs | 58 ++++++++++++++ .../CountMinSketch/ICmsCommands.cs | 68 ---------------- .../CountMinSketch/ICmsCommandsAsync.cs | 77 +++++++++++++++++++ 5 files changed, 139 insertions(+), 116 deletions(-) create mode 100644 src/NRedisStack/CountMinSketch/CmsCommandsAsync.cs create mode 100644 src/NRedisStack/CountMinSketch/ICmsCommandsAsync.cs diff --git a/src/NRedisStack/Bloom/BloomCommandsAsync.cs b/src/NRedisStack/Bloom/BloomCommandsAsync.cs index fabb1dad..6797caa4 100644 --- a/src/NRedisStack/Bloom/BloomCommandsAsync.cs +++ b/src/NRedisStack/Bloom/BloomCommandsAsync.cs @@ -5,8 +5,8 @@ namespace NRedisStack public class BloomCommandsAsync : IBloomCommandsAsync { - IDatabase _db; - public BloomCommandsAsync(IDatabase db) + IDatabaseAsync _db; + public BloomCommandsAsync(IDatabaseAsync db) { _db = db; } diff --git a/src/NRedisStack/CountMinSketch/CmsCommands.cs b/src/NRedisStack/CountMinSketch/CmsCommands.cs index abf1ef2d..cfb075be 100644 --- a/src/NRedisStack/CountMinSketch/CmsCommands.cs +++ b/src/NRedisStack/CountMinSketch/CmsCommands.cs @@ -3,10 +3,10 @@ namespace NRedisStack { - public class CmsCommands : ICmsCommands + public class CmsCommands : CmsCommandsAsync, ICmsCommands { IDatabase _db; - public CmsCommands(IDatabase db) + public CmsCommands(IDatabase db) : base(db) { _db = db; } @@ -17,25 +17,12 @@ public long IncrBy(RedisKey key, RedisValue item, long increment) return _db.Execute(CmsCommandBuilder.IncrBy(key, item, increment)).ToLong(); } - /// - public async Task IncrByAsync(RedisKey key, RedisValue item, long increment) - { - return (await _db.ExecuteAsync(CmsCommandBuilder.IncrBy(key, item, increment))).ToLong(); - } - /// public long[] IncrBy(RedisKey key, Tuple[] itemIncrements) { return _db.Execute(CmsCommandBuilder.IncrBy(key, itemIncrements)).ToLongArray(); } - /// - public async Task IncrByAsync(RedisKey key, Tuple[] itemIncrements) - { - return (await _db.ExecuteAsync(CmsCommandBuilder.IncrBy(key, itemIncrements))).ToLongArray(); - - } - /// public CmsInformation Info(RedisKey key) { @@ -43,59 +30,28 @@ public CmsInformation Info(RedisKey key) return info.ToCmsInfo(); } - /// - public async Task InfoAsync(RedisKey key) - { - var info = await _db.ExecuteAsync(CmsCommandBuilder.Info(key)); - return info.ToCmsInfo(); - } - /// public bool InitByDim(RedisKey key, long width, long depth) { return _db.Execute(CmsCommandBuilder.InitByDim(key, width, depth)).OKtoBoolean(); } - /// - public async Task InitByDimAsync(RedisKey key, long width, long depth) - { - return (await _db.ExecuteAsync(CmsCommandBuilder.InitByDim(key, width, depth))).OKtoBoolean(); - } - /// public bool InitByProb(RedisKey key, double error, double probability) { return _db.Execute(CmsCommandBuilder.InitByProb(key, error, probability)).OKtoBoolean(); } - /// - public async Task InitByProbAsync(RedisKey key, double error, double probability) - { - return (await _db.ExecuteAsync(CmsCommandBuilder.InitByProb(key, error, probability))).OKtoBoolean(); - } - /// public bool Merge(RedisValue destination, long numKeys, RedisValue[] source, long[]? weight = null) { return _db.Execute(CmsCommandBuilder.Merge(destination, numKeys, source, weight)).OKtoBoolean(); } - /// - public async Task MergeAsync(RedisValue destination, long numKeys, RedisValue[] source, long[]? weight = null) - { - return (await _db.ExecuteAsync(CmsCommandBuilder.Merge(destination, numKeys, source, weight))).OKtoBoolean(); - } - /// public long[] Query(RedisKey key, params RedisValue[] items) { return _db.Execute(CmsCommandBuilder.Query(key, items)).ToLongArray(); } - - /// - public async Task QueryAsync(RedisKey key, params RedisValue[] items) - { - return (await _db.ExecuteAsync(CmsCommandBuilder.Query(key, items))).ToLongArray(); - } } } \ No newline at end of file diff --git a/src/NRedisStack/CountMinSketch/CmsCommandsAsync.cs b/src/NRedisStack/CountMinSketch/CmsCommandsAsync.cs new file mode 100644 index 00000000..fcaae3be --- /dev/null +++ b/src/NRedisStack/CountMinSketch/CmsCommandsAsync.cs @@ -0,0 +1,58 @@ +using NRedisStack.CountMinSketch.DataTypes; +using StackExchange.Redis; +namespace NRedisStack +{ + + public class CmsCommandsAsync : ICmsCommandsAsync + { + IDatabaseAsync _db; + public CmsCommandsAsync(IDatabaseAsync db) + { + _db = db; + } + + /// + public async Task IncrByAsync(RedisKey key, RedisValue item, long increment) + { + return (await _db.ExecuteAsync(CmsCommandBuilder.IncrBy(key, item, increment))).ToLong(); + } + + /// + public async Task IncrByAsync(RedisKey key, Tuple[] itemIncrements) + { + return (await _db.ExecuteAsync(CmsCommandBuilder.IncrBy(key, itemIncrements))).ToLongArray(); + + } + + /// + public async Task InfoAsync(RedisKey key) + { + var info = await _db.ExecuteAsync(CmsCommandBuilder.Info(key)); + return info.ToCmsInfo(); + } + + /// + public async Task InitByDimAsync(RedisKey key, long width, long depth) + { + return (await _db.ExecuteAsync(CmsCommandBuilder.InitByDim(key, width, depth))).OKtoBoolean(); + } + + /// + public async Task InitByProbAsync(RedisKey key, double error, double probability) + { + return (await _db.ExecuteAsync(CmsCommandBuilder.InitByProb(key, error, probability))).OKtoBoolean(); + } + + /// + public async Task MergeAsync(RedisValue destination, long numKeys, RedisValue[] source, long[]? weight = null) + { + return (await _db.ExecuteAsync(CmsCommandBuilder.Merge(destination, numKeys, source, weight))).OKtoBoolean(); + } + + /// + public async Task QueryAsync(RedisKey key, params RedisValue[] items) + { + return (await _db.ExecuteAsync(CmsCommandBuilder.Query(key, items))).ToLongArray(); + } + } +} \ No newline at end of file diff --git a/src/NRedisStack/CountMinSketch/ICmsCommands.cs b/src/NRedisStack/CountMinSketch/ICmsCommands.cs index 338cdd0d..ca98a1db 100644 --- a/src/NRedisStack/CountMinSketch/ICmsCommands.cs +++ b/src/NRedisStack/CountMinSketch/ICmsCommands.cs @@ -15,16 +15,6 @@ public interface ICmsCommands /// long IncrBy(RedisKey key, RedisValue item, long increment); - /// - /// Increases the count of item by increment. - /// - /// The name of the sketch. - /// The item which counter is to be increased. - /// Amount by which the item counter is to be increased. - /// Count of each item after increment. - /// - Task IncrByAsync(RedisKey key, RedisValue item, long increment); - /// /// Increases the count of item by increment. /// @@ -34,15 +24,6 @@ public interface ICmsCommands /// Count of each item after increment. /// long[] IncrBy(RedisKey key, Tuple[] itemIncrements); - /// - /// Increases the count of item by increment. - /// - /// The name of the sketch. - /// Tuple of The items which counter is to be increased - /// and the Amount by which the item counter is to be increased. - /// Count of each item after increment. - /// - Task IncrByAsync(RedisKey key, Tuple[] itemIncrements); /// /// Return information about a sketch. @@ -52,14 +33,6 @@ public interface ICmsCommands /// CmsInformation Info(RedisKey key); - /// - /// Return information about a sketch. - /// - /// Name of the key to return information about. - /// Information of the sketch. - /// - Task InfoAsync(RedisKey key); - /// /// Initializes a Count-Min Sketch to dimensions specified by user. /// @@ -71,17 +44,6 @@ public interface ICmsCommands /// bool InitByDim(RedisKey key, long width, long depth); - /// - /// Initializes a Count-Min Sketch to dimensions specified by user. - /// - /// TThe name of the sketch. - /// Number of counters in each array. Reduces the error size. - /// Number of counter-arrays. Reduces the probability for an error - /// of a certain size (percentage of total count). - /// if if executed correctly, Error otherwise. - /// - Task InitByDimAsync(RedisKey key, long width, long depth); - /// /// Initializes a Count-Min Sketch to accommodate requested tolerances. /// @@ -92,16 +54,6 @@ public interface ICmsCommands /// bool InitByProb(RedisKey key, double error, double probability); - /// - /// Initializes a Count-Min Sketch to accommodate requested tolerances. - /// - /// The name of the sketch. - /// Estimate size of error. - /// The desired probability for inflated count. - /// if if executed correctly, Error otherwise. - /// - Task InitByProbAsync(RedisKey key, double error, double probability); - /// /// Merges several sketches into one sketch. /// @@ -113,17 +65,6 @@ public interface ICmsCommands /// bool Merge(RedisValue destination, long numKeys, RedisValue[] source, long[]? weight = null); - /// - /// Merges several sketches into one sketch. - /// - /// The name of destination sketch. Must be initialized - /// Number of sketches to be merged. - /// Names of source sketches to be merged. - /// Multiple of each sketch. Default = 1. - /// if if executed correctly, Error otherwise. - /// - Task MergeAsync(RedisValue destination, long numKeys, RedisValue[] source, long[]? weight = null); - /// /// Returns the count for one or more items in a sketch. /// @@ -132,14 +73,5 @@ public interface ICmsCommands /// Array with a min-count of each of the items in the sketch /// long[] Query(RedisKey key, params RedisValue[] items); - - /// - /// Returns the count for one or more items in a sketch. - /// - /// The name of the sketch - /// One or more items for which to return the count. - /// Array with a min-count of each of the items in the sketch - /// - Task QueryAsync(RedisKey key, params RedisValue[] items); } } \ No newline at end of file diff --git a/src/NRedisStack/CountMinSketch/ICmsCommandsAsync.cs b/src/NRedisStack/CountMinSketch/ICmsCommandsAsync.cs new file mode 100644 index 00000000..fb483a5d --- /dev/null +++ b/src/NRedisStack/CountMinSketch/ICmsCommandsAsync.cs @@ -0,0 +1,77 @@ +using NRedisStack.CountMinSketch.DataTypes; +using StackExchange.Redis; + +namespace NRedisStack +{ + public interface ICmsCommandsAsync + { + /// + /// Increases the count of item by increment. + /// + /// The name of the sketch. + /// The item which counter is to be increased. + /// Amount by which the item counter is to be increased. + /// Count of each item after increment. + /// + Task IncrByAsync(RedisKey key, RedisValue item, long increment); + + /// + /// Increases the count of item by increment. + /// + /// The name of the sketch. + /// Tuple of The items which counter is to be increased + /// and the Amount by which the item counter is to be increased. + /// Count of each item after increment. + /// + Task IncrByAsync(RedisKey key, Tuple[] itemIncrements); + + /// + /// Return information about a sketch. + /// + /// Name of the key to return information about. + /// Information of the sketch. + /// + Task InfoAsync(RedisKey key); + + /// + /// Initializes a Count-Min Sketch to dimensions specified by user. + /// + /// TThe name of the sketch. + /// Number of counters in each array. Reduces the error size. + /// Number of counter-arrays. Reduces the probability for an error + /// of a certain size (percentage of total count). + /// if if executed correctly, Error otherwise. + /// + Task InitByDimAsync(RedisKey key, long width, long depth); + + /// + /// Initializes a Count-Min Sketch to accommodate requested tolerances. + /// + /// The name of the sketch. + /// Estimate size of error. + /// The desired probability for inflated count. + /// if if executed correctly, Error otherwise. + /// + Task InitByProbAsync(RedisKey key, double error, double probability); + + /// + /// Merges several sketches into one sketch. + /// + /// The name of destination sketch. Must be initialized + /// Number of sketches to be merged. + /// Names of source sketches to be merged. + /// Multiple of each sketch. Default = 1. + /// if if executed correctly, Error otherwise. + /// + Task MergeAsync(RedisValue destination, long numKeys, RedisValue[] source, long[]? weight = null); + + /// + /// Returns the count for one or more items in a sketch. + /// + /// The name of the sketch + /// One or more items for which to return the count. + /// Array with a min-count of each of the items in the sketch + /// + Task QueryAsync(RedisKey key, params RedisValue[] items); + } +} \ No newline at end of file From 0d8683d4e0b3aeceef08a20e69a52b1abe86e550 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Thu, 26 Jan 2023 13:37:22 +0200 Subject: [PATCH 13/21] separate CF --- .../CuckooFilter/CuckooCommands.cs | 77 +---------- .../CuckooFilter/CuckooCommandsAsync.cs | 88 ++++++++++++ .../CuckooFilter/ICuckooCommands.cs | 122 ----------------- .../CuckooFilter/ICuckooCommandsAsync.cs | 129 ++++++++++++++++++ 4 files changed, 219 insertions(+), 197 deletions(-) create mode 100644 src/NRedisStack/CuckooFilter/CuckooCommandsAsync.cs create mode 100644 src/NRedisStack/CuckooFilter/ICuckooCommandsAsync.cs diff --git a/src/NRedisStack/CuckooFilter/CuckooCommands.cs b/src/NRedisStack/CuckooFilter/CuckooCommands.cs index 8adc38b7..f197472f 100644 --- a/src/NRedisStack/CuckooFilter/CuckooCommands.cs +++ b/src/NRedisStack/CuckooFilter/CuckooCommands.cs @@ -4,10 +4,10 @@ namespace NRedisStack { - public class CuckooCommands : ICuckooCommands + public class CuckooCommands : CuckooCommandsAsync, ICuckooCommands { IDatabase _db; - public CuckooCommands(IDatabase db) + public CuckooCommands(IDatabase db) : base(db) { _db = db; } @@ -18,120 +18,60 @@ public bool Add(RedisKey key, RedisValue item) return _db.Execute(CuckooCommandBuilder.Add(key, item)).ToString() == "1"; } - /// - public async Task AddAsync(RedisKey key, RedisValue item) - { - return (await _db.ExecuteAsync(CuckooCommandBuilder.Add(key, item))).ToString() == "1"; - } - /// public bool AddNX(RedisKey key, RedisValue item) { return _db.Execute(CuckooCommandBuilder.AddNX(key, item)).ToString() == "1"; } - /// - public async Task AddNXAsync(RedisKey key, RedisValue item) - { - return (await _db.ExecuteAsync(CuckooCommandBuilder.AddNX(key, item))).ToString() == "1"; - } - /// public long Count(RedisKey key, RedisValue item) { return _db.Execute(CuckooCommandBuilder.Count(key, item)).ToLong(); } - /// - public async Task CountAsync(RedisKey key, RedisValue item) - { - return (await _db.ExecuteAsync(CuckooCommandBuilder.Count(key, item))).ToLong(); - } - /// public bool Del(RedisKey key, RedisValue item) { return _db.Execute(CuckooCommandBuilder.Del(key, item)).ToString() == "1"; } - /// - public async Task DelAsync(RedisKey key, RedisValue item) - { - return (await _db.ExecuteAsync(CuckooCommandBuilder.Del(key, item))).ToString() == "1"; - } - /// public bool Exists(RedisKey key, RedisValue item) { return _db.Execute(CuckooCommandBuilder.Exists(key, item)).ToString() == "1"; } - /// - public async Task ExistsAsync(RedisKey key, RedisValue item) - { - return (await _db.ExecuteAsync(CuckooCommandBuilder.Exists(key, item))).ToString() == "1"; - } - /// public CuckooInformation Info(RedisKey key) { return _db.Execute(CuckooCommandBuilder.Info(key)).ToCuckooInfo(); } - /// - public async Task InfoAsync(RedisKey key) - { - return (await _db.ExecuteAsync(CuckooCommandBuilder.Info(key))).ToCuckooInfo(); - } - /// public bool[] Insert(RedisKey key, RedisValue[] items, int? capacity = null, bool nocreate = false) { return _db.Execute(CuckooCommandBuilder.Insert(key, items, capacity, nocreate)).ToBooleanArray(); } - /// - public async Task InsertAsync(RedisKey key, RedisValue[] items, int? capacity = null, bool nocreate = false) - { - return (await _db.ExecuteAsync(CuckooCommandBuilder.Insert(key, items, capacity, nocreate))).ToBooleanArray(); - } - /// public bool[] InsertNX(RedisKey key, RedisValue[] items, int? capacity = null, bool nocreate = false) { return _db.Execute(CuckooCommandBuilder.InsertNX(key, items, capacity, nocreate)).ToBooleanArray(); } - /// - public async Task InsertNXAsync(RedisKey key, RedisValue[] items, int? capacity = null, bool nocreate = false) - { - return (await _db.ExecuteAsync(CuckooCommandBuilder.InsertNX(key, items, capacity, nocreate))).ToBooleanArray(); - } - /// public bool LoadChunk(RedisKey key, long iterator, Byte[] data) { return _db.Execute(CuckooCommandBuilder.LoadChunk(key, iterator, data)).OKtoBoolean(); } - /// - public async Task LoadChunkAsync(RedisKey key, long iterator, Byte[] data) - { - return (await _db.ExecuteAsync(CuckooCommandBuilder.LoadChunk(key, iterator, data))).OKtoBoolean(); - } - /// public bool[] MExists(RedisKey key, params RedisValue[] items) { return _db.Execute(CuckooCommandBuilder.MExists(key, items)).ToBooleanArray(); } - /// - public async Task MExistsAsync(RedisKey key, params RedisValue[] items) - { - return (await _db.ExecuteAsync(CuckooCommandBuilder.MExists(key, items))).ToBooleanArray(); - } - /// public bool Reserve(RedisKey key, long capacity, long? bucketSize = null, int? maxIterations = null, int? expansion = null) @@ -139,23 +79,10 @@ public bool Reserve(RedisKey key, long capacity, return _db.Execute(CuckooCommandBuilder.Reserve(key, capacity, bucketSize, maxIterations, expansion)).OKtoBoolean(); } - /// - public async Task ReserveAsync(RedisKey key, long capacity, - long? bucketSize = null, int? maxIterations = null, int? expansion = null) - { - return (await _db.ExecuteAsync(CuckooCommandBuilder.Reserve(key, capacity, bucketSize, maxIterations, expansion))).OKtoBoolean(); - } - /// public Tuple ScanDump(RedisKey key, long iterator) { return _db.Execute(CuckooCommandBuilder.ScanDump(key, iterator)).ToScanDumpTuple(); } - - /// - public async Task> ScanDumpAsync(RedisKey key, long iterator) - { - return (await _db.ExecuteAsync(CuckooCommandBuilder.ScanDump(key, iterator))).ToScanDumpTuple(); - } } } \ No newline at end of file diff --git a/src/NRedisStack/CuckooFilter/CuckooCommandsAsync.cs b/src/NRedisStack/CuckooFilter/CuckooCommandsAsync.cs new file mode 100644 index 00000000..fcae47a9 --- /dev/null +++ b/src/NRedisStack/CuckooFilter/CuckooCommandsAsync.cs @@ -0,0 +1,88 @@ +using NRedisStack.CuckooFilter.DataTypes; +using NRedisStack.Literals; +using StackExchange.Redis; +namespace NRedisStack +{ + + public class CuckooCommandsAsync : ICuckooCommandsAsync + { + IDatabaseAsync _db; + public CuckooCommandsAsync(IDatabaseAsync db) + { + _db = db; + } + + /// + public async Task AddAsync(RedisKey key, RedisValue item) + { + return (await _db.ExecuteAsync(CuckooCommandBuilder.Add(key, item))).ToString() == "1"; + } + + /// + public async Task AddNXAsync(RedisKey key, RedisValue item) + { + return (await _db.ExecuteAsync(CuckooCommandBuilder.AddNX(key, item))).ToString() == "1"; + } + + /// + public async Task CountAsync(RedisKey key, RedisValue item) + { + return (await _db.ExecuteAsync(CuckooCommandBuilder.Count(key, item))).ToLong(); + } + + /// + public async Task DelAsync(RedisKey key, RedisValue item) + { + return (await _db.ExecuteAsync(CuckooCommandBuilder.Del(key, item))).ToString() == "1"; + } + + /// + public async Task ExistsAsync(RedisKey key, RedisValue item) + { + return (await _db.ExecuteAsync(CuckooCommandBuilder.Exists(key, item))).ToString() == "1"; + } + + /// + public async Task InfoAsync(RedisKey key) + { + return (await _db.ExecuteAsync(CuckooCommandBuilder.Info(key))).ToCuckooInfo(); + } + + /// + public async Task InsertAsync(RedisKey key, RedisValue[] items, int? capacity = null, bool nocreate = false) + { + return (await _db.ExecuteAsync(CuckooCommandBuilder.Insert(key, items, capacity, nocreate))).ToBooleanArray(); + } + + /// + public async Task InsertNXAsync(RedisKey key, RedisValue[] items, int? capacity = null, bool nocreate = false) + { + return (await _db.ExecuteAsync(CuckooCommandBuilder.InsertNX(key, items, capacity, nocreate))).ToBooleanArray(); + } + + /// + public async Task LoadChunkAsync(RedisKey key, long iterator, Byte[] data) + { + return (await _db.ExecuteAsync(CuckooCommandBuilder.LoadChunk(key, iterator, data))).OKtoBoolean(); + } + + /// + public async Task MExistsAsync(RedisKey key, params RedisValue[] items) + { + return (await _db.ExecuteAsync(CuckooCommandBuilder.MExists(key, items))).ToBooleanArray(); + } + + /// + public async Task ReserveAsync(RedisKey key, long capacity, + long? bucketSize = null, int? maxIterations = null, int? expansion = null) + { + return (await _db.ExecuteAsync(CuckooCommandBuilder.Reserve(key, capacity, bucketSize, maxIterations, expansion))).OKtoBoolean(); + } + + /// + public async Task> ScanDumpAsync(RedisKey key, long iterator) + { + return (await _db.ExecuteAsync(CuckooCommandBuilder.ScanDump(key, iterator))).ToScanDumpTuple(); + } + } +} \ No newline at end of file diff --git a/src/NRedisStack/CuckooFilter/ICuckooCommands.cs b/src/NRedisStack/CuckooFilter/ICuckooCommands.cs index d0e38f92..18852203 100644 --- a/src/NRedisStack/CuckooFilter/ICuckooCommands.cs +++ b/src/NRedisStack/CuckooFilter/ICuckooCommands.cs @@ -13,15 +13,6 @@ public interface ICuckooCommands /// bool Add(RedisKey key, RedisValue item); - /// - /// Adds an item to a Cuckoo Filter. - /// - /// The key under which the filter is found. - /// The item to add. - /// if the item did not exist in the filter, otherwise. - /// - Task AddAsync(RedisKey key, RedisValue item); - /// /// Adds an item to a Cuckoo Filter if the item did not exist previously. /// @@ -31,15 +22,6 @@ public interface ICuckooCommands /// bool AddNX(RedisKey key, RedisValue item); - /// - /// Adds an item to a Cuckoo Filter if the item did not exist previously. - /// - /// The key under which the filter is found. - /// The item to add. - /// if the item did not exist in the filter, otherwise. - /// - Task AddNXAsync(RedisKey key, RedisValue item); - /// /// Returns the number of times an item may be in the filter. /// @@ -49,15 +31,6 @@ public interface ICuckooCommands /// long Count(RedisKey key, RedisValue item); - /// - /// Returns the number of times an item may be in the filter. - /// - /// The name of the filter - /// The item to count. - /// the count of possible matching copies of the item in the filter. - /// - Task CountAsync(RedisKey key, RedisValue item); - /// /// Deletes an item from the Cuckoo Filter. /// @@ -67,15 +40,6 @@ public interface ICuckooCommands /// bool Del(RedisKey key, RedisValue item); - /// - /// Deletes an item from the Cuckoo Filter. - /// - /// The name of the filter - /// The item to delete from the filter. - /// see langword="true"/> if the item has been deleted from the filter, otherwise. - /// - Task DelAsync(RedisKey key, RedisValue item); - /// /// Checks whether an item exist in the Cuckoo Filter or not. /// @@ -86,16 +50,6 @@ public interface ICuckooCommands /// bool Exists(RedisKey key, RedisValue item); - /// - /// Checks whether an item exist in the Cuckoo Filter or not. - /// - /// The name of the filter. - /// The item to check for. - /// means the item may exist in the filter, - /// and means it does not exist in the filter. - /// - Task ExistsAsync(RedisKey key, RedisValue item); - /// /// Return information about a Cuckoo filter. /// @@ -104,14 +58,6 @@ public interface ICuckooCommands /// CuckooInformation Info(RedisKey key); - /// - /// Return information about a Cuckoo filter. - /// - /// Name of the key to return information about. - /// Information of the filter. - /// - Task InfoAsync(RedisKey key); - /// /// Adds one or more items to a Cuckoo Filter. A filter will be created if it does not exist. /// @@ -123,17 +69,6 @@ public interface ICuckooCommands /// bool[] Insert(RedisKey key, RedisValue[] items, int? capacity = null, bool nocreate = false); - /// - /// Adds one or more items to a Cuckoo Filter. A filter will be created if it does not exist. - /// - /// The name of the filter. - /// One or more items to add. - /// (Optional) Specifies the desired capacity for the filter to be created. - /// (Optional) to indicates that the - /// An array of booleans. - /// - Task InsertAsync(RedisKey key, RedisValue[] items, int? capacity = null, bool nocreate = false); - /// /// Adds one or more items to a Cuckoo Filter if the items did not exist previously. /// A filter will be created if it does not exist. @@ -147,19 +82,6 @@ public interface ICuckooCommands /// bool[] InsertNX(RedisKey key, RedisValue[] items, int? capacity = null, bool nocreate = false); - /// - /// Adds one or more items to a Cuckoo Filter if the items did not exist previously. - /// A filter will be created if it does not exist. - /// - /// The name of the filter. - /// One or more items to add. - /// (Optional) Specifies the desired capacity for the filter to be created. - /// (Optional) to indicates that the - /// An array of booleans.where means the item has been added to the filter, - /// and mean, the item already existed - /// - Task InsertNXAsync(RedisKey key, RedisValue[] items, int? capacity = null, bool nocreate = false); - /// /// Restores a filter previosly saved using SCANDUMP. /// @@ -170,16 +92,6 @@ public interface ICuckooCommands /// bool LoadChunk(RedisKey key, long iterator, Byte[] data); - /// - /// Restores a filter previosly saved using SCANDUMP. - /// - /// Name of the key to restore. - /// Iterator value associated with data (returned by SCANDUMP). - /// Current data chunk (returned by SCANDUMP). - /// Array with information of the filter. - /// - Task LoadChunkAsync(RedisKey key, long iterator, Byte[] data); - /// /// Checks whether one or more items may exist in the a Cuckoo Filter. /// @@ -190,16 +102,6 @@ public interface ICuckooCommands /// bool[] MExists(RedisKey key, params RedisValue[] items); - /// - /// Checks whether one or more items may exist in the a Cuckoo Filter. - /// - /// The name of the filter. - /// One or more items to check. - /// An array of booleans, for each item means the item may exist in the filter, - /// and means the item may exist in the filter. - /// - Task MExistsAsync(RedisKey key, params RedisValue[] items); - /// /// Creates a new Cuckoo Filter. /// @@ -215,21 +117,6 @@ public interface ICuckooCommands bool Reserve(RedisKey key, long capacity, long? bucketSize = null, int? maxIterations = null, int? expansion = null); - /// - /// Creates a new Cuckoo Filter. - /// - /// The key under which the filter is found. - /// The number of entries intended to be added to the filter. - /// Number of items in each bucket. - /// Number of attempts to swap items between buckets before - /// declaring filter as full and creating an additional filter. - /// (Optional) When capacity is reached, an additional sub-filter is - /// created in size of the last sub-filter multiplied by expansion. - /// if executed correctly, Error otherwise. - /// - Task ReserveAsync(RedisKey key, long capacity, - long? bucketSize = null, int? maxIterations = null, int? expansion = null); - /// /// Begins an incremental save of the Cuckoo Filter. /// @@ -238,14 +125,5 @@ Task ReserveAsync(RedisKey key, long capacity, /// Tuple of iterator and data. /// Tuple ScanDump(RedisKey key, long iterator); - - /// - /// Begins an incremental save of the Cuckoo Filter. - /// - /// Name of the filter. - /// Iterator value; either 0 or the iterator from a previous invocation of this command. - /// Tuple of iterator and data. - /// - Task> ScanDumpAsync(RedisKey key, long iterator); } } \ No newline at end of file diff --git a/src/NRedisStack/CuckooFilter/ICuckooCommandsAsync.cs b/src/NRedisStack/CuckooFilter/ICuckooCommandsAsync.cs new file mode 100644 index 00000000..acf67b69 --- /dev/null +++ b/src/NRedisStack/CuckooFilter/ICuckooCommandsAsync.cs @@ -0,0 +1,129 @@ +using NRedisStack.CuckooFilter.DataTypes; +using StackExchange.Redis; +namespace NRedisStack +{ + public interface ICuckooCommandsAsync + { + /// + /// Adds an item to a Cuckoo Filter. + /// + /// The key under which the filter is found. + /// The item to add. + /// if the item did not exist in the filter, otherwise. + /// + Task AddAsync(RedisKey key, RedisValue item); + + /// + /// Adds an item to a Cuckoo Filter if the item did not exist previously. + /// + /// The key under which the filter is found. + /// The item to add. + /// if the item did not exist in the filter, otherwise. + /// + Task AddNXAsync(RedisKey key, RedisValue item); + + /// + /// Returns the number of times an item may be in the filter. + /// + /// The name of the filter + /// The item to count. + /// the count of possible matching copies of the item in the filter. + /// + Task CountAsync(RedisKey key, RedisValue item); + + /// + /// Deletes an item from the Cuckoo Filter. + /// + /// The name of the filter + /// The item to delete from the filter. + /// see langword="true"/> if the item has been deleted from the filter, otherwise. + /// + Task DelAsync(RedisKey key, RedisValue item); + + /// + /// Checks whether an item exist in the Cuckoo Filter or not. + /// + /// The name of the filter. + /// The item to check for. + /// means the item may exist in the filter, + /// and means it does not exist in the filter. + /// + Task ExistsAsync(RedisKey key, RedisValue item); + + /// + /// Return information about a Cuckoo filter. + /// + /// Name of the key to return information about. + /// Information of the filter. + /// + Task InfoAsync(RedisKey key); + + /// + /// Adds one or more items to a Cuckoo Filter. A filter will be created if it does not exist. + /// + /// The name of the filter. + /// One or more items to add. + /// (Optional) Specifies the desired capacity for the filter to be created. + /// (Optional) to indicates that the + /// An array of booleans. + /// + Task InsertAsync(RedisKey key, RedisValue[] items, int? capacity = null, bool nocreate = false); + + /// + /// Adds one or more items to a Cuckoo Filter if the items did not exist previously. + /// A filter will be created if it does not exist. + /// + /// The name of the filter. + /// One or more items to add. + /// (Optional) Specifies the desired capacity for the filter to be created. + /// (Optional) to indicates that the + /// An array of booleans.where means the item has been added to the filter, + /// and mean, the item already existed + /// + Task InsertNXAsync(RedisKey key, RedisValue[] items, int? capacity = null, bool nocreate = false); + + /// + /// Restores a filter previosly saved using SCANDUMP. + /// + /// Name of the key to restore. + /// Iterator value associated with data (returned by SCANDUMP). + /// Current data chunk (returned by SCANDUMP). + /// Array with information of the filter. + /// + Task LoadChunkAsync(RedisKey key, long iterator, Byte[] data); + + /// + /// Checks whether one or more items may exist in the a Cuckoo Filter. + /// + /// The name of the filter. + /// One or more items to check. + /// An array of booleans, for each item means the item may exist in the filter, + /// and means the item may exist in the filter. + /// + Task MExistsAsync(RedisKey key, params RedisValue[] items); + + /// + /// Creates a new Cuckoo Filter. + /// + /// The key under which the filter is found. + /// The number of entries intended to be added to the filter. + /// Number of items in each bucket. + /// Number of attempts to swap items between buckets before + /// declaring filter as full and creating an additional filter. + /// (Optional) When capacity is reached, an additional sub-filter is + /// created in size of the last sub-filter multiplied by expansion. + /// if executed correctly, Error otherwise. + /// + Task ReserveAsync(RedisKey key, long capacity, + long? bucketSize = null, int? maxIterations = null, int? expansion = null); + + /// + /// Begins an incremental save of the Cuckoo Filter. + /// + /// Name of the filter. + /// Iterator value; either 0 or the iterator from a previous invocation of this command. + /// Tuple of iterator and data. + /// + Task> ScanDumpAsync(RedisKey key, long iterator); + } +} \ No newline at end of file From 3af4af22a4c25c53ed1ec0f203659646f8f861d6 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Thu, 26 Jan 2023 17:20:16 +0200 Subject: [PATCH 14/21] split graph --- src/NRedisStack/Graph/GraphCache.cs | 7 + src/NRedisStack/Graph/GraphCacheList.cs | 28 +++- src/NRedisStack/Graph/GraphCommands.cs | 97 +------------ src/NRedisStack/Graph/GraphCommandsAsync.cs | 144 +++++++++++++++++++ src/NRedisStack/Graph/IGraphCommands.cs | 103 ------------- src/NRedisStack/Graph/IGraphCommandsAsync.cs | 139 ++++++++++++++++++ 6 files changed, 314 insertions(+), 204 deletions(-) create mode 100644 src/NRedisStack/Graph/GraphCommandsAsync.cs create mode 100644 src/NRedisStack/Graph/IGraphCommandsAsync.cs diff --git a/src/NRedisStack/Graph/GraphCache.cs b/src/NRedisStack/Graph/GraphCache.cs index d8867615..fc9a2c39 100644 --- a/src/NRedisStack/Graph/GraphCache.cs +++ b/src/NRedisStack/Graph/GraphCache.cs @@ -13,6 +13,13 @@ public GraphCache(string graphName, GraphCommands redisGraph) RelationshipTypes = new GraphCacheList(graphName, "db.relationshipTypes", redisGraph); } + public GraphCache(string graphName, GraphCommandsAsync redisGraph) + { + Labels = new GraphCacheList(graphName, "db.labels", redisGraph); + PropertyNames = new GraphCacheList(graphName, "db.propertyKeys", redisGraph); + RelationshipTypes = new GraphCacheList(graphName, "db.relationshipTypes", redisGraph); + } + public string GetLabel(int index) => Labels.GetCachedData(index); public string GetRelationshipType(int index) => RelationshipTypes.GetCachedData(index); diff --git a/src/NRedisStack/Graph/GraphCacheList.cs b/src/NRedisStack/Graph/GraphCacheList.cs index b6e16d92..b490a7fb 100644 --- a/src/NRedisStack/Graph/GraphCacheList.cs +++ b/src/NRedisStack/Graph/GraphCacheList.cs @@ -7,15 +7,27 @@ internal class GraphCacheList private string[] _data; protected readonly GraphCommands graph; + protected readonly GraphCommandsAsync asyncGraph; + private bool asyncGraphUsed; private readonly object _locker = new object(); + internal GraphCacheList(string graphName, string procedure, GraphCommands redisGraph) : this(graphName, procedure) + { + graph = redisGraph; + asyncGraphUsed = false; + } - internal GraphCacheList(string graphName, string procedure, GraphCommands redisGraph) + internal GraphCacheList(string graphName, string procedure, GraphCommandsAsync redisGraph) : this(graphName, procedure) + { + asyncGraph = redisGraph; + asyncGraphUsed = true; + } + + private GraphCacheList(string graphName, string procedure) { GraphName = graphName; Procedure = procedure; - graph = redisGraph; } // TODO: Change this to use Lazy? @@ -23,7 +35,7 @@ internal string GetCachedData(int index) { if (_data == null || index >= _data.Length) { - lock(_locker) + lock (_locker) { if (_data == null || index >= _data.Length) { @@ -37,7 +49,7 @@ internal string GetCachedData(int index) private void GetProcedureInfo() { - var resultSet = CallProcedure(); + var resultSet = CallProcedure(asyncGraphUsed); var newData = new string[resultSet.Count]; var i = 0; @@ -49,7 +61,11 @@ private void GetProcedureInfo() _data = newData; } - protected virtual ResultSet CallProcedure() => - graph.CallProcedure(GraphName, Procedure); + protected virtual ResultSet CallProcedure(bool asyncGraphUsed = false) + { + return asyncGraphUsed + ? asyncGraph.CallProcedureAsync(GraphName, Procedure).Result + : graph.CallProcedure(GraphName, Procedure); + } } } \ No newline at end of file diff --git a/src/NRedisStack/Graph/GraphCommands.cs b/src/NRedisStack/Graph/GraphCommands.cs index a1363f6b..bfa25f00 100644 --- a/src/NRedisStack/Graph/GraphCommands.cs +++ b/src/NRedisStack/Graph/GraphCommands.cs @@ -7,11 +7,11 @@ namespace NRedisStack { - public class GraphCommands : IGraphCommands + public class GraphCommands : GraphCommandsAsync, IGraphCommands { IDatabase _db; - public GraphCommands(IDatabase db) + public GraphCommands(IDatabase db) : base(db) { _db = db; } @@ -26,14 +26,6 @@ public ResultSet Query(string graphName, string query, IDictionary - public async Task QueryAsync(string graphName, string query, IDictionary parameters, long? timeout = null) - { - var preparedQuery = PrepareQuery(query, parameters); - - return await QueryAsync(graphName, preparedQuery, timeout); - } - /// public ResultSet Query(string graphName, string query, long? timeout = null) { @@ -45,17 +37,6 @@ public ResultSet Query(string graphName, string query, long? timeout = null) return new ResultSet(_db.Execute(GraphCommandBuilder.Query(graphName, query, timeout)), _graphCaches[graphName]); } - /// - public async Task QueryAsync(string graphName, string query, long? timeout = null) - { - if (!_graphCaches.ContainsKey(graphName)) - { - _graphCaches.Add(graphName, new GraphCache(graphName, this)); - } - - return new ResultSet(await _db.ExecuteAsync(GraphCommandBuilder.Query(graphName, query, timeout)), _graphCaches[graphName]); - } - /// public ResultSet RO_Query(string graphName, string query, IDictionary parameters, long? timeout = null) { @@ -64,14 +45,6 @@ public ResultSet RO_Query(string graphName, string query, IDictionary - public async Task RO_QueryAsync(string graphName, string query, IDictionary parameters, long? timeout = null) - { - var preparedQuery = PrepareQuery(query, parameters); - - return await RO_QueryAsync(graphName, preparedQuery, timeout); - } - /// public ResultSet RO_Query(string graphName, string query, long? timeout = null) { @@ -83,17 +56,6 @@ public ResultSet RO_Query(string graphName, string query, long? timeout = null) return new ResultSet(_db.Execute(GraphCommandBuilder.RO_Query(graphName, query, timeout)), _graphCaches[graphName]); } - /// - public async Task RO_QueryAsync(string graphName, string query, long? timeout = null) - { - if (!_graphCaches.ContainsKey(graphName)) - { - _graphCaches.Add(graphName, new GraphCache(graphName, this)); - } - - return new ResultSet(await _db.ExecuteAsync(GraphCommandBuilder.RO_Query(graphName, query, timeout)), _graphCaches[graphName]); - } - internal static readonly Dictionary> EmptyKwargsDictionary = new Dictionary>(); @@ -135,78 +97,36 @@ public ResultSet Delete(string graphName) return processedResult; } - /// - public async Task DeleteAsync(string graphName) - { - var result = await _db.ExecuteAsync(GRAPH.DELETE, graphName); - - var processedResult = new ResultSet(result, _graphCaches[graphName]); - - _graphCaches.Remove(graphName); - - return processedResult; - } - /// public IReadOnlyList Explain(string graphName, string query) { return _db.Execute(GraphCommandBuilder.Explain(graphName, query)).ToStringList(); } - /// - public async Task> ExplainAsync(string graphName, string query) - { - return (await _db.ExecuteAsync(GRAPH.EXPLAIN, graphName, query)).ToStringList(); - } - /// public IReadOnlyList Profile(string graphName, string query, long? timeout = null) { return _db.Execute(GraphCommandBuilder.Profile(graphName, query, timeout)).ToStringList(); } - /// - public async Task> ProfileAsync(string graphName, string query, long? timeout = null) - { - return (await _db.ExecuteAsync(GraphCommandBuilder.Profile(graphName, query, timeout))).ToStringList(); - } - /// public IReadOnlyList List() { return _db.Execute(GraphCommandBuilder.List()).ToStringList(); } - /// - public async Task> ListAsync() - { - return (await _db.ExecuteAsync(GraphCommandBuilder.List())).ToStringList(); - } - /// public bool ConfigSet(string configName, object value) { return _db.Execute(GraphCommandBuilder.ConfigSet(configName, value)).OKtoBoolean(); } - /// - public async Task ConfigSetAsync(string configName, object value) - { - return (await _db.ExecuteAsync(GraphCommandBuilder.ConfigSet(configName, value))).OKtoBoolean(); - } - /// public Dictionary ConfigGet(string configName) { return _db.Execute(GraphCommandBuilder.ConfigGet(configName)).ToDictionary(); } - /// - public async Task> ConfigGetAsync(string configName) - { - return (await _db.ExecuteAsync(GRAPH.CONFIG, GraphArgs.GET, configName)).ToDictionary(); - } - /// public List> Slowlog(string graphName) { @@ -219,18 +139,5 @@ public List> Slowlog(string graphName) return slowlog; } - - /// - public async Task>> SlowlogAsync(string graphName) - { - var result = (await _db.ExecuteAsync(GraphCommandBuilder.Slowlog(graphName))).ToArray(); - List> slowlog = new List>(result.Length); - foreach (var item in result) - { - slowlog.Add(item.ToStringList()); - } - - return slowlog; - } } } \ No newline at end of file diff --git a/src/NRedisStack/Graph/GraphCommandsAsync.cs b/src/NRedisStack/Graph/GraphCommandsAsync.cs new file mode 100644 index 00000000..154dbd74 --- /dev/null +++ b/src/NRedisStack/Graph/GraphCommandsAsync.cs @@ -0,0 +1,144 @@ +using System.Text; +using NRedisStack.Graph; +using NRedisStack.Literals; +using StackExchange.Redis; +using static NRedisStack.Graph.RedisGraphUtilities; + + +namespace NRedisStack +{ + public class GraphCommandsAsync : IGraphCommandsAsync + { + IDatabaseAsync _db; + + public GraphCommandsAsync(IDatabaseAsync db) + { + _db = db; + } + + private readonly IDictionary _graphCaches = new Dictionary(); + + /// + public async Task QueryAsync(string graphName, string query, IDictionary parameters, long? timeout = null) + { + var preparedQuery = PrepareQuery(query, parameters); + + return await QueryAsync(graphName, preparedQuery, timeout); + } + + /// + public async Task QueryAsync(string graphName, string query, long? timeout = null) + { + if (!_graphCaches.ContainsKey(graphName)) + { + _graphCaches.Add(graphName, new GraphCache(graphName, this)); + } + + return new ResultSet(await _db.ExecuteAsync(GraphCommandBuilder.Query(graphName, query, timeout)), _graphCaches[graphName]); + } + + /// + public async Task RO_QueryAsync(string graphName, string query, IDictionary parameters, long? timeout = null) + { + var preparedQuery = PrepareQuery(query, parameters); + + return await RO_QueryAsync(graphName, preparedQuery, timeout); + } + + /// + public async Task RO_QueryAsync(string graphName, string query, long? timeout = null) + { + if (!_graphCaches.ContainsKey(graphName)) + { + _graphCaches.Add(graphName, new GraphCache(graphName, this)); + } + + return new ResultSet(await _db.ExecuteAsync(GraphCommandBuilder.RO_Query(graphName, query, timeout)), _graphCaches[graphName]); + } + + internal static readonly Dictionary> EmptyKwargsDictionary = + new Dictionary>(); + + // TODO: Check if this is needed: + /// + public async Task CallProcedureAsync(string graphName, string procedure) => + await CallProcedureAsync(graphName, procedure, Enumerable.Empty(), EmptyKwargsDictionary); + + /// + public async Task CallProcedureAsync(string graphName, string procedure, IEnumerable args) => + await CallProcedureAsync(graphName, procedure, args, EmptyKwargsDictionary); + + /// + public async Task CallProcedureAsync(string graphName, string procedure, IEnumerable args, Dictionary> kwargs) + { + args = args.Select(a => QuoteString(a)); + + var queryBody = new StringBuilder(); + + queryBody.Append($"CALL {procedure}({string.Join(",", args)})"); + + if (kwargs.TryGetValue("y", out var kwargsList)) + { + queryBody.Append(string.Join(",", kwargsList)); + } + + return await QueryAsync(graphName, queryBody.ToString()); + } + + + /// + public async Task DeleteAsync(string graphName) + { + var result = await _db.ExecuteAsync(GRAPH.DELETE, graphName); + + var processedResult = new ResultSet(result, _graphCaches[graphName]); + + _graphCaches.Remove(graphName); + + return processedResult; + } + + /// + public async Task> ExplainAsync(string graphName, string query) + { + return (await _db.ExecuteAsync(GRAPH.EXPLAIN, graphName, query)).ToStringList(); + } + + /// + public async Task> ProfileAsync(string graphName, string query, long? timeout = null) + { + return (await _db.ExecuteAsync(GraphCommandBuilder.Profile(graphName, query, timeout))).ToStringList(); + } + + /// + public async Task> ListAsync() + { + return (await _db.ExecuteAsync(GraphCommandBuilder.List())).ToStringList(); + } + + /// + public async Task ConfigSetAsync(string configName, object value) + { + return (await _db.ExecuteAsync(GraphCommandBuilder.ConfigSet(configName, value))).OKtoBoolean(); + } + + /// + public async Task> ConfigGetAsync(string configName) + { + return (await _db.ExecuteAsync(GRAPH.CONFIG, GraphArgs.GET, configName)).ToDictionary(); + } + + /// + public async Task>> SlowlogAsync(string graphName) + { + var result = (await _db.ExecuteAsync(GraphCommandBuilder.Slowlog(graphName))).ToArray(); + List> slowlog = new List>(result.Length); + foreach (var item in result) + { + slowlog.Add(item.ToStringList()); + } + + return slowlog; + } + } +} \ No newline at end of file diff --git a/src/NRedisStack/Graph/IGraphCommands.cs b/src/NRedisStack/Graph/IGraphCommands.cs index e2470b64..bd1a3100 100644 --- a/src/NRedisStack/Graph/IGraphCommands.cs +++ b/src/NRedisStack/Graph/IGraphCommands.cs @@ -16,17 +16,6 @@ public interface IGraphCommands /// ResultSet Query(string graphName, string query, IDictionary parameters, long? timeout = null); - /// - /// Execute a Cypher query with parameters. - /// - /// A graph to perform the query on. - /// The Cypher query. - /// Parameters map. - /// Timeout (optional). - /// A result set. - /// - Task QueryAsync(string graphName, string query, IDictionary parameters, long? timeout = null); - /// /// Execute a Cypher query. /// @@ -37,16 +26,6 @@ public interface IGraphCommands /// ResultSet Query(string graphName, string query, long? timeout = null); - /// - /// Execute a Cypher query. - /// - /// A graph to perform the query on. - /// The Cypher query. - /// Timeout (optional). - /// A result set. - /// - Task QueryAsync(string graphName, string query, long? timeout = null); - /// /// Execute a Cypher query with parameters. /// @@ -58,17 +37,6 @@ public interface IGraphCommands /// ResultSet RO_Query(string graphName, string query, IDictionary parameters, long? timeout = null); - /// - /// Execute a Cypher query with parameters. - /// - /// A graph to perform the query on. - /// The Cypher query. - /// Parameters map. - /// Timeout (optional). - /// A result set. - /// - Task RO_QueryAsync(string graphName, string query, IDictionary parameters, long? timeout = null); - /// /// Execute a Cypher query. /// @@ -79,16 +47,6 @@ public interface IGraphCommands /// ResultSet RO_Query(string graphName, string query, long? timeout = null); - /// - /// Execute a Cypher query. - /// - /// A graph to perform the query on. - /// The Cypher query. - /// Timeout (optional). - /// A result set. - /// - Task RO_QueryAsync(string graphName, string query, long? timeout = null); - // TODO: Check if needed /// /// Call a saved procedure. @@ -125,14 +83,6 @@ public interface IGraphCommands /// ResultSet Delete(string graphName); - /// - /// Delete an existing graph. - /// - /// The graph to delete. - /// A result set. - /// - Task DeleteAsync(string graphName); - /// /// Constructs a query execution plan but does not run it. Inspect this execution plan to better understand how your /// query will get executed. @@ -143,16 +93,6 @@ public interface IGraphCommands /// IReadOnlyList Explain(string graphName, string query); - /// - /// Constructs a query execution plan but does not run it. Inspect this execution plan to better understand how your - /// query will get executed. - /// - /// The graph name. - /// The query. - /// String representation of a query execution plan. - /// - Task> ExplainAsync(string graphName, string query); - /// /// Executes a query and produces an execution plan augmented with metrics for each operation's execution. /// @@ -164,17 +104,6 @@ public interface IGraphCommands /// IReadOnlyList Profile(string graphName, string query, long? timeout = null); - /// - /// Executes a query and produces an execution plan augmented with metrics for each operation's execution. - /// - /// The graph name. - /// The query. - /// Timeout (optional). - /// String representation of a query execution plan, - /// with details on results produced by and time spent in each operation. - /// - Task> ProfileAsync(string graphName, string query, long? timeout = null); - /// /// Lists all graph keys in the keyspace. /// @@ -182,13 +111,6 @@ public interface IGraphCommands /// IReadOnlyList List(); - /// - /// Lists all graph keys in the keyspace. - /// - /// List of all graph keys in the keyspace. - /// - Task> ListAsync(); - /// /// Set the value of a RedisGraph configuration parameter. /// @@ -198,15 +120,6 @@ public interface IGraphCommands /// bool ConfigSet(string configName, object value); - /// - /// Set the value of a RedisGraph configuration parameter. - /// - /// The config name. - /// Value to set. - /// if executed correctly, error otherwise - /// - Task ConfigSetAsync(string configName, object value); - /// /// Set the value of a RedisGraph configuration parameter. /// @@ -215,14 +128,6 @@ public interface IGraphCommands /// Dictionary ConfigGet(string configName); - /// - /// Set the value of a RedisGraph configuration parameter. - /// - /// The config name. - /// Dictionary of . - /// - Task> ConfigGetAsync(string configName); - /// /// Returns a list containing up to 10 of the slowest queries issued against the given graph Name. /// @@ -230,13 +135,5 @@ public interface IGraphCommands /// Dictionary of . /// List> Slowlog(string graphName); - - /// - /// Returns a list containing up to 10 of the slowest queries issued against the given graph Name. - /// - /// The graph name. - /// Dictionary of . - /// - Task>> SlowlogAsync(string graphName); } } \ No newline at end of file diff --git a/src/NRedisStack/Graph/IGraphCommandsAsync.cs b/src/NRedisStack/Graph/IGraphCommandsAsync.cs new file mode 100644 index 00000000..46b84889 --- /dev/null +++ b/src/NRedisStack/Graph/IGraphCommandsAsync.cs @@ -0,0 +1,139 @@ +using NRedisStack.Graph; +using StackExchange.Redis; + +namespace NRedisStack +{ + public interface IGraphCommandsAsync + { + /// + /// Execute a Cypher query with parameters. + /// + /// A graph to perform the query on. + /// The Cypher query. + /// Parameters map. + /// Timeout (optional). + /// A result set. + /// + Task QueryAsync(string graphName, string query, IDictionary parameters, long? timeout = null); + + /// + /// Execute a Cypher query. + /// + /// A graph to perform the query on. + /// The Cypher query. + /// Timeout (optional). + /// A result set. + /// + Task QueryAsync(string graphName, string query, long? timeout = null); + + /// + /// Execute a Cypher query with parameters. + /// + /// A graph to perform the query on. + /// The Cypher query. + /// Parameters map. + /// Timeout (optional). + /// A result set. + /// + Task RO_QueryAsync(string graphName, string query, IDictionary parameters, long? timeout = null); + + /// + /// Execute a Cypher query. + /// + /// A graph to perform the query on. + /// The Cypher query. + /// Timeout (optional). + /// A result set. + /// + Task RO_QueryAsync(string graphName, string query, long? timeout = null); + + // TODO: Check if needed + /// + /// Call a saved procedure. + /// + /// The graph containing the saved procedure. + /// The procedure name. + /// A result set. + Task CallProcedureAsync(string graphName, string procedure); + + /// + /// Call a saved procedure with parameters. + /// + /// The graph containing the saved procedure. + /// The procedure name. + /// A collection of positional arguments. + /// A result set. + Task CallProcedureAsync(string graphName, string procedure, IEnumerable args); + + /// + /// Call a saved procedure with parameters. + /// + /// The graph containing the saved procedure. + /// The procedure name. + /// A collection of positional arguments. + /// A collection of keyword arguments. + /// A result set. + Task CallProcedureAsync(string graphName, string procedure, IEnumerable args, Dictionary> kwargs); + + /// + /// Delete an existing graph. + /// + /// The graph to delete. + /// A result set. + /// + Task DeleteAsync(string graphName); + + /// + /// Constructs a query execution plan but does not run it. Inspect this execution plan to better understand how your + /// query will get executed. + /// + /// The graph name. + /// The query. + /// String representation of a query execution plan. + /// + Task> ExplainAsync(string graphName, string query); + + /// + /// Executes a query and produces an execution plan augmented with metrics for each operation's execution. + /// + /// The graph name. + /// The query. + /// Timeout (optional). + /// String representation of a query execution plan, + /// with details on results produced by and time spent in each operation. + /// + Task> ProfileAsync(string graphName, string query, long? timeout = null); + + /// + /// Lists all graph keys in the keyspace. + /// + /// List of all graph keys in the keyspace. + /// + Task> ListAsync(); + + /// + /// Set the value of a RedisGraph configuration parameter. + /// + /// The config name. + /// Value to set. + /// if executed correctly, error otherwise + /// + Task ConfigSetAsync(string configName, object value); + + /// + /// Set the value of a RedisGraph configuration parameter. + /// + /// The config name. + /// Dictionary of . + /// + Task> ConfigGetAsync(string configName); + + /// + /// Returns a list containing up to 10 of the slowest queries issued against the given graph Name. + /// + /// The graph name. + /// Dictionary of . + /// + Task>> SlowlogAsync(string graphName); + } +} \ No newline at end of file From 302d00f037cf860f7ae4e455b3d5c05d674717cc Mon Sep 17 00:00:00 2001 From: shacharPash Date: Thu, 26 Jan 2023 18:07:21 +0200 Subject: [PATCH 15/21] split search --- src/NRedisStack/Search/ISearchCommands.cs | 205 ----------------- .../Search/ISearchCommandsAsync.cs | 213 ++++++++++++++++++ src/NRedisStack/Search/SearchCommands.cs | 153 +------------ src/NRedisStack/Search/SearchCommandsAsync.cs | 169 ++++++++++++++ 4 files changed, 384 insertions(+), 356 deletions(-) create mode 100644 src/NRedisStack/Search/ISearchCommandsAsync.cs create mode 100644 src/NRedisStack/Search/SearchCommandsAsync.cs diff --git a/src/NRedisStack/Search/ISearchCommands.cs b/src/NRedisStack/Search/ISearchCommands.cs index 5752f7a1..157942f7 100644 --- a/src/NRedisStack/Search/ISearchCommands.cs +++ b/src/NRedisStack/Search/ISearchCommands.cs @@ -16,13 +16,6 @@ public interface ISearchCommands /// RedisResult[] _List(); - /// - /// Returns a list of all existing indexes. - /// - /// Array with index names. - /// - Task _ListAsync(); - /// /// Run a search query on an index, and perform aggregate transformations on the results. /// @@ -32,15 +25,6 @@ public interface ISearchCommands /// AggregationResult Aggregate(string index, AggregationRequest query); - /// - /// Run a search query on an index, and perform aggregate transformations on the results. - /// - /// The index name. - /// The query - /// An object - /// - Task AggregateAsync(string index, AggregationRequest query); - /// /// Add an alias to an index. /// @@ -50,15 +34,6 @@ public interface ISearchCommands /// bool AliasAdd(string alias, string index); - /// - /// Add an alias to an index. - /// - /// Alias to be added to an index. - /// The index name. - /// if executed correctly, error otherwise - /// - Task AliasAddAsync(string alias, string index); - /// /// Remove an alias to an index. /// @@ -67,14 +42,6 @@ public interface ISearchCommands /// bool AliasDel(string alias); - /// - /// Remove an alias to an index. - /// - /// Alias to be removed. - /// if executed correctly, error otherwise - /// - Task AliasDelAsync(string alias); - /// /// Add an alias to an index. If the alias is already associated with another index, /// FT.ALIASUPDATE removes the alias association with the previous index. @@ -85,16 +52,6 @@ public interface ISearchCommands /// bool AliasUpdate(string alias, string index); - /// - /// Add an alias to an index. If the alias is already associated with another index, - /// FT.ALIASUPDATE removes the alias association with the previous index. - /// - /// Alias to be removed. - /// The index name. - /// if executed correctly, error otherwise - /// - Task AliasUpdateAsync(string alias, string index); - /// /// Add a new attribute to the index /// @@ -105,16 +62,6 @@ public interface ISearchCommands /// bool Alter(string index, Schema schema, bool skipInitialScan = false); - /// - /// Add a new attribute to the index - /// - /// The index name. - /// If set, does not scan and index. - /// the schema. - /// if executed correctly, error otherwise - /// - Task AlterAsync(string index, Schema schema, bool skipInitialScan = false); - /// /// Retrieve configuration options. /// @@ -123,13 +70,6 @@ public interface ISearchCommands /// Dictionary ConfigGet(string option); - /// - /// Retrieve configuration options. - /// - /// is name of the configuration option, or '*' for all. - /// An array reply of the configuration name and value. - /// - Task> ConfigGetAsync(string option); /// /// Describe configuration options. /// @@ -139,15 +79,6 @@ public interface ISearchCommands /// bool ConfigSet(string option, string value); - /// - /// Describe configuration options. - /// - /// is name of the configuration option, or '*' for all. - /// is value of the configuration option. - /// if executed correctly, error otherwise. - /// - Task ConfigSetAsync(string option, string value); - /// /// Create an index with the given specification. /// @@ -158,16 +89,6 @@ public interface ISearchCommands /// bool Create(string indexName, FTCreateParams parameters, Schema schema); - /// - /// Create an index with the given specification. - /// - /// The index name. - /// Command's parameters. - /// The index schema. - /// if executed correctly, error otherwise - /// - Task CreateAsync(string indexName, FTCreateParams parameters, Schema schema); - /// /// Delete a cursor from the index. /// @@ -177,15 +98,6 @@ public interface ISearchCommands /// bool CursorDel(string indexName, long cursorId); - /// - /// Delete a cursor from the index. - /// - /// The index name - /// The cursor's ID. - /// if it has been deleted, if it did not exist. - /// - Task CursorDelAsync(string indexName, long cursorId); - /// /// Read next results from an existing cursor. /// @@ -196,16 +108,6 @@ public interface ISearchCommands /// AggregationResult CursorRead(string indexName, long cursorId, int? count = null); - /// - /// Read next results from an existing cursor. - /// - /// The index name - /// The cursor's ID. - /// Limit the amount of returned results. - /// A AggregationResult object with the results - /// - Task CursorReadAsync(string indexName, long cursorId, int? count = null); - /// /// Add terms to a dictionary. /// @@ -215,15 +117,6 @@ public interface ISearchCommands /// long DictAdd(string dict, params string[] terms); - /// - /// Add terms to a dictionary. - /// - /// The dictionary name - /// Terms to add to the dictionary.. - /// The number of new terms that were added. - /// - Task DictAddAsync(string dict, params string[] terms); - /// /// Delete terms from a dictionary. /// @@ -233,15 +126,6 @@ public interface ISearchCommands /// long DictDel(string dict, params string[] terms); - /// - /// Delete terms from a dictionary. - /// - /// The dictionary name - /// Terms to delete to the dictionary.. - /// The number of new terms that were deleted. - /// - Task DictDelAsync(string dict, params string[] terms); - /// /// Dump all terms in the given dictionary. /// @@ -250,14 +134,6 @@ public interface ISearchCommands /// RedisResult[] DictDump(string dict); - /// - /// Dump all terms in the given dictionary. - /// - /// The dictionary name - /// An array, where each element is term. - /// - Task DictDumpAsync(string dict); - /// /// Delete an index. /// @@ -267,15 +143,6 @@ public interface ISearchCommands /// bool DropIndex(string indexName, bool dd = false); - /// - /// Delete an index. - /// - /// The index name - /// If set, deletes the actual document hashes. - /// if executed correctly, error otherwise - /// - Task DropIndexAsync(string indexName, bool dd = false); - /// /// Return the execution plan for a complex query /// @@ -285,15 +152,6 @@ public interface ISearchCommands /// string Explain(string indexName, Query q); - /// - /// Return the execution plan for a complex query - /// - /// The index name - /// The query to explain - /// String that representing the execution plan - /// - Task ExplainAsync(string indexName, Query q); - /// /// Return the execution plan for a complex query /// @@ -303,23 +161,6 @@ public interface ISearchCommands /// RedisResult[] ExplainCli(string indexName, Query q); - /// - /// Return the execution plan for a complex query - /// - /// The index name - /// The query to explain - /// An array reply with a string representing the execution plan - /// - Task ExplainCliAsync(string indexName, Query q); - - // /// - // /// Return information and statistics on the index. - // /// - // /// The name of the index. - // /// Dictionary of key and value with information about the index - // /// - // Dictionary Info(RedisValue index); - /// /// Return information and statistics on the index. /// @@ -328,14 +169,6 @@ public interface ISearchCommands /// InfoResult Info(RedisValue index); - /// - /// Return information and statistics on the index. - /// - /// The name of the index. - /// Dictionary of key and value with information about the index - /// - Task InfoAsync(RedisValue index); - // TODO: FT.PROFILE (jedis doesn't have it) /// @@ -347,15 +180,6 @@ public interface ISearchCommands /// SearchResult Search(string indexName, Query q); - /// - /// Search the index - /// - /// The index name - /// a object with the query string and optional parameters - /// a object with the results - /// - Task SearchAsync(string indexName, Query q); - /// /// Dump the contents of a synonym group. /// @@ -366,14 +190,6 @@ public interface ISearchCommands // TODO: FT.SPELLCHECK (jedis doesn't have it) - /// - /// Dump the contents of a synonym group. - /// - /// The index name - /// Pairs of term and an array of synonym groups. - /// - Task>> SynDumpAsync(string indexName); - /// /// Update a synonym group. /// @@ -386,18 +202,6 @@ public interface ISearchCommands /// bool SynUpdate(string indexName, string synonymGroupId, bool skipInitialScan = false, params string[] terms); - /// - /// Update a synonym group. - /// - /// The index name - /// Is synonym group to return - /// does not scan and index, and only documents - /// that are indexed after the update are affected - /// The terms - /// Pairs of term and an array of synonym groups. - /// - Task SynUpdateAsync(string indexName, string synonymGroupId, bool skipInitialScan = false, params string[] terms); - /// /// Return a distinct set of values indexed in a Tag field. /// @@ -406,14 +210,5 @@ public interface ISearchCommands /// List of TAG field values /// RedisResult[] TagVals(string indexName, string fieldName); - - /// - /// Return a distinct set of values indexed in a Tag field. - /// - /// The index name - /// TAG field name - /// List of TAG field values - /// - Task TagValsAsync(string indexName, string fieldName); } } \ No newline at end of file diff --git a/src/NRedisStack/Search/ISearchCommandsAsync.cs b/src/NRedisStack/Search/ISearchCommandsAsync.cs new file mode 100644 index 00000000..20599e9b --- /dev/null +++ b/src/NRedisStack/Search/ISearchCommandsAsync.cs @@ -0,0 +1,213 @@ +using NRedisStack.Search; +using NRedisStack.Search.Aggregation; +using NRedisStack.Search.DataTypes; +using NRedisStack.Search.FT.CREATE; +using StackExchange.Redis; + +namespace NRedisStack +{ + public interface ISearchCommandsAsync + { + /// + /// Returns a list of all existing indexes. + /// + /// Array with index names. + /// + Task _ListAsync(); + + /// + /// Run a search query on an index, and perform aggregate transformations on the results. + /// + /// The index name. + /// The query + /// An object + /// + Task AggregateAsync(string index, AggregationRequest query); + + /// + /// Add an alias to an index. + /// + /// Alias to be added to an index. + /// The index name. + /// if executed correctly, error otherwise + /// + Task AliasAddAsync(string alias, string index); + + /// + /// Remove an alias to an index. + /// + /// Alias to be removed. + /// if executed correctly, error otherwise + /// + Task AliasDelAsync(string alias); + + /// + /// Add an alias to an index. If the alias is already associated with another index, + /// FT.ALIASUPDATE removes the alias association with the previous index. + /// + /// Alias to be removed. + /// The index name. + /// if executed correctly, error otherwise + /// + Task AliasUpdateAsync(string alias, string index); + + /// + /// Add a new attribute to the index + /// + /// The index name. + /// If set, does not scan and index. + /// the schema. + /// if executed correctly, error otherwise + /// + Task AlterAsync(string index, Schema schema, bool skipInitialScan = false); + + /// + /// Retrieve configuration options. + /// + /// is name of the configuration option, or '*' for all. + /// An array reply of the configuration name and value. + /// + Task> ConfigGetAsync(string option); + + /// + /// Describe configuration options. + /// + /// is name of the configuration option, or '*' for all. + /// is value of the configuration option. + /// if executed correctly, error otherwise. + /// + Task ConfigSetAsync(string option, string value); + + /// + /// Create an index with the given specification. + /// + /// The index name. + /// Command's parameters. + /// The index schema. + /// if executed correctly, error otherwise + /// + Task CreateAsync(string indexName, FTCreateParams parameters, Schema schema); + + /// + /// Delete a cursor from the index. + /// + /// The index name + /// The cursor's ID. + /// if it has been deleted, if it did not exist. + /// + Task CursorDelAsync(string indexName, long cursorId); + + /// + /// Read next results from an existing cursor. + /// + /// The index name + /// The cursor's ID. + /// Limit the amount of returned results. + /// A AggregationResult object with the results + /// + Task CursorReadAsync(string indexName, long cursorId, int? count = null); + + /// + /// Add terms to a dictionary. + /// + /// The dictionary name + /// Terms to add to the dictionary.. + /// The number of new terms that were added. + /// + Task DictAddAsync(string dict, params string[] terms); + + /// + /// Delete terms from a dictionary. + /// + /// The dictionary name + /// Terms to delete to the dictionary.. + /// The number of new terms that were deleted. + /// + Task DictDelAsync(string dict, params string[] terms); + + /// + /// Dump all terms in the given dictionary. + /// + /// The dictionary name + /// An array, where each element is term. + /// + Task DictDumpAsync(string dict); + + /// + /// Delete an index. + /// + /// The index name + /// If set, deletes the actual document hashes. + /// if executed correctly, error otherwise + /// + Task DropIndexAsync(string indexName, bool dd = false); + + /// + /// Return the execution plan for a complex query + /// + /// The index name + /// The query to explain + /// String that representing the execution plan + /// + Task ExplainAsync(string indexName, Query q); + + /// + /// Return the execution plan for a complex query + /// + /// The index name + /// The query to explain + /// An array reply with a string representing the execution plan + /// + Task ExplainCliAsync(string indexName, Query q); + + /// + /// Return information and statistics on the index. + /// + /// The name of the index. + /// Dictionary of key and value with information about the index + /// + Task InfoAsync(RedisValue index); + + // TODO: FT.PROFILE (jedis doesn't have it) + + /// + /// Search the index + /// + /// The index name + /// a object with the query string and optional parameters + /// a object with the results + /// + Task SearchAsync(string indexName, Query q); + + // TODO: FT.SPELLCHECK (jedis doesn't have it) + + /// + /// Dump the contents of a synonym group. + /// + /// The index name + /// Pairs of term and an array of synonym groups. + /// + Task>> SynDumpAsync(string indexName); + + /// + /// Update a synonym group. + /// + /// The index name + /// Is synonym group to return + /// does not scan and index, and only documents + /// that are indexed after the update are affected + /// The terms + /// Pairs of term and an array of synonym groups. + /// + Task SynUpdateAsync(string indexName, string synonymGroupId, bool skipInitialScan = false, params string[] terms); + + /// + /// Return a distinct set of values indexed in a Tag field. + /// + /// The index name + /// TAG field name + /// List of TAG field values + /// + Task TagValsAsync(string indexName, string fieldName); + } +} \ No newline at end of file diff --git a/src/NRedisStack/Search/SearchCommands.cs b/src/NRedisStack/Search/SearchCommands.cs index 26b2a525..c1d97c68 100644 --- a/src/NRedisStack/Search/SearchCommands.cs +++ b/src/NRedisStack/Search/SearchCommands.cs @@ -5,10 +5,10 @@ using StackExchange.Redis; namespace NRedisStack { - public class SearchCommands : ISearchCommands + public class SearchCommands : SearchCommandsAsync, ISearchCommands { IDatabase _db; - public SearchCommands(IDatabase db) + public SearchCommands(IDatabase db) : base(db) { _db = db; } @@ -19,12 +19,6 @@ public RedisResult[] _List() return _db.Execute(SearchCommandBuilder._List()).ToArray(); } - /// - public async Task _ListAsync() - { - return (await _db.ExecuteAsync(SearchCommandBuilder._List())).ToArray(); - } - /// public AggregationResult Aggregate(string index, AggregationRequest query) { @@ -41,119 +35,54 @@ public AggregationResult Aggregate(string index, AggregationRequest query) } } - /// - public async Task AggregateAsync(string index, AggregationRequest query) - { - - var result = await _db.ExecuteAsync(SearchCommandBuilder.Aggregate(index, query)); - if (query.IsWithCursor()) - { - var results = (RedisResult[])result; - - return new AggregationResult(results[0], (long)results[1]); - } - else - { - return new AggregationResult(result); - } - } - /// public bool AliasAdd(string alias, string index) { return _db.Execute(SearchCommandBuilder.AliasAdd(alias, index)).OKtoBoolean(); } - /// - public async Task AliasAddAsync(string alias, string index) - { - return (await _db.ExecuteAsync(SearchCommandBuilder.AliasAdd(alias, index))).OKtoBoolean(); - } - /// public bool AliasDel(string alias) { return _db.Execute(SearchCommandBuilder.AliasDel(alias)).OKtoBoolean(); } - /// - public async Task AliasDelAsync(string alias) - { - return (await _db.ExecuteAsync(SearchCommandBuilder.AliasDel(alias))).OKtoBoolean(); - } - /// public bool AliasUpdate(string alias, string index) { return _db.Execute(SearchCommandBuilder.AliasUpdate(alias, index)).OKtoBoolean(); } - /// - public async Task AliasUpdateAsync(string alias, string index) - { - return (await _db.ExecuteAsync(SearchCommandBuilder.AliasUpdate(alias, index))).OKtoBoolean(); - } - /// public bool Alter(string index, Schema schema, bool skipInitialScan = false) { return _db.Execute(SearchCommandBuilder.Alter(index, schema, skipInitialScan)).OKtoBoolean(); } - /// - public async Task AlterAsync(string index, Schema schema, bool skipInitialScan = false) - { - return (await _db.ExecuteAsync(SearchCommandBuilder.Alter(index, schema, skipInitialScan))).OKtoBoolean(); - } - /// public Dictionary ConfigGet(string option) { return _db.Execute(SearchCommandBuilder.ConfigGet(option)).ToConfigDictionary(); } - /// - public async Task> ConfigGetAsync(string option) - { - return (await _db.ExecuteAsync(SearchCommandBuilder.ConfigGet(option))).ToConfigDictionary(); - } - /// public bool ConfigSet(string option, string value) { return _db.Execute(SearchCommandBuilder.ConfigSet(option, value)).OKtoBoolean(); } - /// - public async Task ConfigSetAsync(string option, string value) - { - return (await _db.ExecuteAsync(SearchCommandBuilder.ConfigSet(option, value))).OKtoBoolean(); - } - /// public bool Create(string indexName, FTCreateParams parameters, Schema schema) { return _db.Execute(SearchCommandBuilder.Create(indexName, parameters, schema)).OKtoBoolean(); } - /// - public async Task CreateAsync(string indexName, FTCreateParams parameters, Schema schema) - { - return (await _db.ExecuteAsync(SearchCommandBuilder.Create(indexName, parameters, schema))).OKtoBoolean(); - } - /// public bool CursorDel(string indexName, long cursorId) { return _db.Execute(SearchCommandBuilder.CursorDel(indexName, cursorId)).OKtoBoolean(); } - /// - public async Task CursorDelAsync(string indexName, long cursorId) - { - return (await _db.ExecuteAsync(SearchCommandBuilder.CursorDel(indexName, cursorId))).OKtoBoolean(); - } - /// public AggregationResult CursorRead(string indexName, long cursorId, int? count = null) { @@ -161,93 +90,46 @@ public AggregationResult CursorRead(string indexName, long cursorId, int? count return new AggregationResult(resp[0], (long)resp[1]); } - /// - public async Task CursorReadAsync(string indexName, long cursorId, int? count = null) - { - var resp = (await _db.ExecuteAsync(SearchCommandBuilder.CursorRead(indexName, cursorId, count))).ToArray(); - return new AggregationResult(resp[0], (long)resp[1]); - } - /// public long DictAdd(string dict, params string[] terms) { return _db.Execute(SearchCommandBuilder.DictAdd(dict, terms)).ToLong(); } - /// - public async Task DictAddAsync(string dict, params string[] terms) - { - return (await _db.ExecuteAsync(SearchCommandBuilder.DictAdd(dict, terms))).ToLong(); - } - /// public long DictDel(string dict, params string[] terms) { return _db.Execute(SearchCommandBuilder.DictDel(dict, terms)).ToLong(); } - /// - public async Task DictDelAsync(string dict, params string[] terms) - { - return (await _db.ExecuteAsync(SearchCommandBuilder.DictDel(dict, terms))).ToLong(); - } - /// public RedisResult[] DictDump(string dict) { return _db.Execute(SearchCommandBuilder.DictDump(dict)).ToArray(); } - /// - public async Task DictDumpAsync(string dict) - { - return (await _db.ExecuteAsync(SearchCommandBuilder.DictDump(dict))).ToArray(); - } - /// public bool DropIndex(string indexName, bool dd = false) { return _db.Execute(SearchCommandBuilder.DropIndex(indexName, dd)).OKtoBoolean(); } - /// - public async Task DropIndexAsync(string indexName, bool dd = false) - { - return (await _db.ExecuteAsync(SearchCommandBuilder.DropIndex(indexName, dd))).OKtoBoolean(); - } - /// public string Explain(string indexName, Query q) { return _db.Execute(SearchCommandBuilder.Explain(indexName, q)).ToString(); } - /// - public async Task ExplainAsync(string indexName, Query q) - { - return (await _db.ExecuteAsync(SearchCommandBuilder.Explain(indexName, q))).ToString(); - } - /// public RedisResult[] ExplainCli(string indexName, Query q) { return _db.Execute(SearchCommandBuilder.ExplainCli(indexName, q)).ToArray(); } - /// - public async Task ExplainCliAsync(string indexName, Query q) - { - return (await _db.ExecuteAsync(SearchCommandBuilder.ExplainCli(indexName, q))).ToArray(); - } - /// public InfoResult Info(RedisValue index) => new InfoResult(_db.Execute(SearchCommandBuilder.Info(index))); - /// - public async Task InfoAsync(RedisValue index) => - new InfoResult(await _db.ExecuteAsync(SearchCommandBuilder.Info(index))); - // TODO: FT.PROFILE (jedis doesn't have it) /// @@ -257,13 +139,6 @@ public SearchResult Search(string indexName, Query q) return new SearchResult(resp, !q.NoContent, q.WithScores, q.WithPayloads/*, q.ExplainScore*/); } - /// - public async Task SearchAsync(string indexName, Query q) - { - var resp = (await _db.ExecuteAsync(SearchCommandBuilder.Search(indexName, q))).ToArray(); - return new SearchResult(resp, !q.NoContent, q.WithScores, q.WithPayloads/*, q.ExplainScore*/); - } - /// public Dictionary> SynDump(string indexName) { @@ -280,38 +155,14 @@ public Dictionary> SynDump(string indexName) // TODO: FT.SPELLCHECK (jedis doesn't have it) - /// - public async Task>> SynDumpAsync(string indexName) - { - var resp = (await _db.ExecuteAsync(SearchCommandBuilder.SynDump(indexName))).ToArray(); - var result = new Dictionary>(); - for (int i = 0; i < resp.Length; i += 2) - { - var term = resp[i].ToString(); - var synonyms = (resp[i + 1]).ToArray().Select(x => x.ToString()).ToList(); // TODO: consider leave synonyms as RedisValue[] - result.Add(term, synonyms); - } - return result; - } - /// public bool SynUpdate(string indexName, string synonymGroupId, bool skipInitialScan = false, params string[] terms) { return _db.Execute(SearchCommandBuilder.SynUpdate(indexName, synonymGroupId, skipInitialScan, terms)).OKtoBoolean(); } - /// - public async Task SynUpdateAsync(string indexName, string synonymGroupId, bool skipInitialScan = false, params string[] terms) - { - return (await _db.ExecuteAsync(SearchCommandBuilder.SynUpdate(indexName, synonymGroupId, skipInitialScan, terms))).OKtoBoolean(); - } - /// public RedisResult[] TagVals(string indexName, string fieldName) => //TODO: consider return Set _db.Execute(SearchCommandBuilder.TagVals(indexName, fieldName)).ToArray(); - - /// - public async Task TagValsAsync(string indexName, string fieldName) => //TODO: consider return Set - (await _db.ExecuteAsync(SearchCommandBuilder.TagVals(indexName, fieldName))).ToArray(); } } \ No newline at end of file diff --git a/src/NRedisStack/Search/SearchCommandsAsync.cs b/src/NRedisStack/Search/SearchCommandsAsync.cs new file mode 100644 index 00000000..22c03014 --- /dev/null +++ b/src/NRedisStack/Search/SearchCommandsAsync.cs @@ -0,0 +1,169 @@ +using NRedisStack.Search; +using NRedisStack.Search.Aggregation; +using NRedisStack.Search.DataTypes; +using NRedisStack.Search.FT.CREATE; +using StackExchange.Redis; +namespace NRedisStack +{ + public class SearchCommandsAsync : ISearchCommandsAsync + { + IDatabaseAsync _db; + public SearchCommandsAsync(IDatabaseAsync db) + { + _db = db; + } + + /// + public async Task _ListAsync() + { + return (await _db.ExecuteAsync(SearchCommandBuilder._List())).ToArray(); + } + + /// + public async Task AggregateAsync(string index, AggregationRequest query) + { + + var result = await _db.ExecuteAsync(SearchCommandBuilder.Aggregate(index, query)); + if (query.IsWithCursor()) + { + var results = (RedisResult[])result; + + return new AggregationResult(results[0], (long)results[1]); + } + else + { + return new AggregationResult(result); + } + } + + /// + public async Task AliasAddAsync(string alias, string index) + { + return (await _db.ExecuteAsync(SearchCommandBuilder.AliasAdd(alias, index))).OKtoBoolean(); + } + + /// + public async Task AliasDelAsync(string alias) + { + return (await _db.ExecuteAsync(SearchCommandBuilder.AliasDel(alias))).OKtoBoolean(); + } + + /// + public async Task AliasUpdateAsync(string alias, string index) + { + return (await _db.ExecuteAsync(SearchCommandBuilder.AliasUpdate(alias, index))).OKtoBoolean(); + } + + /// + public async Task AlterAsync(string index, Schema schema, bool skipInitialScan = false) + { + return (await _db.ExecuteAsync(SearchCommandBuilder.Alter(index, schema, skipInitialScan))).OKtoBoolean(); + } + + /// + public async Task> ConfigGetAsync(string option) + { + return (await _db.ExecuteAsync(SearchCommandBuilder.ConfigGet(option))).ToConfigDictionary(); + } + + /// + public async Task ConfigSetAsync(string option, string value) + { + return (await _db.ExecuteAsync(SearchCommandBuilder.ConfigSet(option, value))).OKtoBoolean(); + } + + /// + public async Task CreateAsync(string indexName, FTCreateParams parameters, Schema schema) + { + return (await _db.ExecuteAsync(SearchCommandBuilder.Create(indexName, parameters, schema))).OKtoBoolean(); + } + + /// + public async Task CursorDelAsync(string indexName, long cursorId) + { + return (await _db.ExecuteAsync(SearchCommandBuilder.CursorDel(indexName, cursorId))).OKtoBoolean(); + } + + /// + public async Task CursorReadAsync(string indexName, long cursorId, int? count = null) + { + var resp = (await _db.ExecuteAsync(SearchCommandBuilder.CursorRead(indexName, cursorId, count))).ToArray(); + return new AggregationResult(resp[0], (long)resp[1]); + } + + /// + public async Task DictAddAsync(string dict, params string[] terms) + { + return (await _db.ExecuteAsync(SearchCommandBuilder.DictAdd(dict, terms))).ToLong(); + } + + /// + public async Task DictDelAsync(string dict, params string[] terms) + { + return (await _db.ExecuteAsync(SearchCommandBuilder.DictDel(dict, terms))).ToLong(); + } + + /// + public async Task DictDumpAsync(string dict) + { + return (await _db.ExecuteAsync(SearchCommandBuilder.DictDump(dict))).ToArray(); + } + + /// + public async Task DropIndexAsync(string indexName, bool dd = false) + { + return (await _db.ExecuteAsync(SearchCommandBuilder.DropIndex(indexName, dd))).OKtoBoolean(); + } + + /// + public async Task ExplainAsync(string indexName, Query q) + { + return (await _db.ExecuteAsync(SearchCommandBuilder.Explain(indexName, q))).ToString(); + } + + /// + public async Task ExplainCliAsync(string indexName, Query q) + { + return (await _db.ExecuteAsync(SearchCommandBuilder.ExplainCli(indexName, q))).ToArray(); + } + + /// + public async Task InfoAsync(RedisValue index) => + new InfoResult(await _db.ExecuteAsync(SearchCommandBuilder.Info(index))); + + // TODO: FT.PROFILE (jedis doesn't have it) + + /// + public async Task SearchAsync(string indexName, Query q) + { + var resp = (await _db.ExecuteAsync(SearchCommandBuilder.Search(indexName, q))).ToArray(); + return new SearchResult(resp, !q.NoContent, q.WithScores, q.WithPayloads/*, q.ExplainScore*/); + } + + // TODO: FT.SPELLCHECK (jedis doesn't have it) + + /// + public async Task>> SynDumpAsync(string indexName) + { + var resp = (await _db.ExecuteAsync(SearchCommandBuilder.SynDump(indexName))).ToArray(); + var result = new Dictionary>(); + for (int i = 0; i < resp.Length; i += 2) + { + var term = resp[i].ToString(); + var synonyms = (resp[i + 1]).ToArray().Select(x => x.ToString()).ToList(); // TODO: consider leave synonyms as RedisValue[] + result.Add(term, synonyms); + } + return result; + } + + /// + public async Task SynUpdateAsync(string indexName, string synonymGroupId, bool skipInitialScan = false, params string[] terms) + { + return (await _db.ExecuteAsync(SearchCommandBuilder.SynUpdate(indexName, synonymGroupId, skipInitialScan, terms))).OKtoBoolean(); + } + + /// + public async Task TagValsAsync(string indexName, string fieldName) => //TODO: consider return Set + (await _db.ExecuteAsync(SearchCommandBuilder.TagVals(indexName, fieldName))).ToArray(); + } +} \ No newline at end of file From fed18cb13a064232e7158c2032e389abe45a99ca Mon Sep 17 00:00:00 2001 From: shacharPash Date: Thu, 26 Jan 2023 18:16:59 +0200 Subject: [PATCH 16/21] split Tdigest --- src/NRedisStack/Tdigest/ITdigestCommands.cs | 128 ----------------- .../Tdigest/ITdigestCommandsAsync.cs | 134 ++++++++++++++++++ src/NRedisStack/Tdigest/TdigestCommands.cs | 91 +----------- .../Tdigest/TdigestCommandsAsync.cs | 99 +++++++++++++ 4 files changed, 235 insertions(+), 217 deletions(-) create mode 100644 src/NRedisStack/Tdigest/ITdigestCommandsAsync.cs create mode 100644 src/NRedisStack/Tdigest/TdigestCommandsAsync.cs diff --git a/src/NRedisStack/Tdigest/ITdigestCommands.cs b/src/NRedisStack/Tdigest/ITdigestCommands.cs index bec47178..667ab676 100644 --- a/src/NRedisStack/Tdigest/ITdigestCommands.cs +++ b/src/NRedisStack/Tdigest/ITdigestCommands.cs @@ -15,15 +15,6 @@ public interface ITdigestCommands /// bool Add(RedisKey key, params double[] values); - /// - /// Adds one or more observations to a t-digest sketch. - /// - /// The name of the sketch. - /// The value of the observation. - /// if executed correctly, error otherwise - /// - Task AddAsync(RedisKey key, params double[] values); - /// /// Estimate the fraction of all observations added which are <= value. /// @@ -33,15 +24,6 @@ public interface ITdigestCommands /// double[] CDF(RedisKey key, params double[] values); - /// - /// Estimate the fraction of all observations added which are <= value. - /// - /// The name of the sketch. - /// upper limit of observation value. - /// double-reply - estimation of the fraction of all observations added which are <= value - /// - Task CDFAsync(RedisKey key, params double[] values); - /// /// Allocate memory and initialize a t-digest sketch. /// @@ -51,15 +33,6 @@ public interface ITdigestCommands /// bool Create(RedisKey key, long compression = 100); - /// - /// Allocate memory and initialize a t-digest sketch. - /// - /// The name of the sketch. - /// The compression parameter. - /// if executed correctly, error otherwise - /// - Task CreateAsync(RedisKey key, long compression = 100); - /// /// Returns information about a sketch. /// @@ -68,14 +41,6 @@ public interface ITdigestCommands /// TdigestInformation Info(RedisKey key); - /// - /// Returns information about a sketch. - /// - /// The name of the sketch. - /// information about a sketch - /// - Task InfoAsync(RedisKey key); - /// /// Get the maximum observation value from the sketch. @@ -85,14 +50,6 @@ public interface ITdigestCommands /// double Max(RedisKey key); - /// - /// Get the maximum observation value from the sketch. - /// - /// The name of the sketch. - /// the maximum observation value from the sketch - /// - Task MaxAsync(RedisKey key); - /// /// Get the minimum observation value from the sketch. /// @@ -101,14 +58,6 @@ public interface ITdigestCommands /// double Min(RedisKey key); - /// - /// Get the minimum observation value from the sketch. - /// - /// The name of the sketch. - /// the minimum observation value from the sketch - /// - Task MinAsync(RedisKey key); - /// /// Merges all of the values from 'from' keys to 'destination-key' sketch /// @@ -120,17 +69,6 @@ public interface ITdigestCommands /// bool Merge(RedisKey destinationKey, long compression = default(long), bool overide = false, params RedisKey[] sourceKeys); - /// - /// Merges all of the values from 'from' keys to 'destination-key' sketch - /// - /// TSketch to copy observation values to (a t-digest data structure). - /// The compression parameter. - /// If destination already exists, it is overwritten. - /// Sketch to copy observation values from (a t-digest data structure). - /// if executed correctly, error otherwise - /// - Task MergeAsync(RedisKey destinationKey, long compression = default(long), bool overide = false, params RedisKey[] sourceKeys); - /// /// Returns estimates of one or more cutoffs such that a specified fraction of the observations /// added to this t-digest would be less than or equal to each of the specified cutoffs. @@ -140,16 +78,6 @@ public interface ITdigestCommands /// An array of results populated with quantile_1, cutoff_1, quantile_2, cutoff_2, ..., quantile_N, cutoff_N. /// double[] Quantile(RedisKey key, params double[] quantile); - - /// - /// Returns estimates of one or more cutoffs such that a specified fraction of the observations - ///added to this t-digest would be less than or equal to each of the specified cutoffs. - /// - /// The name of the sketch (a t-digest data structure). - /// The desired fraction (between 0 and 1 inclusively). - /// An array of results populated with quantile_1, cutoff_1, quantile_2, cutoff_2, ..., quantile_N, cutoff_N. - /// - Task QuantileAsync(RedisKey key, params double[] quantile); /// /// Retrieve the estimated rank of value (the number of observations in the sketch /// that are smaller than value + half the number of observations that are equal to value). @@ -160,16 +88,6 @@ public interface ITdigestCommands /// long[] Rank(RedisKey key, params long[] values); - /// - /// Retrieve the estimated rank of value (the number of observations in the sketch - /// that are smaller than value + half the number of observations that are equal to value). - /// - /// The name of the sketch (a t-digest data structure). - /// input value, for which the rank will be determined. - /// an array of results populated with rank_1, rank_2, ..., rank_N. - /// - Task RankAsync(RedisKey key, params long[] values); - /// /// Retrieve the estimated rank of value (the number of observations in the sketch /// that are larger than value + half the number of observations that are equal to value). @@ -180,16 +98,6 @@ public interface ITdigestCommands /// long[] RevRank(RedisKey key, params long[] values); - /// - /// Retrieve the estimated rank of value (the number of observations in the sketch - /// that are larger than value + half the number of observations that are equal to value). - /// - /// The name of the sketch (a t-digest data structure). - /// input value, for which the rank will be determined. - /// an array of results populated with rank_1, rank_2, ..., rank_N. - /// - Task RevRankAsync(RedisKey key, params long[] values); - /// /// Retrieve an estimation of the value with the given the rank. /// @@ -199,15 +107,6 @@ public interface ITdigestCommands /// double[] ByRank(RedisKey key, params long[] ranks); - /// - /// Retrieve an estimation of the value with the given the rank. - /// - /// The name of the sketch (a t-digest data structure). - /// input rank, for which the value will be determined. - /// an array of results populated with value_1, value_2, ..., value_N. - /// - Task ByRankAsync(RedisKey key, params long[] ranks); - /// /// Retrieve an estimation of the value with the given the reverse rank. /// @@ -217,15 +116,6 @@ public interface ITdigestCommands /// double[] ByRevRank(RedisKey key, params long[] ranks); - /// - /// Retrieve an estimation of the value with the given the reverse rank. - /// - /// The name of the sketch (a t-digest data structure). - /// input reverse rank, for which the value will be determined. - /// an array of results populated with value_1, value_2, ..., value_N. - /// - Task ByRevRankAsync(RedisKey key, params long[] ranks); - /// /// Reset the sketch - empty the sketch and re-initialize it /// @@ -234,14 +124,6 @@ public interface ITdigestCommands /// bool Reset(RedisKey key); - /// - /// Reset the sketch - empty the sketch and re-initialize it - /// - /// The name of the sketch (a t-digest data structure). - /// if executed correctly, error otherwise. - /// - Task ResetAsync(RedisKey key); - /// /// Reset the sketch - empty the sketch and re-initialize it /// @@ -251,15 +133,5 @@ public interface ITdigestCommands /// estimation of the mean value. Will return NaN if the sketch is empty. /// double TrimmedMean(RedisKey key, double lowCutQuantile, double highCutQuantile); - - /// - /// Reset the sketch - empty the sketch and re-initialize it - /// - /// The name of the sketch (a t-digest data structure). - /// Exclude observation values lower than this quantile. - /// Exclude observation values higher than this quantile. - /// estimation of the mean value. Will return NaN if the sketch is empty. - /// - Task TrimmedMeanAsync(RedisKey key, double lowCutQuantile, double highCutQuantile); } } \ No newline at end of file diff --git a/src/NRedisStack/Tdigest/ITdigestCommandsAsync.cs b/src/NRedisStack/Tdigest/ITdigestCommandsAsync.cs new file mode 100644 index 00000000..c1cf850b --- /dev/null +++ b/src/NRedisStack/Tdigest/ITdigestCommandsAsync.cs @@ -0,0 +1,134 @@ +using NRedisStack.Tdigest.DataTypes; +using StackExchange.Redis; +namespace NRedisStack +{ + public interface ITdigestCommandsAsync + { + /// + /// Adds one or more observations to a t-digest sketch. + /// + /// The name of the sketch. + /// The value of the observation. + /// if executed correctly, error otherwise + /// + Task AddAsync(RedisKey key, params double[] values); + + /// + /// Estimate the fraction of all observations added which are <= value. + /// + /// The name of the sketch. + /// upper limit of observation value. + /// double-reply - estimation of the fraction of all observations added which are <= value + /// + Task CDFAsync(RedisKey key, params double[] values); + + /// + /// Allocate memory and initialize a t-digest sketch. + /// + /// The name of the sketch. + /// The compression parameter. + /// if executed correctly, error otherwise + /// + Task CreateAsync(RedisKey key, long compression = 100); + /// + /// Returns information about a sketch. + /// + /// The name of the sketch. + /// information about a sketch + /// + Task InfoAsync(RedisKey key); + + /// + /// Get the maximum observation value from the sketch. + /// + /// The name of the sketch. + /// the maximum observation value from the sketch + /// + Task MaxAsync(RedisKey key); + + /// + /// Get the minimum observation value from the sketch. + /// + /// The name of the sketch. + /// the minimum observation value from the sketch + /// + Task MinAsync(RedisKey key); + + /// + /// Merges all of the values from 'from' keys to 'destination-key' sketch + /// + /// TSketch to copy observation values to (a t-digest data structure). + /// The compression parameter. + /// If destination already exists, it is overwritten. + /// Sketch to copy observation values from (a t-digest data structure). + /// if executed correctly, error otherwise + /// + Task MergeAsync(RedisKey destinationKey, long compression = default(long), bool overide = false, params RedisKey[] sourceKeys); + + /// + /// Returns estimates of one or more cutoffs such that a specified fraction of the observations + ///added to this t-digest would be less than or equal to each of the specified cutoffs. + /// + /// The name of the sketch (a t-digest data structure). + /// The desired fraction (between 0 and 1 inclusively). + /// An array of results populated with quantile_1, cutoff_1, quantile_2, cutoff_2, ..., quantile_N, cutoff_N. + /// + Task QuantileAsync(RedisKey key, params double[] quantile); + + /// + /// Retrieve the estimated rank of value (the number of observations in the sketch + /// that are smaller than value + half the number of observations that are equal to value). + /// + /// The name of the sketch (a t-digest data structure). + /// input value, for which the rank will be determined. + /// an array of results populated with rank_1, rank_2, ..., rank_N. + /// + Task RankAsync(RedisKey key, params long[] values); + + /// + /// Retrieve the estimated rank of value (the number of observations in the sketch + /// that are larger than value + half the number of observations that are equal to value). + /// + /// The name of the sketch (a t-digest data structure). + /// input value, for which the rank will be determined. + /// an array of results populated with rank_1, rank_2, ..., rank_N. + /// + Task RevRankAsync(RedisKey key, params long[] values); + + /// + /// Retrieve an estimation of the value with the given the rank. + /// + /// The name of the sketch (a t-digest data structure). + /// input rank, for which the value will be determined. + /// an array of results populated with value_1, value_2, ..., value_N. + /// + Task ByRankAsync(RedisKey key, params long[] ranks); + + /// + /// Retrieve an estimation of the value with the given the reverse rank. + /// + /// The name of the sketch (a t-digest data structure). + /// input reverse rank, for which the value will be determined. + /// an array of results populated with value_1, value_2, ..., value_N. + /// + Task ByRevRankAsync(RedisKey key, params long[] ranks); + + /// + /// Reset the sketch - empty the sketch and re-initialize it + /// + /// The name of the sketch (a t-digest data structure). + /// if executed correctly, error otherwise. + /// + Task ResetAsync(RedisKey key); + + /// + /// Reset the sketch - empty the sketch and re-initialize it + /// + /// The name of the sketch (a t-digest data structure). + /// Exclude observation values lower than this quantile. + /// Exclude observation values higher than this quantile. + /// estimation of the mean value. Will return NaN if the sketch is empty. + /// + Task TrimmedMeanAsync(RedisKey key, double lowCutQuantile, double highCutQuantile); + } +} \ No newline at end of file diff --git a/src/NRedisStack/Tdigest/TdigestCommands.cs b/src/NRedisStack/Tdigest/TdigestCommands.cs index 230571d5..9ee9fd56 100644 --- a/src/NRedisStack/Tdigest/TdigestCommands.cs +++ b/src/NRedisStack/Tdigest/TdigestCommands.cs @@ -1,13 +1,12 @@ using NRedisStack.Tdigest.DataTypes; -using NRedisStack.Literals; using StackExchange.Redis; namespace NRedisStack { - public class TdigestCommands : ITdigestCommands + public class TdigestCommands : TdigestCommandsAsync, ITdigestCommands { IDatabase _db; - public TdigestCommands(IDatabase db) + public TdigestCommands(IDatabase db) : base(db) { _db = db; } @@ -18,168 +17,82 @@ public bool Add(RedisKey key, params double[] values) return _db.Execute(TdigestCommandBuilder.Add(key, values)).OKtoBoolean(); } - /// - public async Task AddAsync(RedisKey key, params double[] values) - { - return (await _db.ExecuteAsync(TdigestCommandBuilder.Add(key, values))).OKtoBoolean(); - } - /// public double[] CDF(RedisKey key, params double[] values) { return _db.Execute(TdigestCommandBuilder.CDF(key, values)).ToDoubleArray(); } - /// - public async Task CDFAsync(RedisKey key, params double[] values) - { - return (await _db.ExecuteAsync(TdigestCommandBuilder.CDF(key, values))).ToDoubleArray(); - } - /// public bool Create(RedisKey key, long compression = 100) { return _db.Execute(TdigestCommandBuilder.Create(key, compression)).OKtoBoolean(); } - /// - public async Task CreateAsync(RedisKey key, long compression = 100) - { - return (await _db.ExecuteAsync(TdigestCommandBuilder.Create(key, compression))).OKtoBoolean(); - } - /// public TdigestInformation Info(RedisKey key) { return _db.Execute(TdigestCommandBuilder.Info(key)).ToTdigestInfo(); } - /// - public async Task InfoAsync(RedisKey key) - { - return (await _db.ExecuteAsync(TdigestCommandBuilder.Info(key))).ToTdigestInfo(); - } - - /// public double Max(RedisKey key) { return _db.Execute(TdigestCommandBuilder.Max(key)).ToDouble(); } - /// - public async Task MaxAsync(RedisKey key) - { - return (await _db.ExecuteAsync(TdigestCommandBuilder.Max(key))).ToDouble(); - } - /// public double Min(RedisKey key) { return _db.Execute(TdigestCommandBuilder.Min(key)).ToDouble(); } - /// - public async Task MinAsync(RedisKey key) - { - return (await _db.ExecuteAsync(TdigestCommandBuilder.Min(key))).ToDouble(); - } - /// public bool Merge(RedisKey destinationKey, long compression = default(long), bool overide = false, params RedisKey[] sourceKeys) { return _db.Execute(TdigestCommandBuilder.Merge(destinationKey, compression, overide, sourceKeys)).OKtoBoolean(); } - /// - public async Task MergeAsync(RedisKey destinationKey, long compression = default(long), bool overide = false, params RedisKey[] sourceKeys) - { - return (await _db.ExecuteAsync(TdigestCommandBuilder.Merge(destinationKey, compression, overide, sourceKeys))).OKtoBoolean(); - } - /// public double[] Quantile(RedisKey key, params double[] quantile) { return _db.Execute(TdigestCommandBuilder.Quantile(key, quantile)).ToDoubleArray(); } - ///added to this t-digest would be less than or equal to each of the specified cutoffs. - /// - public async Task QuantileAsync(RedisKey key, params double[] quantile) - { - return (await _db.ExecuteAsync(TdigestCommandBuilder.Quantile(key, quantile))).ToDoubleArray(); - } - /// public long[] Rank(RedisKey key, params long[] values) { return _db.Execute(TdigestCommandBuilder.Rank(key, values)).ToLongArray(); } - /// - public async Task RankAsync(RedisKey key, params long[] values) - { - return (await _db.ExecuteAsync(TdigestCommandBuilder.Rank(key, values))).ToLongArray(); - } - /// public long[] RevRank(RedisKey key, params long[] values) { return _db.Execute(TdigestCommandBuilder.RevRank(key, values)).ToLongArray(); } - /// - public async Task RevRankAsync(RedisKey key, params long[] values) - { - return (await _db.ExecuteAsync(TdigestCommandBuilder.RevRank(key, values))).ToLongArray(); - } - /// public double[] ByRank(RedisKey key, params long[] ranks) { return _db.Execute(TdigestCommandBuilder.ByRank(key, ranks)).ToDoubleArray(); } - /// - public async Task ByRankAsync(RedisKey key, params long[] ranks) - { - return (await _db.ExecuteAsync(TdigestCommandBuilder.ByRank(key, ranks))).ToDoubleArray(); - } - /// public double[] ByRevRank(RedisKey key, params long[] ranks) { return _db.Execute(TdigestCommandBuilder.ByRevRank(key, ranks)).ToDoubleArray(); } - /// - public async Task ByRevRankAsync(RedisKey key, params long[] ranks) - { - return (await _db.ExecuteAsync(TdigestCommandBuilder.ByRevRank(key, ranks))).ToDoubleArray(); - } - /// public bool Reset(RedisKey key) { return _db.Execute(TdigestCommandBuilder.Reset(key)).OKtoBoolean(); } - /// - public async Task ResetAsync(RedisKey key) - { - return (await _db.ExecuteAsync(TdigestCommandBuilder.Reset(key))).OKtoBoolean(); - } - /// public double TrimmedMean(RedisKey key, double lowCutQuantile, double highCutQuantile) { return _db.Execute(TdigestCommandBuilder.TrimmedMean(key, lowCutQuantile, highCutQuantile)).ToDouble(); } - - /// - public async Task TrimmedMeanAsync(RedisKey key, double lowCutQuantile, double highCutQuantile) - { - return (await _db.ExecuteAsync(TdigestCommandBuilder.TrimmedMean(key, lowCutQuantile, highCutQuantile))).ToDouble(); - } } } \ No newline at end of file diff --git a/src/NRedisStack/Tdigest/TdigestCommandsAsync.cs b/src/NRedisStack/Tdigest/TdigestCommandsAsync.cs new file mode 100644 index 00000000..ee162de4 --- /dev/null +++ b/src/NRedisStack/Tdigest/TdigestCommandsAsync.cs @@ -0,0 +1,99 @@ +using NRedisStack.Tdigest.DataTypes; +using StackExchange.Redis; +namespace NRedisStack +{ + + public class TdigestCommandsAsync : ITdigestCommandsAsync + { + IDatabaseAsync _db; + public TdigestCommandsAsync(IDatabaseAsync db) + { + _db = db; + } + + /// + public async Task AddAsync(RedisKey key, params double[] values) + { + return (await _db.ExecuteAsync(TdigestCommandBuilder.Add(key, values))).OKtoBoolean(); + } + + /// + public async Task CDFAsync(RedisKey key, params double[] values) + { + return (await _db.ExecuteAsync(TdigestCommandBuilder.CDF(key, values))).ToDoubleArray(); + } + + /// + public async Task CreateAsync(RedisKey key, long compression = 100) + { + return (await _db.ExecuteAsync(TdigestCommandBuilder.Create(key, compression))).OKtoBoolean(); + } + + /// + public async Task InfoAsync(RedisKey key) + { + return (await _db.ExecuteAsync(TdigestCommandBuilder.Info(key))).ToTdigestInfo(); + } + + /// + public async Task MaxAsync(RedisKey key) + { + return (await _db.ExecuteAsync(TdigestCommandBuilder.Max(key))).ToDouble(); + } + + /// + public async Task MinAsync(RedisKey key) + { + return (await _db.ExecuteAsync(TdigestCommandBuilder.Min(key))).ToDouble(); + } + + /// + public async Task MergeAsync(RedisKey destinationKey, long compression = default(long), bool overide = false, params RedisKey[] sourceKeys) + { + return (await _db.ExecuteAsync(TdigestCommandBuilder.Merge(destinationKey, compression, overide, sourceKeys))).OKtoBoolean(); + } + + ///added to this t-digest would be less than or equal to each of the specified cutoffs. + /// + public async Task QuantileAsync(RedisKey key, params double[] quantile) + { + return (await _db.ExecuteAsync(TdigestCommandBuilder.Quantile(key, quantile))).ToDoubleArray(); + } + + /// + public async Task RankAsync(RedisKey key, params long[] values) + { + return (await _db.ExecuteAsync(TdigestCommandBuilder.Rank(key, values))).ToLongArray(); + } + + /// + public async Task RevRankAsync(RedisKey key, params long[] values) + { + return (await _db.ExecuteAsync(TdigestCommandBuilder.RevRank(key, values))).ToLongArray(); + } + + /// + public async Task ByRankAsync(RedisKey key, params long[] ranks) + { + return (await _db.ExecuteAsync(TdigestCommandBuilder.ByRank(key, ranks))).ToDoubleArray(); + } + + /// + public async Task ByRevRankAsync(RedisKey key, params long[] ranks) + { + return (await _db.ExecuteAsync(TdigestCommandBuilder.ByRevRank(key, ranks))).ToDoubleArray(); + } + + /// + public async Task ResetAsync(RedisKey key) + { + return (await _db.ExecuteAsync(TdigestCommandBuilder.Reset(key))).OKtoBoolean(); + } + + /// + public async Task TrimmedMeanAsync(RedisKey key, double lowCutQuantile, double highCutQuantile) + { + return (await _db.ExecuteAsync(TdigestCommandBuilder.TrimmedMean(key, lowCutQuantile, highCutQuantile))).ToDouble(); + } + } +} \ No newline at end of file From 2419e120965bf3d3cab8f5fd649ca689ec5f91b3 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Thu, 26 Jan 2023 18:39:25 +0200 Subject: [PATCH 17/21] split TS --- .../TimeSeries/ITimeSeriesCommands.cs | 301 ---------------- .../TimeSeries/ITimeSeriesCommandsAsync.cs | 332 ++++++++++++++++++ .../TimeSeries/TimeSeriesCommands.cs | 178 +--------- .../TimeSeries/TimeSeriesCommandsAsync.cs | 208 +++++++++++ .../TimeSeries/TestAPI/TestDelAsync.cs | 2 +- .../TimeSeries/TestAPI/TestMRangeAsync.cs | 2 +- .../TimeSeries/TestAPI/TestMRevRangeAsync.cs | 2 +- .../TimeSeries/TestAPI/TestRangeAsync.cs | 2 +- .../TimeSeries/TestAPI/TestRevRangeAsync.cs | 2 +- 9 files changed, 547 insertions(+), 482 deletions(-) create mode 100644 src/NRedisStack/TimeSeries/ITimeSeriesCommandsAsync.cs create mode 100644 src/NRedisStack/TimeSeries/TimeSeriesCommandsAsync.cs diff --git a/src/NRedisStack/TimeSeries/ITimeSeriesCommands.cs b/src/NRedisStack/TimeSeries/ITimeSeriesCommands.cs index 61a20ac1..e9c13abf 100644 --- a/src/NRedisStack/TimeSeries/ITimeSeriesCommands.cs +++ b/src/NRedisStack/TimeSeries/ITimeSeriesCommands.cs @@ -20,20 +20,6 @@ public interface ITimeSeriesCommands /// bool Create(string key, long? retentionTime = null, IReadOnlyCollection labels = null, bool? uncompressed = null, long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null); - /// - /// Create a new time-series. - /// - /// Key name for timeseries - /// Optional: Maximum age for samples compared to last event time (in milliseconds) - /// Optional: Collaction of label-value pairs that represent metadata labels of the key - /// Optional: Adding this flag will keep data in an uncompressed form - /// Optional: Each time-series uses chunks of memory of fixed size for time series samples. - /// You can alter the default TS_db chunk size by passing the chunk_size argument (in Bytes) - /// Optinal: Define handling of duplicate samples behavior (avalible for RedisTimeseries >= 1.4) - /// If the operation executed successfully - /// - Task CreateAsync(string key, long? retentionTime = null, IReadOnlyCollection labels = null, bool? uncompressed = null, long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null); - #endregion #region Update @@ -51,19 +37,6 @@ public interface ITimeSeriesCommands /// bool Alter(string key, long? retentionTime = null, long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null, IReadOnlyCollection? labels = null); - /// - /// Update the retention, labels of an existing key. - /// - /// Key name for timeseries - /// Optional: Maximum age for samples compared to last event time (in milliseconds) - /// Optional: Each time-series uses chunks of memory of fixed size for time series samples. - /// You can alter the default TS_db chunk size by passing the chunk_size argument (in Bytes) - /// Optinal: Define handling of duplicate samples behavior (avalible for RedisTimeseries >= 1.4) - /// Optional: Collaction of label-value pairs that represent metadata labels of the key - /// If the operation executed successfully - /// - Task AlterAsync(string key, long? retentionTime = null, long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null, IReadOnlyCollection? labels = null); - /// /// Append (or create and append) a new sample to the series. /// @@ -82,21 +55,6 @@ TimeStamp Add(string key, TimeStamp timestamp, double value, long? retentionTime IReadOnlyCollection labels = null, bool? uncompressed = null, long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null); - /// - /// Append (or create and append) a new sample to the series. - /// - /// Key name for timeseries - /// TimeStamp to add. UNIX timestamp of the sample. * can be used for automatic timestamp (using the system clock) - /// Numeric data value of the sample. - /// Optional: Maximum age for samples compared to last event time (in milliseconds) - /// Optional: Collaction of label-value pairs that represent metadata labels of the key - /// Optional: Adding this flag will keep data in an uncompressed form - /// Optional: Each time-series uses chunks of memory of fixed size for time series samples. - /// You can alter the default TS_db chunk size by passing the chunk_size argument (in Bytes) - /// Optioal: overwrite key and database configuration for DUPLICATE_POLICY - /// The timestamp value of the new sample - /// - Task AddAsync(string key, TimeStamp timestamp, double value, long? retentionTime = null, IReadOnlyCollection labels = null, bool? uncompressed = null, long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null); /// /// Append new samples to multiple series. /// @@ -104,13 +62,6 @@ TimeStamp Add(string key, TimeStamp timestamp, double value, long? retentionTime /// List of timestamps of the new samples /// IReadOnlyList MAdd(IReadOnlyCollection<(string key, TimeStamp timestamp, double value)> sequence); - /// - /// Append new samples to multiple series. - /// - /// An Collection of (key, timestamp, value) tuples - /// List of timestamps of the new samples - /// - Task> MAddAsync(IReadOnlyCollection<(string key, TimeStamp timestamp, double value)> sequence); /// /// Creates a new sample that increments the latest sample's value. @@ -127,21 +78,6 @@ TimeStamp Add(string key, TimeStamp timestamp, double value, long? retentionTime /// TimeStamp IncrBy(string key, double value, TimeStamp? timestamp = null, long? retentionTime = null, IReadOnlyCollection? labels = null, bool? uncompressed = null, long? chunkSizeBytes = null); - /// - /// Creates a new sample that increments the latest sample's value. - /// - /// Key name for timeseries - /// Delta to add - /// Optional: TimeStamp to add. UNIX timestamp of the sample. * can be used for automatic timestamp (using the system clock) - /// Optional: Maximum age for samples compared to last event time (in milliseconds) - /// Optional: Collaction of label-value pairs that represent metadata labels of the key - /// Optional: Adding this flag will keep data in an uncompressed form - /// Optional: Each time-series uses chunks of memory of fixed size for time series samples. - /// You can alter the default TS_db chunk size by passing the chunk_size argument (in Bytes) - /// The latests sample timestamp (updated sample) - /// - Task IncrByAsync(string key, double value, TimeStamp? timestamp = null, long? retentionTime = null, IReadOnlyCollection? labels = null, bool? uncompressed = null, long? chunkSizeBytes = null); - /// /// Creates a new sample that decrements the latest sample's value. /// @@ -157,21 +93,6 @@ TimeStamp Add(string key, TimeStamp timestamp, double value, long? retentionTime /// TimeStamp DecrBy(string key, double value, TimeStamp? timestamp = null, long? retentionTime = null, IReadOnlyCollection? labels = null, bool? uncompressed = null, long? chunkSizeBytes = null); - /// - /// Creates a new sample that decrements the latest sample's value. - /// - /// Key name for timeseries - /// Delta to substract - /// Optional: TimeStamp to add. UNIX timestamp of the sample. * can be used for automatic timestamp (using the system clock) - /// Optional: Maximum age for samples compared to last event time (in milliseconds) - /// Optional: Collaction of label-value pairs that represent metadata labels of the key - /// Optional: Adding this flag will keep data in an uncompressed form - /// Optional: Each time-series uses chunks of memory of fixed size for time series samples. - /// You can alter the default TS_db chunk size by passing the chunk_size argument (in Bytes) - /// The latests sample timestamp (updated sample) - /// - Task DecrByAsync(string key, double value, TimeStamp? timestamp = null, long? retentionTime = null, IReadOnlyCollection? labels = null, bool? uncompressed = null, long? chunkSizeBytes = null); - /// /// Delete data points for a given timeseries and interval range in the form of start and end delete timestamps. /// The given timestamp interval is closed (inclusive), meaning start and end data points will also be deleted. @@ -183,17 +104,6 @@ TimeStamp Add(string key, TimeStamp timestamp, double value, long? retentionTime /// long Del(string key, TimeStamp fromTimeStamp, TimeStamp toTimeStamp); - /// - /// Delete data points for a given timeseries and interval range in the form of start and end delete timestamps. - /// The given timestamp interval is closed (inclusive), meaning start and end data points will also be deleted. - /// - /// Key name for timeseries - /// Start timestamp for the range deletion. - /// End timestamp for the range deletion. - /// The count of deleted items - /// - Task DelAsync(string key, TimeStamp fromTimeStamp, TimeStamp toTimeStamp); - #endregion #region Aggregation, Compaction, Downsampling @@ -211,19 +121,6 @@ TimeStamp Add(string key, TimeStamp timestamp, double value, long? retentionTime /// bool CreateRule(string sourceKey, TimeSeriesRule rule, long alignTimestamp = 0); - /// - /// Create a compaction rule. - /// - /// Key name for source time series - /// TimeSeries rule: - /// Key name for destination time series, Aggregation type and Time bucket for aggregation in milliseconds - /// ensures that there is a bucket that starts - /// exactly at alignTimestamp and aligns all other buckets accordingly. - /// It is expressed in milliseconds. The default value is 0 aligned with the epoch - /// If the operation executed successfully - /// - Task CreateRuleAsync(string sourceKey, TimeSeriesRule rule, long alignTimestamp = 0); - /// /// Deletes a compaction rule. /// @@ -233,15 +130,6 @@ TimeStamp Add(string key, TimeStamp timestamp, double value, long? retentionTime /// bool DeleteRule(string sourceKey, string destKey); - /// - /// Deletes a compaction rule. - /// - /// Key name for source time series - /// Key name for destination time series - /// If the operation executed successfully - /// - Task DeleteRuleAsync(string sourceKey, string destKey); - #endregion #region Query @@ -258,18 +146,6 @@ TimeStamp Add(string key, TimeStamp timestamp, double value, long? retentionTime /// TimeSeriesTuple? Get(string key, bool latest = false); - /// - /// Get the last sample. - /// - /// Key name for timeseries - /// is used when a time series is a compaction. With LATEST, TS.MRANGE also reports - /// the compacted value of the latest possibly partial bucket, given that this bucket's start time falls - /// within [fromTimestamp, toTimestamp]. Without LATEST, TS.MRANGE does not report the latest possibly partial bucket. - /// When a time series is not a compaction, LATEST is ignored. - /// TimeSeriesTuple that represents the last sample. Null if the series is empty. - /// - Task GetAsync(string key, bool latest = false); - /// /// Get the last samples matching the specific filter. /// @@ -285,21 +161,6 @@ TimeStamp Add(string key, TimeStamp timestamp, double value, long? retentionTime IReadOnlyList<(string key, IReadOnlyList labels, TimeSeriesTuple value)> MGet(IReadOnlyCollection filter, bool latest = false, bool? withLabels = null, IReadOnlyCollection? selectedLabels = null); - /// - /// Get the last samples matching the specific filter. - /// - /// is used when a time series is a compaction. With LATEST, TS.MRANGE also reports - /// the compacted value of the latest possibly partial bucket, given that this bucket's start time falls - /// within [fromTimestamp, toTimestamp]. Without LATEST, TS.MRANGE does not report the latest possibly partial bucket. - /// When a time series is not a compaction, LATEST is ignored. - /// A sequence of filters - /// Optional: Include in the reply the label-value pairs that represent metadata labels of the time-series - /// Optional: returns a subset of the label-value pairs that represent metadata labels of the time series - /// The command returns the last sample for entries with labels matching the specified filter. - /// - Task labels, TimeSeriesTuple value)>> MGetAsync(IReadOnlyCollection filter, bool latest = false, - bool? withLabels = null, IReadOnlyCollection? selectedLabels = null); - /// /// Query a range. /// @@ -332,38 +193,6 @@ IReadOnlyList Range(string key, long? timeBucket = null, TsBucketTimestamps? bt = null, bool empty = false); - /// - /// Query a range. - /// - /// Key name for timeseries - /// Start timestamp for the range query. "-" can be used to express the minimum possible timestamp. - /// End timestamp for range query, + can be used to express the maximum possible timestamp. - /// is used when a time series is a compaction. With LATEST, TS.MRANGE also reports - /// the compacted value of the latest possibly partial bucket, given that this bucket's start time falls - /// within [fromTimestamp, toTimestamp]. Without LATEST, TS.MRANGE does not report the latest possibly partial bucket. - /// When a time series is not a compaction, LATEST is ignored. - /// Optional: List of timestamps to filter the result by specific timestamps - /// Optional: Filter result by value using minimum and maximum - /// Optional: Returned list size. - /// Optional: Timestamp for alignment control for aggregation. - /// Optional: Aggregation type - /// Optional: Time bucket for aggregation in milliseconds - /// Optional: controls how bucket timestamps are reported. - /// Optional: when specified, reports aggregations also for empty buckets - /// A list of TimeSeriesTuple - /// - Task> RangeAsync(string key, - TimeStamp fromTimeStamp, - TimeStamp toTimeStamp, - bool latest = false, - IReadOnlyCollection? filterByTs = null, - (long, long)? filterByValue = null, - long? count = null, - TimeStamp? align = null, - TsAggregation? aggregation = null, - long? timeBucket = null, - TsBucketTimestamps? bt = null, - bool empty = false); /// /// Query a range in reverse direction. @@ -398,39 +227,6 @@ IReadOnlyList RevRange(string key, TsBucketTimestamps? bt = null, bool empty = false); - /// - /// Query a range in reverse direction. - /// - /// Key name for timeseries - /// Start timestamp for the range query. "-" can be used to express the minimum possible timestamp. - /// End timestamp for range query, + can be used to express the maximum possible timestamp. - /// is used when a time series is a compaction. With LATEST, TS.MRANGE also reports - /// the compacted value of the latest possibly partial bucket, given that this bucket's start time falls - /// within [fromTimestamp, toTimestamp]. Without LATEST, TS.MRANGE does not report the latest possibly partial bucket. - /// When a time series is not a compaction, LATEST is ignored. - /// Optional: List of timestamps to filter the result by specific timestamps - /// Optional: Filter result by value using minimum and maximum - /// Optional: Returned list size. - /// Optional: Timestamp for alignment control for aggregation. - /// Optional: Aggregation type - /// Optional: Time bucket for aggregation in milliseconds - /// Optional: controls how bucket timestamps are reported. - /// Optional: when specified, reports aggregations also for empty buckets - /// A list of TimeSeriesTuple - /// - Task> RevRangeAsync(string key, - TimeStamp fromTimeStamp, - TimeStamp toTimeStamp, - bool latest = false, - IReadOnlyCollection? filterByTs = null, - (long, long)? filterByValue = null, - long? count = null, - TimeStamp? align = null, - TsAggregation? aggregation = null, - long? timeBucket = null, - TsBucketTimestamps? bt = null, - bool empty = false); - /// /// Query a timestamp range across multiple time-series by filters. /// @@ -471,46 +267,6 @@ Task> RevRangeAsync(string key, bool empty = false, (string, TsReduce)? groupbyTuple = null); - /// - /// Query a timestamp range across multiple time-series by filters. - /// - /// Start timestamp for the range query. - can be used to express the minimum possible timestamp. - /// End timestamp for range query, + can be used to express the maximum possible timestamp. - /// A sequence of filters - /// is used when a time series is a compaction. With LATEST, TS.MRANGE also reports - /// the compacted value of the latest possibly partial bucket, given that this bucket's start time falls - /// within [fromTimestamp, toTimestamp]. Without LATEST, TS.MRANGE does not report the latest possibly partial bucket. - /// When a time series is not a compaction, LATEST is ignored. - /// Optional: List of timestamps to filter the result by specific timestamps - /// Optional: Filter result by value using minimum and maximum - /// Optional: Include in the reply the label-value pairs that represent metadata labels of the time-series - /// Optional: Include in the reply only a subset of the key-value pair labels of a series. - /// Optional: Maximum number of returned results per time-series. - /// Optional: Timestamp for alignment control for aggregation. - /// Optional: Aggregation type - /// Optional: Time bucket for aggregation in milliseconds - /// Optional: controls how bucket timestamps are reported. - /// Optional: when specified, reports aggregations also for empty buckets - /// Optional: Grouping by fields the results, and applying reducer functions on each group. - /// A list of (key, labels, values) tuples. Each tuple contains the key name, its labels and the values which satisfies the given range and filters. - /// - Task labels, IReadOnlyList values)>> MRangeAsync( - TimeStamp fromTimeStamp, - TimeStamp toTimeStamp, - IReadOnlyCollection filter, - bool latest = false, - IReadOnlyCollection? filterByTs = null, - (long, long)? filterByValue = null, - bool? withLabels = null, - IReadOnlyCollection? selectLabels = null, - long? count = null, - TimeStamp? align = null, - TsAggregation? aggregation = null, - long? timeBucket = null, - TsBucketTimestamps? bt = null, - bool empty = false, - (string, TsReduce)? groupbyTuple = null); - /// /// Query a timestamp range in reverse order across multiple time-series by filters. /// @@ -551,46 +307,6 @@ Task> RevRangeAsync(string key, bool empty = false, (string, TsReduce)? groupbyTuple = null); - /// - /// Query a timestamp range in reverse order across multiple time-series by filters. - /// - /// Start timestamp for the range query. - can be used to express the minimum possible timestamp. - /// End timestamp for range query, + can be used to express the maximum possible timestamp. - /// A sequence of filters - /// is used when a time series is a compaction. With LATEST, TS.MRANGE also reports - /// the compacted value of the latest possibly partial bucket, given that this bucket's start time falls - /// within [fromTimestamp, toTimestamp]. Without LATEST, TS.MRANGE does not report the latest possibly partial bucket. - /// When a time series is not a compaction, LATEST is ignored. - /// Optional: List of timestamps to filter the result by specific timestamps - /// Optional: Filter result by value using minimum and maximum - /// Optional: Include in the reply the label-value pairs that represent metadata labels of the time-series - /// Optional: Include in the reply only a subset of the key-value pair labels of a series. - /// Optional: Maximum number of returned results per time-series. - /// Optional: Timestamp for alignment control for aggregation. - /// Optional: Aggregation type - /// Optional: Time bucket for aggregation in milliseconds - /// Optional: controls how bucket timestamps are reported. - /// Optional: when specified, reports aggregations also for empty buckets - /// Optional: Grouping by fields the results, and applying reducer functions on each group. - /// A list of (key, labels, values) tuples. Each tuple contains the key name, its labels and the values which satisfies the given range and filters. - /// - Task labels, IReadOnlyList values)>> MRevRangeAsync( - TimeStamp fromTimeStamp, - TimeStamp toTimeStamp, - IReadOnlyCollection filter, - bool latest = false, - IReadOnlyCollection? filterByTs = null, - (long, long)? filterByValue = null, - bool? withLabels = null, - IReadOnlyCollection? selectLabels = null, - long? count = null, - TimeStamp? align = null, - TsAggregation? aggregation = null, - long? timeBucket = null, - TsBucketTimestamps? bt = null, - bool empty = false, - (string, TsReduce)? groupbyTuple = null); - #endregion #region General @@ -604,15 +320,6 @@ Task> RevRangeAsync(string key, /// TimeSeriesInformation Info(string key, bool debug = false); - /// - /// Returns the information for a specific time-series key. - /// - /// Key name for timeseries - /// An optional flag to get a more detailed information about the chunks. - /// TimeSeriesInformation for the specific key. - /// - Task InfoAsync(string key, bool debug = false); - /// /// Get all the keys matching the filter list. /// @@ -621,14 +328,6 @@ Task> RevRangeAsync(string key, /// IReadOnlyList QueryIndex(IReadOnlyCollection filter); - /// - /// Get all the keys matching the filter list. - /// - /// A sequence of filters - /// A list of keys with labels matching the filters. - /// - Task> QueryIndexAsync(IReadOnlyCollection filter); - #endregion } } \ No newline at end of file diff --git a/src/NRedisStack/TimeSeries/ITimeSeriesCommandsAsync.cs b/src/NRedisStack/TimeSeries/ITimeSeriesCommandsAsync.cs new file mode 100644 index 00000000..57b0ca7e --- /dev/null +++ b/src/NRedisStack/TimeSeries/ITimeSeriesCommandsAsync.cs @@ -0,0 +1,332 @@ +using NRedisStack.Literals.Enums; +using NRedisStack.DataTypes; +namespace NRedisStack +{ + public interface ITimeSeriesCommandsAsync + { + #region Create + + /// + /// Create a new time-series. + /// + /// Key name for timeseries + /// Optional: Maximum age for samples compared to last event time (in milliseconds) + /// Optional: Collaction of label-value pairs that represent metadata labels of the key + /// Optional: Adding this flag will keep data in an uncompressed form + /// Optional: Each time-series uses chunks of memory of fixed size for time series samples. + /// You can alter the default TS_db chunk size by passing the chunk_size argument (in Bytes) + /// Optinal: Define handling of duplicate samples behavior (avalible for RedisTimeseries >= 1.4) + /// If the operation executed successfully + /// + Task CreateAsync(string key, long? retentionTime = null, IReadOnlyCollection labels = null, bool? uncompressed = null, long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null); + + #endregion + + #region Update + + /// + /// Update the retention, labels of an existing key. + /// + /// Key name for timeseries + /// Optional: Maximum age for samples compared to last event time (in milliseconds) + /// Optional: Each time-series uses chunks of memory of fixed size for time series samples. + /// You can alter the default TS_db chunk size by passing the chunk_size argument (in Bytes) + /// Optinal: Define handling of duplicate samples behavior (avalible for RedisTimeseries >= 1.4) + /// Optional: Collaction of label-value pairs that represent metadata labels of the key + /// If the operation executed successfully + /// + Task AlterAsync(string key, long? retentionTime = null, long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null, IReadOnlyCollection? labels = null); + + /// + /// Append (or create and append) a new sample to the series. + /// + /// Key name for timeseries + /// TimeStamp to add. UNIX timestamp of the sample. * can be used for automatic timestamp (using the system clock) + /// Numeric data value of the sample. + /// Optional: Maximum age for samples compared to last event time (in milliseconds) + /// Optional: Collaction of label-value pairs that represent metadata labels of the key + /// Optional: Adding this flag will keep data in an uncompressed form + /// Optional: Each time-series uses chunks of memory of fixed size for time series samples. + /// You can alter the default TS_db chunk size by passing the chunk_size argument (in Bytes) + /// Optioal: overwrite key and database configuration for DUPLICATE_POLICY + /// The timestamp value of the new sample + /// + Task AddAsync(string key, TimeStamp timestamp, double value, long? retentionTime = null, IReadOnlyCollection labels = null, bool? uncompressed = null, long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null); + + /// + /// Append new samples to multiple series. + /// + /// An Collection of (key, timestamp, value) tuples + /// List of timestamps of the new samples + /// + Task> MAddAsync(IReadOnlyCollection<(string key, TimeStamp timestamp, double value)> sequence); + + + /// + /// Creates a new sample that increments the latest sample's value. + /// + /// Key name for timeseries + /// Delta to add + /// Optional: TimeStamp to add. UNIX timestamp of the sample. * can be used for automatic timestamp (using the system clock) + /// Optional: Maximum age for samples compared to last event time (in milliseconds) + /// Optional: Collaction of label-value pairs that represent metadata labels of the key + /// Optional: Adding this flag will keep data in an uncompressed form + /// Optional: Each time-series uses chunks of memory of fixed size for time series samples. + /// You can alter the default TS_db chunk size by passing the chunk_size argument (in Bytes) + /// The latests sample timestamp (updated sample) + /// + Task IncrByAsync(string key, double value, TimeStamp? timestamp = null, long? retentionTime = null, IReadOnlyCollection? labels = null, bool? uncompressed = null, long? chunkSizeBytes = null); + + /// + /// Creates a new sample that decrements the latest sample's value. + /// + /// Key name for timeseries + /// Delta to substract + /// Optional: TimeStamp to add. UNIX timestamp of the sample. * can be used for automatic timestamp (using the system clock) + /// Optional: Maximum age for samples compared to last event time (in milliseconds) + /// Optional: Collaction of label-value pairs that represent metadata labels of the key + /// Optional: Adding this flag will keep data in an uncompressed form + /// Optional: Each time-series uses chunks of memory of fixed size for time series samples. + /// You can alter the default TS_db chunk size by passing the chunk_size argument (in Bytes) + /// The latests sample timestamp (updated sample) + /// + Task DecrByAsync(string key, double value, TimeStamp? timestamp = null, long? retentionTime = null, IReadOnlyCollection? labels = null, bool? uncompressed = null, long? chunkSizeBytes = null); + + /// + /// Delete data points for a given timeseries and interval range in the form of start and end delete timestamps. + /// The given timestamp interval is closed (inclusive), meaning start and end data points will also be deleted. + /// + /// Key name for timeseries + /// Start timestamp for the range deletion. + /// End timestamp for the range deletion. + /// The count of deleted items + /// + Task DelAsync(string key, TimeStamp fromTimeStamp, TimeStamp toTimeStamp); + + #endregion + + #region Aggregation, Compaction, Downsampling + + /// + /// Create a compaction rule. + /// + /// Key name for source time series + /// TimeSeries rule: + /// Key name for destination time series, Aggregation type and Time bucket for aggregation in milliseconds + /// ensures that there is a bucket that starts + /// exactly at alignTimestamp and aligns all other buckets accordingly. + /// It is expressed in milliseconds. The default value is 0 aligned with the epoch + /// If the operation executed successfully + /// + Task CreateRuleAsync(string sourceKey, TimeSeriesRule rule, long alignTimestamp = 0); + + /// + /// Deletes a compaction rule. + /// + /// Key name for source time series + /// Key name for destination time series + /// If the operation executed successfully + /// + Task DeleteRuleAsync(string sourceKey, string destKey); + + #endregion + + #region Query + + /// + /// Get the last sample. + /// + /// Key name for timeseries + /// is used when a time series is a compaction. With LATEST, TS.MRANGE also reports + /// the compacted value of the latest possibly partial bucket, given that this bucket's start time falls + /// within [fromTimestamp, toTimestamp]. Without LATEST, TS.MRANGE does not report the latest possibly partial bucket. + /// When a time series is not a compaction, LATEST is ignored. + /// TimeSeriesTuple that represents the last sample. Null if the series is empty. + /// + Task GetAsync(string key, bool latest = false); + + /// + /// Get the last samples matching the specific filter. + /// + /// is used when a time series is a compaction. With LATEST, TS.MRANGE also reports + /// the compacted value of the latest possibly partial bucket, given that this bucket's start time falls + /// within [fromTimestamp, toTimestamp]. Without LATEST, TS.MRANGE does not report the latest possibly partial bucket. + /// When a time series is not a compaction, LATEST is ignored. + /// A sequence of filters + /// Optional: Include in the reply the label-value pairs that represent metadata labels of the time-series + /// Optional: returns a subset of the label-value pairs that represent metadata labels of the time series + /// The command returns the last sample for entries with labels matching the specified filter. + /// + Task labels, TimeSeriesTuple value)>> MGetAsync(IReadOnlyCollection filter, bool latest = false, + bool? withLabels = null, IReadOnlyCollection? selectedLabels = null); + + /// + /// Query a range. + /// + /// Key name for timeseries + /// Start timestamp for the range query. "-" can be used to express the minimum possible timestamp. + /// End timestamp for range query, + can be used to express the maximum possible timestamp. + /// is used when a time series is a compaction. With LATEST, TS.MRANGE also reports + /// the compacted value of the latest possibly partial bucket, given that this bucket's start time falls + /// within [fromTimestamp, toTimestamp]. Without LATEST, TS.MRANGE does not report the latest possibly partial bucket. + /// When a time series is not a compaction, LATEST is ignored. + /// Optional: List of timestamps to filter the result by specific timestamps + /// Optional: Filter result by value using minimum and maximum + /// Optional: Returned list size. + /// Optional: Timestamp for alignment control for aggregation. + /// Optional: Aggregation type + /// Optional: Time bucket for aggregation in milliseconds + /// Optional: controls how bucket timestamps are reported. + /// Optional: when specified, reports aggregations also for empty buckets + /// A list of TimeSeriesTuple + /// + Task> RangeAsync(string key, + TimeStamp fromTimeStamp, + TimeStamp toTimeStamp, + bool latest = false, + IReadOnlyCollection? filterByTs = null, + (long, long)? filterByValue = null, + long? count = null, + TimeStamp? align = null, + TsAggregation? aggregation = null, + long? timeBucket = null, + TsBucketTimestamps? bt = null, + bool empty = false); + + /// + /// Query a range in reverse direction. + /// + /// Key name for timeseries + /// Start timestamp for the range query. "-" can be used to express the minimum possible timestamp. + /// End timestamp for range query, + can be used to express the maximum possible timestamp. + /// is used when a time series is a compaction. With LATEST, TS.MRANGE also reports + /// the compacted value of the latest possibly partial bucket, given that this bucket's start time falls + /// within [fromTimestamp, toTimestamp]. Without LATEST, TS.MRANGE does not report the latest possibly partial bucket. + /// When a time series is not a compaction, LATEST is ignored. + /// Optional: List of timestamps to filter the result by specific timestamps + /// Optional: Filter result by value using minimum and maximum + /// Optional: Returned list size. + /// Optional: Timestamp for alignment control for aggregation. + /// Optional: Aggregation type + /// Optional: Time bucket for aggregation in milliseconds + /// Optional: controls how bucket timestamps are reported. + /// Optional: when specified, reports aggregations also for empty buckets + /// A list of TimeSeriesTuple + /// + Task> RevRangeAsync(string key, + TimeStamp fromTimeStamp, + TimeStamp toTimeStamp, + bool latest = false, + IReadOnlyCollection? filterByTs = null, + (long, long)? filterByValue = null, + long? count = null, + TimeStamp? align = null, + TsAggregation? aggregation = null, + long? timeBucket = null, + TsBucketTimestamps? bt = null, + bool empty = false); + + /// + /// Query a timestamp range across multiple time-series by filters. + /// + /// Start timestamp for the range query. - can be used to express the minimum possible timestamp. + /// End timestamp for range query, + can be used to express the maximum possible timestamp. + /// A sequence of filters + /// is used when a time series is a compaction. With LATEST, TS.MRANGE also reports + /// the compacted value of the latest possibly partial bucket, given that this bucket's start time falls + /// within [fromTimestamp, toTimestamp]. Without LATEST, TS.MRANGE does not report the latest possibly partial bucket. + /// When a time series is not a compaction, LATEST is ignored. + /// Optional: List of timestamps to filter the result by specific timestamps + /// Optional: Filter result by value using minimum and maximum + /// Optional: Include in the reply the label-value pairs that represent metadata labels of the time-series + /// Optional: Include in the reply only a subset of the key-value pair labels of a series. + /// Optional: Maximum number of returned results per time-series. + /// Optional: Timestamp for alignment control for aggregation. + /// Optional: Aggregation type + /// Optional: Time bucket for aggregation in milliseconds + /// Optional: controls how bucket timestamps are reported. + /// Optional: when specified, reports aggregations also for empty buckets + /// Optional: Grouping by fields the results, and applying reducer functions on each group. + /// A list of (key, labels, values) tuples. Each tuple contains the key name, its labels and the values which satisfies the given range and filters. + /// + Task labels, IReadOnlyList values)>> MRangeAsync( + TimeStamp fromTimeStamp, + TimeStamp toTimeStamp, + IReadOnlyCollection filter, + bool latest = false, + IReadOnlyCollection? filterByTs = null, + (long, long)? filterByValue = null, + bool? withLabels = null, + IReadOnlyCollection? selectLabels = null, + long? count = null, + TimeStamp? align = null, + TsAggregation? aggregation = null, + long? timeBucket = null, + TsBucketTimestamps? bt = null, + bool empty = false, + (string, TsReduce)? groupbyTuple = null); + + /// + /// Query a timestamp range in reverse order across multiple time-series by filters. + /// + /// Start timestamp for the range query. - can be used to express the minimum possible timestamp. + /// End timestamp for range query, + can be used to express the maximum possible timestamp. + /// A sequence of filters + /// is used when a time series is a compaction. With LATEST, TS.MRANGE also reports + /// the compacted value of the latest possibly partial bucket, given that this bucket's start time falls + /// within [fromTimestamp, toTimestamp]. Without LATEST, TS.MRANGE does not report the latest possibly partial bucket. + /// When a time series is not a compaction, LATEST is ignored. + /// Optional: List of timestamps to filter the result by specific timestamps + /// Optional: Filter result by value using minimum and maximum + /// Optional: Include in the reply the label-value pairs that represent metadata labels of the time-series + /// Optional: Include in the reply only a subset of the key-value pair labels of a series. + /// Optional: Maximum number of returned results per time-series. + /// Optional: Timestamp for alignment control for aggregation. + /// Optional: Aggregation type + /// Optional: Time bucket for aggregation in milliseconds + /// Optional: controls how bucket timestamps are reported. + /// Optional: when specified, reports aggregations also for empty buckets + /// Optional: Grouping by fields the results, and applying reducer functions on each group. + /// A list of (key, labels, values) tuples. Each tuple contains the key name, its labels and the values which satisfies the given range and filters. + /// + Task labels, IReadOnlyList values)>> MRevRangeAsync( + TimeStamp fromTimeStamp, + TimeStamp toTimeStamp, + IReadOnlyCollection filter, + bool latest = false, + IReadOnlyCollection? filterByTs = null, + (long, long)? filterByValue = null, + bool? withLabels = null, + IReadOnlyCollection? selectLabels = null, + long? count = null, + TimeStamp? align = null, + TsAggregation? aggregation = null, + long? timeBucket = null, + TsBucketTimestamps? bt = null, + bool empty = false, + (string, TsReduce)? groupbyTuple = null); + + #endregion + + #region General + + /// + /// Returns the information for a specific time-series key. + /// + /// Key name for timeseries + /// An optional flag to get a more detailed information about the chunks. + /// TimeSeriesInformation for the specific key. + /// + Task InfoAsync(string key, bool debug = false); + + /// + /// Get all the keys matching the filter list. + /// + /// A sequence of filters + /// A list of keys with labels matching the filters. + /// + Task> QueryIndexAsync(IReadOnlyCollection filter); + + #endregion + } +} \ No newline at end of file diff --git a/src/NRedisStack/TimeSeries/TimeSeriesCommands.cs b/src/NRedisStack/TimeSeries/TimeSeriesCommands.cs index b312e98f..b6566fa1 100644 --- a/src/NRedisStack/TimeSeries/TimeSeriesCommands.cs +++ b/src/NRedisStack/TimeSeries/TimeSeriesCommands.cs @@ -1,13 +1,12 @@ using StackExchange.Redis; -using NRedisStack.Literals; using NRedisStack.Literals.Enums; using NRedisStack.DataTypes; namespace NRedisStack { - public class TimeSeriesCommands : ITimeSeriesCommands + public class TimeSeriesCommands : TimeSeriesCommandsAsync, ITimeSeriesCommands { IDatabase _db; - public TimeSeriesCommands(IDatabase db) + public TimeSeriesCommands(IDatabase db) : base(db) { _db = db; } @@ -22,14 +21,6 @@ public bool Create(string key, long? retentionTime = null, IReadOnlyCollection - public async Task CreateAsync(string key, long? retentionTime = null, IReadOnlyCollection labels = null, bool? uncompressed = null, long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null) - { - return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.Create(key, retentionTime, labels, - uncompressed, chunkSizeBytes, - duplicatePolicy))).OKtoBoolean(); - } - #endregion #region Update @@ -40,11 +31,6 @@ public bool Alter(string key, long? retentionTime = null, long? chunkSizeBytes = return _db.Execute(TimeSeriesCommandsBuilder.Alter(key, retentionTime, chunkSizeBytes, duplicatePolicy, labels)).OKtoBoolean(); } - /// - public async Task AlterAsync(string key, long? retentionTime = null, long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null, IReadOnlyCollection? labels = null) - { - return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.Alter(key, retentionTime, chunkSizeBytes, duplicatePolicy, labels))).OKtoBoolean(); - } /// public TimeStamp Add(string key, TimeStamp timestamp, double value, long? retentionTime = null, @@ -55,25 +41,12 @@ public TimeStamp Add(string key, TimeStamp timestamp, double value, long? retent uncompressed, chunkSizeBytes, duplicatePolicy)).ToTimeStamp(); } - /// - public async Task AddAsync(string key, TimeStamp timestamp, double value, long? retentionTime = null, IReadOnlyCollection labels = null, bool? uncompressed = null, long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null) - { - return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.Add(key, timestamp, value, retentionTime, labels, - uncompressed, chunkSizeBytes, duplicatePolicy))).ToTimeStamp(); - } - /// public IReadOnlyList MAdd(IReadOnlyCollection<(string key, TimeStamp timestamp, double value)> sequence) { return _db.Execute(TimeSeriesCommandsBuilder.MAdd(sequence)).ToTimeStampArray(); } - /// - public async Task> MAddAsync(IReadOnlyCollection<(string key, TimeStamp timestamp, double value)> sequence) - { - return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.MAdd(sequence))).ToTimeStampArray(); - } - /// public TimeStamp IncrBy(string key, double value, TimeStamp? timestamp = null, long? retentionTime = null, IReadOnlyCollection? labels = null, bool? uncompressed = null, long? chunkSizeBytes = null) { @@ -81,13 +54,6 @@ public TimeStamp IncrBy(string key, double value, TimeStamp? timestamp = null, l labels, uncompressed, chunkSizeBytes)).ToTimeStamp(); } - /// - public async Task IncrByAsync(string key, double value, TimeStamp? timestamp = null, long? retentionTime = null, IReadOnlyCollection? labels = null, bool? uncompressed = null, long? chunkSizeBytes = null) - { - return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.IncrBy(key, value, timestamp, retentionTime, - labels, uncompressed, chunkSizeBytes))).ToTimeStamp(); - } - /// public TimeStamp DecrBy(string key, double value, TimeStamp? timestamp = null, long? retentionTime = null, IReadOnlyCollection? labels = null, bool? uncompressed = null, long? chunkSizeBytes = null) { @@ -95,25 +61,12 @@ public TimeStamp DecrBy(string key, double value, TimeStamp? timestamp = null, l labels, uncompressed, chunkSizeBytes)).ToTimeStamp(); } - /// - public async Task DecrByAsync(string key, double value, TimeStamp? timestamp = null, long? retentionTime = null, IReadOnlyCollection? labels = null, bool? uncompressed = null, long? chunkSizeBytes = null) - { - return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.DecrBy(key, value, timestamp, retentionTime, - labels, uncompressed, chunkSizeBytes))).ToTimeStamp(); - } - /// public long Del(string key, TimeStamp fromTimeStamp, TimeStamp toTimeStamp) { return _db.Execute(TimeSeriesCommandsBuilder.Del(key, fromTimeStamp, toTimeStamp)).ToLong(); } - /// - public async Task DelAsync(string key, TimeStamp fromTimeStamp, TimeStamp toTimeStamp) - { - return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.Del(key, fromTimeStamp, toTimeStamp))).ToLong(); - } - #endregion #region Aggregation, Compaction, Downsampling @@ -124,24 +77,12 @@ public bool CreateRule(string sourceKey, TimeSeriesRule rule, long alignTimestam return _db.Execute(TimeSeriesCommandsBuilder.CreateRule(sourceKey, rule, alignTimestamp)).OKtoBoolean(); } - /// - public async Task CreateRuleAsync(string sourceKey, TimeSeriesRule rule, long alignTimestamp = 0) - { - return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.CreateRule(sourceKey, rule, alignTimestamp))).OKtoBoolean(); - } - /// public bool DeleteRule(string sourceKey, string destKey) { return _db.Execute(TimeSeriesCommandsBuilder.DeleteRule(sourceKey, destKey)).OKtoBoolean(); } - /// - public async Task DeleteRuleAsync(string sourceKey, string destKey) - { - return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.DeleteRule(sourceKey, destKey))).OKtoBoolean(); - } - #endregion #region Query @@ -152,12 +93,6 @@ public async Task DeleteRuleAsync(string sourceKey, string destKey) return _db.Execute(TimeSeriesCommandsBuilder.Get(key, latest)).ToTimeSeriesTuple(); } - /// - public async Task GetAsync(string key, bool latest = false) - { - return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.Get(key, latest))).ToTimeSeriesTuple(); - } - /// public IReadOnlyList<(string key, IReadOnlyList labels, TimeSeriesTuple value)> MGet(IReadOnlyCollection filter, bool latest = false, bool? withLabels = null, IReadOnlyCollection? selectedLabels = null) @@ -165,13 +100,6 @@ public async Task DeleteRuleAsync(string sourceKey, string destKey) return _db.Execute(TimeSeriesCommandsBuilder.MGet(filter, latest, withLabels, selectedLabels)).ParseMGetResponse(); } - /// - public async Task labels, TimeSeriesTuple value)>> MGetAsync(IReadOnlyCollection filter, bool latest = false, - bool? withLabels = null, IReadOnlyCollection? selectedLabels = null) - { - return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.MGet(filter, latest, withLabels, selectedLabels))).ParseMGetResponse(); - } - /// public IReadOnlyList Range(string key, TimeStamp fromTimeStamp, @@ -192,26 +120,6 @@ public IReadOnlyList Range(string key, bt, empty)).ToTimeSeriesTupleArray(); } - /// - public async Task> RangeAsync(string key, - TimeStamp fromTimeStamp, - TimeStamp toTimeStamp, - bool latest = false, - IReadOnlyCollection? filterByTs = null, - (long, long)? filterByValue = null, - long? count = null, - TimeStamp? align = null, - TsAggregation? aggregation = null, - long? timeBucket = null, - TsBucketTimestamps? bt = null, - bool empty = false) - { - return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.Range(key, fromTimeStamp, toTimeStamp, - latest, filterByTs, filterByValue, - count, align, aggregation, timeBucket, - bt, empty))).ToTimeSeriesTupleArray(); - } - /// public IReadOnlyList RevRange(string key, TimeStamp fromTimeStamp, @@ -232,26 +140,6 @@ public IReadOnlyList RevRange(string key, bt, empty)).ToTimeSeriesTupleArray(); } - /// - public async Task> RevRangeAsync(string key, - TimeStamp fromTimeStamp, - TimeStamp toTimeStamp, - bool latest = false, - IReadOnlyCollection? filterByTs = null, - (long, long)? filterByValue = null, - long? count = null, - TimeStamp? align = null, - TsAggregation? aggregation = null, - long? timeBucket = null, - TsBucketTimestamps? bt = null, - bool empty = false) - { - return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.RevRange(key, fromTimeStamp, toTimeStamp, - latest, filterByTs, filterByValue, - count, align, aggregation, timeBucket, - bt, empty))).ToTimeSeriesTupleArray(); - } - /// public IReadOnlyList<(string key, IReadOnlyList labels, IReadOnlyList values)> MRange( TimeStamp fromTimeStamp, @@ -277,31 +165,6 @@ public async Task> RevRangeAsync(string key, groupbyTuple)).ParseMRangeResponse(); } - /// - public async Task labels, IReadOnlyList values)>> MRangeAsync( - TimeStamp fromTimeStamp, - TimeStamp toTimeStamp, - IReadOnlyCollection filter, - bool latest = false, - IReadOnlyCollection? filterByTs = null, - (long, long)? filterByValue = null, - bool? withLabels = null, - IReadOnlyCollection? selectLabels = null, - long? count = null, - TimeStamp? align = null, - TsAggregation? aggregation = null, - long? timeBucket = null, - TsBucketTimestamps? bt = null, - bool empty = false, - (string, TsReduce)? groupbyTuple = null) - { - return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.MRange(fromTimeStamp, toTimeStamp, filter, - latest, filterByTs, filterByValue, - withLabels, selectLabels, count, align, - aggregation, timeBucket, bt, empty, - groupbyTuple))).ParseMRangeResponse(); - } - /// public IReadOnlyList<(string key, IReadOnlyList labels, IReadOnlyList values)> MRevRange( TimeStamp fromTimeStamp, @@ -327,31 +190,6 @@ public async Task> RevRangeAsync(string key, groupbyTuple)).ParseMRangeResponse(); } - /// - public async Task labels, IReadOnlyList values)>> MRevRangeAsync( - TimeStamp fromTimeStamp, - TimeStamp toTimeStamp, - IReadOnlyCollection filter, - bool latest = false, - IReadOnlyCollection? filterByTs = null, - (long, long)? filterByValue = null, - bool? withLabels = null, - IReadOnlyCollection? selectLabels = null, - long? count = null, - TimeStamp? align = null, - TsAggregation? aggregation = null, - long? timeBucket = null, - TsBucketTimestamps? bt = null, - bool empty = false, - (string, TsReduce)? groupbyTuple = null) - { - return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.MRevRange(fromTimeStamp, toTimeStamp, filter, - latest, filterByTs, filterByValue, - withLabels, selectLabels, count, align, - aggregation, timeBucket, bt, empty, - groupbyTuple))).ParseMRangeResponse(); - } - #endregion #region General @@ -362,24 +200,12 @@ public TimeSeriesInformation Info(string key, bool debug = false) return _db.Execute(TimeSeriesCommandsBuilder.Info(key, debug)).ToTimeSeriesInfo(); } - /// - public async Task InfoAsync(string key, bool debug = false) - { - return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.Info(key, debug))).ToTimeSeriesInfo(); - } - /// public IReadOnlyList QueryIndex(IReadOnlyCollection filter) { return _db.Execute(TimeSeriesCommandsBuilder.QueryIndex(filter)).ToStringList(); } - /// - public async Task> QueryIndexAsync(IReadOnlyCollection filter) - { - return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.QueryIndex(filter))).ToStringList(); - } - #endregion } } \ No newline at end of file diff --git a/src/NRedisStack/TimeSeries/TimeSeriesCommandsAsync.cs b/src/NRedisStack/TimeSeries/TimeSeriesCommandsAsync.cs new file mode 100644 index 00000000..ede7f288 --- /dev/null +++ b/src/NRedisStack/TimeSeries/TimeSeriesCommandsAsync.cs @@ -0,0 +1,208 @@ +using StackExchange.Redis; +using NRedisStack.Literals.Enums; +using NRedisStack.DataTypes; +namespace NRedisStack +{ + public class TimeSeriesCommandsAsync : ITimeSeriesCommandsAsync + { + IDatabaseAsync _db; + public TimeSeriesCommandsAsync(IDatabaseAsync db) + { + _db = db; + } + + #region Create + + /// + public async Task CreateAsync(string key, long? retentionTime = null, IReadOnlyCollection labels = null, bool? uncompressed = null, long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null) + { + return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.Create(key, retentionTime, labels, + uncompressed, chunkSizeBytes, + duplicatePolicy))).OKtoBoolean(); + } + + #endregion + + #region Update + + /// + public async Task AlterAsync(string key, long? retentionTime = null, long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null, IReadOnlyCollection? labels = null) + { + return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.Alter(key, retentionTime, chunkSizeBytes, duplicatePolicy, labels))).OKtoBoolean(); + } + + /// + public async Task AddAsync(string key, TimeStamp timestamp, double value, long? retentionTime = null, IReadOnlyCollection labels = null, bool? uncompressed = null, long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null) + { + return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.Add(key, timestamp, value, retentionTime, labels, + uncompressed, chunkSizeBytes, duplicatePolicy))).ToTimeStamp(); + } + + /// + public async Task> MAddAsync(IReadOnlyCollection<(string key, TimeStamp timestamp, double value)> sequence) + { + return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.MAdd(sequence))).ToTimeStampArray(); + } + + /// + public async Task IncrByAsync(string key, double value, TimeStamp? timestamp = null, long? retentionTime = null, IReadOnlyCollection? labels = null, bool? uncompressed = null, long? chunkSizeBytes = null) + { + return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.IncrBy(key, value, timestamp, retentionTime, + labels, uncompressed, chunkSizeBytes))).ToTimeStamp(); + } + + /// + public async Task DecrByAsync(string key, double value, TimeStamp? timestamp = null, long? retentionTime = null, IReadOnlyCollection? labels = null, bool? uncompressed = null, long? chunkSizeBytes = null) + { + return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.DecrBy(key, value, timestamp, retentionTime, + labels, uncompressed, chunkSizeBytes))).ToTimeStamp(); + } + + /// + public async Task DelAsync(string key, TimeStamp fromTimeStamp, TimeStamp toTimeStamp) + { + return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.Del(key, fromTimeStamp, toTimeStamp))).ToLong(); + } + + #endregion + + #region Aggregation, Compaction, Downsampling + + /// + public async Task CreateRuleAsync(string sourceKey, TimeSeriesRule rule, long alignTimestamp = 0) + { + return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.CreateRule(sourceKey, rule, alignTimestamp))).OKtoBoolean(); + } + + /// + public async Task DeleteRuleAsync(string sourceKey, string destKey) + { + return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.DeleteRule(sourceKey, destKey))).OKtoBoolean(); + } + + #endregion + + #region Query + + /// + public async Task GetAsync(string key, bool latest = false) + { + return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.Get(key, latest))).ToTimeSeriesTuple(); + } + + /// + public async Task labels, TimeSeriesTuple value)>> MGetAsync(IReadOnlyCollection filter, bool latest = false, + bool? withLabels = null, IReadOnlyCollection? selectedLabels = null) + { + return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.MGet(filter, latest, withLabels, selectedLabels))).ParseMGetResponse(); + } + + /// + public async Task> RangeAsync(string key, + TimeStamp fromTimeStamp, + TimeStamp toTimeStamp, + bool latest = false, + IReadOnlyCollection? filterByTs = null, + (long, long)? filterByValue = null, + long? count = null, + TimeStamp? align = null, + TsAggregation? aggregation = null, + long? timeBucket = null, + TsBucketTimestamps? bt = null, + bool empty = false) + { + return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.Range(key, fromTimeStamp, toTimeStamp, + latest, filterByTs, filterByValue, + count, align, aggregation, timeBucket, + bt, empty))).ToTimeSeriesTupleArray(); + } + + /// + public async Task> RevRangeAsync(string key, + TimeStamp fromTimeStamp, + TimeStamp toTimeStamp, + bool latest = false, + IReadOnlyCollection? filterByTs = null, + (long, long)? filterByValue = null, + long? count = null, + TimeStamp? align = null, + TsAggregation? aggregation = null, + long? timeBucket = null, + TsBucketTimestamps? bt = null, + bool empty = false) + { + return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.RevRange(key, fromTimeStamp, toTimeStamp, + latest, filterByTs, filterByValue, + count, align, aggregation, timeBucket, + bt, empty))).ToTimeSeriesTupleArray(); + } + + /// + public async Task labels, IReadOnlyList values)>> MRangeAsync( + TimeStamp fromTimeStamp, + TimeStamp toTimeStamp, + IReadOnlyCollection filter, + bool latest = false, + IReadOnlyCollection? filterByTs = null, + (long, long)? filterByValue = null, + bool? withLabels = null, + IReadOnlyCollection? selectLabels = null, + long? count = null, + TimeStamp? align = null, + TsAggregation? aggregation = null, + long? timeBucket = null, + TsBucketTimestamps? bt = null, + bool empty = false, + (string, TsReduce)? groupbyTuple = null) + { + return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.MRange(fromTimeStamp, toTimeStamp, filter, + latest, filterByTs, filterByValue, + withLabels, selectLabels, count, align, + aggregation, timeBucket, bt, empty, + groupbyTuple))).ParseMRangeResponse(); + } + + /// + public async Task labels, IReadOnlyList values)>> MRevRangeAsync( + TimeStamp fromTimeStamp, + TimeStamp toTimeStamp, + IReadOnlyCollection filter, + bool latest = false, + IReadOnlyCollection? filterByTs = null, + (long, long)? filterByValue = null, + bool? withLabels = null, + IReadOnlyCollection? selectLabels = null, + long? count = null, + TimeStamp? align = null, + TsAggregation? aggregation = null, + long? timeBucket = null, + TsBucketTimestamps? bt = null, + bool empty = false, + (string, TsReduce)? groupbyTuple = null) + { + return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.MRevRange(fromTimeStamp, toTimeStamp, filter, + latest, filterByTs, filterByValue, + withLabels, selectLabels, count, align, + aggregation, timeBucket, bt, empty, + groupbyTuple))).ParseMRangeResponse(); + } + + #endregion + + #region General + + /// + public async Task InfoAsync(string key, bool debug = false) + { + return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.Info(key, debug))).ToTimeSeriesInfo(); + } + + /// + public async Task> QueryIndexAsync(IReadOnlyCollection filter) + { + return (await _db.ExecuteAsync(TimeSeriesCommandsBuilder.QueryIndex(filter))).ToStringList(); + } + + #endregion + } +} \ No newline at end of file diff --git a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestDelAsync.cs b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestDelAsync.cs index d9eac8d7..b29bdd69 100644 --- a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestDelAsync.cs +++ b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestDelAsync.cs @@ -11,7 +11,7 @@ public class TestDelAsync : AbstractNRedisStackTest { public TestDelAsync(RedisFixture redisFixture) : base(redisFixture) { } - private async Task> CreateData(ITimeSeriesCommands ts, string key, int timeBucket) + private async Task> CreateData(TimeSeriesCommands ts, string key, int timeBucket) { var tuples = new List(); for (var i = 0; i < 10; i++) diff --git a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestMRangeAsync.cs b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestMRangeAsync.cs index 2733be17..dd326e12 100644 --- a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestMRangeAsync.cs +++ b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestMRangeAsync.cs @@ -13,7 +13,7 @@ public class TestMRangeAsync : AbstractNRedisStackTest { public TestMRangeAsync(RedisFixture redisFixture) : base(redisFixture) { } - private async Task> CreateData(ITimeSeriesCommands ts, string[] keys, int timeBucket) + private async Task> CreateData(TimeSeriesCommands ts, string[] keys, int timeBucket) { var tuples = new List(); diff --git a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestMRevRangeAsync.cs b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestMRevRangeAsync.cs index 4f208a82..297dfff2 100644 --- a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestMRevRangeAsync.cs +++ b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestMRevRangeAsync.cs @@ -13,7 +13,7 @@ public class TestMRevRangeAsync : AbstractNRedisStackTest { public TestMRevRangeAsync(RedisFixture redisFixture) : base(redisFixture) { } - private async Task> CreateData(ITimeSeriesCommands ts, string[] keys, int timeBucket) + private async Task> CreateData(TimeSeriesCommands ts, string[] keys, int timeBucket) { var tuples = new List(); diff --git a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestRangeAsync.cs b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestRangeAsync.cs index 381aac78..54248c63 100644 --- a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestRangeAsync.cs +++ b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestRangeAsync.cs @@ -13,7 +13,7 @@ public class TestRangeAsync : AbstractNRedisStackTest { public TestRangeAsync(RedisFixture redisFixture) : base(redisFixture) { } - private async Task> CreateData(ITimeSeriesCommands ts, string key, int timeBucket) + private async Task> CreateData(TimeSeriesCommands ts, string key, int timeBucket) { var tuples = new List(); for (var i = 0; i < 10; i++) diff --git a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestRevRangeAsync.cs b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestRevRangeAsync.cs index 907725eb..d418ec09 100644 --- a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestRevRangeAsync.cs +++ b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestRevRangeAsync.cs @@ -13,7 +13,7 @@ public class TestRevRangeAsync : AbstractNRedisStackTest { public TestRevRangeAsync(RedisFixture redisFixture) : base(redisFixture) { } - private async Task> CreateData(ITimeSeriesCommands ts, string key, int timeBucket) + private async Task> CreateData(TimeSeriesCommands ts, string key, int timeBucket) { var tuples = new List(); for (var i = 0; i < 10; i++) From a46886a2a1fd631cc61fc352f0156c832e407074 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Thu, 26 Jan 2023 18:55:55 +0200 Subject: [PATCH 18/21] split TopK --- src/NRedisStack/TopK/ITopKCommands.cs | 65 ----------------- src/NRedisStack/TopK/ITopKCommandsAsync.cs | 83 ++++++++++++++++++++++ src/NRedisStack/TopK/TopKCommands.cs | 54 +------------- src/NRedisStack/TopK/TopKCommandsAsync.cs | 62 ++++++++++++++++ 4 files changed, 147 insertions(+), 117 deletions(-) create mode 100644 src/NRedisStack/TopK/ITopKCommandsAsync.cs create mode 100644 src/NRedisStack/TopK/TopKCommandsAsync.cs diff --git a/src/NRedisStack/TopK/ITopKCommands.cs b/src/NRedisStack/TopK/ITopKCommands.cs index 1d7c48d9..93913e62 100644 --- a/src/NRedisStack/TopK/ITopKCommands.cs +++ b/src/NRedisStack/TopK/ITopKCommands.cs @@ -14,9 +14,6 @@ public interface ITopKCommands /// RedisResult[]? Add(RedisKey key, params RedisValue[] items); - /// - Task AddAsync(RedisKey key, params RedisValue[] items); - /// /// Returns count for an items. /// @@ -27,11 +24,6 @@ public interface ITopKCommands [Obsolete("TOPK.COUNT is deprecated as of Bloom 2.4.0")] long[] Count(RedisKey key, params RedisValue[] items); - /// - [Obsolete("TOPK.COUNT is deprecated as of Bloom 2.4.0")] - Task CountAsync(RedisKey key, params RedisValue[] items); - - /// /// Increase the score of an item in the data structure by increment. /// @@ -42,16 +34,6 @@ public interface ITopKCommands /// RedisResult[] IncrBy(RedisKey key, params Tuple[] itemIncrements); - /// - /// Increase the score of an item in the data structure by increment. - /// - /// Name of sketch where item is added. - /// Tuple of The items which counter is to be increased - /// and the Amount by which the item score is to be increased. - /// Score of each item after increment. - /// - Task IncrByAsync(RedisKey key, params Tuple[] itemIncrements); - /// /// Return TopK information. /// @@ -60,14 +42,6 @@ public interface ITopKCommands /// TopKInformation Info(RedisKey key); - /// - /// Return TopK information. - /// - /// Name of the key to return information about. - /// TopK Information. - /// - Task InfoAsync(RedisKey key); - /// /// Return full list of items in Top K list. /// @@ -77,15 +51,6 @@ public interface ITopKCommands /// RedisResult[] List(RedisKey key, bool withcount = false); - /// - /// Return full list of items in Top K list. - /// - /// The name of the sketch. - /// return Count of each element is returned. - /// Full list of items in Top K list - /// - Task ListAsync(RedisKey key, bool withcount = false); - /// /// Returns the count for one or more items in a sketch. /// @@ -95,15 +60,6 @@ public interface ITopKCommands /// bool Query(RedisKey key, RedisValue item); - /// - /// Returns the count for one or more items in a sketch. - /// - /// The name of the sketch - /// Item to be queried. - /// if item is in Top-K, otherwise/> - /// - Task QueryAsync(RedisKey key, RedisValue item); - /// /// Returns the count for one or more items in a sketch. /// @@ -113,15 +69,6 @@ public interface ITopKCommands /// bool[] Query(RedisKey key, params RedisValue[] items); - /// - /// Returns the count for one or more items in a sketch. - /// - /// The name of the sketch - /// Items to be queried. - /// Bolean Array where if item is in Top-K, otherwise/> - /// - Task QueryAsync(RedisKey key, params RedisValue[] items); - /// /// Initializes a TopK with specified parameters. /// @@ -133,17 +80,5 @@ public interface ITopKCommands /// if executed correctly, error otherwise/> /// bool Reserve(RedisKey key, long topk, long width = 7, long depth = 8, double decay = 0.9); - - /// - /// Initializes a TopK with specified parameters. - /// - /// Key under which the sketch is to be found. - /// Number of top occurring items to keep. - /// Number of counters kept in each array. (Default 8) - /// Number of arrays. (Default 7) - /// The probability of reducing a counter in an occupied bucket. (Default 0.9) - /// if executed correctly, error otherwise/> - /// - Task ReserveAsync(RedisKey key, long topk, long width = 7, long depth = 8, double decay = 0.9); } } \ No newline at end of file diff --git a/src/NRedisStack/TopK/ITopKCommandsAsync.cs b/src/NRedisStack/TopK/ITopKCommandsAsync.cs new file mode 100644 index 00000000..b23251a4 --- /dev/null +++ b/src/NRedisStack/TopK/ITopKCommandsAsync.cs @@ -0,0 +1,83 @@ +using NRedisStack.TopK.DataTypes; +using StackExchange.Redis; + +namespace NRedisStack +{ + public interface ITopKCommandsAsync + { + /// + /// Increases the count of item by increment. + /// + /// The name of the sketch. + /// Items to be added + /// Array of simple-string-reply - if an element was dropped from the TopK list, null otherwise + /// + Task AddAsync(RedisKey key, params RedisValue[] items); + + /// + /// Returns count for an items. + /// + /// Name of sketch where item is counted + /// Items to be counted. + /// count for responding item. + /// + [Obsolete("TOPK.COUNT is deprecated as of Bloom 2.4.0")] + Task CountAsync(RedisKey key, params RedisValue[] items); + + /// + /// Increase the score of an item in the data structure by increment. + /// + /// Name of sketch where item is added. + /// Tuple of The items which counter is to be increased + /// and the Amount by which the item score is to be increased. + /// Score of each item after increment. + /// + Task IncrByAsync(RedisKey key, params Tuple[] itemIncrements); + /// + /// Return TopK information. + /// + /// Name of the key to return information about. + /// TopK Information. + /// + Task InfoAsync(RedisKey key); + + /// + /// Return full list of items in Top K list. + /// + /// The name of the sketch. + /// return Count of each element is returned. + /// Full list of items in Top K list + /// + Task ListAsync(RedisKey key, bool withcount = false); + + /// + /// Returns the count for one or more items in a sketch. + /// + /// The name of the sketch + /// Item to be queried. + /// if item is in Top-K, otherwise/> + /// + Task QueryAsync(RedisKey key, RedisValue item); + + /// + /// Returns the count for one or more items in a sketch. + /// + /// The name of the sketch + /// Items to be queried. + /// Bolean Array where if item is in Top-K, otherwise/> + /// + Task QueryAsync(RedisKey key, params RedisValue[] items); + + /// + /// Initializes a TopK with specified parameters. + /// + /// Key under which the sketch is to be found. + /// Number of top occurring items to keep. + /// Number of counters kept in each array. (Default 8) + /// Number of arrays. (Default 7) + /// The probability of reducing a counter in an occupied bucket. (Default 0.9) + /// if executed correctly, error otherwise/> + /// + Task ReserveAsync(RedisKey key, long topk, long width = 7, long depth = 8, double decay = 0.9); + } +} \ No newline at end of file diff --git a/src/NRedisStack/TopK/TopKCommands.cs b/src/NRedisStack/TopK/TopKCommands.cs index 8e6f9026..0eaa7909 100644 --- a/src/NRedisStack/TopK/TopKCommands.cs +++ b/src/NRedisStack/TopK/TopKCommands.cs @@ -1,13 +1,12 @@ using NRedisStack.TopK.DataTypes; -using NRedisStack.Literals; using StackExchange.Redis; namespace NRedisStack { - public class TopKCommands : ITopKCommands + public class TopKCommands : TopKCommandsAsync, ITopKCommands { IDatabase _db; - public TopKCommands(IDatabase db) + public TopKCommands(IDatabase db) : base(db) { _db = db; } @@ -18,95 +17,46 @@ public TopKCommands(IDatabase db) return (RedisResult[]?) _db.Execute(TopKCommandBuilder.Add(key, items)); } - /// - public async Task AddAsync(RedisKey key, params RedisValue[] items) - { - return (RedisResult[]?) await _db.ExecuteAsync(TopKCommandBuilder.Add(key, items)); - } - /// public long[] Count(RedisKey key, params RedisValue[] items) { return _db.Execute(TopKCommandBuilder.Count(key, items)).ToLongArray(); } - /// - public async Task CountAsync(RedisKey key, params RedisValue[] items) - { - return (await _db.ExecuteAsync(TopKCommandBuilder.Count(key, items))).ToLongArray(); - } - - /// public RedisResult[] IncrBy(RedisKey key, params Tuple[] itemIncrements) { return _db.Execute(TopKCommandBuilder.IncrBy(key, itemIncrements)).ToArray(); } - /// - public async Task IncrByAsync(RedisKey key, params Tuple[] itemIncrements) - { - return (await _db.ExecuteAsync(TopKCommandBuilder.IncrBy(key, itemIncrements))).ToArray(); - } - /// public TopKInformation Info(RedisKey key) { return _db.Execute(TopKCommandBuilder.Info(key)).ToTopKInfo(); } - /// - public async Task InfoAsync(RedisKey key) - { - return (await _db.ExecuteAsync(TopKCommandBuilder.Info(key))).ToTopKInfo(); - } - /// public RedisResult[] List(RedisKey key, bool withcount = false) { return _db.Execute(TopKCommandBuilder.List(key, withcount)).ToArray(); } - /// - public async Task ListAsync(RedisKey key, bool withcount = false) - { - return (await _db.ExecuteAsync(TopKCommandBuilder.List(key, withcount))).ToArray(); - } - /// public bool Query(RedisKey key, RedisValue item) { return _db.Execute(TopKCommandBuilder.Query(key, item)).ToString() == "1"; } - /// - public async Task QueryAsync(RedisKey key, RedisValue item) - { - return (await _db.ExecuteAsync(TopKCommandBuilder.Query(key, item))).ToString() == "1"; - } - /// public bool[] Query(RedisKey key, params RedisValue[] items) { return _db.Execute(TopKCommandBuilder.Query(key, items)).ToBooleanArray(); } - /// - public async Task QueryAsync(RedisKey key, params RedisValue[] items) - { - return (await _db.ExecuteAsync(TopKCommandBuilder.Query(key, items))).ToBooleanArray(); - } - /// public bool Reserve(RedisKey key, long topk, long width = 7, long depth = 8, double decay = 0.9) { return _db.Execute(TopKCommandBuilder.Reserve(key, topk, width, depth, decay)).OKtoBoolean(); } - - /// - public async Task ReserveAsync(RedisKey key, long topk, long width = 7, long depth = 8, double decay = 0.9) - { - return (await _db.ExecuteAsync(TopKCommandBuilder.Reserve(key, topk, width, depth, decay))).OKtoBoolean(); - } } } diff --git a/src/NRedisStack/TopK/TopKCommandsAsync.cs b/src/NRedisStack/TopK/TopKCommandsAsync.cs new file mode 100644 index 00000000..20576147 --- /dev/null +++ b/src/NRedisStack/TopK/TopKCommandsAsync.cs @@ -0,0 +1,62 @@ +using NRedisStack.TopK.DataTypes; +using StackExchange.Redis; +namespace NRedisStack + +{ + public class TopKCommandsAsync : ITopKCommandsAsync + { + IDatabaseAsync _db; + public TopKCommandsAsync(IDatabaseAsync db) + { + _db = db; + } + + /// + public async Task AddAsync(RedisKey key, params RedisValue[] items) + { + return (RedisResult[]?) await _db.ExecuteAsync(TopKCommandBuilder.Add(key, items)); + } + + /// + public async Task CountAsync(RedisKey key, params RedisValue[] items) + { + return (await _db.ExecuteAsync(TopKCommandBuilder.Count(key, items))).ToLongArray(); + } + + /// + public async Task IncrByAsync(RedisKey key, params Tuple[] itemIncrements) + { + return (await _db.ExecuteAsync(TopKCommandBuilder.IncrBy(key, itemIncrements))).ToArray(); + } + + /// + public async Task InfoAsync(RedisKey key) + { + return (await _db.ExecuteAsync(TopKCommandBuilder.Info(key))).ToTopKInfo(); + } + + /// + public async Task ListAsync(RedisKey key, bool withcount = false) + { + return (await _db.ExecuteAsync(TopKCommandBuilder.List(key, withcount))).ToArray(); + } + + /// + public async Task QueryAsync(RedisKey key, RedisValue item) + { + return (await _db.ExecuteAsync(TopKCommandBuilder.Query(key, item))).ToString() == "1"; + } + + /// + public async Task QueryAsync(RedisKey key, params RedisValue[] items) + { + return (await _db.ExecuteAsync(TopKCommandBuilder.Query(key, items))).ToBooleanArray(); + } + + /// + public async Task ReserveAsync(RedisKey key, long topk, long width = 7, long depth = 8, double decay = 0.9) + { + return (await _db.ExecuteAsync(TopKCommandBuilder.Reserve(key, topk, width, depth, decay))).OKtoBoolean(); + } + } +} \ No newline at end of file From 98e44c1a04b157627962f5baeab29d0960264b05 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Sun, 29 Jan 2023 10:56:15 +0200 Subject: [PATCH 19/21] Add commands instance for each module in pipeline class --- src/NRedisStack/Pipeline.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/NRedisStack/Pipeline.cs b/src/NRedisStack/Pipeline.cs index e5c80946..f9514b35 100644 --- a/src/NRedisStack/Pipeline.cs +++ b/src/NRedisStack/Pipeline.cs @@ -16,7 +16,15 @@ public void Execute() _batch.Execute(); } + public IBloomCommandsAsync Bloom => new BloomCommandsAsync(_batch); + public ICmsCommandsAsync Cms => new CmsCommandsAsync(_batch); + public ICuckooCommandsAsync Cf => new CuckooCommandsAsync(_batch); + public IGraphCommandsAsync Graph => new GraphCommandsAsync(_batch); public IJsonCommandsAsync Json => new JsonCommandsAsync(_batch); + public ISearchCommandsAsync Search => new SearchCommandsAsync(_batch); + public ITdigestCommandsAsync Tdigest => new TdigestCommandsAsync(_batch); + public ITimeSeriesCommandsAsync Ts => new TimeSeriesCommandsAsync(_batch); + public ITopKCommandsAsync TopK => new TopKCommandsAsync(_batch); public IDatabaseAsync Db => _batch; } \ No newline at end of file From 232e5f69c4c5aae433879e9471c0f7fc35afcb5f Mon Sep 17 00:00:00 2001 From: shacharPash Date: Sun, 29 Jan 2023 12:00:14 +0200 Subject: [PATCH 20/21] Add pipeline test for BF --- src/NRedisStack/Pipeline.cs | 9 +++++-- tests/NRedisStack.Tests/Bloom/BloomTests.cs | 26 +++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/NRedisStack/Pipeline.cs b/src/NRedisStack/Pipeline.cs index f9514b35..a9caecb2 100644 --- a/src/NRedisStack/Pipeline.cs +++ b/src/NRedisStack/Pipeline.cs @@ -9,6 +9,11 @@ public Pipeline(IConnectionMultiplexer muxer) _batch = muxer.GetDatabase().CreateBatch(); } + public Pipeline(IDatabase db) + { + _batch = db.CreateBatch(); + } + private IBatch _batch; public void Execute() @@ -16,12 +21,12 @@ public void Execute() _batch.Execute(); } - public IBloomCommandsAsync Bloom => new BloomCommandsAsync(_batch); + public IBloomCommandsAsync Bf => new BloomCommandsAsync(_batch); public ICmsCommandsAsync Cms => new CmsCommandsAsync(_batch); public ICuckooCommandsAsync Cf => new CuckooCommandsAsync(_batch); public IGraphCommandsAsync Graph => new GraphCommandsAsync(_batch); public IJsonCommandsAsync Json => new JsonCommandsAsync(_batch); - public ISearchCommandsAsync Search => new SearchCommandsAsync(_batch); + public ISearchCommandsAsync Ft => new SearchCommandsAsync(_batch); public ITdigestCommandsAsync Tdigest => new TdigestCommandsAsync(_batch); public ITimeSeriesCommandsAsync Ts => new TimeSeriesCommandsAsync(_batch); public ITopKCommandsAsync TopK => new TopKCommandsAsync(_batch); diff --git a/tests/NRedisStack.Tests/Bloom/BloomTests.cs b/tests/NRedisStack.Tests/Bloom/BloomTests.cs index c8107481..aa0cc652 100644 --- a/tests/NRedisStack.Tests/Bloom/BloomTests.cs +++ b/tests/NRedisStack.Tests/Bloom/BloomTests.cs @@ -33,6 +33,32 @@ public void TestReserveBasic() Assert.False(bf.Exists(key, "item2")); } + [Fact] + public async Task TestPipeline() + { + IDatabase db = redisFixture.Redis.GetDatabase(); + db.Execute("FLUSHALL"); + var pipeline = new Pipeline(db); + + pipeline.Bf.ReserveAsync(key, 0.001, 100); + for(int i = 0; i < 1000; i++) + { + pipeline.Bf.AddAsync(key, i.ToString()); + } + + for(int i = 0; i < 100; i++) + { + Assert.False(db.BF().Exists(key, i.ToString())); + } + + pipeline.Execute(); + + for(int i = 0; i < 1000; i++) + { + Assert.True(db.BF().Exists(key, i.ToString())); + } + } + [Fact] public async Task TestReserveBasicAsync() { From c15b78099f1307e186ad206f4d2522c73c44a67e Mon Sep 17 00:00:00 2001 From: shacharPash Date: Sun, 29 Jan 2023 15:13:55 +0200 Subject: [PATCH 21/21] create separate test class for pipeline --- tests/NRedisStack.Tests/Bloom/BloomTests.cs | 28 ----- tests/NRedisStack.Tests/Json/JsonTests.cs | 16 --- tests/NRedisStack.Tests/PipelineTests.cs | 129 ++++++++++++++++++++ 3 files changed, 129 insertions(+), 44 deletions(-) create mode 100644 tests/NRedisStack.Tests/PipelineTests.cs diff --git a/tests/NRedisStack.Tests/Bloom/BloomTests.cs b/tests/NRedisStack.Tests/Bloom/BloomTests.cs index aa0cc652..a57a5314 100644 --- a/tests/NRedisStack.Tests/Bloom/BloomTests.cs +++ b/tests/NRedisStack.Tests/Bloom/BloomTests.cs @@ -16,8 +16,6 @@ public void Dispose() redisFixture.Redis.GetDatabase().KeyDelete(key); } - // TODO: Add test for bloom pipeline - [Fact] public void TestReserveBasic() { @@ -33,32 +31,6 @@ public void TestReserveBasic() Assert.False(bf.Exists(key, "item2")); } - [Fact] - public async Task TestPipeline() - { - IDatabase db = redisFixture.Redis.GetDatabase(); - db.Execute("FLUSHALL"); - var pipeline = new Pipeline(db); - - pipeline.Bf.ReserveAsync(key, 0.001, 100); - for(int i = 0; i < 1000; i++) - { - pipeline.Bf.AddAsync(key, i.ToString()); - } - - for(int i = 0; i < 100; i++) - { - Assert.False(db.BF().Exists(key, i.ToString())); - } - - pipeline.Execute(); - - for(int i = 0; i < 1000; i++) - { - Assert.True(db.BF().Exists(key, i.ToString())); - } - } - [Fact] public async Task TestReserveBasicAsync() { diff --git a/tests/NRedisStack.Tests/Json/JsonTests.cs b/tests/NRedisStack.Tests/Json/JsonTests.cs index cdc7c497..57227a15 100644 --- a/tests/NRedisStack.Tests/Json/JsonTests.cs +++ b/tests/NRedisStack.Tests/Json/JsonTests.cs @@ -20,22 +20,6 @@ public void Dispose() redisFixture.Redis.GetDatabase().KeyDelete(_testName); } - [Fact] - public async Task TestJsonPipeline() - { - var pipeline = new Pipeline(ConnectionMultiplexer.Connect("localhost")); - pipeline.Db.ExecuteAsync("FLUSHALL"); - - string jsonPerson = JsonSerializer.Serialize(new Person { Name = "Shachar", Age = 23 }); - var setResponse = pipeline.Json.SetAsync("key", "$", jsonPerson); - var getResponse = pipeline.Json.GetAsync("key"); - - pipeline.Execute(); - - Assert.Equal("True", setResponse.Result.ToString()); - Assert.Equal("{\"Name\":\"Shachar\",\"Age\":23}", getResponse.Result.ToString()); - } - [Fact] public void TestSetFromFile() { diff --git a/tests/NRedisStack.Tests/PipelineTests.cs b/tests/NRedisStack.Tests/PipelineTests.cs new file mode 100644 index 00000000..fec1012e --- /dev/null +++ b/tests/NRedisStack.Tests/PipelineTests.cs @@ -0,0 +1,129 @@ +using Xunit; +using StackExchange.Redis; +using NRedisStack.RedisStackCommands; +using Moq; +using System.Text.Json; +using NRedisStack.Search.FT.CREATE; +using NRedisStack.Search; + +namespace NRedisStack.Tests.Bloom; + +public class PipelineTests : AbstractNRedisStackTest, IDisposable +{ + Mock _mock = new Mock(); + private readonly string key = "PIPELINE_TESTS"; + public PipelineTests(RedisFixture redisFixture) : base(redisFixture) { } + + public void Dispose() + { + redisFixture.Redis.GetDatabase().KeyDelete(key); + } + + // [Fact] + // public async Task TestPipeline() + // { + // IDatabase db = redisFixture.Redis.GetDatabase(); + // db.Execute("FLUSHALL"); + // var pipeline = new Pipeline(db); + + // pipeline.Db.StringSetAsync("a", "a1"); + // pipeline.Db.StringGetAsync("a"); + // pipeline.Db.SortedSetAddAsync("z", new SortedSetEntry[] { new SortedSetEntry("z1", 1) }); + // pipeline.Db.SortedSetAddAsync("z", new SortedSetEntry[] { new SortedSetEntry("z2", 4) }); + // pipeline.Db.SortedSetIncrementAsync() + // } + + + [Fact] + public async Task TestModulsPipeline() + { + IDatabase db = redisFixture.Redis.GetDatabase(); + db.Execute("FLUSHALL"); + var pipeline = new Pipeline(db); + + pipeline.Bf.ReserveAsync("bf-key", 0.001, 100); + pipeline.Bf.AddAsync("bf-key", "1"); + pipeline.Cms.InitByDimAsync("cms-key", 100, 5); + pipeline.Cf.ReserveAsync("cf-key", 100); + pipeline.Graph.QueryAsync("graph-key", "CREATE ({name:'shachar',age:23})"); + pipeline.Json.SetAsync("json-key", "$", "{}"); + pipeline.Ft.CreateAsync("ft-key", new FTCreateParams(), new Schema().AddTextField("txt")); + pipeline.Tdigest.CreateAsync("tdigest-key", 100); + pipeline.Ts.CreateAsync("ts-key", 100); + pipeline.TopK.ReserveAsync("topk-key", 100, 100, 100); + + Assert.False(db.KeyExists("bf-key")); + Assert.False(db.KeyExists("cms-key")); + Assert.False(db.KeyExists("cf-key")); + Assert.False(db.KeyExists("graph-key")); + Assert.False(db.KeyExists("json-key")); + Assert.Equal(0, db.FT()._List().Length); + Assert.False(db.KeyExists("tdigest-key")); + Assert.False(db.KeyExists("ts-key")); + Assert.False(db.KeyExists("topk-key")); + + pipeline.Execute(); + + Assert.True(db.KeyExists("bf-key")); + Assert.True(db.KeyExists("cms-key")); + Assert.True(db.KeyExists("cf-key")); + Assert.True(db.KeyExists("graph-key")); + Assert.True(db.KeyExists("json-key")); + Assert.True(db.FT()._List().Length == 1); + Assert.True(db.KeyExists("tdigest-key")); + Assert.True(db.KeyExists("ts-key")); + Assert.True(db.KeyExists("topk-key")); + + Assert.True(db.BF().Exists("bf-key", "1")); + Assert.True(db.CMS().Info("cms-key").Width == 100); + Assert.True(db.CF().Info("cf-key").Size > 0); + Assert.True(db.GRAPH().List().Count > 0); + Assert.False(db.JSON().Get("json-key").IsNull); + Assert.NotNull(db.FT().Info("ft-key")); + Assert.NotNull(db.TDIGEST().Info("tdigest-key")); + Assert.NotNull(db.TS().Info("ts-key")); + Assert.NotNull(db.TOPK().Info("topk-key")); + } + + [Fact] + public async Task TestBloomPipeline() + { + IDatabase db = redisFixture.Redis.GetDatabase(); + db.Execute("FLUSHALL"); + var pipeline = new Pipeline(db); + + pipeline.Bf.ReserveAsync(key, 0.001, 100); + for(int i = 0; i < 1000; i++) + { + pipeline.Bf.AddAsync(key, i.ToString()); + } + + for(int i = 0; i < 100; i++) + { + Assert.False(db.BF().Exists(key, i.ToString())); + } + + pipeline.Execute(); + + for(int i = 0; i < 1000; i++) + { + Assert.True(db.BF().Exists(key, i.ToString())); + } + } + + [Fact] + public async Task TestJsonPipeline() + { + var pipeline = new Pipeline(ConnectionMultiplexer.Connect("localhost")); + pipeline.Db.ExecuteAsync("FLUSHALL"); + + string jsonPerson = JsonSerializer.Serialize(new Person { Name = "Shachar", Age = 23 }); + var setResponse = pipeline.Json.SetAsync("key", "$", jsonPerson); + var getResponse = pipeline.Json.GetAsync("key"); + + pipeline.Execute(); + + Assert.Equal("True", setResponse.Result.ToString()); + Assert.Equal("{\"Name\":\"Shachar\",\"Age\":23}", getResponse.Result.ToString()); + } +} \ No newline at end of file