From 61011e374fb638d2efa3f5642a78ef337f688897 Mon Sep 17 00:00:00 2001 From: Gabriel Erzse Date: Thu, 25 Jan 2024 11:41:45 +0200 Subject: [PATCH 01/57] Formatting and typos Fix some typos in the markdown files and run `dotnet format` on existing code. --- CONTRIBUTING.md | 5 +++-- README.md | 4 +++- src/NRedisStack/TimeSeries/TimeSeriesAux.cs | 4 ++-- tests/NRedisStack.Tests/TimeSeries/TestAPI/TestMRange.cs | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7c5e007b..ca1c09eb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -35,7 +35,7 @@ Here's how to get started with your code contribution: 3. Write your tests 4. Use the `docker run -p 6379:6379 -it redis/redis-stack-server:edge` as your local environment for running the functional tests. You can also use Development Container as described below. -5. Run dotnet format to make sure your code is formatted +5. Run `dotnet format` to make sure your code is formatted 6. Make sure your tests pass using `dotnet test` 7. Open a pull request @@ -121,6 +121,7 @@ e.g. : ```bash dotnet test --environment "REDIS_CLUSTER=127.0.0.1:16379" --environment "NUM_REDIS_CLUSTER_NODES=6" ``` + ## How to Report a Bug ### Security Vulnerabilities @@ -145,7 +146,7 @@ issue, so if you're unsure, just email [us](mailto:oss@redis.com). When filing an issue, make sure to answer these five questions: 1. What version of NRedisStack are you using? -2. What version of redis are you using? +2. What version of Redis are you using? 3. What did you do? 4. What did you expect to see? 5. What did you see instead? diff --git a/README.md b/README.md index bc1f65c4..0c96178e 100644 --- a/README.md +++ b/README.md @@ -31,15 +31,17 @@ This project builds on [StackExchange.Redis](https://github.com/StackExchange/St The complete documentation for Redis module commands can be found at the [Redis commands website](https://redis.io/commands/). ### Redis OSS commands + You can use Redis OSS commands in the same way as you use them in [StackExchange.Redis](https://github.com/StackExchange/StackExchange.Redis). ### Stack commands + Each module has a command class with its own commands. + The supported modules are [Search](https://redis.io/commands/?group=search), [JSON](https://redis.io/commands/?group=json), [TimeSeries](https://redis.io/commands/?group=timeseries), [Bloom Filter](https://redis.io/commands/?group=bf), [Cuckoo Filter](https://redis.io/commands/?group=cf), [T-Digest](https://redis.io/commands/?group=tdigest), [Count-min Sketch](https://redis.io/commands/?group=cms), and [Top-K](https://redis.io/commands/?group=topk). **Note:** RedisGraph support has been deprecated starting from Redis Stack version 7.2. For more information, please refer to [this blog post](https://redis.com/blog/redisgraph-eol/). - # Usage ## 💻 Installation diff --git a/src/NRedisStack/TimeSeries/TimeSeriesAux.cs b/src/NRedisStack/TimeSeries/TimeSeriesAux.cs index 65ad7c94..54c20f65 100644 --- a/src/NRedisStack/TimeSeries/TimeSeriesAux.cs +++ b/src/NRedisStack/TimeSeries/TimeSeriesAux.cs @@ -81,7 +81,7 @@ public static void AddOnDuplicate(this IList args, TsDuplicatePolicy? po public static void AddAlign(this IList args, TimeStamp? alignMaybe) { - if (alignMaybe is {} align) + if (alignMaybe is { } align) { args.Add(TimeSeriesArgs.ALIGN); args.Add(align.Value); @@ -251,7 +251,7 @@ public static List BuildTsIncrDecrByArgs(string key, double value, TimeS IReadOnlyCollection? labels, bool? uncompressed, long? chunkSizeBytes) { var args = new List { key, value }; - if (timestampMaybe is {} timestamp) args.AddTimeStamp(timestamp); + if (timestampMaybe is { } timestamp) args.AddTimeStamp(timestamp); args.AddRetentionTime(retentionTime); args.AddChunkSize(chunkSizeBytes); if (labels != null) args.AddLabels(labels); diff --git a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestMRange.cs b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestMRange.cs index 34b9ee38..0c0d7338 100644 --- a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestMRange.cs +++ b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestMRange.cs @@ -318,7 +318,7 @@ public void TestMRangeLatest() var compactedLabel = new TimeSeriesLabel("compact", "true"); string primaryTsKey = _keys[0], compactedTsKey = _keys[1]; var compactionRule = new TimeSeriesRule( - compactedTsKey, + compactedTsKey, (long)TimeSpan.FromHours(1).TotalMilliseconds, // 1h used to force partial bucket TsAggregation.Sum); From 07cdbcc0ad2aa89e50a0a63f2d3699977be7d573 Mon Sep 17 00:00:00 2001 From: Gabriel Erzse Date: Thu, 25 Jan 2024 11:43:57 +0200 Subject: [PATCH 02/57] Include documentation in the build Change the settings so that documentation is included in the build. --- src/NRedisStack/NRedisStack.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NRedisStack/NRedisStack.csproj b/src/NRedisStack/NRedisStack.csproj index 58467115..3ab8cbf9 100644 --- a/src/NRedisStack/NRedisStack.csproj +++ b/src/NRedisStack/NRedisStack.csproj @@ -3,6 +3,7 @@ enable netstandard2.0;net6.0;net7.0 + true latest enable Redis Open Source From 9be88b97f863fac509db2bc7622c49310de12c87 Mon Sep 17 00:00:00 2001 From: Gabriel Erzse Date: Thu, 25 Jan 2024 11:46:41 +0200 Subject: [PATCH 03/57] Add support for BZMPOP (#233) Add support for the BZMPOP command. This command is blocking on the server, so it goes against the current policy of the StackExchange.Redis library. Therefore make it obvious in the code documentation that attention must be given to the timeout in the connection multiplexer. The StackExchange.Redis library already defines a type for the payload returned by BZMPOP (which is the same as for ZMPOP), namely the SortedSetPopResult class. However, the constructor of that class is internal in the library, so we can't create instances of it. Therefore roll our out type for a pair, and use Tuple to pair a key with a list of such pairs. --- .../CoreCommands/CoreCommandBuilder.cs | 26 ++++++++ src/NRedisStack/CoreCommands/CoreCommands.cs | 38 +++++++++++ .../DataTypes/RedisValueWithScore.cs | 22 +++++++ .../CoreCommands/Literals/CommandArgs.cs | 5 +- .../CoreCommands/Literals/Commands.cs | 3 +- src/NRedisStack/ResponseParser.cs | 35 ++++++++++ .../Core Commands/CoreTests.cs | 64 +++++++++++++++++++ 7 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 src/NRedisStack/CoreCommands/DataTypes/RedisValueWithScore.cs diff --git a/src/NRedisStack/CoreCommands/CoreCommandBuilder.cs b/src/NRedisStack/CoreCommands/CoreCommandBuilder.cs index 9677824d..0ed6594a 100644 --- a/src/NRedisStack/CoreCommands/CoreCommandBuilder.cs +++ b/src/NRedisStack/CoreCommands/CoreCommandBuilder.cs @@ -1,6 +1,7 @@ using NRedisStack.RedisStackCommands; using NRedisStack.Core.Literals; using NRedisStack.Core; +using StackExchange.Redis; namespace NRedisStack { @@ -18,5 +19,30 @@ public static SerializedCommand ClientSetInfo(SetInfoAttr attr, string value) return new SerializedCommand(RedisCoreCommands.CLIENT, RedisCoreCommands.SETINFO, attrValue, value); } + + /// + /// Build a SerializedCommand for the BZMPOP command. + /// + /// Keys for the sorted sets to pop from. + /// Server timeout for the blocking operation. If set to 0 then it waits + /// indefinitely. + /// Maximum number of items to pop. + /// In what order to pop items. A value of Order.Ascending means to pop the minimum + /// scores from the sorted set, a value of Order.Descending means to pop the maximum scores. + /// The serialized command that can be executed against the server. + /// + public static SerializedCommand BzmPop(RedisKey[] keys, int timeout = 0, long count = 1, Order order = Order.Ascending) + { + List args = [ + timeout, + keys.Length, + .. keys.Cast(), + order == Order.Ascending ? CoreArgs.MIN : CoreArgs.MAX, + CoreArgs.COUNT, + count + ]; + + return new SerializedCommand(RedisCoreCommands.BZMPOP, args); + } } } diff --git a/src/NRedisStack/CoreCommands/CoreCommands.cs b/src/NRedisStack/CoreCommands/CoreCommands.cs index 4c8917bb..2c4d45e4 100644 --- a/src/NRedisStack/CoreCommands/CoreCommands.cs +++ b/src/NRedisStack/CoreCommands/CoreCommands.cs @@ -1,5 +1,7 @@ using NRedisStack.Core; +using NRedisStack.Core.DataTypes; using StackExchange.Redis; + namespace NRedisStack { @@ -19,5 +21,41 @@ public static bool ClientSetInfo(this IDatabase db, SetInfoAttr attr, string val return false; return db.Execute(CoreCommandBuilder.ClientSetInfo(attr, value)).OKtoBoolean(); } + + /// + /// The BZMPOP command. + ///

+ /// Removes and returns up to entries from the first non-empty sorted set in + /// . If none of the sets contain elements, the call blocks on the server until elements + /// become available or the give passes. A of 0 + /// means to wait indefinitely server-side. Returns null if the server timeout expires. + ///

+ /// When using this, pay attention to the timeout configured on the , which + /// by default can be too small, in which case you want to increase it: + /// + /// ConfigurationOptions configurationOptions = new ConfigurationOptions(); + /// configurationOptions.SyncTimeout = 120000; + /// configurationOptions.EndPoints.Add("localhost"); + /// ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(configurationOptions); + /// + /// If the connection multiplexer timeout expires, a StackExchange.Redis.RedisTimeoutException will be + /// thrown. + ///

+ /// This is an extension method added to the class, for convenience. + ///

+ /// The class where this extension method is applied. + /// The keys to check. + /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. + /// The maximum number of records to pop out. + /// The order to sort by when popping items out of the set. If set to Order.ascending + /// then the minimum elements will be popped, otherwise the maximum values. + /// A collection of sorted set entries paired with their scores, together with the key they were popped + /// from, or null if the server timeout expires. + /// + public static Tuple>? BzmPop(this IDatabase db, RedisKey[] keys, int timeout = 0, long count = 1, Order order = Order.Ascending) + { + var command = CoreCommandBuilder.BzmPop(keys, timeout, count, order); + return db.Execute(command).ToSortedSetPopResult(); + } } } diff --git a/src/NRedisStack/CoreCommands/DataTypes/RedisValueWithScore.cs b/src/NRedisStack/CoreCommands/DataTypes/RedisValueWithScore.cs new file mode 100644 index 00000000..95f98a00 --- /dev/null +++ b/src/NRedisStack/CoreCommands/DataTypes/RedisValueWithScore.cs @@ -0,0 +1,22 @@ +using StackExchange.Redis; + +namespace NRedisStack.Core.DataTypes; + +/// +/// Holds a value with an associated score. +/// Used when working with sorted sets. +/// +public class RedisValueWithScore(RedisValue value, double score) +{ + /// + /// The value of an item stored in a sorted set. For example, in the Redis command + /// ZADD my-set 5.1 my-value, the value is my-value. + /// + public RedisValue Value { get; } = value; + + /// + /// The score of an item stored in a sorted set. For example, in the Redis command + /// ZADD my-set 5.1 my-value, the score is 5.1. + /// + public double Score { get; } = score; +} \ No newline at end of file diff --git a/src/NRedisStack/CoreCommands/Literals/CommandArgs.cs b/src/NRedisStack/CoreCommands/Literals/CommandArgs.cs index 8d9aaf4f..4e6e4242 100644 --- a/src/NRedisStack/CoreCommands/Literals/CommandArgs.cs +++ b/src/NRedisStack/CoreCommands/Literals/CommandArgs.cs @@ -1,8 +1,11 @@ namespace NRedisStack.Core.Literals { - internal class CoreArgs + internal static class CoreArgs { + public const string COUNT = "COUNT"; public const string lib_name = "LIB-NAME"; public const string lib_ver = "LIB-VER"; + public const string MAX = "MAX"; + public const string MIN = "MIN"; } } diff --git a/src/NRedisStack/CoreCommands/Literals/Commands.cs b/src/NRedisStack/CoreCommands/Literals/Commands.cs index aaebaef6..319c87c2 100644 --- a/src/NRedisStack/CoreCommands/Literals/Commands.cs +++ b/src/NRedisStack/CoreCommands/Literals/Commands.cs @@ -3,8 +3,9 @@ namespace NRedisStack.Core.Literals /// /// Redis Core command literals /// - internal class RedisCoreCommands + internal static class RedisCoreCommands { + public const string BZMPOP = "BZMPOP"; public const string CLIENT = "CLIENT"; public const string SETINFO = "SETINFO"; } diff --git a/src/NRedisStack/ResponseParser.cs b/src/NRedisStack/ResponseParser.cs index 81f22eb3..46236c15 100644 --- a/src/NRedisStack/ResponseParser.cs +++ b/src/NRedisStack/ResponseParser.cs @@ -3,6 +3,7 @@ using NRedisStack.Extensions; using StackExchange.Redis; using NRedisStack.Bloom.DataTypes; +using NRedisStack.Core.DataTypes; using NRedisStack.CuckooFilter.DataTypes; using NRedisStack.CountMinSketch.DataTypes; using NRedisStack.TopK.DataTypes; @@ -84,6 +85,16 @@ public static TimeStamp ToTimeStamp(this RedisResult result) return new TimeStamp((long)result); } + public static RedisKey ToRedisKey(this RedisResult result) + { + return new RedisKey(result.ToString()); + } + + public static RedisValue ToRedisValue(this RedisResult result) + { + return new RedisValue(result.ToString()); + } + public static IReadOnlyList ToTimeStampArray(this RedisResult result) { RedisResult[] redisResults = (RedisResult[])result!; @@ -715,5 +726,29 @@ public static Dictionary[] ToDictionarys(this RedisResult r return dicts; } + + public static Tuple>? ToSortedSetPopResult(this RedisResult result) + { + if (result.IsNull) + { + return null; + } + + var resultArray = (RedisResult[])result!; + var resultKey = resultArray[0].ToRedisKey(); + var resultSetItems = resultArray[1].ToArray(); + + List valuesWithScores = []; + + foreach (var resultSetItem in resultSetItems) + { + var resultSetItemArray = (RedisResult[])resultSetItem!; + var value = resultSetItemArray[0].ToRedisValue(); + var score = resultSetItemArray[1].ToDouble(); + valuesWithScores.Add(new RedisValueWithScore(value, score)); + } + + return new Tuple>(resultKey, valuesWithScores); + } } } \ No newline at end of file diff --git a/tests/NRedisStack.Tests/Core Commands/CoreTests.cs b/tests/NRedisStack.Tests/Core Commands/CoreTests.cs index 9a3d763a..57f3f31e 100644 --- a/tests/NRedisStack.Tests/Core Commands/CoreTests.cs +++ b/tests/NRedisStack.Tests/Core Commands/CoreTests.cs @@ -146,4 +146,68 @@ public async Task TestSetInfoNullAsync() // Assert that the extracted sub-strings are equal Assert.Equal(infoAfterLibNameToEnd, infoBeforeLibNameToEnd); } + + [SkipIfRedis(Comparison.LessThan, "7.0.0")] + public void TestBzmPop() + { + var redis = ConnectionMultiplexer.Connect("localhost"); + + var db = redis.GetDatabase(null); + db.Execute("FLUSHALL"); + + var sortedSetKey = "my-set"; + + db.SortedSetAdd(sortedSetKey, "a", 1.5); + db.SortedSetAdd(sortedSetKey, "b", 5.1); + db.SortedSetAdd(sortedSetKey, "c", 3.7); + db.SortedSetAdd(sortedSetKey, "d", 9.4); + db.SortedSetAdd(sortedSetKey, "e", 7.76); + + // Pop two items with default order, which means it will pop the minimum values. + var resultWithDefaultOrder = db.BzmPop([sortedSetKey], count: 2); + + Assert.NotNull(resultWithDefaultOrder); + Assert.Equal(sortedSetKey, resultWithDefaultOrder!.Item1); + Assert.Equal(2, resultWithDefaultOrder.Item2.Count); + Assert.Equal("a", resultWithDefaultOrder.Item2[0].Value.ToString()); + Assert.Equal("c", resultWithDefaultOrder.Item2[1].Value.ToString()); + + // Pop one more item, with descending order, which means it will pop the maximum value. + var resultWithDescendingOrder = db.BzmPop([sortedSetKey], order: Order.Descending); + + Assert.NotNull(resultWithDescendingOrder); + Assert.Equal(sortedSetKey, resultWithDescendingOrder!.Item1); + Assert.Single(resultWithDescendingOrder.Item2); + Assert.Equal("d", resultWithDescendingOrder.Item2[0].Value.ToString()); + } + + [SkipIfRedis(Comparison.LessThan, "7.0.0")] + public void TestBzmPopNull() + { + var redis = ConnectionMultiplexer.Connect("localhost"); + + var db = redis.GetDatabase(null); + db.Execute("FLUSHALL"); + + // Nothing in the set, and a short server timeout, which yields null. + var result = db.BzmPop(["my-set"], timeout: 1); + + Assert.Null(result); + } + + + [SkipIfRedis(Comparison.LessThan, "7.0.0")] + public void TestBzmPopMultiplexerTimeout() + { + var configurationOptions = new ConfigurationOptions(); + configurationOptions.SyncTimeout = 1000; + configurationOptions.EndPoints.Add("localhost"); + var redis = ConnectionMultiplexer.Connect(configurationOptions); + + var db = redis.GetDatabase(null); + db.Execute("FLUSHALL"); + + // Server would wait forever, but the multiplexer times out in 1 second. + Assert.Throws(() => db.BzmPop(["my-set"])); + } } \ No newline at end of file From d5b88801373dc825fabb132ac3991cd9070fd629 Mon Sep 17 00:00:00 2001 From: Gabriel Erzse Date: Thu, 25 Jan 2024 12:08:24 +0200 Subject: [PATCH 04/57] Skip new tests for Redis Cluster --- tests/NRedisStack.Tests/Core Commands/CoreTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/NRedisStack.Tests/Core Commands/CoreTests.cs b/tests/NRedisStack.Tests/Core Commands/CoreTests.cs index 57f3f31e..448a16d1 100644 --- a/tests/NRedisStack.Tests/Core Commands/CoreTests.cs +++ b/tests/NRedisStack.Tests/Core Commands/CoreTests.cs @@ -147,7 +147,7 @@ public async Task TestSetInfoNullAsync() Assert.Equal(infoAfterLibNameToEnd, infoBeforeLibNameToEnd); } - [SkipIfRedis(Comparison.LessThan, "7.0.0")] + [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.0.0")] public void TestBzmPop() { var redis = ConnectionMultiplexer.Connect("localhost"); @@ -181,7 +181,7 @@ public void TestBzmPop() Assert.Equal("d", resultWithDescendingOrder.Item2[0].Value.ToString()); } - [SkipIfRedis(Comparison.LessThan, "7.0.0")] + [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.0.0")] public void TestBzmPopNull() { var redis = ConnectionMultiplexer.Connect("localhost"); @@ -196,7 +196,7 @@ public void TestBzmPopNull() } - [SkipIfRedis(Comparison.LessThan, "7.0.0")] + [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.0.0")] public void TestBzmPopMultiplexerTimeout() { var configurationOptions = new ConfigurationOptions(); From 132a224d9512103e232246fb9541b48034f5c2f8 Mon Sep 17 00:00:00 2001 From: nimanikoo Date: Fri, 26 Jan 2024 20:12:15 +0330 Subject: [PATCH 05/57] Refactor and Change the List Collection to ICollection for better performance and memory usage --- src/NRedisStack/Bloom/BloomAux.cs | 104 ++++++++++++++---------------- 1 file changed, 47 insertions(+), 57 deletions(-) diff --git a/src/NRedisStack/Bloom/BloomAux.cs b/src/NRedisStack/Bloom/BloomAux.cs index c87925e2..84d23152 100644 --- a/src/NRedisStack/Bloom/BloomAux.cs +++ b/src/NRedisStack/Bloom/BloomAux.cs @@ -1,74 +1,64 @@ using NRedisStack.Bloom.Literals; using StackExchange.Redis; -namespace NRedisStack +namespace NRedisStack; + +public static class BloomAux { - public static class BloomAux + public static List BuildInsertArgs(RedisKey key, IEnumerable items, int? capacity, + double? error, int? expansion, bool nocreate, bool nonscaling) { - public static List BuildInsertArgs(RedisKey key, RedisValue[] items, int? capacity, - double? error, int? expansion, bool nocreate, bool nonscaling) - { - var args = new List { key }; - args.AddCapacity(capacity); - args.AddError(error); - args.AddExpansion(expansion); - args.AddNoCreate(nocreate); - args.AddNoScaling(nonscaling); - args.AddItems(items); + var args = new List { key }; + args.AddCapacity(capacity); + args.AddError(error); + args.AddExpansion(expansion); + args.AddNoCreate(nocreate); + args.AddNoScaling(nonscaling); + args.AddItems(items); - return args; - } + return args; + } - private static void AddItems(this List args, RedisValue[] items) - { - args.Add(BloomArgs.ITEMS); - foreach (var item in items) - { - args.Add(item); - } - } + private static void AddItems(this List args, IEnumerable items) + { + args.Add(BloomArgs.ITEMS); + args.AddRange(items.Cast()); + } - private static void AddNoScaling(this List args, bool nonscaling) + private static void AddNoScaling(this ICollection args, bool nonScaling) + { + if (nonScaling) { - if (nonscaling) - { - args.Add(BloomArgs.NONSCALING); - } + args.Add(BloomArgs.NONSCALING); } + } - private static void AddNoCreate(this List args, bool nocreate) + private static void AddNoCreate(this ICollection args, bool nocreate) + { + if (nocreate) { - if (nocreate) - { - args.Add(BloomArgs.NOCREATE); - } + args.Add(BloomArgs.NOCREATE); } + } - private static void AddExpansion(this List args, int? expansion) - { - if (expansion != null) - { - args.Add(BloomArgs.EXPANSION); - args.Add(expansion); - } - } + private static void AddExpansion(this ICollection args, int? expansion) + { + if (expansion == null) return; + args.Add(BloomArgs.EXPANSION); + args.Add(expansion); + } - private static void AddError(this List args, double? error) - { - if (error != null) - { - args.Add(BloomArgs.ERROR); - args.Add(error); - } - } + private static void AddError(this ICollection args, double? error) + { + if (error == null) return; + args.Add(BloomArgs.ERROR); + args.Add(error); + } - private static void AddCapacity(this List args, int? capacity) - { - if (capacity != null) - { - args.Add(BloomArgs.CAPACITY); - args.Add(capacity); - } - } + private static void AddCapacity(this ICollection args, int? capacity) + { + if (capacity == null) return; + args.Add(BloomArgs.CAPACITY); + args.Add(capacity); } -} +} \ No newline at end of file From b82ef2aa9461df49a39a19a18674182039058546 Mon Sep 17 00:00:00 2001 From: nimanikoo Date: Fri, 26 Jan 2024 20:13:47 +0330 Subject: [PATCH 06/57] Change NameSpace to Scoped --- src/NRedisStack/Bloom/BloomCommandBuilder.cs | 134 +++++++++---------- 1 file changed, 62 insertions(+), 72 deletions(-) diff --git a/src/NRedisStack/Bloom/BloomCommandBuilder.cs b/src/NRedisStack/Bloom/BloomCommandBuilder.cs index b654134c..75b621aa 100644 --- a/src/NRedisStack/Bloom/BloomCommandBuilder.cs +++ b/src/NRedisStack/Bloom/BloomCommandBuilder.cs @@ -1,100 +1,90 @@ using NRedisStack.RedisStackCommands; using StackExchange.Redis; using NRedisStack.Bloom.Literals; -namespace NRedisStack -{ +namespace NRedisStack; - public static class BloomCommandBuilder +public static class BloomCommandBuilder +{ + public static SerializedCommand Add(RedisKey key, RedisValue item) { - public static SerializedCommand Add(RedisKey key, RedisValue item) - { - return new SerializedCommand(BF.ADD, key, item); - } - - public static SerializedCommand Card(RedisKey key) - { - return new SerializedCommand(BF.CARD, key); - } + return new SerializedCommand(BF.ADD, key, item); + } - public static SerializedCommand Exists(RedisKey key, RedisValue item) - { - return new SerializedCommand(BF.EXISTS, key, item); - } + public static SerializedCommand Card(RedisKey key) + { + return new SerializedCommand(BF.CARD, key); + } - public static SerializedCommand Info(RedisKey key) - { - return new SerializedCommand(BF.INFO, key); - } + public static SerializedCommand Exists(RedisKey key, RedisValue item) + { + return new SerializedCommand(BF.EXISTS, key, item); + } - public static SerializedCommand Insert(RedisKey key, RedisValue[] items, int? capacity = null, - double? error = null, int? expansion = null, - bool nocreate = false, bool nonscaling = false) - { - if (items.Length < 1) - throw new ArgumentOutOfRangeException(nameof(items)); + public static SerializedCommand Info(RedisKey key) + { + return new SerializedCommand(BF.INFO, key); + } - var args = BloomAux.BuildInsertArgs(key, items, capacity, error, expansion, nocreate, nonscaling); + public static SerializedCommand Insert(RedisKey key, RedisValue[] items, int? capacity = null, + double? error = null, int? expansion = null, + bool nocreate = false, bool nonscaling = false) + { + if (items.Length < 1) + throw new ArgumentOutOfRangeException(nameof(items)); - return new SerializedCommand(BF.INSERT, args); - } + var args = BloomAux.BuildInsertArgs(key, items, capacity, error, expansion, nocreate, nonscaling); - public static SerializedCommand LoadChunk(RedisKey key, long iterator, Byte[] data) - { - return new SerializedCommand(BF.LOADCHUNK, key, iterator, data); - } + return new SerializedCommand(BF.INSERT, args); + } - public static SerializedCommand MAdd(RedisKey key, params RedisValue[] items) - { - if (items.Length < 1) - throw new ArgumentOutOfRangeException(nameof(items)); + public static SerializedCommand LoadChunk(RedisKey key, long iterator, Byte[] data) + { + return new SerializedCommand(BF.LOADCHUNK, key, iterator, data); + } - List args = new List { key }; + public static SerializedCommand MAdd(RedisKey key, params RedisValue[] items) + { + if (items.Length < 1) + throw new ArgumentOutOfRangeException(nameof(items)); - foreach (var item in items) - { - args.Add(item); - } + List args = [key]; + args.AddRange(items.Cast()); - return new SerializedCommand(BF.MADD, args); - } + return new SerializedCommand(BF.MADD, args); + } - public static SerializedCommand MExists(RedisKey key, RedisValue[] items) - { - if (items.Length < 1) - throw new ArgumentOutOfRangeException(nameof(items)); + public static SerializedCommand MExists(RedisKey key, RedisValue[] items) + { + if (items.Length < 1) + throw new ArgumentOutOfRangeException(nameof(items)); - List args = new List { key }; + List args = [key]; + args.AddRange(items.Cast()); - foreach (var item in items) - { - args.Add(item); - } + return new SerializedCommand(BF.MEXISTS, args); - return new SerializedCommand(BF.MEXISTS, args); + } - } + public static SerializedCommand Reserve(RedisKey key, double errorRate, long capacity, + int? expansion = null, bool nonscaling = false) + { + List args = new List { key, errorRate, capacity }; - public static SerializedCommand Reserve(RedisKey key, double errorRate, long capacity, - int? expansion = null, bool nonscaling = false) + if (expansion != null) { - List args = new List { key, errorRate, capacity }; - - if (expansion != null) - { - args.Add(expansion); - } - - if (nonscaling) - { - args.Add(BloomArgs.NONSCALING); - } - - return new SerializedCommand(BF.RESERVE, args); + args.Add(expansion); } - public static SerializedCommand ScanDump(RedisKey key, long iterator) + if (nonscaling) { - return new SerializedCommand(BF.SCANDUMP, key, iterator); + args.Add(BloomArgs.NONSCALING); } + + return new SerializedCommand(BF.RESERVE, args); + } + + public static SerializedCommand ScanDump(RedisKey key, long iterator) + { + return new SerializedCommand(BF.SCANDUMP, key, iterator); } } \ No newline at end of file From 5ffe8ad9a156243358b23b066e3609c500fa269c Mon Sep 17 00:00:00 2001 From: nimanikoo Date: Fri, 26 Jan 2024 20:16:05 +0330 Subject: [PATCH 07/57] Add Db to xml summary doc --- src/NRedisStack/CoreCommands/CoreCommands.cs | 35 ++++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/NRedisStack/CoreCommands/CoreCommands.cs b/src/NRedisStack/CoreCommands/CoreCommands.cs index 4c8917bb..e5f3543a 100644 --- a/src/NRedisStack/CoreCommands/CoreCommands.cs +++ b/src/NRedisStack/CoreCommands/CoreCommands.cs @@ -1,23 +1,22 @@ using NRedisStack.Core; using StackExchange.Redis; -namespace NRedisStack -{ +namespace NRedisStack; - public static class CoreCommands +public static class CoreCommands +{ + /// + /// Sets information specific to the client or connection. + /// + /// + /// which attribute to set + /// the attribute value + /// if the attribute name was successfully set, Error otherwise. + /// + public static bool ClientSetInfo(this IDatabase db, SetInfoAttr attr, string value) { - /// - /// Sets information specific to the client or connection. - /// - /// which attribute to set - /// the attribute value - /// if the attribute name was successfully set, Error otherwise. - /// - public static bool ClientSetInfo(this IDatabase db, SetInfoAttr attr, string value) - { - var compareVersions = db.Multiplexer.GetServer(db.Multiplexer.GetEndPoints()[0]).Version.CompareTo(new Version(7, 1, 242)); - if (compareVersions < 0) // the server does not support the CLIENT SETNAME command - return false; - return db.Execute(CoreCommandBuilder.ClientSetInfo(attr, value)).OKtoBoolean(); - } + var compareVersions = db.Multiplexer.GetServer(db.Multiplexer.GetEndPoints()[0]).Version.CompareTo(new Version(7, 1, 242)); + if (compareVersions < 0) // the server does not support the CLIENT SET NAME command + return false; + return db.Execute(CoreCommandBuilder.ClientSetInfo(attr, value)).OKtoBoolean(); } -} +} \ No newline at end of file From bdd0b799a7cfc8c4c9b247a6c733692af388cc8c Mon Sep 17 00:00:00 2001 From: nimanikoo Date: Fri, 26 Jan 2024 20:23:43 +0330 Subject: [PATCH 08/57] Fix Typo problem --- src/NRedisStack/Bloom/IBloomCommands.cs | 207 ++++++++++++------------ 1 file changed, 103 insertions(+), 104 deletions(-) diff --git a/src/NRedisStack/Bloom/IBloomCommands.cs b/src/NRedisStack/Bloom/IBloomCommands.cs index 5afb16d7..8ca224f9 100644 --- a/src/NRedisStack/Bloom/IBloomCommands.cs +++ b/src/NRedisStack/Bloom/IBloomCommands.cs @@ -1,117 +1,116 @@ using NRedisStack.Bloom.DataTypes; using StackExchange.Redis; -namespace NRedisStack +namespace NRedisStack; + +public interface IBloomCommands { - public interface IBloomCommands - { - /// - /// 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. - /// - 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. + /// + bool Add(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. - /// - 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. + /// + long Card(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. - /// - 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. + /// + bool Exists(RedisKey key, RedisValue item); - /// - /// Return information about a bloom filter. - /// - /// Name of the key to return information about. - /// Information of the filter. - /// - BloomInformation Info(RedisKey key); + /// + /// Return information about a bloom filter. + /// + /// Name of the key to return information about. + /// Information of the filter. + /// + BloomInformation Info(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. - /// - 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. + /// + bool[] Insert(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/> - /// - bool LoadChunk(RedisKey key, long iterator, Byte[] data); + /// + /// Restores a filter previously 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/> + /// + bool LoadChunk(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. - /// - 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. + /// + bool[] MAdd(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. - /// - 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. + /// + bool[] MExists(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/> - /// - 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/> + /// + bool Reserve(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. - /// - Tuple ScanDump(RedisKey key, long iterator); - } -} + /// + /// Restores a filter previously 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. + /// + Tuple ScanDump(RedisKey key, long iterator); +} \ No newline at end of file From cbfaa7b91474523fc982474a10df8a0ba057883e Mon Sep 17 00:00:00 2001 From: nimanikoo Date: Fri, 26 Jan 2024 20:24:30 +0330 Subject: [PATCH 09/57] Change constructor to primary constructor based on new feature in .net 8 --- src/NRedisStack/Bloom/BloomCommands.cs | 115 +++++++++---------- src/NRedisStack/Bloom/BloomCommandsAsync.cs | 118 +++++++++----------- 2 files changed, 107 insertions(+), 126 deletions(-) diff --git a/src/NRedisStack/Bloom/BloomCommands.cs b/src/NRedisStack/Bloom/BloomCommands.cs index d4f3acb9..a030a5e8 100644 --- a/src/NRedisStack/Bloom/BloomCommands.cs +++ b/src/NRedisStack/Bloom/BloomCommands.cs @@ -1,77 +1,66 @@ using NRedisStack.Bloom.DataTypes; using StackExchange.Redis; -namespace NRedisStack +namespace NRedisStack; + +public class BloomCommands(IDatabase db) : BloomCommandsAsync(db), IBloomCommands { + /// + public bool Add(RedisKey key, RedisValue item) => db.Execute(BloomCommandBuilder.Add(key, item)).ToString() == "1"; - public class BloomCommands : BloomCommandsAsync, IBloomCommands + /// + public long Card(RedisKey key) { - IDatabase _db; - public BloomCommands(IDatabase db) : base(db) - { - _db = db; - } - - /// - public bool Add(RedisKey key, RedisValue item) - { - return _db.Execute(BloomCommandBuilder.Add(key, item)).ToString() == "1"; - } - - /// - public long Card(RedisKey key) - { - return _db.Execute(BloomCommandBuilder.Card(key)).ToLong(); - } + return db.Execute(BloomCommandBuilder.Card(key)).ToLong(); + } - /// - public bool Exists(RedisKey key, RedisValue item) - { - return _db.Execute(BloomCommandBuilder.Exists(key, item)).ToString() == "1"; - } + /// + public bool Exists(RedisKey key, RedisValue item) + { + return db.Execute(BloomCommandBuilder.Exists(key, item)).ToString() == "1"; + } - /// - public BloomInformation Info(RedisKey key) - { - return _db.Execute(BloomCommandBuilder.Info(key)).ToBloomInfo(); - } + /// + public BloomInformation Info(RedisKey key) + { + return db.Execute(BloomCommandBuilder.Info(key)).ToBloomInfo(); + } - /// - public bool[] Insert(RedisKey key, RedisValue[] items, int? capacity = null, - double? error = null, int? expansion = null, - bool nocreate = false, bool nonscaling = false) - { - return _db.Execute(BloomCommandBuilder.Insert(key, items, capacity, error, expansion, nocreate, nonscaling)).ToBooleanArray(); - } + /// + public bool[] Insert(RedisKey key, RedisValue[] items, int? capacity = null, + double? error = null, int? expansion = null, + bool nocreate = false, bool nonscaling = false) + { + return db.Execute(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 bool LoadChunk(RedisKey key, long iterator, Byte[] data) + { + return db.Execute(BloomCommandBuilder.LoadChunk(key, iterator, data)).OKtoBoolean(); + } - /// - public bool[] MAdd(RedisKey key, params RedisValue[] items) - { - return _db.Execute(BloomCommandBuilder.MAdd(key, items)).ToBooleanArray(); - } + /// + public bool[] MAdd(RedisKey key, params RedisValue[] items) + { + return db.Execute(BloomCommandBuilder.MAdd(key, items)).ToBooleanArray(); + } - /// - public bool[] MExists(RedisKey key, RedisValue[] items) - { - return _db.Execute(BloomCommandBuilder.MExists(key, items)).ToBooleanArray(); - } + /// + public bool[] MExists(RedisKey key, RedisValue[] items) + { + return db.Execute(BloomCommandBuilder.MExists(key, items)).ToBooleanArray(); + } - /// - public bool Reserve(RedisKey key, double errorRate, long capacity, - int? expansion = null, bool nonscaling = false) - { - return _db.Execute(BloomCommandBuilder.Reserve(key, errorRate, capacity, expansion, nonscaling)).OKtoBoolean(); - } + /// + public bool Reserve(RedisKey key, double errorRate, long capacity, + int? expansion = null, bool nonscaling = false) + { + return db.Execute(BloomCommandBuilder.Reserve(key, errorRate, capacity, expansion, nonscaling)).OKtoBoolean(); + } - /// - public Tuple ScanDump(RedisKey key, long iterator) - { - return _db.Execute(BloomCommandBuilder.ScanDump(key, iterator)).ToScanDumpTuple(); - } + /// + public Tuple ScanDump(RedisKey key, long iterator) + { + return db.Execute(BloomCommandBuilder.ScanDump(key, iterator)).ToScanDumpTuple(); } -} +} \ No newline at end of file diff --git a/src/NRedisStack/Bloom/BloomCommandsAsync.cs b/src/NRedisStack/Bloom/BloomCommandsAsync.cs index 6797caa4..33d7afb5 100644 --- a/src/NRedisStack/Bloom/BloomCommandsAsync.cs +++ b/src/NRedisStack/Bloom/BloomCommandsAsync.cs @@ -1,79 +1,71 @@ using NRedisStack.Bloom.DataTypes; using StackExchange.Redis; -namespace NRedisStack -{ +namespace NRedisStack; - public class BloomCommandsAsync : IBloomCommandsAsync +public class BloomCommandsAsync(IDatabaseAsync db) : IBloomCommandsAsync +{ + /// + public async Task AddAsync(RedisKey key, RedisValue item) { - IDatabaseAsync _db; - public BloomCommandsAsync(IDatabaseAsync db) - { - _db = db; - } - - /// - public async Task AddAsync(RedisKey key, RedisValue item) - { - return (await _db.ExecuteAsync(BloomCommandBuilder.Add(key, item))).ToString() == "1"; - } + 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 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 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 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 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 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 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 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 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(); - } + /// + public async Task> ScanDumpAsync(RedisKey key, long iterator) + { + return (await db.ExecuteAsync(BloomCommandBuilder.ScanDump(key, iterator))).ToScanDumpTuple(); } } \ No newline at end of file From 9ceafb68f0386f7ba2bb502a87f3dc4e3964236c Mon Sep 17 00:00:00 2001 From: nimanikoo Date: Fri, 26 Jan 2024 20:26:37 +0330 Subject: [PATCH 10/57] Fix Type for previously --- src/NRedisStack/Bloom/IBloomCommandsAsync.cs | 205 +++++++++---------- 1 file changed, 102 insertions(+), 103 deletions(-) diff --git a/src/NRedisStack/Bloom/IBloomCommandsAsync.cs b/src/NRedisStack/Bloom/IBloomCommandsAsync.cs index ca7f832d..f4f278bb 100644 --- a/src/NRedisStack/Bloom/IBloomCommandsAsync.cs +++ b/src/NRedisStack/Bloom/IBloomCommandsAsync.cs @@ -1,118 +1,117 @@ using NRedisStack.Bloom.DataTypes; using StackExchange.Redis; -namespace NRedisStack +namespace NRedisStack; + +public interface IBloomCommandsAsync { - 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); + /// + /// 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); + /// + /// 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); + /// + /// 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); + /// + /// 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); + /// + /// 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); + /// + /// Restores a filter previously 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); + /// + /// 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); + /// + /// 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); + /// + /// 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); - } + /// + /// Restores a filter previously 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 From ac81e9097509a2ee327c54a69c9e6653713f8dd8 Mon Sep 17 00:00:00 2001 From: nimanikoo Date: Fri, 26 Jan 2024 20:29:28 +0330 Subject: [PATCH 11/57] refactor and Use Collection Expression for list initializing and change foreach to linq expression --- .../CountMinSketch/CmsCommandBuilder.cs | 101 +++++++++--------- 1 file changed, 48 insertions(+), 53 deletions(-) diff --git a/src/NRedisStack/CountMinSketch/CmsCommandBuilder.cs b/src/NRedisStack/CountMinSketch/CmsCommandBuilder.cs index d8ff2363..d5025ce9 100644 --- a/src/NRedisStack/CountMinSketch/CmsCommandBuilder.cs +++ b/src/NRedisStack/CountMinSketch/CmsCommandBuilder.cs @@ -2,73 +2,68 @@ using NRedisStack.RedisStackCommands; using StackExchange.Redis; -namespace NRedisStack -{ +namespace NRedisStack; - public static class CmsCommandBuilder +public static class CmsCommandBuilder +{ + public static SerializedCommand IncrBy(RedisKey key, RedisValue item, long increment) { - public static SerializedCommand IncrBy(RedisKey key, RedisValue item, long increment) - { - return new SerializedCommand(CMS.INCRBY, key, item, increment); - } - - public static SerializedCommand IncrBy(RedisKey key, Tuple[] itemIncrements) - { - if (itemIncrements.Length < 1) - throw new ArgumentOutOfRangeException(nameof(itemIncrements)); + return new SerializedCommand(CMS.INCRBY, key, item, increment); + } - List args = new List { key }; - foreach (var pair in itemIncrements) - { - args.Add(pair.Item1); - args.Add(pair.Item2); - } - return new SerializedCommand(CMS.INCRBY, args); - } + public static SerializedCommand IncrBy(RedisKey key, Tuple[] itemIncrements) + { + if (itemIncrements.Length < 1) + throw new ArgumentOutOfRangeException(nameof(itemIncrements)); - public static SerializedCommand Info(RedisKey key) + List args = [key]; + foreach (var pair in itemIncrements) { - var info = new SerializedCommand(CMS.INFO, key); - return info; + args.Add(pair.Item1); + args.Add(pair.Item2); } + return new SerializedCommand(CMS.INCRBY, args); + } - public static SerializedCommand InitByDim(RedisKey key, long width, long depth) - { - return new SerializedCommand(CMS.INITBYDIM, key, width, depth); - } + public static SerializedCommand Info(RedisKey key) + { + var info = new SerializedCommand(CMS.INFO, key); + return info; + } - public static SerializedCommand InitByProb(RedisKey key, double error, double probability) - { - return new SerializedCommand(CMS.INITBYPROB, key, error, probability); - } + public static SerializedCommand InitByDim(RedisKey key, long width, long depth) + { + return new SerializedCommand(CMS.INITBYDIM, key, width, depth); + } - public static SerializedCommand Merge(RedisValue destination, long numKeys, RedisValue[] source, long[]? weight = null) - { - if (source.Length < 1) - throw new ArgumentOutOfRangeException(nameof(source)); + public static SerializedCommand InitByProb(RedisKey key, double error, double probability) + { + return new SerializedCommand(CMS.INITBYPROB, key, error, probability); + } - List args = new List { destination, numKeys }; + public static SerializedCommand Merge(RedisValue destination, long numKeys, RedisValue[] source, long[]? weight = null) + { + if (source.Length < 1) + throw new ArgumentOutOfRangeException(nameof(source)); - foreach (var s in source) args.Add(s); + List args = [destination, numKeys]; + args.AddRange(source.Cast()); - if (weight != null && weight.Length >= 1) - { - args.Add(CmsArgs.WEIGHTS); - foreach (var w in weight) args.Add(w); - } + if (weight is not { Length: >= 1 }) return new SerializedCommand(CMS.MERGE, args); + args.Add(CmsArgs.WEIGHTS); + args.AddRange(weight.Cast()); - return new SerializedCommand(CMS.MERGE, args); - } + return new SerializedCommand(CMS.MERGE, args); + } - public static SerializedCommand Query(RedisKey key, params RedisValue[] items) - { - if (items.Length < 1) - throw new ArgumentOutOfRangeException(nameof(items)); + public static SerializedCommand Query(RedisKey key, params RedisValue[] items) + { + if (items.Length < 1) + throw new ArgumentOutOfRangeException(nameof(items)); - List args = new List { key }; - foreach (var item in items) args.Add(item); + List args = [key]; + args.AddRange(items.Cast()); - return new SerializedCommand(CMS.QUERY, args); - } + return new SerializedCommand(CMS.QUERY, args); } -} +} \ No newline at end of file From 24ad2aa8cf9b2c6df11d8411209ddf0e4eb41372 Mon Sep 17 00:00:00 2001 From: nimanikoo Date: Fri, 26 Jan 2024 20:30:09 +0330 Subject: [PATCH 12/57] use primary constructor in CmsCommands.cs --- src/NRedisStack/CountMinSketch/CmsCommands.cs | 82 +++++++++---------- 1 file changed, 37 insertions(+), 45 deletions(-) diff --git a/src/NRedisStack/CountMinSketch/CmsCommands.cs b/src/NRedisStack/CountMinSketch/CmsCommands.cs index cfb075be..3a5c1206 100644 --- a/src/NRedisStack/CountMinSketch/CmsCommands.cs +++ b/src/NRedisStack/CountMinSketch/CmsCommands.cs @@ -1,57 +1,49 @@ using NRedisStack.CountMinSketch.DataTypes; using StackExchange.Redis; -namespace NRedisStack -{ +namespace NRedisStack; - public class CmsCommands : CmsCommandsAsync, ICmsCommands +public class CmsCommands(IDatabase db) : CmsCommandsAsync(db), ICmsCommands +{ + /// + public long IncrBy(RedisKey key, RedisValue item, long increment) { - IDatabase _db; - public CmsCommands(IDatabase db) : base(db) - { - _db = db; - } - - /// - public long IncrBy(RedisKey key, RedisValue item, long increment) - { - return _db.Execute(CmsCommandBuilder.IncrBy(key, item, increment)).ToLong(); - } + return db.Execute(CmsCommandBuilder.IncrBy(key, item, increment)).ToLong(); + } - /// - public long[] IncrBy(RedisKey key, Tuple[] itemIncrements) - { - return _db.Execute(CmsCommandBuilder.IncrBy(key, itemIncrements)).ToLongArray(); - } + /// + public long[] IncrBy(RedisKey key, Tuple[] itemIncrements) + { + return db.Execute(CmsCommandBuilder.IncrBy(key, itemIncrements)).ToLongArray(); + } - /// - public CmsInformation Info(RedisKey key) - { - var info = _db.Execute(CmsCommandBuilder.Info(key)); - return info.ToCmsInfo(); - } + /// + public CmsInformation Info(RedisKey key) + { + var info = db.Execute(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 bool InitByDim(RedisKey key, long width, long depth) + { + return db.Execute(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 bool InitByProb(RedisKey key, double error, double probability) + { + return db.Execute(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 bool Merge(RedisValue destination, long numKeys, RedisValue[] source, long[]? weight = null) + { + return db.Execute(CmsCommandBuilder.Merge(destination, numKeys, source, weight)).OKtoBoolean(); + } - /// - public long[] Query(RedisKey key, params RedisValue[] items) - { - return _db.Execute(CmsCommandBuilder.Query(key, items)).ToLongArray(); - } + /// + public long[] Query(RedisKey key, params RedisValue[] items) + { + return db.Execute(CmsCommandBuilder.Query(key, items)).ToLongArray(); } } \ No newline at end of file From d2f877a1fd9b7ccb05e441afae0c8be603436f76 Mon Sep 17 00:00:00 2001 From: nimanikoo Date: Fri, 26 Jan 2024 20:30:09 +0330 Subject: [PATCH 13/57] use primary constructor in CmsCommands.cs --- src/NRedisStack/CountMinSketch/CmsCommands.cs | 82 ++++++++-------- .../CountMinSketch/CmsCommandsAsync.cs | 94 +++++++++---------- 2 files changed, 80 insertions(+), 96 deletions(-) diff --git a/src/NRedisStack/CountMinSketch/CmsCommands.cs b/src/NRedisStack/CountMinSketch/CmsCommands.cs index cfb075be..3a5c1206 100644 --- a/src/NRedisStack/CountMinSketch/CmsCommands.cs +++ b/src/NRedisStack/CountMinSketch/CmsCommands.cs @@ -1,57 +1,49 @@ using NRedisStack.CountMinSketch.DataTypes; using StackExchange.Redis; -namespace NRedisStack -{ +namespace NRedisStack; - public class CmsCommands : CmsCommandsAsync, ICmsCommands +public class CmsCommands(IDatabase db) : CmsCommandsAsync(db), ICmsCommands +{ + /// + public long IncrBy(RedisKey key, RedisValue item, long increment) { - IDatabase _db; - public CmsCommands(IDatabase db) : base(db) - { - _db = db; - } - - /// - public long IncrBy(RedisKey key, RedisValue item, long increment) - { - return _db.Execute(CmsCommandBuilder.IncrBy(key, item, increment)).ToLong(); - } + return db.Execute(CmsCommandBuilder.IncrBy(key, item, increment)).ToLong(); + } - /// - public long[] IncrBy(RedisKey key, Tuple[] itemIncrements) - { - return _db.Execute(CmsCommandBuilder.IncrBy(key, itemIncrements)).ToLongArray(); - } + /// + public long[] IncrBy(RedisKey key, Tuple[] itemIncrements) + { + return db.Execute(CmsCommandBuilder.IncrBy(key, itemIncrements)).ToLongArray(); + } - /// - public CmsInformation Info(RedisKey key) - { - var info = _db.Execute(CmsCommandBuilder.Info(key)); - return info.ToCmsInfo(); - } + /// + public CmsInformation Info(RedisKey key) + { + var info = db.Execute(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 bool InitByDim(RedisKey key, long width, long depth) + { + return db.Execute(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 bool InitByProb(RedisKey key, double error, double probability) + { + return db.Execute(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 bool Merge(RedisValue destination, long numKeys, RedisValue[] source, long[]? weight = null) + { + return db.Execute(CmsCommandBuilder.Merge(destination, numKeys, source, weight)).OKtoBoolean(); + } - /// - public long[] Query(RedisKey key, params RedisValue[] items) - { - return _db.Execute(CmsCommandBuilder.Query(key, items)).ToLongArray(); - } + /// + public long[] Query(RedisKey key, params RedisValue[] items) + { + return db.Execute(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 index fcaae3be..489a0b0b 100644 --- a/src/NRedisStack/CountMinSketch/CmsCommandsAsync.cs +++ b/src/NRedisStack/CountMinSketch/CmsCommandsAsync.cs @@ -1,58 +1,50 @@ using NRedisStack.CountMinSketch.DataTypes; using StackExchange.Redis; -namespace NRedisStack +namespace NRedisStack; + +public class CmsCommandsAsync(IDatabaseAsync db) : ICmsCommandsAsync { + /// + 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 class CmsCommandsAsync : ICmsCommandsAsync + /// + public async Task QueryAsync(RedisKey key, params RedisValue[] items) { - 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(); - } + return (await db.ExecuteAsync(CmsCommandBuilder.Query(key, items))).ToLongArray(); } } \ No newline at end of file From 3cc522107d2e4a686d85fbf0d5413c04efc18d8c Mon Sep 17 00:00:00 2001 From: nimanikoo Date: Fri, 26 Jan 2024 20:33:22 +0330 Subject: [PATCH 14/57] Refactor and change constructor to primary --- .../Json/DataTypes/KeyValuePath.cs | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/src/NRedisStack/Json/DataTypes/KeyValuePath.cs b/src/NRedisStack/Json/DataTypes/KeyValuePath.cs index a5801e7e..5487c451 100644 --- a/src/NRedisStack/Json/DataTypes/KeyValuePath.cs +++ b/src/NRedisStack/Json/DataTypes/KeyValuePath.cs @@ -2,24 +2,14 @@ namespace NRedisStack.Json.DataTypes; -public struct KeyPathValue +public struct KeyPathValue(string key, string path, object value) { - public string Key { get; set; } - public string Path { get; set; } - public object Value { get; set; } + private string Key { get; set; } = key; + private string Path { get; set; } = path; + private object Value { get; set; } = value; - public KeyPathValue(string key, string path, object value) + public IEnumerable ToArray() { - Key = key; - Path = path; - Value = value; - } - public string[] ToArray() - { - if (Value is string) - { - return new string[] { Key, Path, Value.ToString()! }; - } - return new string[] { Key, Path, JsonSerializer.Serialize(Value) }; + return Value is string ? new string[] { Key, Path, Value.ToString()! } : new string[] { Key, Path, JsonSerializer.Serialize(Value) }; } } \ No newline at end of file From fd45c005a1dabafe6674a5c00c67be02edfca228 Mon Sep 17 00:00:00 2001 From: nimanikoo Date: Fri, 26 Jan 2024 20:34:55 +0330 Subject: [PATCH 15/57] Fix Typo and indent in CommandArgs.cs and IJsonCommands.cs --- src/NRedisStack/Json/IJsonCommands.cs | 2 +- src/NRedisStack/Json/Literals/CommandArgs.cs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/NRedisStack/Json/IJsonCommands.cs b/src/NRedisStack/Json/IJsonCommands.cs index 377084e5..069a9237 100644 --- a/src/NRedisStack/Json/IJsonCommands.cs +++ b/src/NRedisStack/Json/IJsonCommands.cs @@ -136,7 +136,7 @@ public interface IJsonCommands /// The key to pull from. /// The path to pull. /// The type. - /// An enumerable of the requested tyep + /// An enumerable of the requested type /// IEnumerable GetEnumerable(RedisKey key, string path = "$"); diff --git a/src/NRedisStack/Json/Literals/CommandArgs.cs b/src/NRedisStack/Json/Literals/CommandArgs.cs index 86e51ec6..3b2a2e33 100644 --- a/src/NRedisStack/Json/Literals/CommandArgs.cs +++ b/src/NRedisStack/Json/Literals/CommandArgs.cs @@ -5,6 +5,5 @@ internal class JsonArgs public const string INDENT = "INDENT"; public const string NEWLINE = "NEWLINE"; public const string SPACE = "SPACE"; - } } \ No newline at end of file From 0713820ff65223984c21b50904e13561e2957470 Mon Sep 17 00:00:00 2001 From: nimanikoo Date: Fri, 26 Jan 2024 20:36:06 +0330 Subject: [PATCH 16/57] Fix Typo in ExampleTests.cs and IJsonCommandsAsync.cs and JsonCommandsAsync.cs and JsonTests.cs --- src/NRedisStack/Json/IJsonCommandsAsync.cs | 4 +- src/NRedisStack/Json/JsonCommandsAsync.cs | 2 +- .../Examples/ExampleTests.cs | 6 +- tests/NRedisStack.Tests/Json/JsonTests.cs | 82 +++++++++---------- 4 files changed, 47 insertions(+), 47 deletions(-) diff --git a/src/NRedisStack/Json/IJsonCommandsAsync.cs b/src/NRedisStack/Json/IJsonCommandsAsync.cs index 309db723..ce5c999a 100644 --- a/src/NRedisStack/Json/IJsonCommandsAsync.cs +++ b/src/NRedisStack/Json/IJsonCommandsAsync.cs @@ -136,7 +136,7 @@ public interface IJsonCommandsAsync /// The key to pull from. /// The path to pull. /// The type. - /// An enumerable of the requested tyep + /// An enumerable of the requested type /// Task> GetEnumerableAsync(RedisKey key, string path = "$"); @@ -157,7 +157,7 @@ public interface IJsonCommandsAsync /// 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); + Task NumIncrByAsync(RedisKey key, string path, double value); /// /// Gets the keys of the object at the provided path. diff --git a/src/NRedisStack/Json/JsonCommandsAsync.cs b/src/NRedisStack/Json/JsonCommandsAsync.cs index 1e3126a8..ab385814 100644 --- a/src/NRedisStack/Json/JsonCommandsAsync.cs +++ b/src/NRedisStack/Json/JsonCommandsAsync.cs @@ -105,7 +105,7 @@ 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) + 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()!)!; diff --git a/tests/NRedisStack.Tests/Examples/ExampleTests.cs b/tests/NRedisStack.Tests/Examples/ExampleTests.cs index adc5636f..f7b5f906 100644 --- a/tests/NRedisStack.Tests/Examples/ExampleTests.cs +++ b/tests/NRedisStack.Tests/Examples/ExampleTests.cs @@ -105,7 +105,7 @@ public void PipelineExample() pipeline.Json.SetAsync("person", "$", new { name = "John", age = 30, city = "New York", nicknames = new[] { "John", "Johny", "Jo" } }); // Increase age by 2 - _ = pipeline.Json.NumIncrbyAsync("person", "$.age", 2); + _ = pipeline.Json.NumIncrByAsync("person", "$.age", 2); // Clear the nicknames from the Json _ = pipeline.Json.ClearAsync("person", "$.nicknames"); @@ -253,10 +253,10 @@ public void TransactionExample() var getJeeva = tran.Json.GetAsync("accdetails:Jeeva"); // Debit 200 from Jeeva - _ = tran.Json.NumIncrbyAsync("accdetails:Jeeva", "$.totalAmount", -200); + _ = tran.Json.NumIncrByAsync("accdetails:Jeeva", "$.totalAmount", -200); // Credit 200 from Shachar - _ = tran.Json.NumIncrbyAsync("accdetails:Shachar", "$.totalAmount", 200); + _ = tran.Json.NumIncrByAsync("accdetails:Shachar", "$.totalAmount", 200); // Get total amount for both Jeeva = 800 & Shachar = 1200 var totalAmtOfJeeva = tran.Json.GetAsync("accdetails:Jeeva", path: "$.totalAmount"); diff --git a/tests/NRedisStack.Tests/Json/JsonTests.cs b/tests/NRedisStack.Tests/Json/JsonTests.cs index 052fb836..7fc010e8 100644 --- a/tests/NRedisStack.Tests/Json/JsonTests.cs +++ b/tests/NRedisStack.Tests/Json/JsonTests.cs @@ -866,7 +866,7 @@ public async Task NumIncrbyAsync() var keys = CreateKeyNames(1); var key = keys[0]; await commands.SetAsync(key, "$", new { age = 33, a = new { age = 34 }, b = new { age = "cat" } }); - var result = await commands.NumIncrbyAsync(key, "$..age", 2); + var result = await commands.NumIncrByAsync(key, "$..age", 2); Assert.Equal(35, result[0]); Assert.Equal(36, result[1]); Assert.Null(result[2]); @@ -1154,80 +1154,80 @@ public async Task TestGetIssue198_Async() } [Fact] - public void TestSetWithSerializationOptions() - { - var commands = new JsonCommands(redisFixture.Redis.GetDatabase()); + public void TestSetWithSerializationOptions() + { + var commands = new JsonCommands(redisFixture.Redis.GetDatabase()); var keys = CreateKeyNames(1); - var key = keys[0]; - var jsonOptions = new JsonSerializerOptions { IncludeFields = true }; + var key = keys[0]; + var jsonOptions = new JsonSerializerOptions { IncludeFields = true }; var person = new Person { Name = "Developer", Age = 23, Birthday = DateTime.Today }; - commands.Set(key, "$", person, serializerOptions: jsonOptions); + commands.Set(key, "$", person, serializerOptions: jsonOptions); Person? result = commands.Get(key, serializerOptions: jsonOptions); - Assert.NotNull(result); - Assert.Equal(person.Name, result!.Name); - Assert.Equal(person.Age, result!.Age); - Assert.NotNull(result!.Birthday); - Assert.Equal(person.Birthday, result!.Birthday); + Assert.NotNull(result); + Assert.Equal(person.Name, result!.Name); + Assert.Equal(person.Age, result!.Age); + Assert.NotNull(result!.Birthday); + Assert.Equal(person.Birthday, result!.Birthday); } [Fact] - public async Task TestSetWithSerializationOptionsAsync() - { - var commands = new JsonCommands(redisFixture.Redis.GetDatabase()); + public async Task TestSetWithSerializationOptionsAsync() + { + var commands = new JsonCommands(redisFixture.Redis.GetDatabase()); var keys = CreateKeyNames(1); - var key = keys[0]; - var jsonOptions = new JsonSerializerOptions { IncludeFields = true }; - var person = new Person { Name = "Developer", Age = 23, Birthday = DateTime.Today }; - - await commands.SetAsync(key, "$", person, serializerOptions: jsonOptions); + var key = keys[0]; + var jsonOptions = new JsonSerializerOptions { IncludeFields = true }; + var person = new Person { Name = "Developer", Age = 23, Birthday = DateTime.Today }; + + await commands.SetAsync(key, "$", person, serializerOptions: jsonOptions); Person? result = await commands.GetAsync(key, serializerOptions: jsonOptions); - Assert.NotNull(result); - Assert.Equal(person.Name, result!.Name); - Assert.Equal(person.Age, result!.Age); - Assert.NotNull(result!.Birthday); - Assert.Equal(person.Birthday, result!.Birthday); + Assert.NotNull(result); + Assert.Equal(person.Name, result!.Name); + Assert.Equal(person.Age, result!.Age); + Assert.NotNull(result!.Birthday); + Assert.Equal(person.Birthday, result!.Birthday); } [SkipIfRedis("7.1.242")] - public void MergeWithSerializationOptions() - { + public void MergeWithSerializationOptions() + { string expected = "{\"age\":23,\"birthday\":\"2023-12-31T00:00:00\",\"name\":\"Developer\"}"; var commands = new JsonCommands(redisFixture.Redis.GetDatabase()); var keys = CreateKeyNames(1); - var key = keys[0]; + var key = keys[0]; commands.Set(key, "$", new { age = 5, birthday = new DateTime(2000, 1, 1) }); var jsonOptions = new JsonSerializerOptions { IncludeFields = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; var person = new Person { Name = "Developer", Age = 23, Birthday = new DateTime(2023, 12, 31) }; - commands.Merge(key, "$", person, serializerOptions: jsonOptions); - RedisResult rr = commands.Get(key); - - Assert.False(rr.IsNull); - string actual = rr.ToString()!; + commands.Merge(key, "$", person, serializerOptions: jsonOptions); + RedisResult rr = commands.Get(key); + + Assert.False(rr.IsNull); + string actual = rr.ToString()!; Assert.Equal(expected, actual); } [SkipIfRedis("7.1.242")] - public async Task MergeWithSerializationOptionsAsync() - { + public async Task MergeWithSerializationOptionsAsync() + { string expected = "{\"age\":23,\"birthday\":\"2023-12-31T00:00:00\",\"name\":\"Developer\"}"; var commands = new JsonCommands(redisFixture.Redis.GetDatabase()); var keys = CreateKeyNames(1); - var key = keys[0]; + var key = keys[0]; await commands.SetAsync(key, "$", new { age = 5, birthday = new DateTime(2000, 1, 1) }); var jsonOptions = new JsonSerializerOptions { IncludeFields = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; var person = new Person { Name = "Developer", Age = 23, Birthday = new DateTime(2023, 12, 31) }; - await commands.MergeAsync(key, "$", person, serializerOptions: jsonOptions); - RedisResult rr = await commands.GetAsync(key); - - Assert.False(rr.IsNull); - string actual = rr.ToString()!; + await commands.MergeAsync(key, "$", person, serializerOptions: jsonOptions); + RedisResult rr = await commands.GetAsync(key); + + Assert.False(rr.IsNull); + string actual = rr.ToString()!; Assert.Equal(expected, actual); } } \ No newline at end of file From 32d83d49802f82afbe36638aeadd16676104f756 Mon Sep 17 00:00:00 2001 From: nimanikoo Date: Fri, 26 Jan 2024 20:40:46 +0330 Subject: [PATCH 17/57] Use Linq and List Expression --- src/NRedisStack/Json/JsonCommandBuilder.cs | 62 ++++++++++------------ 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/src/NRedisStack/Json/JsonCommandBuilder.cs b/src/NRedisStack/Json/JsonCommandBuilder.cs index c78845f0..aada5790 100644 --- a/src/NRedisStack/Json/JsonCommandBuilder.cs +++ b/src/NRedisStack/Json/JsonCommandBuilder.cs @@ -11,12 +11,9 @@ public static class JsonCommandBuilder { public static SerializedCommand Resp(RedisKey key, string? path = null) { - if (string.IsNullOrEmpty(path)) - { - return new SerializedCommand(JSON.RESP, key); - } - - return new SerializedCommand(JSON.RESP, key, path!); + return string.IsNullOrEmpty(path) + ? new SerializedCommand(JSON.RESP, key) + : new SerializedCommand(JSON.RESP, key, path!); } public static SerializedCommand Set(RedisKey key, RedisValue path, RedisValue json, When when = When.Always) @@ -45,36 +42,37 @@ public static SerializedCommand Merge(RedisKey key, RedisValue path, RedisValue public static SerializedCommand StrAppend(RedisKey key, string value, string? path = null) { - if (path == null) - { - return new SerializedCommand(JSON.STRAPPEND, key, JsonSerializer.Serialize(value)); - } - - return new SerializedCommand(JSON.STRAPPEND, key, path, JsonSerializer.Serialize(value)); + return path == null + ? new SerializedCommand(JSON.STRAPPEND, key, JsonSerializer.Serialize(value)) + : new SerializedCommand(JSON.STRAPPEND, key, path, JsonSerializer.Serialize(value)); } public static SerializedCommand StrLen(RedisKey key, string? path = null) { - return (path != null) ? new SerializedCommand(JSON.STRLEN, key, path) - : new SerializedCommand(JSON.STRLEN, key); + return path != null + ? new SerializedCommand(JSON.STRLEN, key, path) + : new SerializedCommand(JSON.STRLEN, key); } public static SerializedCommand Toggle(RedisKey key, string? path = null) { - return (path != null) ? new SerializedCommand(JSON.TOGGLE, key, path) - : new SerializedCommand(JSON.TOGGLE, key, "$"); + return path != null + ? new SerializedCommand(JSON.TOGGLE, key, path) + : new SerializedCommand(JSON.TOGGLE, key, "$"); } public static SerializedCommand Type(RedisKey key, string? path = null) { - return (path != null) ? new SerializedCommand(JSON.TYPE, key, path) - : new SerializedCommand(JSON.TYPE, key); + return (path != null) + ? new SerializedCommand(JSON.TYPE, key, path) + : new SerializedCommand(JSON.TYPE, key); } 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); + 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) @@ -93,7 +91,8 @@ 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 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"); @@ -107,10 +106,7 @@ public static SerializedCommand ArrInsert(RedisKey key, string path, long index, if (values.Length < 1) throw new ArgumentOutOfRangeException(nameof(values)); var args = new List { key, path, index }; - foreach (var val in values) - { - args.Add(JsonSerializer.Serialize(val)); - } + args.AddRange(values.Select(val => JsonSerializer.Serialize(val))); return new SerializedCommand(JSON.ARRINSERT, args); } @@ -145,9 +141,10 @@ public static SerializedCommand Del(RedisKey key, string? path = null) 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 static SerializedCommand Get(RedisKey key, RedisValue? indent = null, RedisValue? newLine = null, + RedisValue? space = null, RedisValue? path = null) { - List args = new List() { key }; + List args = [key]; if (indent != null) { @@ -175,9 +172,10 @@ 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 static SerializedCommand Get(RedisKey key, string[] paths, RedisValue? indent = null, + RedisValue? newLine = null, RedisValue? space = null) { - List args = new List() { key }; + List args = [key]; if (indent != null) { @@ -197,10 +195,7 @@ public static SerializedCommand Get(RedisKey key, string[] paths, RedisValue? in args.Add(space); } - foreach (var path in paths) - { - args.Add(path); - } + args.AddRange(paths); return new SerializedCommand(JSON.GET, args); } @@ -208,7 +203,6 @@ public static SerializedCommand Get(RedisKey key, string[] paths, RedisValue? in public static SerializedCommand Get(RedisKey key, string path = "$") { return new SerializedCommand(JSON.GET, key, path); - } public static SerializedCommand MGet(RedisKey[] keys, string path) From bac351519ca2614a295def205485a743fac0c31c Mon Sep 17 00:00:00 2001 From: nimanikoo Date: Fri, 26 Jan 2024 20:43:21 +0330 Subject: [PATCH 18/57] Refactor --- src/NRedisStack/Json/JsonCommands.cs | 61 ++++++------- src/NRedisStack/Json/JsonCommandsAsync.cs | 100 ++++++++-------------- 2 files changed, 65 insertions(+), 96 deletions(-) diff --git a/src/NRedisStack/Json/JsonCommands.cs b/src/NRedisStack/Json/JsonCommands.cs index e16bc701..033ced97 100644 --- a/src/NRedisStack/Json/JsonCommands.cs +++ b/src/NRedisStack/Json/JsonCommands.cs @@ -5,19 +5,12 @@ namespace NRedisStack; -public class JsonCommands : JsonCommandsAsync, IJsonCommands +public class JsonCommands(IDatabase db) : JsonCommandsAsync(db), IJsonCommands { - IDatabase _db; - - public JsonCommands(IDatabase db) : base(db) - { - _db = db; - } - /// public RedisResult[] Resp(RedisKey key, string? path = null) { - RedisResult result = _db.Execute(JsonCommandBuilder.Resp(key, path)); + RedisResult result = db.Execute(JsonCommandBuilder.Resp(key, path)); if (result.IsNull) { @@ -37,26 +30,26 @@ 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(JsonCommandBuilder.Set(key, path, json, when)).OKtoBoolean(); } /// public bool MSet(KeyPathValue[] KeyPathValueList) { - return _db.Execute(JsonCommandBuilder.MSet(KeyPathValueList)).OKtoBoolean(); + return db.Execute(JsonCommandBuilder.MSet(KeyPathValueList)).OKtoBoolean(); } /// public bool Merge(RedisKey key, RedisValue path, RedisValue json) { - return _db.Execute(JsonCommandBuilder.Merge(key, path, json)).OKtoBoolean(); + return db.Execute(JsonCommandBuilder.Merge(key, path, json)).OKtoBoolean(); } /// public bool Merge(RedisKey key, RedisValue path, object obj, JsonSerializerOptions? serializerOptions = default) { string json = JsonSerializer.Serialize(obj, options: serializerOptions); - return _db.Execute(JsonCommandBuilder.Merge(key, path, json)).OKtoBoolean(); + return db.Execute(JsonCommandBuilder.Merge(key, path, json)).OKtoBoolean(); } /// @@ -97,19 +90,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(JsonCommandBuilder.StrAppend(key, value, path)).ToNullableLongArray(); } /// public long?[] StrLen(RedisKey key, string? path = null) { - return _db.Execute(JsonCommandBuilder.StrLen(key, path)).ToNullableLongArray(); + return db.Execute(JsonCommandBuilder.StrLen(key, path)).ToNullableLongArray(); } /// public bool?[] Toggle(RedisKey key, string? path = null) { - RedisResult result = _db.Execute(JsonCommandBuilder.Toggle(key, path)); + RedisResult result = db.Execute(JsonCommandBuilder.Toggle(key, path)); if (result.IsNull) { @@ -127,7 +120,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(JsonCommandBuilder.Type(key, path)); if (result.Type == ResultType.MultiBulk) { @@ -145,37 +138,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(); + return db.Execute(JsonCommandBuilder.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(JsonCommandBuilder.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(JsonCommandBuilder.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(JsonCommandBuilder.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(JsonCommandBuilder.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(JsonCommandBuilder.ArrPop(key, path, index)); if (result.Type == ResultType.MultiBulk) { @@ -192,18 +185,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(JsonCommandBuilder.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(JsonCommandBuilder.Clear(key, path)).ToLong(); } /// public long Del(RedisKey key, string? path = null) { - return _db.Execute(JsonCommandBuilder.Del(key, path)).ToLong(); + return db.Execute(JsonCommandBuilder.Del(key, path)).ToLong(); } /// @@ -212,19 +205,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(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(JsonCommandBuilder.Get(key, paths, indent, newLine, space)); + return db.Execute(JsonCommandBuilder.Get(key, paths, indent, newLine, space)); } /// public T? Get(RedisKey key, string path = "$", JsonSerializerOptions? serializerOptions = default) { - var res = _db.Execute(JsonCommandBuilder.Get(key, path)); + var res = db.Execute(JsonCommandBuilder.Get(key, path)); if (res.Type == ResultType.BulkString && !res.IsNull) { var arr = JsonSerializer.Deserialize(res.ToString()!); @@ -240,32 +233,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(JsonCommandBuilder.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(JsonCommandBuilder.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(JsonCommandBuilder.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(JsonCommandBuilder.ObjKeys(key, path)).ToHashSets(); } /// public long?[] ObjLen(RedisKey key, string? path = null) { - return _db.Execute(JsonCommandBuilder.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 ab385814..1d1eb1e7 100644 --- a/src/NRedisStack/Json/JsonCommandsAsync.cs +++ b/src/NRedisStack/Json/JsonCommandsAsync.cs @@ -5,63 +5,51 @@ namespace NRedisStack; -public class JsonCommandsAsync : IJsonCommandsAsync +public class JsonCommandsAsync(IDatabaseAsync db) : IJsonCommandsAsync { - IDatabaseAsync _db; - - public JsonCommandsAsync(IDatabaseAsync db) - { - _db = db; - } - public async Task ArrAppendAsync(RedisKey key, string? path = null, params object[] values) { - return (await _db.ExecuteAsync(JsonCommandBuilder.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(JsonCommandBuilder.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(JsonCommandBuilder.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(JsonCommandBuilder.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(JsonCommandBuilder.ArrPop(key, path, index)); + RedisResult result = await db.ExecuteAsync(JsonCommandBuilder.ArrPop(key, path, index)); - if (result.Type == ResultType.MultiBulk) + return result.Type switch { - return (RedisResult[])result!; - } - - if (result.Type == ResultType.BulkString) - { - return new[] { result }; - } - - return Array.Empty(); + ResultType.MultiBulk => (RedisResult[])result!, + ResultType.BulkString => [result], + _ => Array.Empty() + }; } public async Task ArrTrimAsync(RedisKey key, string path, long start, long stop) => - (await _db.ExecuteAsync(JsonCommandBuilder.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(JsonCommandBuilder.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(JsonCommandBuilder.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,61 +57,54 @@ 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(JsonCommandBuilder.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(JsonCommandBuilder.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 = "$", JsonSerializerOptions? serializerOptions = default) { - var res = await _db.ExecuteAsync(JsonCommandBuilder.Get(key, path)); - if (res.Type == ResultType.BulkString && !res.IsNull) - { - var arr = JsonSerializer.Deserialize(res.ToString()!); - if (arr?.Count > 0) - { - return JsonSerializer.Deserialize(JsonSerializer.Serialize(arr[0]), serializerOptions); - } - } - - return default; + var res = await db.ExecuteAsync(JsonCommandBuilder.Get(key, path)); + if (res.Type != ResultType.BulkString || res.IsNull) return default; + var arr = JsonSerializer.Deserialize(res.ToString()!); + return arr?.Count > 0 ? JsonSerializer.Deserialize(JsonSerializer.Serialize(arr[0]), serializerOptions) : default; } /// public async Task> GetEnumerableAsync(RedisKey key, string path = "$") { - RedisResult res = await _db.ExecuteAsync(JsonCommandBuilder.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(JsonCommandBuilder.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(JsonCommandBuilder.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(JsonCommandBuilder.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(JsonCommandBuilder.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(JsonCommandBuilder.Resp(key, path)); + RedisResult result = await db.ExecuteAsync(JsonCommandBuilder.Resp(key, path)); if (result.IsNull) { @@ -142,25 +123,25 @@ 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(JsonCommandBuilder.Set(key, path, json, when))).OKtoBoolean(); + return (await db.ExecuteAsync(JsonCommandBuilder.Set(key, path, json, when))).OKtoBoolean(); } public async Task MSetAsync(KeyPathValue[] KeyPathValueList) { - return (await _db.ExecuteAsync(JsonCommandBuilder.MSet(KeyPathValueList))).OKtoBoolean(); + return (await db.ExecuteAsync(JsonCommandBuilder.MSet(KeyPathValueList))).OKtoBoolean(); } /// public async Task MergeAsync(RedisKey key, RedisValue path, RedisValue json) { - return (await _db.ExecuteAsync(JsonCommandBuilder.Merge(key, path, json))).OKtoBoolean(); + return (await db.ExecuteAsync(JsonCommandBuilder.Merge(key, path, json))).OKtoBoolean(); } /// public async Task MergeAsync(RedisKey key, RedisValue path, object obj, JsonSerializerOptions? serializerOptions = default) { string json = JsonSerializer.Serialize(obj, options: serializerOptions); - return (await _db.ExecuteAsync(JsonCommandBuilder.Merge(key, path, json))).OKtoBoolean(); + return (await db.ExecuteAsync(JsonCommandBuilder.Merge(key, path, json))).OKtoBoolean(); } public async Task SetFromFileAsync(RedisKey key, RedisValue path, string filePath, When when = When.Always) @@ -181,7 +162,7 @@ public async Task SetFromDirectoryAsync(RedisValue path, string filesPath, var files = Directory.EnumerateFiles(filesPath, "*.json"); foreach (var filePath in files) { - key = filePath.Substring(0, filePath.IndexOf(".")); + key = filePath.Substring(0, filePath.IndexOf(".", StringComparison.Ordinal)); if (await SetFromFileAsync(key, path, filePath, when)) { inserted++; @@ -198,17 +179,17 @@ public async Task SetFromDirectoryAsync(RedisValue path, string filesPath, public async Task StrAppendAsync(RedisKey key, string value, string? path = null) { - return (await _db.ExecuteAsync(JsonCommandBuilder.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(JsonCommandBuilder.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(JsonCommandBuilder.Toggle(key, path)); + RedisResult result = await db.ExecuteAsync(JsonCommandBuilder.Toggle(key, path)); if (result.IsNull) { @@ -217,7 +198,7 @@ public async Task SetFromDirectoryAsync(RedisValue path, string filesPath, if (result.Type == ResultType.Integer) { - return new bool?[] { (long)result == 1 }; + return [(long)result == 1]; } return ((RedisResult[])result!).Select(x => (bool?)((long)x == 1)).ToArray(); @@ -225,23 +206,18 @@ public async Task SetFromDirectoryAsync(RedisValue path, string filesPath, public async Task TypeAsync(RedisKey key, string? path = null) { - RedisResult result = await _db.ExecuteAsync(JsonCommandBuilder.Type(key, path)); + RedisResult result = await db.ExecuteAsync(JsonCommandBuilder.Type(key, path)); if (result.Type == ResultType.MultiBulk) { return ((RedisResult[])result!).Select(x => (JsonType)Enum.Parse(typeof(JsonType), x.ToString()!.ToUpper())).ToArray(); } - if (result.Type == ResultType.BulkString) - { - return new[] { (JsonType)Enum.Parse(typeof(JsonType), result.ToString()!.ToUpper()) }; - } - - return Array.Empty(); + return result.Type == ResultType.BulkString ? [(JsonType)Enum.Parse(typeof(JsonType), result.ToString()!.ToUpper())] : Array.Empty(); } public async Task DebugMemoryAsync(string key, string? path = null) { - return (await _db.ExecuteAsync(JsonCommandBuilder.DebugMemory(key, path))).ToLong(); + return (await db.ExecuteAsync(JsonCommandBuilder.DebugMemory(key, path))).ToLong(); } } \ No newline at end of file From 794bbcaf99c7111021248c8b03ece63d79b95664 Mon Sep 17 00:00:00 2001 From: Gabriel Erzse Date: Mon, 29 Jan 2024 12:13:38 +0200 Subject: [PATCH 19/57] Improve the signatures of the new methods Improve the signatures of the new methods, to transparently replicate the structure of the Redis command, i.e. timeout is mandatory and the first argument, order is mandatory. Add a version of the method that works for a single argument, in the spirit of the StackExchange.Redis library. --- .../CoreCommands/CoreCommandBuilder.cs | 28 +++++----- src/NRedisStack/CoreCommands/CoreCommands.cs | 32 +++++++++--- .../Core Commands/CoreTests.cs | 52 +++++++++++++++++-- 3 files changed, 87 insertions(+), 25 deletions(-) diff --git a/src/NRedisStack/CoreCommands/CoreCommandBuilder.cs b/src/NRedisStack/CoreCommands/CoreCommandBuilder.cs index 0ed6594a..ee832c95 100644 --- a/src/NRedisStack/CoreCommands/CoreCommandBuilder.cs +++ b/src/NRedisStack/CoreCommands/CoreCommandBuilder.cs @@ -20,28 +20,26 @@ public static SerializedCommand ClientSetInfo(SetInfoAttr attr, string value) return new SerializedCommand(RedisCoreCommands.CLIENT, RedisCoreCommands.SETINFO, attrValue, value); } - /// - /// Build a SerializedCommand for the BZMPOP command. - /// - /// Keys for the sorted sets to pop from. - /// Server timeout for the blocking operation. If set to 0 then it waits - /// indefinitely. - /// Maximum number of items to pop. - /// In what order to pop items. A value of Order.Ascending means to pop the minimum - /// scores from the sorted set, a value of Order.Descending means to pop the maximum scores. - /// The serialized command that can be executed against the server. - /// - public static SerializedCommand BzmPop(RedisKey[] keys, int timeout = 0, long count = 1, Order order = Order.Ascending) + public static SerializedCommand BzmPop(int timeout, RedisKey[] keys, Order order, long? count) { + if (keys.Length == 0) + { + throw new ArgumentException("At least one key must be provided."); + } + List args = [ timeout, keys.Length, .. keys.Cast(), - order == Order.Ascending ? CoreArgs.MIN : CoreArgs.MAX, - CoreArgs.COUNT, - count + order == Order.Ascending ? CoreArgs.MIN : CoreArgs.MAX ]; + if (count != null) + { + args.Add(CoreArgs.COUNT); + args.Add(count); + } + return new SerializedCommand(RedisCoreCommands.BZMPOP, args); } } diff --git a/src/NRedisStack/CoreCommands/CoreCommands.cs b/src/NRedisStack/CoreCommands/CoreCommands.cs index 2c4d45e4..f572e6dd 100644 --- a/src/NRedisStack/CoreCommands/CoreCommands.cs +++ b/src/NRedisStack/CoreCommands/CoreCommands.cs @@ -27,14 +27,14 @@ public static bool ClientSetInfo(this IDatabase db, SetInfoAttr attr, string val ///

/// Removes and returns up to entries from the first non-empty sorted set in /// . If none of the sets contain elements, the call blocks on the server until elements - /// become available or the give passes. A of 0 + /// become available or the given passes. A of 0 /// means to wait indefinitely server-side. Returns null if the server timeout expires. ///

/// When using this, pay attention to the timeout configured on the , which /// by default can be too small, in which case you want to increase it: /// /// ConfigurationOptions configurationOptions = new ConfigurationOptions(); - /// configurationOptions.SyncTimeout = 120000; + /// configurationOptions.SyncTimeout = 120000; // set a meaningful value here /// configurationOptions.EndPoints.Add("localhost"); /// ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(configurationOptions); /// @@ -44,18 +44,38 @@ public static bool ClientSetInfo(this IDatabase db, SetInfoAttr attr, string val /// This is an extension method added to the class, for convenience. /// /// The class where this extension method is applied. - /// The keys to check. /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. - /// The maximum number of records to pop out. + /// The keys to check. /// The order to sort by when popping items out of the set. If set to Order.ascending /// then the minimum elements will be popped, otherwise the maximum values. + /// The maximum number of records to pop out. If set to null then the server default + /// will be used. /// A collection of sorted set entries paired with their scores, together with the key they were popped /// from, or null if the server timeout expires. /// - public static Tuple>? BzmPop(this IDatabase db, RedisKey[] keys, int timeout = 0, long count = 1, Order order = Order.Ascending) + public static Tuple>? BzmPop(this IDatabase db, int timeout, RedisKey[] keys, Order order, long? count = null) { - var command = CoreCommandBuilder.BzmPop(keys, timeout, count, order); + var command = CoreCommandBuilder.BzmPop(timeout, keys, order, count); return db.Execute(command).ToSortedSetPopResult(); } + + ///

+ /// Syntactic sugar for , + /// where only one key is used. + /// + /// The class where this extension method is applied. + /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. + /// The key to check. + /// The order to sort by when popping items out of the set. If set to Order.ascending + /// then the minimum elements will be popped, otherwise the maximum values. + /// The maximum number of records to pop out. If set to null then the server default + /// will be used. + /// A collection of sorted set entries paired with their scores, together with the key they were popped + /// from, or null if the server timeout expires. + /// + public static Tuple>? BzmPop(this IDatabase db, int timeout, RedisKey key, Order order, long? count = null) + { + return BzmPop(db, timeout, [key], order, count); + } } } diff --git a/tests/NRedisStack.Tests/Core Commands/CoreTests.cs b/tests/NRedisStack.Tests/Core Commands/CoreTests.cs index 448a16d1..0d0f1d91 100644 --- a/tests/NRedisStack.Tests/Core Commands/CoreTests.cs +++ b/tests/NRedisStack.Tests/Core Commands/CoreTests.cs @@ -164,7 +164,7 @@ public void TestBzmPop() db.SortedSetAdd(sortedSetKey, "e", 7.76); // Pop two items with default order, which means it will pop the minimum values. - var resultWithDefaultOrder = db.BzmPop([sortedSetKey], count: 2); + var resultWithDefaultOrder = db.BzmPop(0, [sortedSetKey], Order.Ascending, 2); Assert.NotNull(resultWithDefaultOrder); Assert.Equal(sortedSetKey, resultWithDefaultOrder!.Item1); @@ -173,7 +173,7 @@ public void TestBzmPop() Assert.Equal("c", resultWithDefaultOrder.Item2[1].Value.ToString()); // Pop one more item, with descending order, which means it will pop the maximum value. - var resultWithDescendingOrder = db.BzmPop([sortedSetKey], order: Order.Descending); + var resultWithDescendingOrder = db.BzmPop(0, [sortedSetKey], Order.Descending, 1); Assert.NotNull(resultWithDescendingOrder); Assert.Equal(sortedSetKey, resultWithDescendingOrder!.Item1); @@ -190,7 +190,7 @@ public void TestBzmPopNull() db.Execute("FLUSHALL"); // Nothing in the set, and a short server timeout, which yields null. - var result = db.BzmPop(["my-set"], timeout: 1); + var result = db.BzmPop(1, ["my-set"], Order.Ascending, null); Assert.Null(result); } @@ -208,6 +208,50 @@ public void TestBzmPopMultiplexerTimeout() db.Execute("FLUSHALL"); // Server would wait forever, but the multiplexer times out in 1 second. - Assert.Throws(() => db.BzmPop(["my-set"])); + Assert.Throws(() => db.BzmPop(0, ["my-set"], Order.Ascending)); + } + + [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.0.0")] + public void TestBzmPopMultipleSets() + { + var redis = ConnectionMultiplexer.Connect("localhost"); + + var db = redis.GetDatabase(null); + db.Execute("FLUSHALL"); + + db.SortedSetAdd("set-one", "a", 1.5); + db.SortedSetAdd("set-one", "b", 5.1); + db.SortedSetAdd("set-one", "c", 3.7); + db.SortedSetAdd("set-two", "d", 9.4); + db.SortedSetAdd("set-two", "e", 7.76); + + var result = db.BzmPop(0, "set-two", Order.Descending); + + Assert.NotNull(result); + Assert.Equal("set-two", result!.Item1); + Assert.Single(result.Item2); + Assert.Equal("d", result.Item2[0].Value.ToString()); + + result = db.BzmPop(0, ["set-two", "set-one"], Order.Ascending); + + Assert.NotNull(result); + Assert.Equal("set-two", result!.Item1); + Assert.Single(result.Item2); + Assert.Equal("e", result.Item2[0].Value.ToString()); + + result = db.BzmPop(0, ["set-two", "set-one"], Order.Descending); + + Assert.NotNull(result); + Assert.Equal("set-one", result!.Item1); + Assert.Single(result.Item2); + Assert.Equal("b", result.Item2[0].Value.ToString()); + + result = db.BzmPop(0, "set-one", Order.Ascending, count: 2); + + Assert.NotNull(result); + Assert.Equal("set-one", result!.Item1); + Assert.Equal(2, result.Item2.Count); + Assert.Equal("a", result.Item2[0].Value.ToString()); + Assert.Equal("c", result.Item2[1].Value.ToString()); } } \ No newline at end of file From 0a8047ac301d35240bf8e537bec57f3504da263d Mon Sep 17 00:00:00 2001 From: Gabriel Erzse Date: Mon, 29 Jan 2024 12:29:47 +0200 Subject: [PATCH 20/57] Add test for BzmPop without keys --- tests/NRedisStack.Tests/Core Commands/CoreTests.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/NRedisStack.Tests/Core Commands/CoreTests.cs b/tests/NRedisStack.Tests/Core Commands/CoreTests.cs index 0d0f1d91..9cf901f3 100644 --- a/tests/NRedisStack.Tests/Core Commands/CoreTests.cs +++ b/tests/NRedisStack.Tests/Core Commands/CoreTests.cs @@ -195,7 +195,6 @@ public void TestBzmPopNull() Assert.Null(result); } - [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.0.0")] public void TestBzmPopMultiplexerTimeout() { @@ -254,4 +253,16 @@ public void TestBzmPopMultipleSets() Assert.Equal("a", result.Item2[0].Value.ToString()); Assert.Equal("c", result.Item2[1].Value.ToString()); } + + [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.0.0")] + public void TestBzmPopNoKeysProvided() + { + var redis = ConnectionMultiplexer.Connect("localhost"); + + var db = redis.GetDatabase(null); + db.Execute("FLUSHALL"); + + // Server would wait forever, but the multiplexer times out in 1 second. + Assert.Throws(() => db.BzmPop(0, [], Order.Ascending)); + } } \ No newline at end of file From bbe2c4a472184af34c9442eaa74902ee294e699f Mon Sep 17 00:00:00 2001 From: Gabriel Erzse Date: Mon, 29 Jan 2024 18:53:34 +0200 Subject: [PATCH 21/57] Add dedicated enum for MIN/MAX Add a dedicated enum for the MIN and MAX arguments. It feels cleaner than using Order and having to mentally map Ascending to Min and Descending to Max. --- .../CoreCommands/CoreCommandBuilder.cs | 5 +- src/NRedisStack/CoreCommands/CoreCommands.cs | 12 ++--- .../CoreCommands/DataTypes/MinMaxModifier.cs | 35 ++++++++++++ .../Core Commands/CoreTests.cs | 53 ++++++++++++++----- 4 files changed, 85 insertions(+), 20 deletions(-) create mode 100644 src/NRedisStack/CoreCommands/DataTypes/MinMaxModifier.cs diff --git a/src/NRedisStack/CoreCommands/CoreCommandBuilder.cs b/src/NRedisStack/CoreCommands/CoreCommandBuilder.cs index ee832c95..f3e1dff8 100644 --- a/src/NRedisStack/CoreCommands/CoreCommandBuilder.cs +++ b/src/NRedisStack/CoreCommands/CoreCommandBuilder.cs @@ -1,6 +1,7 @@ using NRedisStack.RedisStackCommands; using NRedisStack.Core.Literals; using NRedisStack.Core; +using NRedisStack.Core.DataTypes; using StackExchange.Redis; namespace NRedisStack @@ -20,7 +21,7 @@ public static SerializedCommand ClientSetInfo(SetInfoAttr attr, string value) return new SerializedCommand(RedisCoreCommands.CLIENT, RedisCoreCommands.SETINFO, attrValue, value); } - public static SerializedCommand BzmPop(int timeout, RedisKey[] keys, Order order, long? count) + public static SerializedCommand BzmPop(int timeout, RedisKey[] keys, MinMaxModifier minMaxModifier, long? count) { if (keys.Length == 0) { @@ -31,7 +32,7 @@ public static SerializedCommand BzmPop(int timeout, RedisKey[] keys, Order order timeout, keys.Length, .. keys.Cast(), - order == Order.Ascending ? CoreArgs.MIN : CoreArgs.MAX + minMaxModifier == MinMaxModifier.Min ? CoreArgs.MIN : CoreArgs.MAX ]; if (count != null) diff --git a/src/NRedisStack/CoreCommands/CoreCommands.cs b/src/NRedisStack/CoreCommands/CoreCommands.cs index f572e6dd..6c930964 100644 --- a/src/NRedisStack/CoreCommands/CoreCommands.cs +++ b/src/NRedisStack/CoreCommands/CoreCommands.cs @@ -46,16 +46,16 @@ public static bool ClientSetInfo(this IDatabase db, SetInfoAttr attr, string val /// The class where this extension method is applied. /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. /// The keys to check. - /// The order to sort by when popping items out of the set. If set to Order.ascending + /// Specify from which end of the sorted set to pop values. If set to MinMaxModifier.Min /// then the minimum elements will be popped, otherwise the maximum values. /// The maximum number of records to pop out. If set to null then the server default /// will be used. /// A collection of sorted set entries paired with their scores, together with the key they were popped /// from, or null if the server timeout expires. /// - public static Tuple>? BzmPop(this IDatabase db, int timeout, RedisKey[] keys, Order order, long? count = null) + public static Tuple>? BzmPop(this IDatabase db, int timeout, RedisKey[] keys, MinMaxModifier minMaxModifier, long? count = null) { - var command = CoreCommandBuilder.BzmPop(timeout, keys, order, count); + var command = CoreCommandBuilder.BzmPop(timeout, keys, minMaxModifier, count); return db.Execute(command).ToSortedSetPopResult(); } @@ -66,16 +66,16 @@ public static bool ClientSetInfo(this IDatabase db, SetInfoAttr attr, string val /// The class where this extension method is applied. /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. /// The key to check. - /// The order to sort by when popping items out of the set. If set to Order.ascending + /// Specify from which end of the sorted set to pop values. If set to MinMaxModifier.Min /// then the minimum elements will be popped, otherwise the maximum values. /// The maximum number of records to pop out. If set to null then the server default /// will be used. /// A collection of sorted set entries paired with their scores, together with the key they were popped /// from, or null if the server timeout expires. /// - public static Tuple>? BzmPop(this IDatabase db, int timeout, RedisKey key, Order order, long? count = null) + public static Tuple>? BzmPop(this IDatabase db, int timeout, RedisKey key, MinMaxModifier minMaxModifier, long? count = null) { - return BzmPop(db, timeout, [key], order, count); + return BzmPop(db, timeout, [key], minMaxModifier, count); } } } diff --git a/src/NRedisStack/CoreCommands/DataTypes/MinMaxModifier.cs b/src/NRedisStack/CoreCommands/DataTypes/MinMaxModifier.cs new file mode 100644 index 00000000..c38e2231 --- /dev/null +++ b/src/NRedisStack/CoreCommands/DataTypes/MinMaxModifier.cs @@ -0,0 +1,35 @@ +using StackExchange.Redis; + +namespace NRedisStack.Core.DataTypes; + +/// +/// Modifier that can be used for sorted set commands, where a MIN/MAX argument is expected by the Redis server. +/// +public enum MinMaxModifier +{ + /// + /// Maps to the MIN argument on the Redis server. + /// + Min, + + /// + /// Maps to the MAX argument on the Redis server. + /// + Max +} + +/// +/// Conversion methods from/to other common data types. +/// +public static class MinMaxModifierExtensions +{ + /// + /// Convert from to . + /// + public static MinMaxModifier ToMinMax(this Order order) => order switch + { + Order.Ascending => MinMaxModifier.Min, + Order.Descending => MinMaxModifier.Max, + _ => throw new ArgumentOutOfRangeException(nameof(order)) + }; +} \ No newline at end of file diff --git a/tests/NRedisStack.Tests/Core Commands/CoreTests.cs b/tests/NRedisStack.Tests/Core Commands/CoreTests.cs index 9cf901f3..0b6d9e80 100644 --- a/tests/NRedisStack.Tests/Core Commands/CoreTests.cs +++ b/tests/NRedisStack.Tests/Core Commands/CoreTests.cs @@ -1,10 +1,8 @@ using Xunit; using NRedisStack.Core; -using NRedisStack; using static NRedisStack.Auxiliary; using StackExchange.Redis; -using System.Xml.Linq; -using System.Reflection; +using NRedisStack.Core.DataTypes; using NRedisStack.RedisStackCommands; @@ -164,7 +162,7 @@ public void TestBzmPop() db.SortedSetAdd(sortedSetKey, "e", 7.76); // Pop two items with default order, which means it will pop the minimum values. - var resultWithDefaultOrder = db.BzmPop(0, [sortedSetKey], Order.Ascending, 2); + var resultWithDefaultOrder = db.BzmPop(0, [sortedSetKey], MinMaxModifier.Min, 2); Assert.NotNull(resultWithDefaultOrder); Assert.Equal(sortedSetKey, resultWithDefaultOrder!.Item1); @@ -173,7 +171,7 @@ public void TestBzmPop() Assert.Equal("c", resultWithDefaultOrder.Item2[1].Value.ToString()); // Pop one more item, with descending order, which means it will pop the maximum value. - var resultWithDescendingOrder = db.BzmPop(0, [sortedSetKey], Order.Descending, 1); + var resultWithDescendingOrder = db.BzmPop(0, [sortedSetKey], MinMaxModifier.Max, 1); Assert.NotNull(resultWithDescendingOrder); Assert.Equal(sortedSetKey, resultWithDescendingOrder!.Item1); @@ -190,7 +188,7 @@ public void TestBzmPopNull() db.Execute("FLUSHALL"); // Nothing in the set, and a short server timeout, which yields null. - var result = db.BzmPop(1, ["my-set"], Order.Ascending, null); + var result = db.BzmPop(1, ["my-set"], MinMaxModifier.Min, null); Assert.Null(result); } @@ -207,7 +205,7 @@ public void TestBzmPopMultiplexerTimeout() db.Execute("FLUSHALL"); // Server would wait forever, but the multiplexer times out in 1 second. - Assert.Throws(() => db.BzmPop(0, ["my-set"], Order.Ascending)); + Assert.Throws(() => db.BzmPop(0, ["my-set"], MinMaxModifier.Min)); } [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.0.0")] @@ -224,28 +222,28 @@ public void TestBzmPopMultipleSets() db.SortedSetAdd("set-two", "d", 9.4); db.SortedSetAdd("set-two", "e", 7.76); - var result = db.BzmPop(0, "set-two", Order.Descending); + var result = db.BzmPop(0, "set-two", MinMaxModifier.Max); Assert.NotNull(result); Assert.Equal("set-two", result!.Item1); Assert.Single(result.Item2); Assert.Equal("d", result.Item2[0].Value.ToString()); - result = db.BzmPop(0, ["set-two", "set-one"], Order.Ascending); + result = db.BzmPop(0, ["set-two", "set-one"], MinMaxModifier.Min); Assert.NotNull(result); Assert.Equal("set-two", result!.Item1); Assert.Single(result.Item2); Assert.Equal("e", result.Item2[0].Value.ToString()); - result = db.BzmPop(0, ["set-two", "set-one"], Order.Descending); + result = db.BzmPop(0, ["set-two", "set-one"], MinMaxModifier.Max); Assert.NotNull(result); Assert.Equal("set-one", result!.Item1); Assert.Single(result.Item2); Assert.Equal("b", result.Item2[0].Value.ToString()); - result = db.BzmPop(0, "set-one", Order.Ascending, count: 2); + result = db.BzmPop(0, "set-one", MinMaxModifier.Min, count: 2); Assert.NotNull(result); Assert.Equal("set-one", result!.Item1); @@ -263,6 +261,37 @@ public void TestBzmPopNoKeysProvided() db.Execute("FLUSHALL"); // Server would wait forever, but the multiplexer times out in 1 second. - Assert.Throws(() => db.BzmPop(0, [], Order.Ascending)); + Assert.Throws(() => db.BzmPop(0, [], MinMaxModifier.Min)); + } + + [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.0.0")] + public void TestBzmPopWithOrderEnum() + { + var redis = ConnectionMultiplexer.Connect("localhost"); + + var db = redis.GetDatabase(null); + db.Execute("FLUSHALL"); + + var sortedSetKey = "my-set"; + + db.SortedSetAdd(sortedSetKey, "a", 1.5); + db.SortedSetAdd(sortedSetKey, "b", 5.1); + db.SortedSetAdd(sortedSetKey, "c", 3.7); + + // Pop two items with default order, which means it will pop the minimum values. + var resultWithDefaultOrder = db.BzmPop(0, [sortedSetKey], Order.Ascending.ToMinMax()); + + Assert.NotNull(resultWithDefaultOrder); + Assert.Equal(sortedSetKey, resultWithDefaultOrder!.Item1); + Assert.Single(resultWithDefaultOrder.Item2); + Assert.Equal("a", resultWithDefaultOrder.Item2[0].Value.ToString()); + + // Pop one more item, with descending order, which means it will pop the maximum value. + var resultWithDescendingOrder = db.BzmPop(0, [sortedSetKey], Order.Descending.ToMinMax()); + + Assert.NotNull(resultWithDescendingOrder); + Assert.Equal(sortedSetKey, resultWithDescendingOrder!.Item1); + Assert.Single(resultWithDescendingOrder.Item2); + Assert.Equal("b", resultWithDescendingOrder.Item2[0].Value.ToString()); } } \ No newline at end of file From 117207cc4d437b1e54433c51579d452231cb5246 Mon Sep 17 00:00:00 2001 From: Gabriel Erzse Date: Mon, 29 Jan 2024 19:07:56 +0200 Subject: [PATCH 22/57] Remove primary constructor syntax The primary constructor syntax seems to be not supported by older dotnet versions, so don't use it. Also switch from `class` to `struct`, to better reflect the fact that RedisValueWithScore is just a data storage item. --- .../DataTypes/RedisValueWithScore.cs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/NRedisStack/CoreCommands/DataTypes/RedisValueWithScore.cs b/src/NRedisStack/CoreCommands/DataTypes/RedisValueWithScore.cs index 95f98a00..6587db45 100644 --- a/src/NRedisStack/CoreCommands/DataTypes/RedisValueWithScore.cs +++ b/src/NRedisStack/CoreCommands/DataTypes/RedisValueWithScore.cs @@ -3,20 +3,29 @@ namespace NRedisStack.Core.DataTypes; /// -/// Holds a value with an associated score. +/// Holds a with an associated score. /// Used when working with sorted sets. /// -public class RedisValueWithScore(RedisValue value, double score) +public struct RedisValueWithScore { + /// + /// Pair a with a numeric score. + /// + public RedisValueWithScore(RedisValue value, double score) + { + Value = value; + Score = score; + } + /// /// The value of an item stored in a sorted set. For example, in the Redis command /// ZADD my-set 5.1 my-value, the value is my-value. /// - public RedisValue Value { get; } = value; + public RedisValue Value { get; } /// /// The score of an item stored in a sorted set. For example, in the Redis command /// ZADD my-set 5.1 my-value, the score is 5.1. /// - public double Score { get; } = score; + public double Score { get; } } \ No newline at end of file From 04d0b9b516a48bde400a100ae488cd79bac676e5 Mon Sep 17 00:00:00 2001 From: Gabriel Erzse Date: Mon, 29 Jan 2024 19:42:19 +0200 Subject: [PATCH 23/57] Separate concurrency groups for GitHub workflows It seems that workflows cancel each other out if they are in the same concurrency group: https://github.com/orgs/community/discussions/41518 Try to separate four workflows that run on PRs into separate concurency groups. Ideally this will avoid the cancelation. They should still cancel runs from previous pushes, each in their own group. --- .github/workflows/doctests.yml | 2 +- .github/workflows/integration.yml | 2 +- .github/workflows/linter.yaml | 2 +- .github/workflows/spellcheck.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/doctests.yml b/.github/workflows/doctests.yml index b170bedf..218a9b53 100644 --- a/.github/workflows/doctests.yml +++ b/.github/workflows/doctests.yml @@ -10,7 +10,7 @@ permissions: contents: read concurrency: - group: ${{ github.event.pull_request.number || github.ref }} + group: ${{ github.event.pull_request.number || github.ref }}-doctests cancel-in-progress: true jobs: diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index ac6128a0..2d0bdf5f 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -12,7 +12,7 @@ on: - cron: "0 1 * * *" concurrency: - group: ${{ github.event.pull_request.number || github.ref }} + group: ${{ github.event.pull_request.number || github.ref }}-integration cancel-in-progress: true jobs: diff --git a/.github/workflows/linter.yaml b/.github/workflows/linter.yaml index 3ef14d77..d16f69c7 100644 --- a/.github/workflows/linter.yaml +++ b/.github/workflows/linter.yaml @@ -3,7 +3,7 @@ name: Format check on pull request on: pull_request concurrency: - group: ${{ github.event.pull_request.number || github.ref }} + group: ${{ github.event.pull_request.number || github.ref }}-linter cancel-in-progress: true jobs: diff --git a/.github/workflows/spellcheck.yml b/.github/workflows/spellcheck.yml index a1413e96..228297d5 100644 --- a/.github/workflows/spellcheck.yml +++ b/.github/workflows/spellcheck.yml @@ -4,7 +4,7 @@ on: pull_request: concurrency: - group: ${{ github.event.pull_request.number || github.ref }} + group: ${{ github.event.pull_request.number || github.ref }}-spellcheck cancel-in-progress: true jobs: From b8cd5d67b66eef8f28019925026226e14fa4febf Mon Sep 17 00:00:00 2001 From: nimanikoo Date: Mon, 29 Jan 2024 21:45:43 +0330 Subject: [PATCH 24/57] Fix indent in CuckooInformation.cs --- src/NRedisStack/CuckooFilter/DataTypes/CuckooInformation.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NRedisStack/CuckooFilter/DataTypes/CuckooInformation.cs b/src/NRedisStack/CuckooFilter/DataTypes/CuckooInformation.cs index 74be500c..bcbbac76 100644 --- a/src/NRedisStack/CuckooFilter/DataTypes/CuckooInformation.cs +++ b/src/NRedisStack/CuckooFilter/DataTypes/CuckooInformation.cs @@ -16,8 +16,8 @@ public class CuckooInformation public long MaxIterations { get; private set; } internal CuckooInformation(long size, long numberOfBuckets, long numberOfFilter, - long numberOfItemsInserted, long numberOfItemsDeleted, - long bucketSize, long expansionRate, long maxIteration) + long numberOfItemsInserted, long numberOfItemsDeleted, + long bucketSize, long expansionRate, long maxIteration) { Size = size; NumberOfBuckets = numberOfBuckets; From bc36846e40ea39acc3c5a0df965e8cc0e8b3b09f Mon Sep 17 00:00:00 2001 From: nimanikoo Date: Mon, 29 Jan 2024 21:49:54 +0330 Subject: [PATCH 25/57] RollBack to original version of naming NumIncrbyAsync method in JsonCommandsAsync.cs --- src/NRedisStack/Json/IJsonCommandsAsync.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NRedisStack/Json/IJsonCommandsAsync.cs b/src/NRedisStack/Json/IJsonCommandsAsync.cs index ce5c999a..76913eed 100644 --- a/src/NRedisStack/Json/IJsonCommandsAsync.cs +++ b/src/NRedisStack/Json/IJsonCommandsAsync.cs @@ -157,7 +157,7 @@ public interface IJsonCommandsAsync /// 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); + Task NumIncrbyAsync(RedisKey key, string path, double value); /// /// Gets the keys of the object at the provided path. From 5bbf60fb98df93ed8ce28e36c2a52df7ddb277bd Mon Sep 17 00:00:00 2001 From: Gabriel Erzse Date: Mon, 29 Jan 2024 19:54:49 +0200 Subject: [PATCH 26/57] Remove use of collection literals Collection literals are not supported by older dotnet versions, it seems, so stop using them for now. --- .../CoreCommands/CoreCommandBuilder.cs | 12 ++++++----- src/NRedisStack/CoreCommands/CoreCommands.cs | 2 +- src/NRedisStack/ResponseParser.cs | 2 +- .../Core Commands/CoreTests.cs | 20 +++++++++---------- .../TimeSeries/TestAPI/TestMRange.cs | 10 +++++----- 5 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/NRedisStack/CoreCommands/CoreCommandBuilder.cs b/src/NRedisStack/CoreCommands/CoreCommandBuilder.cs index f3e1dff8..3f01c00a 100644 --- a/src/NRedisStack/CoreCommands/CoreCommandBuilder.cs +++ b/src/NRedisStack/CoreCommands/CoreCommandBuilder.cs @@ -28,12 +28,14 @@ public static SerializedCommand BzmPop(int timeout, RedisKey[] keys, MinMaxModif throw new ArgumentException("At least one key must be provided."); } - List args = [ + List args = new List { timeout, - keys.Length, - .. keys.Cast(), - minMaxModifier == MinMaxModifier.Min ? CoreArgs.MIN : CoreArgs.MAX - ]; + keys.Length + }; + + args.AddRange(keys.Cast()); + + args.Add(minMaxModifier == MinMaxModifier.Min ? CoreArgs.MIN : CoreArgs.MAX); if (count != null) { diff --git a/src/NRedisStack/CoreCommands/CoreCommands.cs b/src/NRedisStack/CoreCommands/CoreCommands.cs index 6c930964..e53c3cec 100644 --- a/src/NRedisStack/CoreCommands/CoreCommands.cs +++ b/src/NRedisStack/CoreCommands/CoreCommands.cs @@ -75,7 +75,7 @@ public static bool ClientSetInfo(this IDatabase db, SetInfoAttr attr, string val /// public static Tuple>? BzmPop(this IDatabase db, int timeout, RedisKey key, MinMaxModifier minMaxModifier, long? count = null) { - return BzmPop(db, timeout, [key], minMaxModifier, count); + return BzmPop(db, timeout, new[] { key }, minMaxModifier, count); } } } diff --git a/src/NRedisStack/ResponseParser.cs b/src/NRedisStack/ResponseParser.cs index 46236c15..fba80f95 100644 --- a/src/NRedisStack/ResponseParser.cs +++ b/src/NRedisStack/ResponseParser.cs @@ -738,7 +738,7 @@ public static Dictionary[] ToDictionarys(this RedisResult r var resultKey = resultArray[0].ToRedisKey(); var resultSetItems = resultArray[1].ToArray(); - List valuesWithScores = []; + List valuesWithScores = new List(); foreach (var resultSetItem in resultSetItems) { diff --git a/tests/NRedisStack.Tests/Core Commands/CoreTests.cs b/tests/NRedisStack.Tests/Core Commands/CoreTests.cs index 0b6d9e80..d2dcb872 100644 --- a/tests/NRedisStack.Tests/Core Commands/CoreTests.cs +++ b/tests/NRedisStack.Tests/Core Commands/CoreTests.cs @@ -153,7 +153,7 @@ public void TestBzmPop() var db = redis.GetDatabase(null); db.Execute("FLUSHALL"); - var sortedSetKey = "my-set"; + var sortedSetKey = new RedisKey("my-set"); db.SortedSetAdd(sortedSetKey, "a", 1.5); db.SortedSetAdd(sortedSetKey, "b", 5.1); @@ -162,7 +162,7 @@ public void TestBzmPop() db.SortedSetAdd(sortedSetKey, "e", 7.76); // Pop two items with default order, which means it will pop the minimum values. - var resultWithDefaultOrder = db.BzmPop(0, [sortedSetKey], MinMaxModifier.Min, 2); + var resultWithDefaultOrder = db.BzmPop(0, new[] { sortedSetKey }, MinMaxModifier.Min, 2); Assert.NotNull(resultWithDefaultOrder); Assert.Equal(sortedSetKey, resultWithDefaultOrder!.Item1); @@ -171,7 +171,7 @@ public void TestBzmPop() Assert.Equal("c", resultWithDefaultOrder.Item2[1].Value.ToString()); // Pop one more item, with descending order, which means it will pop the maximum value. - var resultWithDescendingOrder = db.BzmPop(0, [sortedSetKey], MinMaxModifier.Max, 1); + var resultWithDescendingOrder = db.BzmPop(0, new[] { sortedSetKey }, MinMaxModifier.Max, 1); Assert.NotNull(resultWithDescendingOrder); Assert.Equal(sortedSetKey, resultWithDescendingOrder!.Item1); @@ -188,7 +188,7 @@ public void TestBzmPopNull() db.Execute("FLUSHALL"); // Nothing in the set, and a short server timeout, which yields null. - var result = db.BzmPop(1, ["my-set"], MinMaxModifier.Min, null); + var result = db.BzmPop(1, "my-set", MinMaxModifier.Min); Assert.Null(result); } @@ -205,7 +205,7 @@ public void TestBzmPopMultiplexerTimeout() db.Execute("FLUSHALL"); // Server would wait forever, but the multiplexer times out in 1 second. - Assert.Throws(() => db.BzmPop(0, ["my-set"], MinMaxModifier.Min)); + Assert.Throws(() => db.BzmPop(0, "my-set", MinMaxModifier.Min)); } [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.0.0")] @@ -229,14 +229,14 @@ public void TestBzmPopMultipleSets() Assert.Single(result.Item2); Assert.Equal("d", result.Item2[0].Value.ToString()); - result = db.BzmPop(0, ["set-two", "set-one"], MinMaxModifier.Min); + result = db.BzmPop(0, new[] { new RedisKey("set-two"), new RedisKey("set-one") }, MinMaxModifier.Min); Assert.NotNull(result); Assert.Equal("set-two", result!.Item1); Assert.Single(result.Item2); Assert.Equal("e", result.Item2[0].Value.ToString()); - result = db.BzmPop(0, ["set-two", "set-one"], MinMaxModifier.Max); + result = db.BzmPop(0, new[] { new RedisKey("set-two"), new RedisKey("set-one") }, MinMaxModifier.Max); Assert.NotNull(result); Assert.Equal("set-one", result!.Item1); @@ -261,7 +261,7 @@ public void TestBzmPopNoKeysProvided() db.Execute("FLUSHALL"); // Server would wait forever, but the multiplexer times out in 1 second. - Assert.Throws(() => db.BzmPop(0, [], MinMaxModifier.Min)); + Assert.Throws(() => db.BzmPop(0, Array.Empty(), MinMaxModifier.Min)); } [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.0.0")] @@ -279,7 +279,7 @@ public void TestBzmPopWithOrderEnum() db.SortedSetAdd(sortedSetKey, "c", 3.7); // Pop two items with default order, which means it will pop the minimum values. - var resultWithDefaultOrder = db.BzmPop(0, [sortedSetKey], Order.Ascending.ToMinMax()); + var resultWithDefaultOrder = db.BzmPop(0, sortedSetKey, Order.Ascending.ToMinMax()); Assert.NotNull(resultWithDefaultOrder); Assert.Equal(sortedSetKey, resultWithDefaultOrder!.Item1); @@ -287,7 +287,7 @@ public void TestBzmPopWithOrderEnum() Assert.Equal("a", resultWithDefaultOrder.Item2[0].Value.ToString()); // Pop one more item, with descending order, which means it will pop the maximum value. - var resultWithDescendingOrder = db.BzmPop(0, [sortedSetKey], Order.Descending.ToMinMax()); + var resultWithDescendingOrder = db.BzmPop(0, sortedSetKey, Order.Descending.ToMinMax()); Assert.NotNull(resultWithDescendingOrder); Assert.Equal(sortedSetKey, resultWithDescendingOrder!.Item1); diff --git a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestMRange.cs b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestMRange.cs index 0c0d7338..391640d8 100644 --- a/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestMRange.cs +++ b/tests/NRedisStack.Tests/TimeSeries/TestAPI/TestMRange.cs @@ -322,18 +322,18 @@ public void TestMRangeLatest() (long)TimeSpan.FromHours(1).TotalMilliseconds, // 1h used to force partial bucket TsAggregation.Sum); - ts.Create(primaryTsKey, labels: [label]); - ts.Create(compactedTsKey, labels: [label, compactedLabel]); + ts.Create(primaryTsKey, labels: new[] { label }); + ts.Create(compactedTsKey, labels: new[] { label, compactedLabel }); ts.CreateRule(primaryTsKey, compactionRule); - var tuples = CreateData(ts, 50, [primaryTsKey]); + var tuples = CreateData(ts, 50, new[] { primaryTsKey }); - var results = ts.MRange("-", "+", ["key=MRangeLatest", "compact=true"], latest: true); + var results = ts.MRange("-", "+", new[] { "key=MRangeLatest", "compact=true" }, latest: true); Assert.Single(results); Assert.Equal(compactedTsKey, results[0].key); Assert.NotEmpty(results[0].values); Assert.Equal(tuples.Sum(x => x.Val), results[0].values.Sum(x => x.Val)); - results = ts.MRange("-", "+", ["key=MRangeLatest", "compact=true"], latest: false); + results = ts.MRange("-", "+", new[] { "key=MRangeLatest", "compact=true" }, latest: false); Assert.Single(results); Assert.Equal(compactedTsKey, results[0].key); Assert.Empty(results[0].values); From bbb97d6eb35db50de890da46d28c7dc503fbdf15 Mon Sep 17 00:00:00 2001 From: Gabriel Erzse Date: Mon, 29 Jan 2024 20:16:30 +0200 Subject: [PATCH 27/57] Increase multiplexer timeout in tests Some tests (for the Gears module) seem flaky, they fails sometime with RedisTimeoutException. Try to double the timeout in the connection multiplexer, from 5 to 10 seconds, hopefully this helps. --- tests/NRedisStack.Tests/RedisFixture.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/NRedisStack.Tests/RedisFixture.cs b/tests/NRedisStack.Tests/RedisFixture.cs index aca9ba67..7de53fcd 100644 --- a/tests/NRedisStack.Tests/RedisFixture.cs +++ b/tests/NRedisStack.Tests/RedisFixture.cs @@ -32,6 +32,8 @@ public RedisFixture() ConfigurationOptions clusterConfig = new ConfigurationOptions { + SyncTimeout = 10000, + AsyncTimeout = 10000, EndPoints = endpoints }; From 579d1d8f516d76aeb839aed41919e9a5b160eecf Mon Sep 17 00:00:00 2001 From: Gabriel Erzse Date: Mon, 29 Jan 2024 20:21:29 +0200 Subject: [PATCH 28/57] Try to fix the linter workflow --- .github/workflows/linter.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/linter.yaml b/.github/workflows/linter.yaml index d16f69c7..7c776851 100644 --- a/.github/workflows/linter.yaml +++ b/.github/workflows/linter.yaml @@ -14,9 +14,7 @@ jobs: run: dotnet tool install -g dotnet-format - name: Checkout repo - uses: actions/checkout@v2 - with: - ref: ${{ github.head_ref }} + uses: actions/checkout@v3 - name: lint run: | From e89743af45fc8a8307ecb78b4af12eb248a45f8d Mon Sep 17 00:00:00 2001 From: nimanikoo Date: Mon, 29 Jan 2024 22:09:51 +0330 Subject: [PATCH 29/57] [Fix] 1.I fixed typo problems in this class at first After that, 2. I used collection expression to better understand the code and avoid additional coding and optimize coding based on c# doc: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/collection-expressions 3.then Remove unused usings 4.Then I commented the places that were not Handled for Try Catch 5.refactor to primary constructor --- .../Examples/ExampleTests.cs | 473 ++++++++++-------- 1 file changed, 260 insertions(+), 213 deletions(-) diff --git a/tests/NRedisStack.Tests/Examples/ExampleTests.cs b/tests/NRedisStack.Tests/Examples/ExampleTests.cs index f7b5f906..be53360e 100644 --- a/tests/NRedisStack.Tests/Examples/ExampleTests.cs +++ b/tests/NRedisStack.Tests/Examples/ExampleTests.cs @@ -1,15 +1,8 @@ -using System.Net.Security; -using System.Security.Cryptography; -using System.Security.Cryptography.X509Certificates; using NRedisStack.DataTypes; using NRedisStack.RedisStackCommands; using NRedisStack.Search; using NRedisStack.Search.Aggregation; using NRedisStack.Search.Literals.Enums; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Math; -using Org.BouncyCastle.OpenSsl; using StackExchange.Redis; using Xunit; using Xunit.Abstractions; @@ -17,14 +10,11 @@ namespace NRedisStack.Tests; -public class ExampleTests : AbstractNRedisStackTest, IDisposable +public class ExampleTests(RedisFixture redisFixture, ITestOutputHelper testOutputHelper) + : AbstractNRedisStackTest(redisFixture), IDisposable { - private readonly ITestOutputHelper testOutputHelper; + private readonly ITestOutputHelper testOutputHelper = testOutputHelper; // private readonly string key = "EXAMPLES_TESTS"; - public ExampleTests(RedisFixture redisFixture, ITestOutputHelper testOutputHelper) : base(redisFixture) - { - this.testOutputHelper = testOutputHelper; - } [SkipIfRedis(Is.OSSCluster)] public void HSETandSearch() @@ -39,7 +29,7 @@ public void HSETandSearch() var ft = db.FT(); // Use HSET to add a field-value pair to a hash - db.HashSet("profesor:5555", new HashEntry[] { new("first", "Albert"), new("last", "Blue"), new("age", "55") }); + db.HashSet("professor:5555", new HashEntry[] { new("first", "Albert"), new("last", "Blue"), new("age", "55") }); db.HashSet("student:1111", new HashEntry[] { new("first", "Joe"), new("last", "Dod"), new("age", "18") }); db.HashSet("pupil:2222", new HashEntry[] { new("first", "Jen"), new("last", "Rod"), new("age", "14") }); db.HashSet("student:3333", new HashEntry[] { new("first", "El"), new("last", "Mark"), new("age", "17") }); @@ -102,10 +92,11 @@ public void PipelineExample() var pipeline = new Pipeline(db); // Add JsonSet to pipeline - pipeline.Json.SetAsync("person", "$", new { name = "John", age = 30, city = "New York", nicknames = new[] { "John", "Johny", "Jo" } }); + pipeline.Json.SetAsync("person", "$", + new { name = "John", age = 30, city = "New York", nicknames = new[] { "John", "Johny", "Jo" } }); // Increase age by 2 - _ = pipeline.Json.NumIncrByAsync("person", "$.age", 2); + _ = pipeline.Json.NumIncrbyAsync("person", "$.age", 2); // Clear the nicknames from the Json _ = pipeline.Json.ClearAsync("person", "$.nicknames"); @@ -185,7 +176,7 @@ public async Task PipelineWithAsync() var pipeline = new Pipeline(db); - // Create metedata lables for time-series. + // Create metadata labels for time-series. TimeSeriesLabel label1 = new TimeSeriesLabel("temp", "TLV"); TimeSeriesLabel label2 = new TimeSeriesLabel("temp", "JLM"); var labels1 = new List { label1 }; @@ -195,23 +186,23 @@ public async Task PipelineWithAsync() _ = pipeline.Ts.CreateAsync("temp:TLV", labels: labels1); _ = pipeline.Ts.CreateAsync("temp:JLM", labels: labels2); - // Adding multiple sequenece of time-series data. - List<(string, TimeStamp, double)> sequence1 = new List<(string, TimeStamp, double)>() - { - ("temp:TLV",1000,30), - ("temp:TLV", 1010 ,35), + // Adding multiple sequence of time-series data. + List<(string, TimeStamp, double)> sequence1 = + [ + ("temp:TLV", 1000, 30), + ("temp:TLV", 1010, 35), ("temp:TLV", 1020, 9999), ("temp:TLV", 1030, 40) - }; - List<(string, TimeStamp, double)> sequence2 = new List<(string, TimeStamp, double)>() - { - ("temp:JLM",1005,30), - ("temp:JLM", 1015 ,35), + ]; + List<(string, TimeStamp, double)> sequence2 = + [ + ("temp:JLM", 1005, 30), + ("temp:JLM", 1015, 35), ("temp:JLM", 1025, 9999), ("temp:JLM", 1035, 40) - }; + ]; - // Adding mutiple samples to mutiple series. + // Adding multiple samples to multiple series. _ = pipeline.Ts.MAddAsync(sequence1); _ = pipeline.Ts.MAddAsync(sequence2); @@ -222,11 +213,12 @@ public async Task PipelineWithAsync() var ts = db.TS(); // Get only the location label for each last sample, use SELECTED_LABELS. - var respons = await ts.MGetAsync(new List { "temp=JLM" }, selectedLabels: new List { "location" }); + var response = await ts.MGetAsync(new List { "temp=JLM" }, + selectedLabels: new List { "location" }); - // Assert the respons - Assert.Equal(1, respons.Count); - Assert.Equal("temp:JLM", respons[0].key); + // Assert the response + Assert.Equal(1, response.Count); + Assert.Equal("temp:JLM", response[0].key); } [SkipIfRedis(Is.OSSCluster)] @@ -246,17 +238,18 @@ public void TransactionExample() // Add account details with Json.Set to transaction _ = tran.Json.SetAsync("accdetails:Jeeva", "$", new { name = "Jeeva", totalAmount = 1000, bankName = "City" }); - _ = tran.Json.SetAsync("accdetails:Shachar", "$", new { name = "Shachar", totalAmount = 1000, bankName = "City" }); + _ = tran.Json.SetAsync("accdetails:Shachar", "$", + new { name = "Shachar", totalAmount = 1000, bankName = "City" }); // Get the Json response var getShachar = tran.Json.GetAsync("accdetails:Shachar"); var getJeeva = tran.Json.GetAsync("accdetails:Jeeva"); // Debit 200 from Jeeva - _ = tran.Json.NumIncrByAsync("accdetails:Jeeva", "$.totalAmount", -200); + _ = tran.Json.NumIncrbyAsync("accdetails:Jeeva", "$.totalAmount", -200); // Credit 200 from Shachar - _ = tran.Json.NumIncrByAsync("accdetails:Shachar", "$.totalAmount", 200); + _ = tran.Json.NumIncrbyAsync("accdetails:Shachar", "$.totalAmount", 200); // Get total amount for both Jeeva = 800 & Shachar = 1200 var totalAmtOfJeeva = tran.Json.GetAsync("accdetails:Jeeva", path: "$.totalAmount"); @@ -290,6 +283,7 @@ public void TestJsonConvert() { json.Set("doc:" + i, "$", "{\"name\":\"foo\"}"); } + var res = ft.Search("test", new Query("@name:{foo}")); var docs = res.ToJson(); @@ -298,15 +292,14 @@ public void TestJsonConvert() } #if CI_RUN_TESTS - #if NET481 [Fact] public void TestRedisCloudConnection_net481() { var root = Path.GetFullPath(Directory.GetCurrentDirectory()); var redisCaPath = Path.GetFullPath(Path.Combine(root, "redis_ca.pem")); - var redisUserCrtPath = Path.GetFullPath(Path.Combine(root, "redis_user.crt")); - var redisUserPrivateKeyPath = Path.GetFullPath(Path.Combine(root, "redis_user_private.key")); + var redisUserCrtPath = Path.GetFullPath(Path.Combine(root, "redis_user.crt")); + var redisUserPrivateKeyPath = Path.GetFullPath(Path.Combine(root, "redis_user_private.key")); var password = Environment.GetEnvironmentVariable("PASSWORD") ?? throw new Exception("PASSWORD is not set."); var endpoint = Environment.GetEnvironmentVariable("ENDPOINT") ?? throw new Exception("ENDPOINT is not set."); @@ -330,7 +323,8 @@ public void TestRedisCloudConnection_net481() Password = password }; - redisConfiguration.CertificateSelection += (_, _, _, _, _) => new X509Certificate2(clientCert.Export(X509ContentType.Pfx)); + redisConfiguration.CertificateSelection += + (_, _, _, _, _) => new X509Certificate2(clientCert.Export(X509ContentType.Pfx)); redisConfiguration.CertificateValidation += (_, cert, _, errors) => { @@ -416,8 +410,8 @@ public void TestRedisCloudConnection() { var root = Path.GetFullPath(Directory.GetCurrentDirectory()); var redisCaPath = Path.GetFullPath(Path.Combine(root, "redis_ca.pem")); - var redisUserCrtPath = Path.GetFullPath(Path.Combine(root, "redis_user.crt")); - var redisUserPrivateKeyPath = Path.GetFullPath(Path.Combine(root, "redis_user_private.key")); + var redisUserCrtPath = Path.GetFullPath(Path.Combine(root, "redis_user.crt")); + var redisUserPrivateKeyPath = Path.GetFullPath(Path.Combine(root, "redis_user_private.key")); var password = Environment.GetEnvironmentVariable("PASSWORD") ?? throw new Exception("PASSWORD is not set."); var endpoint = Environment.GetEnvironmentVariable("ENDPOINT") ?? throw new Exception("ENDPOINT is not set."); @@ -489,8 +483,8 @@ public void TestRedisCloudConnection_DotnetCore3() // Replace this with your own Redis Cloud credentials var root = Path.GetFullPath(Directory.GetCurrentDirectory()); var redisCaPath = Path.GetFullPath(Path.Combine(root, "redis_ca.pem")); - var redisUserCrtPath = Path.GetFullPath(Path.Combine(root, "redis_user.crt")); - var redisUserPrivateKeyPath = Path.GetFullPath(Path.Combine(root, "redis_user_private.key")); + var redisUserCrtPath = Path.GetFullPath(Path.Combine(root, "redis_user.crt")); + var redisUserPrivateKeyPath = Path.GetFullPath(Path.Combine(root, "redis_user_private.key")); var password = Environment.GetEnvironmentVariable("PASSWORD") ?? throw new Exception("PASSWORD is not set."); var endpoint = Environment.GetEnvironmentVariable("ENDPOINT") ?? throw new Exception("ENDPOINT is not set."); @@ -639,10 +633,10 @@ public void BasicJsonExamplesTest() field1 = "val1" }); res = json.Get(key: "ex2:2", - path: "$.field1", - indent: "\t", - newLine: "\n" - ); + path: "$.field1", + indent: "\t", + newLine: "\n" + ); Assert.Equal("[\n\t\"val1\"\n]", res.ToString()); // Fetch multiple properties: @@ -834,124 +828,136 @@ public void AdvancedJsonExamplesTest() { city = "Boston", location = "42.361145, -71.057083", - inventory = new[] { - new { - id = 15970, - gender = "Men", - season = new[] {"Fall", "Winter"}, - description = "Turtle Check Men Navy Blue Shirt", - price = 34.95 - }, - new { - id = 59263, - gender = "Women", - season = new[] {"Fall", "Winter", "Spring", "Summer"}, - description = "Titan Women Silver Watch", - price = 129.99 - }, - new { - id = 46885, - gender = "Boys", - season = new[] {"Fall"}, - description = "Ben 10 Boys Navy Blue Slippers", - price = 45.99 - } + inventory = new[] + { + new + { + id = 15970, + gender = "Men", + season = new[] { "Fall", "Winter" }, + description = "Turtle Check Men Navy Blue Shirt", + price = 34.95 + }, + new + { + id = 59263, + gender = "Women", + season = new[] { "Fall", "Winter", "Spring", "Summer" }, + description = "Titan Women Silver Watch", + price = 129.99 + }, + new + { + id = 46885, + gender = "Boys", + season = new[] { "Fall" }, + description = "Ben 10 Boys Navy Blue Slippers", + price = 45.99 } + } }); // Fetch all properties of an array: var res = json.Get(key: "warehouse:1", - path: "$.inventory[*]", - indent: "\t", - newLine: "\n" - ); - var expected = "[\n\t{\n\t\t\"id\":15970,\n\t\t\"gender\":\"Men\",\n\t\t\"season\":[\n\t\t\t\"Fall\",\n\t\t\t\"Winter\"\n\t\t],\n\t\t\"description\":\"Turtle Check Men Navy Blue Shirt\",\n\t\t\"price\":34.95\n\t},\n\t{\n\t\t\"id\":59263,\n\t\t\"gender\":\"Women\",\n\t\t\"season\":[\n\t\t\t\"Fall\",\n\t\t\t\"Winter\",\n\t\t\t\"Spring\",\n\t\t\t\"Summer\"\n\t\t],\n\t\t\"description\":\"Titan Women Silver Watch\",\n\t\t\"price\":129.99\n\t},\n\t{\n\t\t\"id\":46885,\n\t\t\"gender\":\"Boys\",\n\t\t\"season\":[\n\t\t\t\"Fall\"\n\t\t],\n\t\t\"description\":\"Ben 10 Boys Navy Blue Slippers\",\n\t\t\"price\":45.99\n\t}\n]"; + path: "$.inventory[*]", + indent: "\t", + newLine: "\n" + ); + var expected = + "[\n\t{\n\t\t\"id\":15970,\n\t\t\"gender\":\"Men\",\n\t\t\"season\":[\n\t\t\t\"Fall\",\n\t\t\t\"Winter\"\n\t\t],\n\t\t\"description\":\"Turtle Check Men Navy Blue Shirt\",\n\t\t\"price\":34.95\n\t},\n\t{\n\t\t\"id\":59263,\n\t\t\"gender\":\"Women\",\n\t\t\"season\":[\n\t\t\t\"Fall\",\n\t\t\t\"Winter\",\n\t\t\t\"Spring\",\n\t\t\t\"Summer\"\n\t\t],\n\t\t\"description\":\"Titan Women Silver Watch\",\n\t\t\"price\":129.99\n\t},\n\t{\n\t\t\"id\":46885,\n\t\t\"gender\":\"Boys\",\n\t\t\"season\":[\n\t\t\t\"Fall\"\n\t\t],\n\t\t\"description\":\"Ben 10 Boys Navy Blue Slippers\",\n\t\t\"price\":45.99\n\t}\n]"; Assert.Equal(expected, res.ToString()); // TODO: fine nicer way to compare the two JSON strings // Fetch all values of a field within an array: res = json.Get( - key: "warehouse:1", - path: "$.inventory[*].price", - indent: "\t", - newLine: "\n" + key: "warehouse:1", + path: "$.inventory[*].price", + indent: "\t", + newLine: "\n" ); expected = "[\n\t34.95,\n\t129.99,\n\t45.99\n]"; Assert.Equal(expected, res.ToString()); // Fetch all items within an array where a text field matches a given value: res = json.Get( - key: "warehouse:1", - path: "$.inventory[?(@.description==\"Turtle Check Men Navy Blue Shirt\")]", - indent: "\t", - newLine: "\n" + key: "warehouse:1", + path: "$.inventory[?(@.description==\"Turtle Check Men Navy Blue Shirt\")]", + indent: "\t", + newLine: "\n" ); - expected = "[\n\t{\n\t\t\"id\":15970,\n\t\t\"gender\":\"Men\",\n\t\t\"season\":[\n\t\t\t\"Fall\",\n\t\t\t\"Winter\"\n\t\t],\n\t\t\"description\":\"Turtle Check Men Navy Blue Shirt\",\n\t\t\"price\":34.95\n\t}\n]"; + expected = + "[\n\t{\n\t\t\"id\":15970,\n\t\t\"gender\":\"Men\",\n\t\t\"season\":[\n\t\t\t\"Fall\",\n\t\t\t\"Winter\"\n\t\t],\n\t\t\"description\":\"Turtle Check Men Navy Blue Shirt\",\n\t\t\"price\":34.95\n\t}\n]"; Assert.Equal(expected, res.ToString()); // Fetch all items within an array where a numeric field is less than a given value: res = json.Get(key: "warehouse:1", - path: "$.inventory[?(@.price<100)]", - indent: "\t", - newLine: "\n" - ); - expected = "[\n\t{\n\t\t\"id\":15970,\n\t\t\"gender\":\"Men\",\n\t\t\"season\":[\n\t\t\t\"Fall\",\n\t\t\t\"Winter\"\n\t\t],\n\t\t\"description\":\"Turtle Check Men Navy Blue Shirt\",\n\t\t\"price\":34.95\n\t},\n\t{\n\t\t\"id\":46885,\n\t\t\"gender\":\"Boys\",\n\t\t\"season\":[\n\t\t\t\"Fall\"\n\t\t],\n\t\t\"description\":\"Ben 10 Boys Navy Blue Slippers\",\n\t\t\"price\":45.99\n\t}\n]"; + path: "$.inventory[?(@.price<100)]", + indent: "\t", + newLine: "\n" + ); + expected = + "[\n\t{\n\t\t\"id\":15970,\n\t\t\"gender\":\"Men\",\n\t\t\"season\":[\n\t\t\t\"Fall\",\n\t\t\t\"Winter\"\n\t\t],\n\t\t\"description\":\"Turtle Check Men Navy Blue Shirt\",\n\t\t\"price\":34.95\n\t},\n\t{\n\t\t\"id\":46885,\n\t\t\"gender\":\"Boys\",\n\t\t\"season\":[\n\t\t\t\"Fall\"\n\t\t],\n\t\t\"description\":\"Ben 10 Boys Navy Blue Slippers\",\n\t\t\"price\":45.99\n\t}\n]"; Assert.Equal(expected, res.ToString()); // Fetch all items within an array where a numeric field is less than a given value: res = json.Get(key: "warehouse:1", - path: "$.inventory[?(@.id>=20000)]", - indent: "\t", - newLine: "\n" - ); - expected = "[\n\t{\n\t\t\"id\":59263,\n\t\t\"gender\":\"Women\",\n\t\t\"season\":[\n\t\t\t\"Fall\",\n\t\t\t\"Winter\",\n\t\t\t\"Spring\",\n\t\t\t\"Summer\"\n\t\t],\n\t\t\"description\":\"Titan Women Silver Watch\",\n\t\t\"price\":129.99\n\t},\n\t{\n\t\t\"id\":46885,\n\t\t\"gender\":\"Boys\",\n\t\t\"season\":[\n\t\t\t\"Fall\"\n\t\t],\n\t\t\"description\":\"Ben 10 Boys Navy Blue Slippers\",\n\t\t\"price\":45.99\n\t}\n]"; + path: "$.inventory[?(@.id>=20000)]", + indent: "\t", + newLine: "\n" + ); + expected = + "[\n\t{\n\t\t\"id\":59263,\n\t\t\"gender\":\"Women\",\n\t\t\"season\":[\n\t\t\t\"Fall\",\n\t\t\t\"Winter\",\n\t\t\t\"Spring\",\n\t\t\t\"Summer\"\n\t\t],\n\t\t\"description\":\"Titan Women Silver Watch\",\n\t\t\"price\":129.99\n\t},\n\t{\n\t\t\"id\":46885,\n\t\t\"gender\":\"Boys\",\n\t\t\"season\":[\n\t\t\t\"Fall\"\n\t\t],\n\t\t\"description\":\"Ben 10 Boys Navy Blue Slippers\",\n\t\t\"price\":45.99\n\t}\n]"; Assert.Equal(expected, res.ToString()); // Fetch all items within an array where a numeric field is less than a given value: res = json.Get(key: "warehouse:1", - path: "$.inventory[?(@.gender==\"Men\"&&@.price>20)]", - indent: "\t", - newLine: "\n" - ); - expected = "[\n\t{\n\t\t\"id\":15970,\n\t\t\"gender\":\"Men\",\n\t\t\"season\":[\n\t\t\t\"Fall\",\n\t\t\t\"Winter\"\n\t\t],\n\t\t\"description\":\"Turtle Check Men Navy Blue Shirt\",\n\t\t\"price\":34.95\n\t}\n]"; + path: "$.inventory[?(@.gender==\"Men\"&&@.price>20)]", + indent: "\t", + newLine: "\n" + ); + expected = + "[\n\t{\n\t\t\"id\":15970,\n\t\t\"gender\":\"Men\",\n\t\t\"season\":[\n\t\t\t\"Fall\",\n\t\t\t\"Winter\"\n\t\t],\n\t\t\"description\":\"Turtle Check Men Navy Blue Shirt\",\n\t\t\"price\":34.95\n\t}\n]"; Assert.Equal(expected, res.ToString()); // Fetch all items within an array that meet at least one relational operation. // In this case, return only the ids of those items: res = json.Get(key: "warehouse:1", - path: "$.inventory[?(@.price<100||@.gender==\"Women\")].id", - indent: "\t", - newLine: "\n" - ); + path: "$.inventory[?(@.price<100||@.gender==\"Women\")].id", + indent: "\t", + newLine: "\n" + ); expected = "[\n\t15970,\n\t59263,\n\t46885\n]"; Assert.Equal(expected, res.ToString()); // Fetch all items within an array that match a given regex pattern. res = json.Get(key: "warehouse:1", - path: "$.inventory[?(@.description =~ \"Blue\")]", - indent: "\t", - newLine: "\n" - ); - expected = "[\n\t{\n\t\t\"id\":15970,\n\t\t\"gender\":\"Men\",\n\t\t\"season\":[\n\t\t\t\"Fall\",\n\t\t\t\"Winter\"\n\t\t],\n\t\t\"description\":\"Turtle Check Men Navy Blue Shirt\",\n\t\t\"price\":34.95\n\t},\n\t{\n\t\t\"id\":46885,\n\t\t\"gender\":\"Boys\",\n\t\t\"season\":[\n\t\t\t\"Fall\"\n\t\t],\n\t\t\"description\":\"Ben 10 Boys Navy Blue Slippers\",\n\t\t\"price\":45.99\n\t}\n]"; + path: "$.inventory[?(@.description =~ \"Blue\")]", + indent: "\t", + newLine: "\n" + ); + expected = + "[\n\t{\n\t\t\"id\":15970,\n\t\t\"gender\":\"Men\",\n\t\t\"season\":[\n\t\t\t\"Fall\",\n\t\t\t\"Winter\"\n\t\t],\n\t\t\"description\":\"Turtle Check Men Navy Blue Shirt\",\n\t\t\"price\":34.95\n\t},\n\t{\n\t\t\"id\":46885,\n\t\t\"gender\":\"Boys\",\n\t\t\"season\":[\n\t\t\t\"Fall\"\n\t\t],\n\t\t\"description\":\"Ben 10 Boys Navy Blue Slippers\",\n\t\t\"price\":45.99\n\t}\n]"; Assert.Equal(expected, res.ToString()); // Fetch all items within an array where a field contains a term, case insensitive res = json.Get(key: "warehouse:1", - path: "$.inventory[?(@.description =~ \"(?i)watch\")]", - indent: "\t", - newLine: "\n" - ); - expected = "[\n\t{\n\t\t\"id\":59263,\n\t\t\"gender\":\"Women\",\n\t\t\"season\":[\n\t\t\t\"Fall\",\n\t\t\t\"Winter\",\n\t\t\t\"Spring\",\n\t\t\t\"Summer\"\n\t\t],\n\t\t\"description\":\"Titan Women Silver Watch\",\n\t\t\"price\":129.99\n\t}\n]"; + path: "$.inventory[?(@.description =~ \"(?i)watch\")]", + indent: "\t", + newLine: "\n" + ); + expected = + "[\n\t{\n\t\t\"id\":59263,\n\t\t\"gender\":\"Women\",\n\t\t\"season\":[\n\t\t\t\"Fall\",\n\t\t\t\"Winter\",\n\t\t\t\"Spring\",\n\t\t\t\"Summer\"\n\t\t],\n\t\t\"description\":\"Titan Women Silver Watch\",\n\t\t\"price\":129.99\n\t}\n]"; Assert.Equal(expected, res.ToString()); // Fetch all items within an array where a field begins with a given expression res = json.Get(key: "warehouse:1", - path: "$.inventory[?(@.description =~ \"^T\")]", - indent: "\t", - newLine: "\n" - ); - expected = "[\n\t{\n\t\t\"id\":15970,\n\t\t\"gender\":\"Men\",\n\t\t\"season\":[\n\t\t\t\"Fall\",\n\t\t\t\"Winter\"\n\t\t],\n\t\t\"description\":\"Turtle Check Men Navy Blue Shirt\",\n\t\t\"price\":34.95\n\t},\n\t{\n\t\t\"id\":59263,\n\t\t\"gender\":\"Women\",\n\t\t\"season\":[\n\t\t\t\"Fall\",\n\t\t\t\"Winter\",\n\t\t\t\"Spring\",\n\t\t\t\"Summer\"\n\t\t],\n\t\t\"description\":\"Titan Women Silver Watch\",\n\t\t\"price\":129.99\n\t}\n]"; + path: "$.inventory[?(@.description =~ \"^T\")]", + indent: "\t", + newLine: "\n" + ); + expected = + "[\n\t{\n\t\t\"id\":15970,\n\t\t\"gender\":\"Men\",\n\t\t\"season\":[\n\t\t\t\"Fall\",\n\t\t\t\"Winter\"\n\t\t],\n\t\t\"description\":\"Turtle Check Men Navy Blue Shirt\",\n\t\t\"price\":34.95\n\t},\n\t{\n\t\t\"id\":59263,\n\t\t\"gender\":\"Women\",\n\t\t\"season\":[\n\t\t\t\"Fall\",\n\t\t\t\"Winter\",\n\t\t\t\"Spring\",\n\t\t\t\"Summer\"\n\t\t],\n\t\t\"description\":\"Titan Women Silver Watch\",\n\t\t\"price\":129.99\n\t}\n]"; Assert.Equal(expected, res.ToString()); } @@ -996,16 +1002,25 @@ public void BasicQueryOperationsTest() coords = "-104.991531, 39.742043" }); - try { ft.DropIndex("idx1"); } catch { }; + try + { + ft.DropIndex("idx1"); + } + catch + { + // ignored + } + + ; ft.Create("idx1", new FTCreateParams().On(IndexDataType.JSON) - .Prefix("product:"), - new Schema().AddNumericField(new FieldName("$.id", "id")) - .AddTagField(new FieldName("$.gender", "gender")) - .AddTagField(new FieldName("$.season.*", "season")) - .AddTextField(new FieldName("$.description", "description")) - .AddNumericField(new FieldName("$.price", "price")) - .AddTextField(new FieldName("$.city", "city")) - .AddGeoField(new FieldName("$.coords", "coords"))); + .Prefix("product:"), + new Schema().AddNumericField(new FieldName("$.id", "id")) + .AddTagField(new FieldName("$.gender", "gender")) + .AddTagField(new FieldName("$.season.*", "season")) + .AddTextField(new FieldName("$.description", "description")) + .AddNumericField(new FieldName("$.price", "price")) + .AddTextField(new FieldName("$.city", "city")) + .AddGeoField(new FieldName("$.coords", "coords"))); // sleep: Thread.Sleep(2000); @@ -1015,7 +1030,7 @@ public void BasicQueryOperationsTest() Assert.NotNull(res); // Assert.Equal(3, res!.Count); - var expectedList = new List() + var expectedList = new List { "{\"id\":59263,\"gender\":\"Women\",\"season\":[\"Fall\",\"Winter\",\"Spring\",\"Summer\"],\"description\":\"Titan Women Silver Watch\",\"price\":129.99,\"city\":\"Dallas\",\"coords\":\"-96.808891, 32.779167\"}", "{\"id\":15970,\"gender\":\"Men\",\"season\":[\"Fall\",\"Winter\"],\"description\":\"Turtle Check Men Navy Blue Shirt\",\"price\":34.95,\"city\":\"Boston\",\"coords\":\"-71.057083, 42.361145\"}", @@ -1025,93 +1040,97 @@ public void BasicQueryOperationsTest() SortAndCompare(expectedList, res); - // Find all documents with a given word in a text field: res = ft.Search("idx1", new Query("@description:Slippers")).ToJson(); - var expected = "{\"id\":46885,\"gender\":\"Boys\",\"season\":[\"Fall\"],\"description\":\"Ben 10 Boys Navy Blue Slippers\",\"price\":45.99,\"city\":\"Denver\",\"coords\":\"-104.991531, 39.742043\"}"; + var expected = + "{\"id\":46885,\"gender\":\"Boys\",\"season\":[\"Fall\"],\"description\":\"Ben 10 Boys Navy Blue Slippers\",\"price\":45.99,\"city\":\"Denver\",\"coords\":\"-104.991531, 39.742043\"}"; Assert.Equal(expected, res![0].ToString()); // Find all documents with a given phrase in a text field: res = ft.Search("idx1", new Query("@description:(\"Blue Shirt\")")).ToJson(); - expected = "{\"id\":15970,\"gender\":\"Men\",\"season\":[\"Fall\",\"Winter\"],\"description\":\"Turtle Check Men Navy Blue Shirt\",\"price\":34.95,\"city\":\"Boston\",\"coords\":\"-71.057083, 42.361145\"}"; - Assert.Equal(expected, res![0].ToString()); + expected = + "{\"id\":15970,\"gender\":\"Men\",\"season\":[\"Fall\",\"Winter\"],\"description\":\"Turtle Check Men Navy Blue Shirt\",\"price\":34.95,\"city\":\"Boston\",\"coords\":\"-71.057083, 42.361145\"}"; + Assert.Equal(expected, res![0]); // Find all documents with a numeric field in a given range: res = ft.Search("idx1", new Query("@price:[40,130]")).ToJson(); - expectedList = new() - { + expectedList = + [ "{\"id\":59263,\"gender\":\"Women\",\"season\":[\"Fall\",\"Winter\",\"Spring\",\"Summer\"],\"description\":\"Titan Women Silver Watch\",\"price\":129.99,\"city\":\"Dallas\",\"coords\":\"-96.808891, 32.779167\"}", "{\"id\":46885,\"gender\":\"Boys\",\"season\":[\"Fall\"],\"description\":\"Ben 10 Boys Navy Blue Slippers\",\"price\":45.99,\"city\":\"Denver\",\"coords\":\"-104.991531, 39.742043\"}" - }; + ]; SortAndCompare(expectedList, res); - // Find all documents that contain a given value in an array field (tag): res = ft.Search("idx1", new Query("@season:{Spring}")).ToJson(); - expected = "{\"id\":59263,\"gender\":\"Women\",\"season\":[\"Fall\",\"Winter\",\"Spring\",\"Summer\"],\"description\":\"Titan Women Silver Watch\",\"price\":129.99,\"city\":\"Dallas\",\"coords\":\"-96.808891, 32.779167\"}"; - Assert.Equal(expected, res[0].ToString()); + expected = + "{\"id\":59263,\"gender\":\"Women\",\"season\":[\"Fall\",\"Winter\",\"Spring\",\"Summer\"],\"description\":\"Titan Women Silver Watch\",\"price\":129.99,\"city\":\"Dallas\",\"coords\":\"-96.808891, 32.779167\"}"; + Assert.Equal(expected, res[0]); // Find all documents contain both a numeric field in a range and a word in a text field: res = ft.Search("idx1", new Query("@price:[40, 100] @description:Blue")).ToJson(); - expected = "{\"id\":46885,\"gender\":\"Boys\",\"season\":[\"Fall\"],\"description\":\"Ben 10 Boys Navy Blue Slippers\",\"price\":45.99,\"city\":\"Denver\",\"coords\":\"-104.991531, 39.742043\"}"; - Assert.Equal(expected, res[0].ToString()); + expected = + "{\"id\":46885,\"gender\":\"Boys\",\"season\":[\"Fall\"],\"description\":\"Ben 10 Boys Navy Blue Slippers\",\"price\":45.99,\"city\":\"Denver\",\"coords\":\"-104.991531, 39.742043\"}"; + Assert.Equal(expected, res[0]); // Find all documents that either match tag value or text value: res = ft.Search("idx1", new Query("(@gender:{Women})|(@city:Boston)")).ToJson(); - expectedList = new() - { + expectedList = + [ "{\"id\":59263,\"gender\":\"Women\",\"season\":[\"Fall\",\"Winter\",\"Spring\",\"Summer\"],\"description\":\"Titan Women Silver Watch\",\"price\":129.99,\"city\":\"Dallas\",\"coords\":\"-96.808891, 32.779167\"}", "{\"id\":15970,\"gender\":\"Men\",\"season\":[\"Fall\",\"Winter\"],\"description\":\"Turtle Check Men Navy Blue Shirt\",\"price\":34.95,\"city\":\"Boston\",\"coords\":\"-71.057083, 42.361145\"}" - }; + ]; SortAndCompare(expectedList, res); // Find all documents that do not contain a given word in a text field: res = ft.Search("idx1", new Query("-(@description:Shirt)")).ToJson(); - expectedList = new() - { + expectedList = + [ "{\"id\":59263,\"gender\":\"Women\",\"season\":[\"Fall\",\"Winter\",\"Spring\",\"Summer\"],\"description\":\"Titan Women Silver Watch\",\"price\":129.99,\"city\":\"Dallas\",\"coords\":\"-96.808891, 32.779167\"}", "{\"id\":46885,\"gender\":\"Boys\",\"season\":[\"Fall\"],\"description\":\"Ben 10 Boys Navy Blue Slippers\",\"price\":45.99,\"city\":\"Denver\",\"coords\":\"-104.991531, 39.742043\"}" - }; + ]; SortAndCompare(expectedList, res); // Find all documents that have a word that begins with a given prefix value: res = ft.Search("idx1", new Query("@description:Nav*")).ToJson(); - expectedList = new() - { + expectedList = + [ "{\"id\":15970,\"gender\":\"Men\",\"season\":[\"Fall\",\"Winter\"],\"description\":\"Turtle Check Men Navy Blue Shirt\",\"price\":34.95,\"city\":\"Boston\",\"coords\":\"-71.057083, 42.361145\"}", "{\"id\":46885,\"gender\":\"Boys\",\"season\":[\"Fall\"],\"description\":\"Ben 10 Boys Navy Blue Slippers\",\"price\":45.99,\"city\":\"Denver\",\"coords\":\"-104.991531, 39.742043\"}" - }; + ]; SortAndCompare(expectedList, res); // Find all documents that contain a word that ends with a given suffix value: res = ft.Search("idx1", new Query("@description:*Watch")).ToJson(); - expected = "{\"id\":59263,\"gender\":\"Women\",\"season\":[\"Fall\",\"Winter\",\"Spring\",\"Summer\"],\"description\":\"Titan Women Silver Watch\",\"price\":129.99,\"city\":\"Dallas\",\"coords\":\"-96.808891, 32.779167\"}"; + expected = + "{\"id\":59263,\"gender\":\"Women\",\"season\":[\"Fall\",\"Winter\",\"Spring\",\"Summer\"],\"description\":\"Titan Women Silver Watch\",\"price\":129.99,\"city\":\"Dallas\",\"coords\":\"-96.808891, 32.779167\"}"; Assert.Equal(expected, res[0].ToString()); // Find all documents that contain a word that is within 1 Levenshtein distance of a given word: res = ft.Search("idx1", new Query("@description:%wavy%")).ToJson(); - expectedList = new() - { + expectedList = + [ "{\"id\":15970,\"gender\":\"Men\",\"season\":[\"Fall\",\"Winter\"],\"description\":\"Turtle Check Men Navy Blue Shirt\",\"price\":34.95,\"city\":\"Boston\",\"coords\":\"-71.057083, 42.361145\"}", "{\"id\":46885,\"gender\":\"Boys\",\"season\":[\"Fall\"],\"description\":\"Ben 10 Boys Navy Blue Slippers\",\"price\":45.99,\"city\":\"Denver\",\"coords\":\"-104.991531, 39.742043\"}" - }; + ]; SortAndCompare(expectedList, res); // Find all documents that have geographic coordinates within a given range of a given coordinate. // Colorado Springs coords(long, lat) = -104.800644, 38.846127: res = ft.Search("idx1", new Query("@coords:[-104.800644 38.846127 100 mi]")).ToJson(); - expected = "{\"id\":46885,\"gender\":\"Boys\",\"season\":[\"Fall\"],\"description\":\"Ben 10 Boys Navy Blue Slippers\",\"price\":45.99,\"city\":\"Denver\",\"coords\":\"-104.991531, 39.742043\"}"; + expected = + "{\"id\":46885,\"gender\":\"Boys\",\"season\":[\"Fall\"],\"description\":\"Ben 10 Boys Navy Blue Slippers\",\"price\":45.99,\"city\":\"Denver\",\"coords\":\"-104.991531, 39.742043\"}"; Assert.Equal(expected, res[0].ToString()); } @@ -1149,18 +1168,26 @@ public void AdvancedQueryOperationsTest() }); // Index creation: - try { ft.DropIndex("vss_idx"); } catch { }; + try + { + ft.DropIndex("vss_idx"); + } + catch + { + } + + ; Assert.True(ft.Create("vss_idx", new FTCreateParams().On(IndexDataType.HASH).Prefix("vec:"), new Schema() - .AddTagField("tag") - .AddVectorField("vector", VectorField.VectorAlgo.FLAT, - new Dictionary() - { - ["TYPE"] = "FLOAT32", - ["DIM"] = "4", - ["DISTANCE_METRIC"] = "L2" - } - ))); + .AddTagField("tag") + .AddVectorField("vector", VectorField.VectorAlgo.FLAT, + new Dictionary() + { + ["TYPE"] = "FLOAT32", + ["DIM"] = "4", + ["DISTANCE_METRIC"] = "L2" + } + ))); // Sleep: Thread.Sleep(2000); @@ -1168,11 +1195,11 @@ public void AdvancedQueryOperationsTest() // Search: float[] vec = new[] { 2f, 3f, 3f, 3f }; var res = ft.Search("vss_idx", - new Query("*=>[KNN 2 @vector $query_vec]") - .AddParam("query_vec", vec.SelectMany(BitConverter.GetBytes).ToArray()) - .SetSortBy("__vector_score") - .Dialect(2)); - HashSet resSet = new HashSet(); + new Query("*=>[KNN 2 @vector $query_vec]") + .AddParam("query_vec", vec.SelectMany(BitConverter.GetBytes).ToArray()) + .SetSortBy("__vector_score") + .Dialect(2)); + HashSet resSet = []; foreach (var doc in res.Documents) { foreach (var item in doc.GetProperties()) @@ -1184,20 +1211,20 @@ public void AdvancedQueryOperationsTest() } } - HashSet expectedResSet = new HashSet() - { + HashSet expectedResSet = + [ "id: vec:3, score: 1", - "id: vec:2, score: 3", - }; + "id: vec:2, score: 3" + ]; Assert.Equal(expectedResSet, resSet); // hybrid query - search only documents with tag A: res = ft.Search("vss_idx", - new Query("@tag:{A}=>[KNN 2 @vector $query_vec]") - .AddParam("query_vec", vec.SelectMany(BitConverter.GetBytes).ToArray()) - .SetSortBy("__vector_score") - .Dialect(2)); + new Query("@tag:{A}=>[KNN 2 @vector $query_vec]") + .AddParam("query_vec", vec.SelectMany(BitConverter.GetBytes).ToArray()) + .SetSortBy("__vector_score") + .Dialect(2)); resSet.Clear(); foreach (var doc in res.Documents) @@ -1211,11 +1238,11 @@ public void AdvancedQueryOperationsTest() } } - expectedResSet = new HashSet() - { + expectedResSet = + [ "id: vec:2, score: 3", - "id: vec:4, score: 7", - }; + "id: vec:4, score: 7" + ]; //Advanced Search Queries: // data load: @@ -1223,25 +1250,29 @@ public void AdvancedQueryOperationsTest() { city = "Boston", location = "-71.057083, 42.361145", - inventory = new[] { - new { + inventory = new[] + { + new + { id = 15970, gender = "Men", - season = new[] {"Fall", "Winter"}, + season = new[] { "Fall", "Winter" }, description = "Turtle Check Men Navy Blue Shirt", price = 34.95 }, - new { + new + { id = 59263, gender = "Women", - season = new[] {"Fall", "Winter", "Spring", "Summer"}, + season = new[] { "Fall", "Winter", "Spring", "Summer" }, description = "Titan Women Silver Watch", price = 129.99 }, - new { + new + { id = 46885, gender = "Boys", - season = new[] {"Fall"}, + season = new[] { "Fall" }, description = "Ben 10 Boys Navy Blue Slippers", price = 45.99 } @@ -1251,25 +1282,29 @@ public void AdvancedQueryOperationsTest() { city = "Dallas", location = "-96.808891, 32.779167", - inventory = new[] { - new { + inventory = new[] + { + new + { id = 51919, gender = "Women", - season = new[] {"Summer"}, + season = new[] { "Summer" }, description = "Nyk Black Horado Handbag", price = 52.49 }, - new { + new + { id = 4602, gender = "Unisex", - season = new[] {"Fall", "Winter"}, + season = new[] { "Fall", "Winter" }, description = "Wildcraft Red Trailblazer Backpack", price = 50.99 }, - new { + new + { id = 37561, gender = "Girls", - season = new[] {"Spring", "Summer"}, + season = new[] { "Spring", "Summer" }, description = "Madagascar3 Infant Pink Snapsuit Romper", price = 23.95 } @@ -1277,29 +1312,39 @@ public void AdvancedQueryOperationsTest() }); // Index creation: - try { ft.DropIndex("wh_idx"); } catch { }; + try + { + ft.DropIndex("wh_idx"); + } + catch + { + // ignored + } + + ; Assert.True(ft.Create("wh_idx", new FTCreateParams() - .On(IndexDataType.JSON) - .Prefix("warehouse:"), - new Schema().AddTextField(new FieldName("$.city", "city")))); + .On(IndexDataType.JSON) + .Prefix("warehouse:"), + new Schema().AddTextField(new FieldName("$.city", "city")))); // Sleep: Thread.Sleep(2000); // Find all inventory ids from all the Boston warehouse that have a price > $50: res = ft.Search("wh_idx", - new Query("@city:Boston") - .ReturnFields(new FieldName("$.inventory[?(@.price>50)].id", "result")) - .Dialect(3)); + new Query("@city:Boston") + .ReturnFields(new FieldName("$.inventory[?(@.price>50)].id", "result")) + .Dialect(3)); Assert.Equal("[59263]", res.Documents[0]["result"].ToString()); // Find all inventory items in Dallas that are for Women or Girls: res = ft.Search("wh_idx", - new Query("@city:(Dallas)") - .ReturnFields(new FieldName("$.inventory[?(@.gender==\"Women\" || @.gender==\"Girls\")]", "result")) - .Dialect(3)); - var expected = "[{\"id\":51919,\"gender\":\"Women\",\"season\":[\"Summer\"],\"description\":\"Nyk Black Horado Handbag\",\"price\":52.49},{\"id\":37561,\"gender\":\"Girls\",\"season\":[\"Spring\",\"Summer\"],\"description\":\"Madagascar3 Infant Pink Snapsuit Romper\",\"price\":23.95}]"; + new Query("@city:(Dallas)") + .ReturnFields(new FieldName("$.inventory[?(@.gender==\"Women\" || @.gender==\"Girls\")]", "result")) + .Dialect(3)); + var expected = + "[{\"id\":51919,\"gender\":\"Women\",\"season\":[\"Summer\"],\"description\":\"Nyk Black Horado Handbag\",\"price\":52.49},{\"id\":37561,\"gender\":\"Girls\",\"season\":[\"Spring\",\"Summer\"],\"description\":\"Madagascar3 Infant Pink Snapsuit Romper\",\"price\":23.95}]"; Assert.Equal(expected, res.Documents[0]["result"].ToString()); // Aggregation @@ -1324,17 +1369,17 @@ public void AdvancedQueryOperationsTest() }); json.Set("book:4", "$", new { - title = "Superintelligence: Path, Dangers, Stategies", + title = "Superintelligence: Path, Dangers, Strategies", year = 2016, price = 14.36 }); Assert.True(ft.Create("book_idx", new FTCreateParams() - .On(IndexDataType.JSON) - .Prefix("book:"), - new Schema().AddTextField(new FieldName("$.title", "title")) - .AddNumericField(new FieldName("$.year", "year")) - .AddNumericField(new FieldName("$.price", "price")))); + .On(IndexDataType.JSON) + .Prefix("book:"), + new Schema().AddTextField(new FieldName("$.title", "title")) + .AddNumericField(new FieldName("$.year", "year")) + .AddNumericField(new FieldName("$.price", "price")))); // sleep: Thread.Sleep(2000); @@ -1348,6 +1393,7 @@ public void AdvancedQueryOperationsTest() var row = result.GetRow(i); resSet.Add($"{row["year"]}: {row["count"]}"); } + expectedResSet.Clear(); expectedResSet.Add("2016: 1"); expectedResSet.Add("2020: 2"); @@ -1365,6 +1411,7 @@ public void AdvancedQueryOperationsTest() var row = result.GetRow(i); resSet.Add($"{row["year"]}: {row["sum"]}"); } + expectedResSet.Clear(); expectedResSet.Add("2016: 14.36"); expectedResSet.Add("2020: 56.98"); @@ -1385,4 +1432,4 @@ private static void SortAndCompare(List expectedList, List res) Assert.Equal(expectedList[i], res[i].ToString()); } } -} +} \ No newline at end of file From a65682155c3f218ba48ebe4b863f4c3a60a72ea2 Mon Sep 17 00:00:00 2001 From: nimanikoo Date: Mon, 29 Jan 2024 22:18:32 +0330 Subject: [PATCH 30/57] Use Linq Expression in JsonCommandBuilder.cs for reduce the amount of code in a file and make the code easier to read, and allow different data sources to have similar query expression --- src/NRedisStack/Json/JsonCommandBuilder.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/NRedisStack/Json/JsonCommandBuilder.cs b/src/NRedisStack/Json/JsonCommandBuilder.cs index aada5790..07a62368 100644 --- a/src/NRedisStack/Json/JsonCommandBuilder.cs +++ b/src/NRedisStack/Json/JsonCommandBuilder.cs @@ -207,11 +207,7 @@ public static SerializedCommand Get(RedisKey key, string path = "$") public static SerializedCommand MGet(RedisKey[] keys, string path) { - var args = new List(); - foreach (var key in keys) - { - args.Add(key); - } + var args = keys.Cast().ToList(); args.Add(path); return new SerializedCommand(JSON.MGET, args); From b9e11974b304193251c48a19963a4ab3ddf71a98 Mon Sep 17 00:00:00 2001 From: nimanikoo Date: Mon, 29 Jan 2024 22:19:21 +0330 Subject: [PATCH 31/57] RollBack to original naming for NumIncrbyAsync --- src/NRedisStack/Json/JsonCommandsAsync.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NRedisStack/Json/JsonCommandsAsync.cs b/src/NRedisStack/Json/JsonCommandsAsync.cs index 1d1eb1e7..307556c2 100644 --- a/src/NRedisStack/Json/JsonCommandsAsync.cs +++ b/src/NRedisStack/Json/JsonCommandsAsync.cs @@ -86,7 +86,7 @@ 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) + 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()!)!; From bcdda60cf48caec11c0b9aa9e582935014b0c948 Mon Sep 17 00:00:00 2001 From: nimanikoo Date: Mon, 29 Jan 2024 22:20:08 +0330 Subject: [PATCH 32/57] RollBack to original naming --- 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 7fc010e8..10f1525d 100644 --- a/tests/NRedisStack.Tests/Json/JsonTests.cs +++ b/tests/NRedisStack.Tests/Json/JsonTests.cs @@ -866,7 +866,7 @@ public async Task NumIncrbyAsync() var keys = CreateKeyNames(1); var key = keys[0]; await commands.SetAsync(key, "$", new { age = 33, a = new { age = 34 }, b = new { age = "cat" } }); - var result = await commands.NumIncrByAsync(key, "$..age", 2); + var result = await commands.NumIncrbyAsync(key, "$..age", 2); Assert.Equal(35, result[0]); Assert.Equal(36, result[1]); Assert.Null(result[2]); From b6ca7fb97bf9292df7e19de8ee352c93811f9799 Mon Sep 17 00:00:00 2001 From: nimanikoo Date: Mon, 29 Jan 2024 22:26:51 +0330 Subject: [PATCH 33/57] Refactored C# code using collection expressions and the :? operator for improved clarity and efficiency. --- src/NRedisStack/Json/JsonCommands.cs | 61 ++++++++++------------------ 1 file changed, 21 insertions(+), 40 deletions(-) diff --git a/src/NRedisStack/Json/JsonCommands.cs b/src/NRedisStack/Json/JsonCommands.cs index 033ced97..c577e2f1 100644 --- a/src/NRedisStack/Json/JsonCommands.cs +++ b/src/NRedisStack/Json/JsonCommands.cs @@ -21,7 +21,8 @@ public RedisResult[] Resp(RedisKey key, string? path = null) } /// - public bool Set(RedisKey key, RedisValue path, object obj, When when = When.Always, JsonSerializerOptions? serializerOptions = default) + public bool Set(RedisKey key, RedisValue path, object obj, When when = When.Always, + JsonSerializerOptions? serializerOptions = default) { string json = JsonSerializer.Serialize(obj, options: serializerOptions); return Set(key, path, json, when); @@ -79,10 +80,7 @@ public int SetFromDirectory(RedisValue path, string filesPath, When when = When. } } - foreach (var dirPath in Directory.EnumerateDirectories(filesPath)) - { - inserted += SetFromDirectory(path, dirPath, when); - } + inserted += Directory.EnumerateDirectories(filesPath).Sum(dirPath => SetFromDirectory(path, dirPath, when)); return inserted; } @@ -109,12 +107,9 @@ public int SetFromDirectory(RedisValue path, string filesPath, When when = When. return Array.Empty(); } - if (result.Type == ResultType.Integer) - { - return new bool?[] { (long)result == 1 }; - } - - return ((RedisResult[])result!).Select(x => (bool?)((long)x == 1)).ToArray(); + return result.Type == ResultType.Integer + ? [(long)result == 1] + : ((RedisResult[])result!).Select(x => (bool?)((long)x == 1)).ToArray(); } /// @@ -122,18 +117,14 @@ public JsonType[] Type(RedisKey key, string? path = null) { RedisResult result = db.Execute(JsonCommandBuilder.Type(key, path)); - if (result.Type == ResultType.MultiBulk) + return result.Type switch { - return ((RedisResult[])result!).Select(x => (JsonType)Enum.Parse(typeof(JsonType), x.ToString()!.ToUpper())).ToArray(); - } - - if (result.Type == ResultType.BulkString) - { - return new[] { (JsonType)Enum.Parse(typeof(JsonType), result.ToString()!.ToUpper()) }; - } - - return Array.Empty(); - + ResultType.MultiBulk => ((RedisResult[])result!) + .Select(x => (JsonType)Enum.Parse(typeof(JsonType), x.ToString()!.ToUpper())) + .ToArray(), + ResultType.BulkString => [(JsonType)Enum.Parse(typeof(JsonType), result.ToString()!.ToUpper())], + _ => Array.Empty() + }; } public long DebugMemory(string key, string? path = null) @@ -175,12 +166,7 @@ public RedisResult[] ArrPop(RedisKey key, string? path = null, long? index = nul return (RedisResult[])result!; } - if (result.Type == ResultType.BulkString) - { - return new[] { result }; - } - - return Array.Empty(); + return result.Type == ResultType.BulkString ? [result] : Array.Empty(); } /// @@ -203,13 +189,15 @@ public long Del(RedisKey key, string? path = null) public long Forget(RedisKey key, string? path = null) => Del(key, path); /// - public RedisResult Get(RedisKey key, RedisValue? indent = null, RedisValue? newLine = null, RedisValue? space = null, RedisValue? 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)); } /// - public RedisResult Get(RedisKey key, string[] paths, RedisValue? indent = null, RedisValue? newLine = null, RedisValue? space = null) + 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)); } @@ -218,16 +206,9 @@ public RedisResult Get(RedisKey key, string[] paths, RedisValue? indent = null, public T? Get(RedisKey key, string path = "$", JsonSerializerOptions? serializerOptions = default) { var res = db.Execute(JsonCommandBuilder.Get(key, path)); - if (res.Type == ResultType.BulkString && !res.IsNull) - { - var arr = JsonSerializer.Deserialize(res.ToString()!); - if (arr?.Count > 0) - { - return JsonSerializer.Deserialize(JsonSerializer.Serialize(arr[0]), serializerOptions); - } - } - - return default; + if (res.Type != ResultType.BulkString || res.IsNull) return default; + var arr = JsonSerializer.Deserialize(res.ToString()!); + return arr?.Count > 0 ? JsonSerializer.Deserialize(JsonSerializer.Serialize(arr[0]), serializerOptions) : default; } /// From f478df339d7b45610d8e06e6350e71854bf7788d Mon Sep 17 00:00:00 2001 From: nimanikoo Date: Mon, 29 Jan 2024 22:38:37 +0330 Subject: [PATCH 34/57] Used Inverted If technique and removed redundant else for code optimization and improved clarity. --- .../Search/DataTypes/InfoResult.cs | 177 ++++++++---------- 1 file changed, 73 insertions(+), 104 deletions(-) diff --git a/src/NRedisStack/Search/DataTypes/InfoResult.cs b/src/NRedisStack/Search/DataTypes/InfoResult.cs index f245b5d8..ac39a3a8 100644 --- a/src/NRedisStack/Search/DataTypes/InfoResult.cs +++ b/src/NRedisStack/Search/DataTypes/InfoResult.cs @@ -1,147 +1,116 @@ using StackExchange.Redis; -namespace NRedisStack.Search.DataTypes -{ - public class InfoResult - { - private readonly Dictionary _all = new Dictionary(); - - public string IndexName => GetString("index_name")!; - public Dictionary IndexOption => GetRedisResultDictionary("index_options")!; - - public Dictionary[] Attributes => GetRedisResultDictionaryArray("attributes")!; - +namespace NRedisStack.Search.DataTypes; - public long NumDocs => GetLong("num_docs"); - - public string MaxDocId => GetString("max_doc_id")!; - - public long NumTerms => GetLong("num_terms"); - - public long NumRecords => GetLong("num_records"); +public class InfoResult +{ + private readonly Dictionary _all = new(); + public string IndexName => GetString("index_name")!; + public Dictionary IndexOption => GetRedisResultDictionary("index_options")!; + public Dictionary[] Attributes => GetRedisResultDictionaryArray("attributes")!; + public long NumDocs => GetLong("num_docs"); + public string MaxDocId => GetString("max_doc_id")!; + public long NumTerms => GetLong("num_terms"); + public long NumRecords => GetLong("num_records"); + public double InvertedSzMebibytes => GetDouble("inverted_sz_mb"); + public double VectorIndexSzMebibytes => GetDouble("vector_index_sz_mb"); // TODO: check if double or long - public double InvertedSzMebibytes => GetDouble("inverted_sz_mb"); + public double TotalInvertedIndexBlocks => GetDouble("total_inverted_index_blocks"); - public double VectorIndexSzMebibytes => GetDouble("vector_index_sz_mb"); // TODO: check if double or long + // public double InvertedCapOvh => GetDouble("inverted_cap_ovh"); + public double OffsetVectorsSzMebibytes => GetDouble("offset_vectors_sz_mb"); + public double DocTableSizeMebibytes => GetDouble("doc_table_size_mb"); + public double SortableValueSizeMebibytes => GetDouble("sortable_value_size_mb"); - public double TotalInvertedIndexBlocks => GetDouble("total_inverted_index_blocks"); + public double KeyTableSizeMebibytes => GetDouble("key_table_size_mb"); - // public double InvertedCapOvh => GetDouble("inverted_cap_ovh"); + // public double SkipIndexSizeMebibytes => GetDouble("skip_index_size_mb"); - public double OffsetVectorsSzMebibytes => GetDouble("offset_vectors_sz_mb"); + // public double ScoreIndexSizeMebibytes => GetDouble("score_index_size_mb"); - public double DocTableSizeMebibytes => GetDouble("doc_table_size_mb"); + public double RecordsPerDocAvg => GetDouble("records_per_doc_avg"); - public double SortableValueSizeMebibytes => GetDouble("sortable_value_size_mb"); + public double BytesPerRecordAvg => GetDouble("bytes_per_record_avg"); - public double KeyTableSizeMebibytes => GetDouble("key_table_size_mb"); + public double OffsetsPerTermAvg => GetDouble("offsets_per_term_avg"); - // public double SkipIndexSizeMebibytes => GetDouble("skip_index_size_mb"); + public double OffsetBitsPerRecordAvg => GetDouble("offset_bits_per_record_avg"); - // public double ScoreIndexSizeMebibytes => GetDouble("score_index_size_mb"); + public long HashIndexingFailures => GetLong("hash_indexing_failures"); - public double RecordsPerDocAvg => GetDouble("records_per_doc_avg"); + public double TotalIndexingTime => GetDouble("total_indexing_time"); - public double BytesPerRecordAvg => GetDouble("bytes_per_record_avg"); + public long Indexing => GetLong("indexing"); - public double OffsetsPerTermAvg => GetDouble("offsets_per_term_avg"); + public double PercentIndexed => GetDouble("percent_indexed"); - public double OffsetBitsPerRecordAvg => GetDouble("offset_bits_per_record_avg"); + public long NumberOfUses => GetLong("number_of_uses"); - public long HashIndexingFailures => GetLong("hash_indexing_failures"); - public double TotalIndexingTime => GetDouble("total_indexing_time"); + public Dictionary GcStats => GetRedisResultDictionary("gc_stats")!; - public long Indexing => GetLong("indexing"); + public Dictionary CursorStats => GetRedisResultDictionary("cursor_stats")!; - public double PercentIndexed => GetDouble("percent_indexed"); + public InfoResult(RedisResult result) + { + var results = (RedisResult[])result!; - public long NumberOfUses => GetLong("number_of_uses"); + for (var i = 0; i < results.Length; i += 2) + { + var key = (string)results[i]!; + var value = results[i + 1]; + _all.Add(key, value); + } + } - public Dictionary GcStats => GetRedisResultDictionary("gc_stats")!; + private string? GetString(string key) => _all.TryGetValue(key, out var value) ? (string)value! : default; - public Dictionary CursorStats => GetRedisResultDictionary("cursor_stats")!; + private long GetLong(string key) => _all.TryGetValue(key, out var value) ? (long)value : default; - public InfoResult(RedisResult result) + private double GetDouble(string key) + { + if (!_all.TryGetValue(key, out var value)) return default; + if ((string)value! == "-nan") { - var results = (RedisResult[])result!; - - for (var i = 0; i < results.Length; i += 2) - { - var key = (string)results[i]!; - var value = results[i + 1]; - - _all.Add(key, value); - } + return default; } - private string? GetString(string key) => _all.TryGetValue(key, out var value) ? (string)value! : default; + return (double)value; + } - private long GetLong(string key) => _all.TryGetValue(key, out var value) ? (long)value : default; + private Dictionary? GetRedisResultDictionary(string key) + { + if (!_all.TryGetValue(key, out var value)) return default; + var values = (RedisResult[])value!; + var result = new Dictionary(); - private double GetDouble(string key) + for (var ii = 0; ii < values.Length; ii += 2) { - if (_all.TryGetValue(key, out var value)) - { - if ((string)value! == "-nan") - { - return default; - } - else - { - return (double)value; - } - } - else - { - return default; - } + result.Add((string)values[ii]!, values[ii + 1]); } - private Dictionary? GetRedisResultDictionary(string key) - { - if (_all.TryGetValue(key, out var value)) - { - var values = (RedisResult[])value!; - var result = new Dictionary(); - - for (var ii = 0; ii < values.Length; ii += 2) - { - result.Add((string)values[ii]!, values[ii + 1]); - } + return result; - return result; - } - else - { - return default; - } - } + } - private Dictionary[]? GetRedisResultDictionaryArray(string key) + private Dictionary[]? GetRedisResultDictionaryArray(string key) + { + if (!_all.TryGetValue(key, out var value)) return default; + var values = (RedisResult[])value!; + var result = new Dictionary[values.Length]; + for (int i = 0; i < values.Length; i++) { - if (_all.TryGetValue(key, out var value)) + var fv = (RedisResult[])values[i]!; + var dict = new Dictionary(); + for (int j = 0; j < fv.Length; j += 2) { - var values = (RedisResult[])value!; - var result = new Dictionary[values.Length]; - for (int i = 0; i < values.Length; i++) - { - var fv = (RedisResult[])values[i]!; - var dict = new Dictionary(); - for (int j = 0; j < fv.Length; j += 2) - { - dict.Add((string)fv[j]!, fv[j + 1]); - } - result[i] = dict; - } - return result; + dict.Add((string)fv[j]!, fv[j + 1]); } - else - { - return default; - } + result[i] = dict; } + + return result; } } \ No newline at end of file From 12c9c872050a009b8a79c0d22e7346e774954e28 Mon Sep 17 00:00:00 2001 From: nimanikoo Date: Mon, 29 Jan 2024 23:03:18 +0330 Subject: [PATCH 35/57] Used Invert If technique and removed redundant else for code optimization and improved clarity --- src/NRedisStack/Search/AggregationRequest.cs | 526 +++++++++--------- .../Search/Literals/AttributeOptions.cs | 17 +- .../Search/Literals/CommandArgs.cs | 117 ++-- src/NRedisStack/Search/Literals/Commands.cs | 59 +- 4 files changed, 347 insertions(+), 372 deletions(-) diff --git a/src/NRedisStack/Search/AggregationRequest.cs b/src/NRedisStack/Search/AggregationRequest.cs index 29eee63c..0dfb87db 100644 --- a/src/NRedisStack/Search/AggregationRequest.cs +++ b/src/NRedisStack/Search/AggregationRequest.cs @@ -1,341 +1,319 @@ -using NRedisStack.Search.Literals; +using NRedisStack.Search.Aggregation; +using NRedisStack.Search.Literals; -namespace NRedisStack.Search.Aggregation +namespace NRedisStack.Search; + +public class AggregationRequest { - public class AggregationRequest - { - private List args = new List(); // Check if Readonly - private bool isWithCursor = false; + private List args = []; // Check if Readonly + private bool isWithCursor = false; - // Parameters: + // Parameters: - private bool? verbatim = null; + private bool? verbatim = null; - // Load - private List fieldNames = new List(); // TODO: Check if the new list suposed to be here - private bool? loadAll = null; + // Load + private List fieldNames = new List(); // TODO: Check if the new list supposed to be here + private bool? loadAll = null; - private long? timeout = null; + private long? timeout = null; - // GroupBy: - private List groups = new List(); + // GroupBy: + private List groups = []; - // SotrBy: - private List sortedFields = new List(); - private int? max = null; + // SotrBy: + private List sortedFields = []; + private int? max = null; - // Apply: - private List> apply = new List>(); + // Apply: + private List> apply = []; - // Limit: - private int? offset = null; - private int? num = null; + // Limit: + private int? offset = null; + private int? num = null; - private string? filter = null; + private string? filter = null; - // WithCursor: - private int? count = null; - private long? maxIdle = null; + // WithCursor: + private int? count = null; + private long? maxIdle = null; - // Params: - private Dictionary nameValue = new Dictionary(); - public int? dialect { get; private set; } = null; + // Params: + private Dictionary nameValue = new(); + public int? dialect { get; private set; } = null; - public AggregationRequest(string query, int? defaultDialect = null) - { - this.dialect = defaultDialect; - args.Add(query); - } + public AggregationRequest(string query, int? defaultDialect = null) + { + this.dialect = defaultDialect; + args.Add(query); + } - public AggregationRequest() : this("*") { } + public AggregationRequest() : this("*") + { + } - public AggregationRequest Verbatim(bool verbatim = true) - { - this.verbatim = true; - return this; - } + public AggregationRequest Verbatim(bool verbatim = true) + { + this.verbatim = true; + return this; + } - private void Verbatim() - { - if (verbatim == true) - args.Add("VERBATIM"); - } + private void Verbatim() + { + if (verbatim == true) + args.Add("VERBATIM"); + } - public AggregationRequest Load(params FieldName[] fields) - { - this.fieldNames.AddRange(fields); - return this; - } + public AggregationRequest Load(params FieldName[] fields) + { + this.fieldNames.AddRange(fields); + return this; + } - public AggregationRequest LoadAll() - { - loadAll = true; - return this; - } + public AggregationRequest LoadAll() + { + loadAll = true; + return this; + } - private void Load() + private void Load() + { + if (loadAll == true) { - if (loadAll == true) - { - args.Add("LOAD"); - args.Add("*"); - return; - } - else if (fieldNames.Count > 0) - { - args.Add("LOAD"); - int loadCountIndex = args.Count; - //args.Add(null); - int loadCount = 0; - foreach (FieldName fn in fieldNames) - { - loadCount += fn.AddCommandArguments(args); - } - - args.Insert(loadCountIndex, loadCount); - // args[loadCountIndex] = loadCount.ToString(); - } + args.Add("LOAD"); + args.Add("*"); + return; } - public AggregationRequest Timeout(long timeout) - { - this.timeout = timeout; - return this; - } + if (fieldNames.Count <= 0) return; + args.Add("LOAD"); + int loadCountIndex = args.Count; + //args.Add(null); + int loadCount = fieldNames.Sum(fn => fn.AddCommandArguments(args)); - private void Timeout() - { - if (timeout != null) - { - args.Add("TIMEOUT"); - args.Add(timeout); - } - } + args.Insert(loadCountIndex, loadCount); + // args[loadCountIndex] = loadCount.ToString(); + } - public AggregationRequest GroupBy(IList fields, IList reducers) - { - Group g = new Group(fields); - foreach (Reducer r in reducers) - { - g.Reduce(r); - } - GroupBy(g); - return this; - } + public AggregationRequest Timeout(long timeout) + { + this.timeout = timeout; + return this; + } - public AggregationRequest GroupBy(string field, params Reducer[] reducers) - { - return GroupBy(new string[] { field }, reducers); - } + private void Timeout() + { + if (timeout == null) return; + args.Add("TIMEOUT"); + args.Add(timeout); + } - public AggregationRequest GroupBy(Group group) + public AggregationRequest GroupBy(IList fields, IList reducers) + { + Group g = new Group(fields); + foreach (Reducer r in reducers) { - this.groups.Add(group); - return this; + g.Reduce(r); } - private void GroupBy() - { - if (groups.Count > 0) - { - args.Add("GROUPBY"); - foreach (Group group in groups) - { - group.SerializeRedisArgs(args); - } - } - } + GroupBy(g); + return this; + } - public AggregationRequest SortBy(string property) => SortBy(SortedField.Asc(property)); + public AggregationRequest GroupBy(string field, params Reducer[] reducers) + { + return GroupBy(new[] { field }, reducers); + } - public AggregationRequest SortBy(params SortedField[] fields) - { - this.sortedFields.AddRange(fields); - return this; - } + private AggregationRequest GroupBy(Group group) + { + groups.Add(group); + return this; + } - private void SortBy() + private void GroupBy() + { + if (groups.Count <= 0) return; + args.Add("GROUPBY"); + foreach (Group group in groups) { - if (sortedFields.Count > 0) - { - args.Add("SORTBY"); - args.Add(sortedFields.Count * 2); - foreach (SortedField field in sortedFields) - { - args.Add(field.FieldName); - args.Add(field.Order.ToString()); - } - - if (max > 0) - { - args.Add("MAX"); - args.Add(max); - } - } + group.SerializeRedisArgs(args); } + } - public AggregationRequest SortBy(int max, params SortedField[] fields) - { - this.max = max; - SortBy(fields); - return this; - } + public AggregationRequest SortBy(string property) => SortBy(SortedField.Asc(property)); - public AggregationRequest Apply(string projection, string alias) - { - apply.Add(new Tuple(projection, alias)); - return this; - } + private AggregationRequest SortBy(params SortedField[] fields) + { + this.sortedFields.AddRange(fields); + return this; + } - private void Apply() + private void SortBy() + { + if (sortedFields.Count <= 0) return; + args.Add("SORTBY"); + args.Add(sortedFields.Count * 2); + foreach (SortedField field in sortedFields) { - if (apply.Count > 0) - { - foreach (Tuple tuple in apply) - { - args.Add("APPLY"); - args.Add(tuple.Item1); - args.Add("AS"); - args.Add(tuple.Item2); - } - } + args.Add(field.FieldName); + args.Add(field.Order.ToString()); } - public AggregationRequest Limit(int count) => Limit(0, count); + if (!(max > 0)) return; + args.Add("MAX"); + args.Add(max); + } - public AggregationRequest Limit(int offset, int count) - { - this.offset = offset; - this.num = count; + public AggregationRequest SortBy(int max, params SortedField[] fields) + { + this.max = max; + SortBy(fields); + return this; + } - return this; - } + public AggregationRequest Apply(string projection, string alias) + { + apply.Add(new Tuple(projection, alias)); + return this; + } - private void Limit() + private void Apply() + { + if (apply.Count <= 0) return; + foreach (Tuple tuple in apply) { - if (offset != null && num != null) - { - new Limit(offset.Value, num.Value).SerializeRedisArgs(args); - } + args.Add("APPLY"); + args.Add(tuple.Item1); + args.Add("AS"); + args.Add(tuple.Item2); } + } - public AggregationRequest Filter(string filter) - { - this.filter = filter; - return this; - } + public AggregationRequest Limit(int count) => Limit(0, count); - private void Filter() - { - if (filter != null) - { - args.Add(SearchArgs.FILTER); - args.Add(filter!); - } + public AggregationRequest Limit(int offset, int count) + { + this.offset = offset; + num = count; - } + return this; + } - public AggregationRequest Cursor(int? count = null, long? maxIdle = null) + private void Limit() + { + if (offset != null && num != null) { - isWithCursor = true; - if (count != null) - this.count = count; - if (maxIdle != null) - this.maxIdle = maxIdle; - return this; + new Limit(offset.Value, num.Value).SerializeRedisArgs(args); } + } - private void Cursor() - { - if (isWithCursor) - { - args.Add("WITHCURSOR"); - - if (count != null) - { - args.Add("COUNT"); - args.Add(count); - } - - if (maxIdle != null && maxIdle < long.MaxValue && maxIdle >= 0) - { - args.Add("MAXIDLE"); - args.Add(maxIdle); - } - } - } + public AggregationRequest Filter(string filter) + { + this.filter = filter; + return this; + } - public AggregationRequest Params(Dictionary nameValue) - { - foreach (var entry in nameValue) - { - this.nameValue.Add(entry.Key, entry.Value); - } - return this; - } + private void Filter() + { + if (filter == null) return; + args.Add(SearchArgs.FILTER); + args.Add(filter!); + } - private void Params() - { - if (nameValue.Count > 0) - { - args.Add("PARAMS"); - args.Add(nameValue.Count * 2); - foreach (var entry in nameValue) - { - args.Add(entry.Key); - args.Add(entry.Value); - } - } - } + public AggregationRequest Cursor(int? count = null, long? maxIdle = null) + { + isWithCursor = true; + if (count != null) + this.count = count; + if (maxIdle != null) + this.maxIdle = maxIdle; + return this; + } - public AggregationRequest Dialect(int dialect) - { - this.dialect = dialect; - return this; - } + private void Cursor() + { + if (!isWithCursor) return; + args.Add("WITHCURSOR"); - private void Dialect() + if (count != null) { - if (dialect != null) - { - args.Add("DIALECT"); - args.Add(dialect); - } + args.Add("COUNT"); + args.Add(count); } - public List GetArgs() - { - return args; - } + if (maxIdle == null || !(maxIdle < long.MaxValue) || !(maxIdle >= 0)) return; + args.Add("MAXIDLE"); + args.Add(maxIdle); + } - public void SerializeRedisArgs() + public AggregationRequest Params(Dictionary nameValue) + { + foreach (var entry in nameValue) { - Verbatim(); - Load(); - Timeout(); - Apply(); - GroupBy(); - SortBy(); - Limit(); - Filter(); - Cursor(); - Params(); - Dialect(); + this.nameValue.Add(entry.Key, entry.Value); } - // public string getArgsstring() - // { - // StringBuilder sj = new StringBuilder(" "); - // foreach (var s in GetArgs()) - // { - // sj.Add(s.ToString()); - // } - // return sj.tostring(); - // } - - public bool IsWithCursor() + return this; + } + + private void Params() + { + if (nameValue.Count <= 0) return; + args.Add("PARAMS"); + args.Add(nameValue.Count * 2); + foreach (var entry in nameValue) { - return isWithCursor; + args.Add(entry.Key); + args.Add(entry.Value); } } -} + + public AggregationRequest Dialect(int dialect) + { + this.dialect = dialect; + return this; + } + + private void Dialect() + { + if (dialect == null) return; + args.Add("DIALECT"); + args.Add(dialect); + } + + public List GetArgs() + { + return args; + } + + public void SerializeRedisArgs() + { + Verbatim(); + Load(); + Timeout(); + Apply(); + GroupBy(); + SortBy(); + Limit(); + Filter(); + Cursor(); + Params(); + Dialect(); + } + + // public string getArgsstring() + // { + // StringBuilder sj = new StringBuilder(" "); + // foreach (var s in GetArgs()) + // { + // sj.Add(s.ToString()); + // } + // return sj.tostring(); + // } + + public bool IsWithCursor() + { + return isWithCursor; + } +} \ No newline at end of file diff --git a/src/NRedisStack/Search/Literals/AttributeOptions.cs b/src/NRedisStack/Search/Literals/AttributeOptions.cs index 5510151b..41a13714 100644 --- a/src/NRedisStack/Search/Literals/AttributeOptions.cs +++ b/src/NRedisStack/Search/Literals/AttributeOptions.cs @@ -1,12 +1,11 @@ -namespace NRedisStack.Search.Literals +namespace NRedisStack.Search.Literals; + +internal class AttributeOptions { - internal class AttributeOptions - { - public const string SORTABLE = "SORTABLE"; - public const string UNF = "UNF"; - public const string NOSTEM = "NOSTEM"; - public const string NOINDEX = "NOINDEX"; + public const string SORTABLE = "SORTABLE"; + public const string UNF = "UNF"; + public const string NOSTEM = "NOSTEM"; + public const string NOINDEX = "NOINDEX"; - //TODO: add all options - } + //TODO: add all options } \ No newline at end of file diff --git a/src/NRedisStack/Search/Literals/CommandArgs.cs b/src/NRedisStack/Search/Literals/CommandArgs.cs index fb957db7..3995c40e 100644 --- a/src/NRedisStack/Search/Literals/CommandArgs.cs +++ b/src/NRedisStack/Search/Literals/CommandArgs.cs @@ -1,61 +1,60 @@ -namespace NRedisStack.Search.Literals +namespace NRedisStack.Search.Literals; + +internal class SearchArgs { - internal class SearchArgs - { - public const string ON_HASH = "ON HASH"; - public const string JSON = "JSON"; - public const string PREFIX = "PREFIX"; - public const string FILTER = "FILTER"; - public const string LANGUAGE = "LANGUAGE"; - public const string LANGUAGE_FIELD = "LANGUAGE_FIELD"; - public const string SCORE = "SCORE"; - public const string SCORE_FIELD = "SCORE_FIELD"; - public const string PAYLOAD_FIELD = "PAYLOAD_FIELD"; - public const string MAXTEXTFIELDS = "MAXTEXTFIELDS"; - public const string TEMPORARY = "TEMPORARY"; - public const string NOOFFSETS = "NOOFFSETS"; - public const string NOHL = "NOHL"; - public const string NOFIELDS = "NOFIELDS"; - public const string NOFREQS = "NOFREQS"; - public const string STOPWORDS = "STOPWORDS"; - public const string SKIPINITIALSCAN = "SKIPINITIALSCAN"; - public const string INCLUDE = "INCLUDE"; - public const string EXCLUDE = "EXCLUDE"; - public const string DIALECT = "DIALECT"; - public const string TERMS = "TERMS"; - public const string DISTANCE = "DISTANCE"; - public const string INCR = "INCR"; - public const string PAYLOAD = "PAYLOAD"; - public const string FUZZY = "FUZZY"; - public const string WITHSCORES = "WITHSCORES"; - public const string WITHPAYLOADS = "WITHPAYLOADS"; - public const string MAX = "MAX"; - public const string VERBATIM = "VERBATIM"; - public const string NOCONTENT = "NOCONTENT"; - public const string NOSTOPWORDS = "NOSTOPWORDS"; - public const string SCORER = "SCORER"; - public const string INFIELDS = "INFIELDS"; - public const string SORTBY = "SORTBY"; - public const string ASC = "ASC"; - public const string DESC = "DESC"; - public const string LIMIT = "LIMIT"; - public const string HIGHLIGHT = "HIGHLIGHT"; - public const string FIELDS = "FIELDS"; - public const string TAGS = "TAGS"; - public const string SUMMARIZE = "SUMMARIZE"; - public const string FRAGS = "FRAGS"; - public const string LEN = "LEN"; - public const string SEPARATOR = "SEPARATOR"; - public const string INKEYS = "INKEYS"; - public const string RETURN = "RETURN"; - public const string PARAMS = "PARAMS"; - public const string SLOP = "SLOP"; - public const string TIMEOUT = "TIMEOUT"; - public const string INORDER = "INORDER"; - public const string EXPANDER = "EXPANDER"; - public const string SEARCH = "SEARCH"; - public const string AGGREGATE = "AGGREGATE"; - public const string LIMITED = "LIMITED"; - public const string QUERY = "QUERY"; - } + public const string ON_HASH = "ON HASH"; + public const string JSON = "JSON"; + public const string PREFIX = "PREFIX"; + public const string FILTER = "FILTER"; + public const string LANGUAGE = "LANGUAGE"; + public const string LANGUAGE_FIELD = "LANGUAGE_FIELD"; + public const string SCORE = "SCORE"; + public const string SCORE_FIELD = "SCORE_FIELD"; + public const string PAYLOAD_FIELD = "PAYLOAD_FIELD"; + public const string MAXTEXTFIELDS = "MAXTEXTFIELDS"; + public const string TEMPORARY = "TEMPORARY"; + public const string NOOFFSETS = "NOOFFSETS"; + public const string NOHL = "NOHL"; + public const string NOFIELDS = "NOFIELDS"; + public const string NOFREQS = "NOFREQS"; + public const string STOPWORDS = "STOPWORDS"; + public const string SKIPINITIALSCAN = "SKIPINITIALSCAN"; + public const string INCLUDE = "INCLUDE"; + public const string EXCLUDE = "EXCLUDE"; + public const string DIALECT = "DIALECT"; + public const string TERMS = "TERMS"; + public const string DISTANCE = "DISTANCE"; + public const string INCR = "INCR"; + public const string PAYLOAD = "PAYLOAD"; + public const string FUZZY = "FUZZY"; + public const string WITHSCORES = "WITHSCORES"; + public const string WITHPAYLOADS = "WITHPAYLOADS"; + public const string MAX = "MAX"; + public const string VERBATIM = "VERBATIM"; + public const string NOCONTENT = "NOCONTENT"; + public const string NOSTOPWORDS = "NOSTOPWORDS"; + public const string SCORER = "SCORER"; + public const string INFIELDS = "INFIELDS"; + public const string SORTBY = "SORTBY"; + public const string ASC = "ASC"; + public const string DESC = "DESC"; + public const string LIMIT = "LIMIT"; + public const string HIGHLIGHT = "HIGHLIGHT"; + public const string FIELDS = "FIELDS"; + public const string TAGS = "TAGS"; + public const string SUMMARIZE = "SUMMARIZE"; + public const string FRAGS = "FRAGS"; + public const string LEN = "LEN"; + public const string SEPARATOR = "SEPARATOR"; + public const string INKEYS = "INKEYS"; + public const string RETURN = "RETURN"; + public const string PARAMS = "PARAMS"; + public const string SLOP = "SLOP"; + public const string TIMEOUT = "TIMEOUT"; + public const string INORDER = "INORDER"; + public const string EXPANDER = "EXPANDER"; + public const string SEARCH = "SEARCH"; + public const string AGGREGATE = "AGGREGATE"; + public const string LIMITED = "LIMITED"; + public const string QUERY = "QUERY"; } \ No newline at end of file diff --git a/src/NRedisStack/Search/Literals/Commands.cs b/src/NRedisStack/Search/Literals/Commands.cs index 8d94b306..ab024cf2 100644 --- a/src/NRedisStack/Search/Literals/Commands.cs +++ b/src/NRedisStack/Search/Literals/Commands.cs @@ -1,32 +1,31 @@ -namespace NRedisStack.Search.Literals +namespace NRedisStack.Search.Literals; + +internal class FT { - internal class FT - { - public const string _LIST = "FT._LIST"; - public const string AGGREGATE = "FT.AGGREGATE"; - public const string ALIASADD = "FT.ALIASADD"; - public const string ALIASDEL = "FT.ALIASDEL"; - public const string ALIASUPDATE = "FT.ALIASUPDATE"; - public const string ALTER = "FT.ALTER"; - public const string CONFIG = "FT.CONFIG"; - public const string CREATE = "FT.CREATE"; - public const string CURSOR = "FT.CURSOR"; - public const string DICTADD = "FT.DICTADD"; - public const string DICTDEL = "FT.DICTDEL"; - public const string DICTDUMP = "FT.DICTDUMP"; - public const string DROPINDEX = "FT.DROPINDEX"; - public const string EXPLAIN = "FT.EXPLAIN"; - public const string EXPLAINCLI = "FT.EXPLAINCLI"; - public const string INFO = "FT.INFO"; - public const string PROFILE = "FT.PROFILE"; - public const string SEARCH = "FT.SEARCH"; - public const string SPELLCHECK = "FT.SPELLCHECK"; - public const string SUGADD = "FT.SUGADD"; - public const string SUGDEL = "FT.SUGDEL"; - public const string SUGGET = "FT.SUGGET"; - public const string SUGLEN = "FT.SUGLEN"; - public const string SYNDUMP = "FT.SYNDUMP"; - public const string SYNUPDATE = "FT.SYNUPDATE"; - public const string TAGVALS = "FT.TAGVALS"; - } + public const string _LIST = "FT._LIST"; + public const string AGGREGATE = "FT.AGGREGATE"; + public const string ALIASADD = "FT.ALIASADD"; + public const string ALIASDEL = "FT.ALIASDEL"; + public const string ALIASUPDATE = "FT.ALIASUPDATE"; + public const string ALTER = "FT.ALTER"; + public const string CONFIG = "FT.CONFIG"; + public const string CREATE = "FT.CREATE"; + public const string CURSOR = "FT.CURSOR"; + public const string DICTADD = "FT.DICTADD"; + public const string DICTDEL = "FT.DICTDEL"; + public const string DICTDUMP = "FT.DICTDUMP"; + public const string DROPINDEX = "FT.DROPINDEX"; + public const string EXPLAIN = "FT.EXPLAIN"; + public const string EXPLAINCLI = "FT.EXPLAINCLI"; + public const string INFO = "FT.INFO"; + public const string PROFILE = "FT.PROFILE"; + public const string SEARCH = "FT.SEARCH"; + public const string SPELLCHECK = "FT.SPELLCHECK"; + public const string SUGADD = "FT.SUGADD"; + public const string SUGDEL = "FT.SUGDEL"; + public const string SUGGET = "FT.SUGGET"; + public const string SUGLEN = "FT.SUGLEN"; + public const string SYNDUMP = "FT.SYNDUMP"; + public const string SYNUPDATE = "FT.SYNUPDATE"; + public const string TAGVALS = "FT.TAGVALS"; } \ No newline at end of file From bce49c6a256e648689a9bcd40ef9e9d644eb7397 Mon Sep 17 00:00:00 2001 From: nimanikoo Date: Mon, 29 Jan 2024 23:09:41 +0330 Subject: [PATCH 36/57] Sync Namespace and use scoped namespace and use operator instead if --- src/NRedisStack/Search/AggregationResult.cs | 69 ++++++++++----------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/src/NRedisStack/Search/AggregationResult.cs b/src/NRedisStack/Search/AggregationResult.cs index b8e4d38e..24f2159d 100644 --- a/src/NRedisStack/Search/AggregationResult.cs +++ b/src/NRedisStack/Search/AggregationResult.cs @@ -1,48 +1,47 @@ -using StackExchange.Redis; +using NRedisStack.Search.Aggregation; +using StackExchange.Redis; -namespace NRedisStack.Search.Aggregation +namespace NRedisStack.Search; + +public sealed class AggregationResult { - public sealed class AggregationResult - { - public long TotalResults { get; } - private readonly Dictionary[] _results; - public long CursorId { get; } + public long TotalResults { get; } + private readonly Dictionary[] _results; + public long CursorId { get; } - internal AggregationResult(RedisResult result, long cursorId = -1) - { - var arr = (RedisResult[])result!; + internal AggregationResult(RedisResult result, long cursorId = -1) + { + var arr = (RedisResult[])result!; - // the first element is always the number of results - TotalResults = (long)arr[0]; + // the first element is always the number of results + TotalResults = (long)arr[0]; - _results = new Dictionary[arr.Length - 1]; - for (int i = 1; i < arr.Length; i++) + _results = new Dictionary[arr.Length - 1]; + for (int i = 1; i < arr.Length; i++) + { + var raw = (RedisResult[])arr[i]!; + var cur = new Dictionary(); + for (int j = 0; j < raw.Length;) { - var raw = (RedisResult[])arr[i]!; - var cur = new Dictionary(); - for (int j = 0; j < raw.Length;) - { - var key = (string)raw[j++]!; - var val = raw[j++]; - if (val.Type == ResultType.MultiBulk) - continue; // TODO: handle multi-bulk (maybe change to object?) - cur.Add(key, (RedisValue)val); - } - _results[i - 1] = cur; + var key = (string)raw[j++]!; + var val = raw[j++]; + if (val.Type == ResultType.MultiBulk) + continue; // TODO: handle multi-bulk (maybe change to object?) + cur.Add(key, (RedisValue)val); } - - CursorId = cursorId; + _results[i - 1] = cur; } - public IReadOnlyList> GetResults() => _results; - public Dictionary? this[int index] - => index >= _results.Length ? null : _results[index]; + CursorId = cursorId; + } + public IReadOnlyList> GetResults() => _results; - public Row GetRow(int index) - { - if (index >= _results.Length) return default; - return new Row(_results[index]); - } + public Dictionary? this[int index] + => index >= _results.Length ? null : _results[index]; + + public Row GetRow(int index) + { + return index >= _results.Length ? default : new Row(_results[index]); } } \ No newline at end of file From 94c133cd0f2e3b261bd82f10815b26a4e75c4f08 Mon Sep 17 00:00:00 2001 From: nimanikoo Date: Mon, 29 Jan 2024 23:19:26 +0330 Subject: [PATCH 37/57] ConvertMultiBulkToObject for handle multi-bulk based on your todo in AggregationResult.cs --- src/NRedisStack/Search/AggregationResult.cs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/NRedisStack/Search/AggregationResult.cs b/src/NRedisStack/Search/AggregationResult.cs index 24f2159d..c3f55f1c 100644 --- a/src/NRedisStack/Search/AggregationResult.cs +++ b/src/NRedisStack/Search/AggregationResult.cs @@ -30,11 +30,31 @@ internal AggregationResult(RedisResult result, long cursorId = -1) continue; // TODO: handle multi-bulk (maybe change to object?) cur.Add(key, (RedisValue)val); } + _results[i - 1] = cur; } CursorId = cursorId; } + + + /// + /// takes a Redis multi-bulk array represented by a RedisResult[] and recursively processes its elements. + /// For each element in the array, it checks if it's another multi-bulk array, and if so, it recursively calls itself. + /// If the element is not a multi-bulk array, it's added directly to a List. + /// The method returns a nested list structure, reflecting the hierarchy of the original multi-bulk array, + /// with each element either being a direct value or a nested list. + /// + /// + /// object + private object ConvertMultiBulkToObject(IEnumerable multiBulkArray) + { + return multiBulkArray.Select(item => item.Type == ResultType.MultiBulk + ? ConvertMultiBulkToObject((RedisResult[])item!) + : item) + .ToList(); + } + public IReadOnlyList> GetResults() => _results; public Dictionary? this[int index] From 481b7e9ff3ec4a7aa55aece9d007708894876d8a Mon Sep 17 00:00:00 2001 From: nimanikoo Date: Mon, 29 Jan 2024 23:22:35 +0330 Subject: [PATCH 38/57] Optimized codebase by removing redundant elements for improved efficiency and maintainability --- src/NRedisStack/Search/Document.cs | 115 ++++++++++++++--------------- 1 file changed, 56 insertions(+), 59 deletions(-) diff --git a/src/NRedisStack/Search/Document.cs b/src/NRedisStack/Search/Document.cs index 159071d4..3223054f 100644 --- a/src/NRedisStack/Search/Document.cs +++ b/src/NRedisStack/Search/Document.cs @@ -1,79 +1,76 @@ using StackExchange.Redis; -namespace NRedisStack.Search +namespace NRedisStack.Search; + +/// +/// Document represents a single indexed document or entity in the engine +/// +public class Document { - /// - /// Document represents a single indexed document or entity in the engine - /// - public class Document - { - public string Id { get; } - public double Score { get; set; } - public byte[]? Payload { get; } - public string[]? ScoreExplained { get; private set; } // TODO: check if this is needed (Jedis does not have it) - internal readonly Dictionary _properties; - public Document(string id, double score, byte[]? payload) : this(id, null, score, payload) { } - public Document(string id) : this(id, null, 1.0, null) { } + public string Id { get; } + public double Score { get; set; } + public byte[]? Payload { get; } + public string[]? ScoreExplained { get; private set; } // TODO: check if this is needed (Jedis does not have it) + internal readonly Dictionary _properties; + public Document(string id, double score, byte[]? payload) : this(id, null, score, payload) { } + public Document(string id) : this(id, null, 1.0, null) { } - public Document(string id, Dictionary fields, double score = 1.0) : this(id, fields, score, null) { } + public Document(string id, Dictionary fields, double score = 1.0) : this(id, fields, score, null) { } - public Document(string id, Dictionary? fields, double score, byte[]? payload) - { - Id = id; - _properties = fields ?? new Dictionary(); - Score = score; - Payload = payload; - } + public Document(string id, Dictionary? fields, double score, byte[]? payload) + { + Id = id; + _properties = fields ?? new Dictionary(); + Score = score; + Payload = payload; + } - public IEnumerable> GetProperties() => _properties; + public IEnumerable> GetProperties() => _properties; - public static Document Load(string id, double score, byte[]? payload, RedisValue[]? fields) + public static Document Load(string id, double score, byte[]? payload, RedisValue[]? fields) + { + Document ret = new Document(id, score, payload); + if (fields == null) return ret; + for (int i = 0; i < fields.Length; i += 2) { - Document ret = new Document(id, score, payload); - if (fields != null) + string fieldName = fields[i]!; + if (fieldName == "$") { - for (int i = 0; i < fields.Length; i += 2) - { - string fieldName = (string)fields[i]!; - if (fieldName == "$") - { - ret["json"] = fields[i + 1]; - } - else - { - ret[fieldName] = fields[i + 1]; - } - } + ret["json"] = fields[i + 1]; } - return ret; - } - - public static Document Load(string id, double score, byte[]? payload, RedisValue[]? fields, string[]? scoreExplained) - { - Document ret = Document.Load(id, score, payload, fields); - if (scoreExplained != null) + else { - ret.ScoreExplained = scoreExplained; + ret[fieldName] = fields[i + 1]; } - return ret; } + return ret; + } - public RedisValue this[string key] + public static Document Load(string id, double score, byte[]? payload, RedisValue[]? fields, string[]? scoreExplained) + { + Document ret = Load(id, score, payload, fields); + if (scoreExplained != null) { - get { return _properties.TryGetValue(key, out var val) ? val : default(RedisValue); } - internal set { _properties[key] = value; } + ret.ScoreExplained = scoreExplained; } + return ret; + } - public Document Set(string field, RedisValue value) - { - this[field] = value; - return this; - } + public RedisValue this[string key] + { + get => _properties.TryGetValue(key, out var val) ? val : default(RedisValue); + internal set => _properties[key] = value; + } - public Document SetScore(double score) - { - Score = score; - return this; - } + public Document Set(string field, RedisValue value) + { + this[field] = value; + return this; + } + + public Document SetScore(double score) + { + Score = score; + return this; } } \ No newline at end of file From 6f6c14738025171faa12ab062c4c4286b1be8f56 Mon Sep 17 00:00:00 2001 From: nimanikoo Date: Thu, 1 Feb 2024 17:38:22 +0330 Subject: [PATCH 39/57] Sort Modifier and inverting if in Auxiliary.cs ExecuteAsync Method and RedisResult method and change foreach in MergeArgs to linq expression I think methods like "ExecuteBroadcastAsync" can be private --- src/NRedisStack/Auxiliary.cs | 197 +++++++++++++++++------------------ 1 file changed, 96 insertions(+), 101 deletions(-) diff --git a/src/NRedisStack/Auxiliary.cs b/src/NRedisStack/Auxiliary.cs index 3a508c2d..8cc96a7e 100644 --- a/src/NRedisStack/Auxiliary.cs +++ b/src/NRedisStack/Auxiliary.cs @@ -2,133 +2,128 @@ using NRedisStack.RedisStackCommands; using StackExchange.Redis; -namespace NRedisStack +namespace NRedisStack; + +public static class Auxiliary { - public static class Auxiliary + private static string? _libraryName = $"NRedisStack(.NET_v{Environment.Version})"; + private static bool _setInfo = true; + public static void ResetInfoDefaults() { - private static string? _libraryName = $"NRedisStack(.NET_v{Environment.Version})"; - private static bool _setInfo = true; - public static void ResetInfoDefaults() - { - _setInfo = true; - _libraryName = $"NRedisStack(.NET_v{Environment.Version})"; - } - public static List MergeArgs(RedisKey key, params RedisValue[] items) - { - var args = new List(items.Length + 1) { key }; - foreach (var item in items) args.Add(item); - return args; - } + _setInfo = true; + _libraryName = $"NRedisStack(.NET_v{Environment.Version})"; + } + public static List MergeArgs(RedisKey key, params RedisValue[] items) + { + var args = new List(items.Length + 1) { key }; + args.AddRange(items.Cast()); + return args; + } - public static object[] AssembleNonNullArguments(params object?[] arguments) + public static object[] AssembleNonNullArguments(params object?[] arguments) + { + var args = new List(); + foreach (var arg in arguments) { - var args = new List(); - foreach (var arg in arguments) + if (arg != null) { - if (arg != null) - { - args.Add(arg); - } + args.Add(arg); } - - return args.ToArray(); } - // TODO: add all the signatures of GetDatabase - public static IDatabase GetDatabase(this ConnectionMultiplexer redis, - string? LibraryName) - { - var _db = redis.GetDatabase(); - if (LibraryName == null) // the user wants to disable the library name and version sending - _setInfo = false; + return args.ToArray(); + } - else // the user set his own the library name - _libraryName = $"NRedisStack({LibraryName};.NET_v{Environment.Version})"; + // TODO: add all the signatures of GetDatabase + public static IDatabase GetDatabase(this ConnectionMultiplexer redis, + string? LibraryName) + { + var _db = redis.GetDatabase(); + if (LibraryName == null) // the user wants to disable the library name and version sending + _setInfo = false; - return _db; - } + else // the user set his own the library name + _libraryName = $"NRedisStack({LibraryName};.NET_v{Environment.Version})"; - private static void SetInfoInPipeline(this IDatabase db) - { - if (_libraryName == null) return; - Pipeline pipeline = new Pipeline(db); - _ = pipeline.Db.ClientSetInfoAsync(SetInfoAttr.LibraryName, _libraryName!); - _ = pipeline.Db.ClientSetInfoAsync(SetInfoAttr.LibraryVersion, GetNRedisStackVersion()); - pipeline.Execute(); - } + return _db; + } - public static RedisResult Execute(this IDatabase db, SerializedCommand command) - { - if (_setInfo) - { - _setInfo = false; - db.SetInfoInPipeline(); - } - return db.Execute(command.Command, command.Args); - } + private static void SetInfoInPipeline(this IDatabase db) + { + if (_libraryName == null) return; + Pipeline pipeline = new Pipeline(db); + _ = pipeline.Db.ClientSetInfoAsync(SetInfoAttr.LibraryName, _libraryName!); + _ = pipeline.Db.ClientSetInfoAsync(SetInfoAttr.LibraryVersion, GetNRedisStackVersion()); + pipeline.Execute(); + } - public async static Task ExecuteAsync(this IDatabaseAsync db, SerializedCommand command) - { - if (_setInfo) - { - _setInfo = false; - ((IDatabase)db).SetInfoInPipeline(); - } - return await db.ExecuteAsync(command.Command, command.Args); - } + public static RedisResult Execute(this IDatabase db, SerializedCommand command) + { + if (!_setInfo) return db.Execute(command.Command, command.Args); + _setInfo = false; + db.SetInfoInPipeline(); + return db.Execute(command.Command, command.Args); + } + + public static async Task ExecuteAsync(this IDatabaseAsync db, SerializedCommand command) + { + if (!_setInfo) return await db.ExecuteAsync(command.Command, command.Args); + _setInfo = false; + ((IDatabase)db).SetInfoInPipeline(); + return await db.ExecuteAsync(command.Command, command.Args); + } + + public static List ExecuteBroadcast(this IDatabase db, string command) + => db.ExecuteBroadcast(new SerializedCommand(command)); - public static List ExecuteBroadcast(this IDatabase db, string command) - => db.ExecuteBroadcast(new SerializedCommand(command)); + public static List ExecuteBroadcast(this IDatabase db, SerializedCommand command) + { + var redis = db.Multiplexer; + var endpoints = redis.GetEndPoints(); + var results = new List(endpoints.Length); - public static List ExecuteBroadcast(this IDatabase db, SerializedCommand command) + foreach (var endPoint in endpoints) { - var redis = db.Multiplexer; - var endpoints = redis.GetEndPoints(); - var results = new List(endpoints.Length); + var server = redis.GetServer(endPoint); - foreach (var endPoint in endpoints) + if (server.IsReplica) { - var server = redis.GetServer(endPoint); - - if (server.IsReplica) - { - continue; // Skip replica nodes - } - // Send your command to the master node - - results.Add(server.Multiplexer.GetDatabase().Execute(command)); + continue; // Skip replica nodes } - return results; + // Send your command to the master node + + results.Add(server.Multiplexer.GetDatabase().Execute(command)); } + return results; + } + + public static async Task> ExecuteBroadcastAsync(this IDatabaseAsync db, string command) + => await db.ExecuteBroadcastAsync(new SerializedCommand(command)); - public async static Task> ExecuteBroadcastAsync(this IDatabaseAsync db, string command) - => await db.ExecuteBroadcastAsync(new SerializedCommand(command)); + private static async Task> ExecuteBroadcastAsync(this IDatabaseAsync db, SerializedCommand command) + { + var redis = db.Multiplexer; + var endpoints = redis.GetEndPoints(); + var results = new List(endpoints.Length); - public async static Task> ExecuteBroadcastAsync(this IDatabaseAsync db, SerializedCommand command) + foreach (var endPoint in endpoints) { - var redis = db.Multiplexer; - var endpoints = redis.GetEndPoints(); - var results = new List(endpoints.Length); + var server = redis.GetServer(endPoint); - foreach (var endPoint in endpoints) + if (server.IsReplica) { - var server = redis.GetServer(endPoint); - - if (server.IsReplica) - { - continue; // Skip replica nodes - } - // Send your command to the master node - - results.Add(await server.Multiplexer.GetDatabase().ExecuteAsync(command)); + continue; // Skip replica nodes } - return results; - } + // Send your command to the master node - public static string GetNRedisStackVersion() - { - Version version = typeof(Auxiliary).Assembly.GetName().Version!; - return $"{version.Major}.{version.Minor}.{version.Build}"; + results.Add(await server.Multiplexer.GetDatabase().ExecuteAsync(command)); } + return results; + } + + public static string GetNRedisStackVersion() + { + Version version = typeof(Auxiliary).Assembly.GetName().Version!; + return $"{version.Major}.{version.Minor}.{version.Build}"; } -} +} \ No newline at end of file From 20166299e21749895e3c4c29b256268df5589f53 Mon Sep 17 00:00:00 2001 From: nimanikoo Date: Thu, 1 Feb 2024 17:56:36 +0330 Subject: [PATCH 40/57] Sync NameSpaces also you can use ITestOutputHelper for output your test results based on xUnit Doc: https://xunit.net/docs/capturing-output --- tests/Doc/HashExample.cs | 38 +++++++++++++++++----------- tests/Doc/SearchQuickstartExample.cs | 23 ++++++++++++----- tests/Doc/SetGetExample.cs | 15 ++++++++--- tests/Doc/StringSnippets.cs | 27 ++++++++++++-------- 4 files changed, 67 insertions(+), 36 deletions(-) diff --git a/tests/Doc/HashExample.cs b/tests/Doc/HashExample.cs index 38c279fd..7be9202c 100644 --- a/tests/Doc/HashExample.cs +++ b/tests/Doc/HashExample.cs @@ -1,14 +1,22 @@ // EXAMPLE: hash_tutorial // HIDE_START + using NRedisStack.Tests; using StackExchange.Redis; //REMOVE_START -namespace NRedisStack.Doc; +namespace Doc; [Collection("DocsTests")] //REMOVE_END public class HashExample { + private readonly ITestOutputHelper testOutputHelper; + + public HashExample(ITestOutputHelper testOutputHelper) + { + this.testOutputHelper = testOutputHelper; + } + [SkipIfRedis(Is.OSSCluster)] public void run() { @@ -25,20 +33,20 @@ public void run() new HashEntry("price", 4972) }); - Console.WriteLine("Hash Created"); + testOutputHelper.WriteLine("Hash Created"); // Hash Created var model = db.HashGet("bike:1", "model"); - Console.WriteLine($"Model: {model}"); + testOutputHelper.WriteLine($"Model: {model}"); // Model: Deimos var price = db.HashGet("bike:1", "price"); - Console.WriteLine($"Price: {price}"); + testOutputHelper.WriteLine($"Price: {price}"); // Price: 4972 var bike = db.HashGetAll("bike:1"); - Console.WriteLine("bike:1"); - Console.WriteLine(string.Join("\n", bike.Select(b => $"{b.Name}: {b.Value}"))); + testOutputHelper.WriteLine("bike:1"); + testOutputHelper.WriteLine(string.Join("\n", bike.Select(b => $"{b.Name}: {b.Value}"))); // Bike:1: // model: Deimos // brand: Ergonom @@ -54,7 +62,7 @@ public void run() //STEP_START hmget var values = db.HashGet("bike:1", new RedisValue[] { "model", "price" }); - Console.WriteLine(string.Join(" ", values)); + testOutputHelper.WriteLine(string.Join(" ", values)); // Deimos 4972 //REMOVE_START Assert.Equal("Deimos", values[0]); @@ -64,14 +72,14 @@ public void run() //STEP_START hincrby var newPrice = db.HashIncrement("bike:1", "price", 100); - Console.WriteLine($"New price: {newPrice}"); + testOutputHelper.WriteLine($"New price: {newPrice}"); //REMOVE_START Assert.Equal(5072, newPrice); //REMOVE_END // New price: 5072 newPrice = db.HashIncrement("bike:1", "price", -100); - Console.WriteLine($"New price: {newPrice}"); + testOutputHelper.WriteLine($"New price: {newPrice}"); //REMOVE_START Assert.Equal(4972, newPrice); //REMOVE_END @@ -80,42 +88,42 @@ public void run() //STEP_START incrby_get_mget var rides = db.HashIncrement("bike:1", "rides"); - Console.WriteLine($"Rides: {rides}"); + testOutputHelper.WriteLine($"Rides: {rides}"); //REMOVE_START Assert.Equal(1, rides); //REMOVE_END // Rides: 1 rides = db.HashIncrement("bike:1", "rides"); - Console.WriteLine($"Rides: {rides}"); + testOutputHelper.WriteLine($"Rides: {rides}"); //REMOVE_START Assert.Equal(2, rides); //REMOVE_END // Rides: 2 rides = db.HashIncrement("bike:1", "rides"); - Console.WriteLine($"Rides: {rides}"); + testOutputHelper.WriteLine($"Rides: {rides}"); //REMOVE_START Assert.Equal(3, rides); //REMOVE_END // Rides: 3 var crashes = db.HashIncrement("bike:1", "crashes"); - Console.WriteLine($"Crashes: {crashes}"); + testOutputHelper.WriteLine($"Crashes: {crashes}"); //REMOVE_START Assert.Equal(1, crashes); //REMOVE_END // Crashes: 1 var owners = db.HashIncrement("bike:1", "owners"); - Console.WriteLine($"Owners: {owners}"); + testOutputHelper.WriteLine($"Owners: {owners}"); //REMOVE_START Assert.Equal(1, owners); //REMOVE_END // Owners: 1 var stats = db.HashGet("bike:1", new RedisValue[] { "crashes", "owners" }); - Console.WriteLine($"Bike stats: crashes={stats[0]}, owners={stats[1]}"); + testOutputHelper.WriteLine($"Bike stats: crashes={stats[0]}, owners={stats[1]}"); //REMOVE_START Assert.Equal(1, stats[0]); Assert.Equal(1, stats[1]); diff --git a/tests/Doc/SearchQuickstartExample.cs b/tests/Doc/SearchQuickstartExample.cs index 256e3833..aa6ae29c 100644 --- a/tests/Doc/SearchQuickstartExample.cs +++ b/tests/Doc/SearchQuickstartExample.cs @@ -1,4 +1,5 @@ // EXAMPLE: search_quickstart + using NRedisStack.RedisStackCommands; using NRedisStack.Search; using NRedisStack.Search.Aggregation; @@ -7,11 +8,18 @@ using StackExchange.Redis; // REMOVE_START -namespace NRedisStack.Doc; +namespace Doc; [Collection("DocsTests")] // REMOVE_END public class SearchQuickstartExample { + private readonly ITestOutputHelper testOutputHelper; + + public SearchQuickstartExample(ITestOutputHelper testOutputHelper) + { + this.testOutputHelper = testOutputHelper; + } + [SkipIfRedis(Is.OSSCluster)] public void run() { @@ -29,6 +37,7 @@ public void run() } catch { + // ignored } // REMOVE_END @@ -211,7 +220,7 @@ public void run() // STEP_START wildcard_query var query1 = new Query("*"); var res1 = ft.Search("idx:bicycle", query1).Documents; - Console.WriteLine(string.Join("\n", res1.Count())); + testOutputHelper.WriteLine(string.Join("\n", res1.Count())); // Prints: Documents found: 10 // STEP_END // REMOVE_START @@ -221,7 +230,7 @@ public void run() // STEP_START query_single_term var query2 = new Query("@Model:Jigger"); var res2 = ft.Search("idx:bicycle", query2).Documents; - Console.WriteLine(string.Join("\n", res2.Select(x => x["json"]))); + testOutputHelper.WriteLine(string.Join("\n", res2.Select(x => x["json"]))); // Prints: {"Brand":"Moore PLC","Model":"Award Race","Price":3790.76, // "Description":"This olive folding bike features a carbon frame // and 27.5 inch wheels. This folding bike is perfect for compact @@ -235,7 +244,7 @@ public void run() // STEP_START query_single_term_and_num_range var query3 = new Query("basic @Price:[500 1000]"); var res3 = ft.Search("idx:bicycle", query3).Documents; - Console.WriteLine(string.Join("\n", res3.Select(x => x["json"]))); + testOutputHelper.WriteLine(string.Join("\n", res3.Select(x => x["json"]))); // Prints: {"Brand":"Moore PLC","Model":"Award Race","Price":3790.76, // "Description":"This olive folding bike features a carbon frame // and 27.5 inch wheels. This folding bike is perfect for compact @@ -249,7 +258,7 @@ public void run() // STEP_START query_exact_matching var query4 = new Query("@Brand:\"Noka Bikes\""); var res4 = ft.Search("idx:bicycle", query4).Documents; - Console.WriteLine(string.Join("\n", res4.Select(x => x["json"]))); + testOutputHelper.WriteLine(string.Join("\n", res4.Select(x => x["json"]))); // Prints: {"Brand":"Moore PLC","Model":"Award Race","Price":3790.76, // "Description":"This olive folding bike features a carbon frame // and 27.5 inch wheels. This folding bike is perfect for compact @@ -263,7 +272,7 @@ public void run() // STEP_START query_single_term_limit_fields var query5 = new Query("@Model:Jigger").ReturnFields("Price"); var res5 = ft.Search("idx:bicycle", query5).Documents; - Console.WriteLine(res5.First()["Price"]); + testOutputHelper.WriteLine(res5.First()["Price"]); // Prints: 270 // STEP_END // REMOVE_START @@ -279,7 +288,7 @@ public void run() for (var i = 0; i < result.TotalResults; i++) { var row = result.GetRow(i); - Console.WriteLine($"{row["Condition"]} - {row["Count"]}"); + testOutputHelper.WriteLine($"{row["Condition"]} - {row["Count"]}"); } // Prints: diff --git a/tests/Doc/SetGetExample.cs b/tests/Doc/SetGetExample.cs index 447d1dbc..9d5aa431 100644 --- a/tests/Doc/SetGetExample.cs +++ b/tests/Doc/SetGetExample.cs @@ -1,15 +1,22 @@ // EXAMPLE: set_and_get // HIDE_START -using System; + using NRedisStack.Tests; using StackExchange.Redis; //REMOVE_START -namespace NRedisStack.Doc; +namespace Doc; [Collection("DocsTests")] //REMOVE_END public class SetGetExample { + private readonly ITestOutputHelper testOutputHelper; + + public SetGetExample(ITestOutputHelper testOutputHelper) + { + this.testOutputHelper = testOutputHelper; + } + [SkipIfRedis(Is.OSSCluster)] public void run() { @@ -20,12 +27,12 @@ public void run() bool status = db.StringSet("bike:1", "Process 134"); if (status) - Console.WriteLine("Successfully added a bike."); + testOutputHelper.WriteLine("Successfully added a bike."); var value = db.StringGet("bike:1"); if (value.HasValue) - Console.WriteLine("The name of the bike is: " + value + "."); + testOutputHelper.WriteLine("The name of the bike is: " + value + "."); //REMOVE_START Assert.True(status); diff --git a/tests/Doc/StringSnippets.cs b/tests/Doc/StringSnippets.cs index eaa269ce..c79de0fe 100644 --- a/tests/Doc/StringSnippets.cs +++ b/tests/Doc/StringSnippets.cs @@ -6,11 +6,18 @@ using NRedisStack.Tests; using StackExchange.Redis; -namespace NRedisStack.Doc; +namespace Doc; [Collection("DocsTests")] //REMOVE_END public class StringSnippets { + private readonly ITestOutputHelper testOutputHelper; + + public StringSnippets(ITestOutputHelper testOutputHelper) + { + this.testOutputHelper = testOutputHelper; + } + //REMOVE_START [SkipIfRedis(Is.OSSCluster)] //REMOVE_END @@ -27,9 +34,9 @@ public void run() // STEP_START set_get var res1 = db.StringSet("bike:1", "Deimos"); - Console.WriteLine(res1); // true + testOutputHelper.WriteLine(res1.ToString()); // true var res2 = db.StringGet("bike:1"); - Console.WriteLine(res2); // Deimos + testOutputHelper.WriteLine(res2); // Deimos // STEP_END //REMOVE_START @@ -39,10 +46,10 @@ public void run() //STEP_START setnx_xx var res3 = db.StringSet("bike:1", "bike", when: When.NotExists); - Console.WriteLine(res3); // false - Console.WriteLine(db.StringGet("bike:1")); + testOutputHelper.WriteLine(res3.ToString()); // false + testOutputHelper.WriteLine(db.StringGet("bike:1")); var res4 = db.StringSet("bike:1", "bike", when: When.Exists); - Console.WriteLine(res4); // true + testOutputHelper.WriteLine(res4.ToString()); // true //STEP_END //REMOVE_START @@ -55,9 +62,9 @@ public void run() { new ("bike:1", "Deimos"), new("bike:2", "Ares"), new("bike:3", "Vanth") }); - Console.WriteLine(res5); + testOutputHelper.WriteLine(res5.ToString()); var res6 = db.StringGet(new RedisKey[] { "bike:1", "bike:2", "bike:3" }); - Console.WriteLine(res6); + testOutputHelper.WriteLine(res6.ToString()); //STEP_END //REMOVE_START @@ -68,9 +75,9 @@ public void run() //STEP_START incr db.StringSet("total_crashes", 0); var res7 = db.StringIncrement("total_crashes"); - Console.WriteLine(res7); // 1 + testOutputHelper.WriteLine(res7.ToString()); // 1 var res8 = db.StringIncrement("total_crashes", 10); - Console.WriteLine(res8); + testOutputHelper.WriteLine(res8.ToString()); //STEP_END //REMOVE_START From 97d01aaacf6e7d128d87ff56a3327bc535b14aa4 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Wed, 14 Feb 2024 11:31:07 +0200 Subject: [PATCH 41/57] fix CoreCommand file --- src/NRedisStack/CoreCommands/CoreCommands.cs | 56 -------------------- 1 file changed, 56 deletions(-) diff --git a/src/NRedisStack/CoreCommands/CoreCommands.cs b/src/NRedisStack/CoreCommands/CoreCommands.cs index 549e9093..5c0827da 100644 --- a/src/NRedisStack/CoreCommands/CoreCommands.cs +++ b/src/NRedisStack/CoreCommands/CoreCommands.cs @@ -175,59 +175,3 @@ public static bool ClientSetInfo(this IDatabase db, SetInfoAttr attr, string val return BzPopMax(db, new[] { key }, timeout); } } - -/// -/// The BZMPOP command. -///

-/// Removes and returns up to entries from the first non-empty sorted set in -/// . If none of the sets contain elements, the call blocks on the server until elements -/// become available or the given passes. A of 0 -/// means to wait indefinitely server-side. Returns null if the server timeout expires. -///

-/// When using this, pay attention to the timeout configured on the , which -/// by default can be too small, in which case you want to increase it: -/// -/// ConfigurationOptions configurationOptions = new ConfigurationOptions(); -/// configurationOptions.SyncTimeout = 120000; // set a meaningful value here -/// configurationOptions.EndPoints.Add("localhost"); -/// ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(configurationOptions); -/// -/// If the connection multiplexer timeout expires, a StackExchange.Redis.RedisTimeoutException will be -/// thrown. -///

-/// This is an extension method added to the class, for convenience. -///

-/// The class where this extension method is applied. -/// Server-side timeout for the wait. A value of 0 means to wait indefinitely. -/// The keys to check. -/// Specify from which end of the sorted set to pop values. If set to MinMaxModifier.Min -/// then the minimum elements will be popped, otherwise the maximum values. -/// The maximum number of records to pop out. If set to null then the server default -/// will be used. -/// A collection of sorted set entries paired with their scores, together with the key they were popped -/// from, or null if the server timeout expires. -/// -public static Tuple>? BzmPop(this IDatabase db, int timeout, RedisKey[] keys, MinMaxModifier minMaxModifier, long? count = null) -{ - var command = CoreCommandBuilder.BzmPop(timeout, keys, minMaxModifier, count); - return db.Execute(command).ToSortedSetPopResult(); -} - -/// -/// Syntactic sugar for , -/// where only one key is used. -/// -/// The class where this extension method is applied. -/// Server-side timeout for the wait. A value of 0 means to wait indefinitely. -/// The key to check. -/// Specify from which end of the sorted set to pop values. If set to MinMaxModifier.Min -/// then the minimum elements will be popped, otherwise the maximum values. -/// The maximum number of records to pop out. If set to null then the server default -/// will be used. -/// A collection of sorted set entries paired with their scores, together with the key they were popped -/// from, or null if the server timeout expires. -/// -public static Tuple>? BzmPop(this IDatabase db, int timeout, RedisKey key, MinMaxModifier minMaxModifier, long? count = null) -{ - return BzmPop(db, timeout, new[] { key }, minMaxModifier, count); -} From 83081104ed26fe0aa9559f759e6acd9dd0fff367 Mon Sep 17 00:00:00 2001 From: nima nikoonazar Date: Sun, 25 Feb 2024 18:01:01 +0330 Subject: [PATCH 42/57] Fix bug for build Doc Tests and return to orginal version beacuse the old version of .net doesnt support test console for xunit and its failed --- tests/Doc/HashExample.cs | 35 +++++++++++----------------- tests/Doc/SearchQuickstartExample.cs | 19 +++++---------- tests/Doc/SetGetExample.cs | 10 ++------ tests/Doc/StringSnippets.cs | 25 +++++++------------- 4 files changed, 31 insertions(+), 58 deletions(-) diff --git a/tests/Doc/HashExample.cs b/tests/Doc/HashExample.cs index 7be9202c..10c108cd 100644 --- a/tests/Doc/HashExample.cs +++ b/tests/Doc/HashExample.cs @@ -10,13 +10,6 @@ namespace Doc; //REMOVE_END public class HashExample { - private readonly ITestOutputHelper testOutputHelper; - - public HashExample(ITestOutputHelper testOutputHelper) - { - this.testOutputHelper = testOutputHelper; - } - [SkipIfRedis(Is.OSSCluster)] public void run() { @@ -33,20 +26,20 @@ public void run() new HashEntry("price", 4972) }); - testOutputHelper.WriteLine("Hash Created"); + Console.WriteLine("Hash Created"); // Hash Created var model = db.HashGet("bike:1", "model"); - testOutputHelper.WriteLine($"Model: {model}"); + Console.WriteLine($"Model: {model}"); // Model: Deimos var price = db.HashGet("bike:1", "price"); - testOutputHelper.WriteLine($"Price: {price}"); + Console.WriteLine($"Price: {price}"); // Price: 4972 var bike = db.HashGetAll("bike:1"); - testOutputHelper.WriteLine("bike:1"); - testOutputHelper.WriteLine(string.Join("\n", bike.Select(b => $"{b.Name}: {b.Value}"))); + Console.WriteLine("bike:1"); + Console.WriteLine(string.Join("\n", bike.Select(b => $"{b.Name}: {b.Value}"))); // Bike:1: // model: Deimos // brand: Ergonom @@ -62,7 +55,7 @@ public void run() //STEP_START hmget var values = db.HashGet("bike:1", new RedisValue[] { "model", "price" }); - testOutputHelper.WriteLine(string.Join(" ", values)); + Console.WriteLine(string.Join(" ", values)); // Deimos 4972 //REMOVE_START Assert.Equal("Deimos", values[0]); @@ -72,14 +65,14 @@ public void run() //STEP_START hincrby var newPrice = db.HashIncrement("bike:1", "price", 100); - testOutputHelper.WriteLine($"New price: {newPrice}"); + Console.WriteLine($"New price: {newPrice}"); //REMOVE_START Assert.Equal(5072, newPrice); //REMOVE_END // New price: 5072 newPrice = db.HashIncrement("bike:1", "price", -100); - testOutputHelper.WriteLine($"New price: {newPrice}"); + Console.WriteLine($"New price: {newPrice}"); //REMOVE_START Assert.Equal(4972, newPrice); //REMOVE_END @@ -88,42 +81,42 @@ public void run() //STEP_START incrby_get_mget var rides = db.HashIncrement("bike:1", "rides"); - testOutputHelper.WriteLine($"Rides: {rides}"); + Console.WriteLine($"Rides: {rides}"); //REMOVE_START Assert.Equal(1, rides); //REMOVE_END // Rides: 1 rides = db.HashIncrement("bike:1", "rides"); - testOutputHelper.WriteLine($"Rides: {rides}"); + Console.WriteLine($"Rides: {rides}"); //REMOVE_START Assert.Equal(2, rides); //REMOVE_END // Rides: 2 rides = db.HashIncrement("bike:1", "rides"); - testOutputHelper.WriteLine($"Rides: {rides}"); + Console.WriteLine($"Rides: {rides}"); //REMOVE_START Assert.Equal(3, rides); //REMOVE_END // Rides: 3 var crashes = db.HashIncrement("bike:1", "crashes"); - testOutputHelper.WriteLine($"Crashes: {crashes}"); + Console.WriteLine($"Crashes: {crashes}"); //REMOVE_START Assert.Equal(1, crashes); //REMOVE_END // Crashes: 1 var owners = db.HashIncrement("bike:1", "owners"); - testOutputHelper.WriteLine($"Owners: {owners}"); + Console.WriteLine($"Owners: {owners}"); //REMOVE_START Assert.Equal(1, owners); //REMOVE_END // Owners: 1 var stats = db.HashGet("bike:1", new RedisValue[] { "crashes", "owners" }); - testOutputHelper.WriteLine($"Bike stats: crashes={stats[0]}, owners={stats[1]}"); + Console.WriteLine($"Bike stats: crashes={stats[0]}, owners={stats[1]}"); //REMOVE_START Assert.Equal(1, stats[0]); Assert.Equal(1, stats[1]); diff --git a/tests/Doc/SearchQuickstartExample.cs b/tests/Doc/SearchQuickstartExample.cs index aa6ae29c..c7a1f5b9 100644 --- a/tests/Doc/SearchQuickstartExample.cs +++ b/tests/Doc/SearchQuickstartExample.cs @@ -13,13 +13,6 @@ namespace Doc; // REMOVE_END public class SearchQuickstartExample { - private readonly ITestOutputHelper testOutputHelper; - - public SearchQuickstartExample(ITestOutputHelper testOutputHelper) - { - this.testOutputHelper = testOutputHelper; - } - [SkipIfRedis(Is.OSSCluster)] public void run() { @@ -220,7 +213,7 @@ public void run() // STEP_START wildcard_query var query1 = new Query("*"); var res1 = ft.Search("idx:bicycle", query1).Documents; - testOutputHelper.WriteLine(string.Join("\n", res1.Count())); + Console.WriteLine(string.Join("\n", res1.Count())); // Prints: Documents found: 10 // STEP_END // REMOVE_START @@ -230,7 +223,7 @@ public void run() // STEP_START query_single_term var query2 = new Query("@Model:Jigger"); var res2 = ft.Search("idx:bicycle", query2).Documents; - testOutputHelper.WriteLine(string.Join("\n", res2.Select(x => x["json"]))); + Console.WriteLine(string.Join("\n", res2.Select(x => x["json"]))); // Prints: {"Brand":"Moore PLC","Model":"Award Race","Price":3790.76, // "Description":"This olive folding bike features a carbon frame // and 27.5 inch wheels. This folding bike is perfect for compact @@ -244,7 +237,7 @@ public void run() // STEP_START query_single_term_and_num_range var query3 = new Query("basic @Price:[500 1000]"); var res3 = ft.Search("idx:bicycle", query3).Documents; - testOutputHelper.WriteLine(string.Join("\n", res3.Select(x => x["json"]))); + Console.WriteLine(string.Join("\n", res3.Select(x => x["json"]))); // Prints: {"Brand":"Moore PLC","Model":"Award Race","Price":3790.76, // "Description":"This olive folding bike features a carbon frame // and 27.5 inch wheels. This folding bike is perfect for compact @@ -258,7 +251,7 @@ public void run() // STEP_START query_exact_matching var query4 = new Query("@Brand:\"Noka Bikes\""); var res4 = ft.Search("idx:bicycle", query4).Documents; - testOutputHelper.WriteLine(string.Join("\n", res4.Select(x => x["json"]))); + Console.WriteLine(string.Join("\n", res4.Select(x => x["json"]))); // Prints: {"Brand":"Moore PLC","Model":"Award Race","Price":3790.76, // "Description":"This olive folding bike features a carbon frame // and 27.5 inch wheels. This folding bike is perfect for compact @@ -272,7 +265,7 @@ public void run() // STEP_START query_single_term_limit_fields var query5 = new Query("@Model:Jigger").ReturnFields("Price"); var res5 = ft.Search("idx:bicycle", query5).Documents; - testOutputHelper.WriteLine(res5.First()["Price"]); + Console.WriteLine(res5.First()["Price"]); // Prints: 270 // STEP_END // REMOVE_START @@ -288,7 +281,7 @@ public void run() for (var i = 0; i < result.TotalResults; i++) { var row = result.GetRow(i); - testOutputHelper.WriteLine($"{row["Condition"]} - {row["Count"]}"); + Console.WriteLine($"{row["Condition"]} - {row["Count"]}"); } // Prints: diff --git a/tests/Doc/SetGetExample.cs b/tests/Doc/SetGetExample.cs index 9d5aa431..3d9af1e2 100644 --- a/tests/Doc/SetGetExample.cs +++ b/tests/Doc/SetGetExample.cs @@ -10,12 +10,6 @@ namespace Doc; //REMOVE_END public class SetGetExample { - private readonly ITestOutputHelper testOutputHelper; - - public SetGetExample(ITestOutputHelper testOutputHelper) - { - this.testOutputHelper = testOutputHelper; - } [SkipIfRedis(Is.OSSCluster)] public void run() @@ -27,12 +21,12 @@ public void run() bool status = db.StringSet("bike:1", "Process 134"); if (status) - testOutputHelper.WriteLine("Successfully added a bike."); + Console.WriteLine("Successfully added a bike."); var value = db.StringGet("bike:1"); if (value.HasValue) - testOutputHelper.WriteLine("The name of the bike is: " + value + "."); + Console.WriteLine("The name of the bike is: " + value + "."); //REMOVE_START Assert.True(status); diff --git a/tests/Doc/StringSnippets.cs b/tests/Doc/StringSnippets.cs index c79de0fe..0386c7d4 100644 --- a/tests/Doc/StringSnippets.cs +++ b/tests/Doc/StringSnippets.cs @@ -11,13 +11,6 @@ namespace Doc; //REMOVE_END public class StringSnippets { - private readonly ITestOutputHelper testOutputHelper; - - public StringSnippets(ITestOutputHelper testOutputHelper) - { - this.testOutputHelper = testOutputHelper; - } - //REMOVE_START [SkipIfRedis(Is.OSSCluster)] //REMOVE_END @@ -34,9 +27,9 @@ public void run() // STEP_START set_get var res1 = db.StringSet("bike:1", "Deimos"); - testOutputHelper.WriteLine(res1.ToString()); // true + Console.WriteLine(res1.ToString()); // true var res2 = db.StringGet("bike:1"); - testOutputHelper.WriteLine(res2); // Deimos + Console.WriteLine(res2); // Deimos // STEP_END //REMOVE_START @@ -46,10 +39,10 @@ public void run() //STEP_START setnx_xx var res3 = db.StringSet("bike:1", "bike", when: When.NotExists); - testOutputHelper.WriteLine(res3.ToString()); // false - testOutputHelper.WriteLine(db.StringGet("bike:1")); + Console.WriteLine(res3.ToString()); // false + Console.WriteLine(db.StringGet("bike:1")); var res4 = db.StringSet("bike:1", "bike", when: When.Exists); - testOutputHelper.WriteLine(res4.ToString()); // true + Console.WriteLine(res4.ToString()); // true //STEP_END //REMOVE_START @@ -62,9 +55,9 @@ public void run() { new ("bike:1", "Deimos"), new("bike:2", "Ares"), new("bike:3", "Vanth") }); - testOutputHelper.WriteLine(res5.ToString()); + Console.WriteLine(res5.ToString()); var res6 = db.StringGet(new RedisKey[] { "bike:1", "bike:2", "bike:3" }); - testOutputHelper.WriteLine(res6.ToString()); + Console.WriteLine(res6.ToString()); //STEP_END //REMOVE_START @@ -75,9 +68,9 @@ public void run() //STEP_START incr db.StringSet("total_crashes", 0); var res7 = db.StringIncrement("total_crashes"); - testOutputHelper.WriteLine(res7.ToString()); // 1 + Console.WriteLine(res7.ToString()); // 1 var res8 = db.StringIncrement("total_crashes", 10); - testOutputHelper.WriteLine(res8.ToString()); + Console.WriteLine(res8.ToString()); //STEP_END //REMOVE_START From 389bcf6155af381f518aae3fc26ccabfad579c1f Mon Sep 17 00:00:00 2001 From: shacharPash Date: Sun, 25 Feb 2024 18:37:44 +0200 Subject: [PATCH 43/57] fix error --- src/NRedisStack/CoreCommands/CoreCommands.cs | 668 +++++++++---------- src/NRedisStack/Search/AggregationResult.cs | 2 +- 2 files changed, 335 insertions(+), 335 deletions(-) diff --git a/src/NRedisStack/CoreCommands/CoreCommands.cs b/src/NRedisStack/CoreCommands/CoreCommands.cs index 4ea02ffb..8ceeb20d 100644 --- a/src/NRedisStack/CoreCommands/CoreCommands.cs +++ b/src/NRedisStack/CoreCommands/CoreCommands.cs @@ -21,353 +21,353 @@ public static bool ClientSetInfo(this IDatabase db, SetInfoAttr attr, string val return db.Execute(CoreCommandBuilder.ClientSetInfo(attr, value)).OKtoBoolean(); } - /// - /// The BZMPOP command. - ///

- /// Removes and returns up to entries from the first non-empty sorted set in - /// . If none of the sets contain elements, the call blocks on the server until elements - /// become available, or the given expires. A of 0 - /// means to wait indefinitely server-side. Returns null if the server timeout expires. - ///

- /// When using this, pay attention to the timeout configured in the client, on the - /// , which by default can be too small: - /// - /// ConfigurationOptions configurationOptions = new ConfigurationOptions(); - /// configurationOptions.SyncTimeout = 120000; // set a meaningful value here - /// configurationOptions.EndPoints.Add("localhost"); - /// ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(configurationOptions); - /// - /// If the connection multiplexer timeout expires in the client, a StackExchange.Redis.RedisTimeoutException - /// is thrown. - ///

- /// This is an extension method added to the class, for convenience. - ///

- /// The class where this extension method is applied. - /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. - /// The keys to check. - /// Specify from which end of the sorted set to pop values. If set to MinMaxModifier.Min - /// then the minimum elements will be popped, otherwise the maximum values. - /// The maximum number of records to pop out. If set to null then the server default - /// will be used. - /// A collection of sorted set entries paired with their scores, together with the key they were popped - /// from, or null if the server timeout expires. - /// - public static Tuple>? BZMPop(this IDatabase db, double timeout, RedisKey[] keys, MinMaxModifier minMaxModifier, long? count = null) - { - var command = CoreCommandBuilder.BZMPop(timeout, keys, minMaxModifier, count); - return db.Execute(command).ToSortedSetPopResults(); - } + /// + /// The BZMPOP command. + ///

+ /// Removes and returns up to entries from the first non-empty sorted set in + /// . If none of the sets contain elements, the call blocks on the server until elements + /// become available, or the given expires. A of 0 + /// means to wait indefinitely server-side. Returns null if the server timeout expires. + ///

+ /// When using this, pay attention to the timeout configured in the client, on the + /// , which by default can be too small: + /// + /// ConfigurationOptions configurationOptions = new ConfigurationOptions(); + /// configurationOptions.SyncTimeout = 120000; // set a meaningful value here + /// configurationOptions.EndPoints.Add("localhost"); + /// ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(configurationOptions); + /// + /// If the connection multiplexer timeout expires in the client, a StackExchange.Redis.RedisTimeoutException + /// is thrown. + ///

+ /// This is an extension method added to the class, for convenience. + ///

+ /// The class where this extension method is applied. + /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. + /// The keys to check. + /// Specify from which end of the sorted set to pop values. If set to MinMaxModifier.Min + /// then the minimum elements will be popped, otherwise the maximum values. + /// The maximum number of records to pop out. If set to null then the server default + /// will be used. + /// A collection of sorted set entries paired with their scores, together with the key they were popped + /// from, or null if the server timeout expires. + /// + public static Tuple>? BZMPop(this IDatabase db, double timeout, RedisKey[] keys, MinMaxModifier minMaxModifier, long? count = null) + { + var command = CoreCommandBuilder.BZMPop(timeout, keys, minMaxModifier, count); + return db.Execute(command).ToSortedSetPopResults(); + } - /// - /// Syntactic sugar for - /// , - /// where only one key is used. - /// - /// The class where this extension method is applied. - /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. - /// The key to check. - /// Specify from which end of the sorted set to pop values. If set to MinMaxModifier.Min - /// then the minimum elements will be popped, otherwise the maximum values. - /// The maximum number of records to pop out. If set to null then the server default - /// will be used. - /// A collection of sorted set entries paired with their scores, together with the key they were popped - /// from, or null if the server timeout expires. - /// - public static Tuple>? BZMPop(this IDatabase db, double timeout, RedisKey key, MinMaxModifier minMaxModifier, long? count = null) - { - return BZMPop(db, timeout, new[] { key }, minMaxModifier, count); - } + /// + /// Syntactic sugar for + /// , + /// where only one key is used. + /// + /// The class where this extension method is applied. + /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. + /// The key to check. + /// Specify from which end of the sorted set to pop values. If set to MinMaxModifier.Min + /// then the minimum elements will be popped, otherwise the maximum values. + /// The maximum number of records to pop out. If set to null then the server default + /// will be used. + /// A collection of sorted set entries paired with their scores, together with the key they were popped + /// from, or null if the server timeout expires. + /// + public static Tuple>? BZMPop(this IDatabase db, double timeout, RedisKey key, MinMaxModifier minMaxModifier, long? count = null) + { + return BZMPop(db, timeout, new[] { key }, minMaxModifier, count); + } - /// - /// The BZPOPMIN command. - ///

- /// Removes and returns the entry with the smallest score from the first non-empty sorted set in - /// . If none of the sets contain elements, the call blocks on the server until elements - /// become available, or the given expires. A of 0 - /// means to wait indefinitely server-side. Returns null if the server timeout expires. - ///

- /// When using this, pay attention to the timeout configured in the client, on the - /// , which by default can be too small: - /// - /// ConfigurationOptions configurationOptions = new ConfigurationOptions(); - /// configurationOptions.SyncTimeout = 120000; // set a meaningful value here - /// configurationOptions.EndPoints.Add("localhost"); - /// ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(configurationOptions); - /// - /// If the connection multiplexer timeout expires in the client, a StackExchange.Redis.RedisTimeoutException - /// is thrown. - ///

- /// This is an extension method added to the class, for convenience. - ///

- /// The class where this extension method is applied. - /// The keys to check. - /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. - /// A sorted set entry paired with its score, together with the key it was popped from, or null - /// if the server timeout expires. - /// - public static Tuple? BZPopMin(this IDatabase db, RedisKey[] keys, double timeout) - { - var command = CoreCommandBuilder.BZPopMin(keys, timeout); - return db.Execute(command).ToSortedSetPopResult(); - } + /// + /// The BZPOPMIN command. + ///

+ /// Removes and returns the entry with the smallest score from the first non-empty sorted set in + /// . If none of the sets contain elements, the call blocks on the server until elements + /// become available, or the given expires. A of 0 + /// means to wait indefinitely server-side. Returns null if the server timeout expires. + ///

+ /// When using this, pay attention to the timeout configured in the client, on the + /// , which by default can be too small: + /// + /// ConfigurationOptions configurationOptions = new ConfigurationOptions(); + /// configurationOptions.SyncTimeout = 120000; // set a meaningful value here + /// configurationOptions.EndPoints.Add("localhost"); + /// ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(configurationOptions); + /// + /// If the connection multiplexer timeout expires in the client, a StackExchange.Redis.RedisTimeoutException + /// is thrown. + ///

+ /// This is an extension method added to the class, for convenience. + ///

+ /// The class where this extension method is applied. + /// The keys to check. + /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. + /// A sorted set entry paired with its score, together with the key it was popped from, or null + /// if the server timeout expires. + /// + public static Tuple? BZPopMin(this IDatabase db, RedisKey[] keys, double timeout) + { + var command = CoreCommandBuilder.BZPopMin(keys, timeout); + return db.Execute(command).ToSortedSetPopResult(); + } - /// - /// Syntactic sugar for , - /// where only one key is used. - /// - /// The class where this extension method is applied. - /// The key to check. - /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. - /// A sorted set entry paired with its score, together with the key it was popped from, or null - /// if the server timeout expires. - /// - public static Tuple? BZPopMin(this IDatabase db, RedisKey key, double timeout) - { - return BZPopMin(db, new[] { key }, timeout); - } + /// + /// Syntactic sugar for , + /// where only one key is used. + /// + /// The class where this extension method is applied. + /// The key to check. + /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. + /// A sorted set entry paired with its score, together with the key it was popped from, or null + /// if the server timeout expires. + /// + public static Tuple? BZPopMin(this IDatabase db, RedisKey key, double timeout) + { + return BZPopMin(db, new[] { key }, timeout); + } - /// - /// The BZPOPMAX command. - ///

- /// Removes and returns the entry with the highest score from the first non-empty sorted set in - /// . If none of the sets contain elements, the call blocks on the server until elements - /// become available, or the given expires. A of 0 - /// means to wait indefinitely server-side. Returns null if the server timeout expires. - ///

- /// When using this, pay attention to the timeout configured in the client, on the - /// , which by default can be too small: - /// - /// ConfigurationOptions configurationOptions = new ConfigurationOptions(); - /// configurationOptions.SyncTimeout = 120000; // set a meaningful value here - /// configurationOptions.EndPoints.Add("localhost"); - /// ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(configurationOptions); - /// - /// If the connection multiplexer timeout expires in the client, a StackExchange.Redis.RedisTimeoutException - /// is thrown. - ///

- /// This is an extension method added to the class, for convenience. - ///

- /// The class where this extension method is applied. - /// The keys to check. - /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. - /// A sorted set entry paired with its score, together with the key it was popped from, or null - /// if the server timeout expires. - /// - public static Tuple? BZPopMax(this IDatabase db, RedisKey[] keys, double timeout) - { - var command = CoreCommandBuilder.BZPopMax(keys, timeout); - return db.Execute(command).ToSortedSetPopResult(); - } + /// + /// The BZPOPMAX command. + ///

+ /// Removes and returns the entry with the highest score from the first non-empty sorted set in + /// . If none of the sets contain elements, the call blocks on the server until elements + /// become available, or the given expires. A of 0 + /// means to wait indefinitely server-side. Returns null if the server timeout expires. + ///

+ /// When using this, pay attention to the timeout configured in the client, on the + /// , which by default can be too small: + /// + /// ConfigurationOptions configurationOptions = new ConfigurationOptions(); + /// configurationOptions.SyncTimeout = 120000; // set a meaningful value here + /// configurationOptions.EndPoints.Add("localhost"); + /// ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(configurationOptions); + /// + /// If the connection multiplexer timeout expires in the client, a StackExchange.Redis.RedisTimeoutException + /// is thrown. + ///

+ /// This is an extension method added to the class, for convenience. + ///

+ /// The class where this extension method is applied. + /// The keys to check. + /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. + /// A sorted set entry paired with its score, together with the key it was popped from, or null + /// if the server timeout expires. + /// + public static Tuple? BZPopMax(this IDatabase db, RedisKey[] keys, double timeout) + { + var command = CoreCommandBuilder.BZPopMax(keys, timeout); + return db.Execute(command).ToSortedSetPopResult(); + } - /// - /// Syntactic sugar for , - /// where only one key is used. - /// - /// The class where this extension method is applied. - /// The key to check. - /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. - /// A sorted set entry paired with its score, together with the key it was popped from, or null - /// if the server timeout expires. - /// - public static Tuple? BZPopMax(this IDatabase db, RedisKey key, double timeout) - { - return BZPopMax(db, new[] { key }, timeout); - } + /// + /// Syntactic sugar for , + /// where only one key is used. + /// + /// The class where this extension method is applied. + /// The key to check. + /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. + /// A sorted set entry paired with its score, together with the key it was popped from, or null + /// if the server timeout expires. + /// + public static Tuple? BZPopMax(this IDatabase db, RedisKey key, double timeout) + { + return BZPopMax(db, new[] { key }, timeout); + } - /// - /// The BLMPOP command. - ///

- /// Removes and returns up to entries from the first non-empty list in - /// . If none of the lists contain elements, the call blocks on the server until elements - /// become available, or the given expires. A of 0 - /// means to wait indefinitely server-side. Returns null if the server timeout expires. - ///

- /// When using this, pay attention to the timeout configured in the client, on the - /// , which by default can be too small: - /// - /// ConfigurationOptions configurationOptions = new ConfigurationOptions(); - /// configurationOptions.SyncTimeout = 120000; // set a meaningful value here - /// configurationOptions.EndPoints.Add("localhost"); - /// ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(configurationOptions); - /// - /// If the connection multiplexer timeout expires in the client, a StackExchange.Redis.RedisTimeoutException - /// is thrown. - ///

- /// This is an extension method added to the class, for convenience. - ///

- /// The class where this extension method is applied. - /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. - /// The keys to check. - /// Specify from which end of the list to pop values: left or right. - /// The maximum number of records to pop. If set to null then the server default - /// will be used. - /// A collection of values, together with the key they were popped from, or null if the - /// server timeout expires. - /// - public static Tuple>? BLMPop(this IDatabase db, double timeout, RedisKey[] keys, ListSide listSide, long? count = null) - { - var command = CoreCommandBuilder.BLMPop(timeout, keys, listSide, count); - return db.Execute(command).ToListPopResults(); - } + /// + /// The BLMPOP command. + ///

+ /// Removes and returns up to entries from the first non-empty list in + /// . If none of the lists contain elements, the call blocks on the server until elements + /// become available, or the given expires. A of 0 + /// means to wait indefinitely server-side. Returns null if the server timeout expires. + ///

+ /// When using this, pay attention to the timeout configured in the client, on the + /// , which by default can be too small: + /// + /// ConfigurationOptions configurationOptions = new ConfigurationOptions(); + /// configurationOptions.SyncTimeout = 120000; // set a meaningful value here + /// configurationOptions.EndPoints.Add("localhost"); + /// ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(configurationOptions); + /// + /// If the connection multiplexer timeout expires in the client, a StackExchange.Redis.RedisTimeoutException + /// is thrown. + ///

+ /// This is an extension method added to the class, for convenience. + ///

+ /// The class where this extension method is applied. + /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. + /// The keys to check. + /// Specify from which end of the list to pop values: left or right. + /// The maximum number of records to pop. If set to null then the server default + /// will be used. + /// A collection of values, together with the key they were popped from, or null if the + /// server timeout expires. + /// + public static Tuple>? BLMPop(this IDatabase db, double timeout, RedisKey[] keys, ListSide listSide, long? count = null) + { + var command = CoreCommandBuilder.BLMPop(timeout, keys, listSide, count); + return db.Execute(command).ToListPopResults(); + } - /// - /// Syntactic sugar for - /// , - /// where only one key is used. - /// - /// The class where this extension method is applied. - /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. - /// The key to check. - /// Specify from which end of the list to pop values: left or right. - /// The maximum number of records to pop. If set to null then the server default - /// will be used. - /// A collection of values, together with the key they were popped from, or null if the - /// server timeout expires. - /// - public static Tuple>? BLMPop(this IDatabase db, double timeout, RedisKey key, ListSide listSide, long? count = null) - { - return BLMPop(db, timeout, new[] { key }, listSide, count); - } + /// + /// Syntactic sugar for + /// , + /// where only one key is used. + /// + /// The class where this extension method is applied. + /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. + /// The key to check. + /// Specify from which end of the list to pop values: left or right. + /// The maximum number of records to pop. If set to null then the server default + /// will be used. + /// A collection of values, together with the key they were popped from, or null if the + /// server timeout expires. + /// + public static Tuple>? BLMPop(this IDatabase db, double timeout, RedisKey key, ListSide listSide, long? count = null) + { + return BLMPop(db, timeout, new[] { key }, listSide, count); + } - /// - /// The BLPOP command. - ///

- /// Removes and returns an entry from the head (left side) of the first non-empty list in . - /// If none of the lists contain elements, the call blocks on the server until elements - /// become available, or the given expires. A of 0 - /// means to wait indefinitely server-side. Returns null if the server timeout expires. - ///

- /// When using this, pay attention to the timeout configured in the client, on the - /// , which by default can be too small: - /// - /// ConfigurationOptions configurationOptions = new ConfigurationOptions(); - /// configurationOptions.SyncTimeout = 120000; // set a meaningful value here - /// configurationOptions.EndPoints.Add("localhost"); - /// ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(configurationOptions); - /// - /// If the connection multiplexer timeout expires in the client, a StackExchange.Redis.RedisTimeoutException - /// is thrown. - ///

- /// This is an extension method added to the class, for convenience. - ///

- /// The class where this extension method is applied. - /// The keys to check. - /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. - /// A value, together with the key it was popped from, or null if the server timeout - /// expires. - /// - public static Tuple? BLPop(this IDatabase db, RedisKey[] keys, double timeout) - { - var command = CoreCommandBuilder.BLPop(keys, timeout); - return db.Execute(command).ToListPopResult(); - } + /// + /// The BLPOP command. + ///

+ /// Removes and returns an entry from the head (left side) of the first non-empty list in . + /// If none of the lists contain elements, the call blocks on the server until elements + /// become available, or the given expires. A of 0 + /// means to wait indefinitely server-side. Returns null if the server timeout expires. + ///

+ /// When using this, pay attention to the timeout configured in the client, on the + /// , which by default can be too small: + /// + /// ConfigurationOptions configurationOptions = new ConfigurationOptions(); + /// configurationOptions.SyncTimeout = 120000; // set a meaningful value here + /// configurationOptions.EndPoints.Add("localhost"); + /// ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(configurationOptions); + /// + /// If the connection multiplexer timeout expires in the client, a StackExchange.Redis.RedisTimeoutException + /// is thrown. + ///

+ /// This is an extension method added to the class, for convenience. + ///

+ /// The class where this extension method is applied. + /// The keys to check. + /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. + /// A value, together with the key it was popped from, or null if the server timeout + /// expires. + /// + public static Tuple? BLPop(this IDatabase db, RedisKey[] keys, double timeout) + { + var command = CoreCommandBuilder.BLPop(keys, timeout); + return db.Execute(command).ToListPopResult(); + } - /// - /// Syntactic sugar for , - /// where only one key is used. - /// - /// The class where this extension method is applied. - /// The key to check. - /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. - /// A value, together with the key it was popped from, or null if the server timeout - /// expires. - /// - public static Tuple? BLPop(this IDatabase db, RedisKey key, double timeout) - { - return BLPop(db, new[] { key }, timeout); - } + /// + /// Syntactic sugar for , + /// where only one key is used. + /// + /// The class where this extension method is applied. + /// The key to check. + /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. + /// A value, together with the key it was popped from, or null if the server timeout + /// expires. + /// + public static Tuple? BLPop(this IDatabase db, RedisKey key, double timeout) + { + return BLPop(db, new[] { key }, timeout); + } - /// - /// The BRPOP command. - ///

- /// Removes and returns an entry from the tail (right side) of the first non-empty list in . - /// If none of the lists contain elements, the call blocks on the server until elements - /// become available, or the given expires. A of 0 - /// means to wait indefinitely server-side. Returns null if the server timeout expires. - ///

- /// When using this, pay attention to the timeout configured in the client, on the - /// , which by default can be too small: - /// - /// ConfigurationOptions configurationOptions = new ConfigurationOptions(); - /// configurationOptions.SyncTimeout = 120000; // set a meaningful value here - /// configurationOptions.EndPoints.Add("localhost"); - /// ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(configurationOptions); - /// - /// If the connection multiplexer timeout expires in the client, a StackExchange.Redis.RedisTimeoutException - /// is thrown. - ///

- /// This is an extension method added to the class, for convenience. - ///

- /// The class where this extension method is applied. - /// The keys to check. - /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. - /// A value, together with the key it was popped from, or null if the server timeout - /// expires. - /// - public static Tuple? BRPop(this IDatabase db, RedisKey[] keys, double timeout) - { - var command = CoreCommandBuilder.BRPop(keys, timeout); - return db.Execute(command).ToListPopResult(); - } + /// + /// The BRPOP command. + ///

+ /// Removes and returns an entry from the tail (right side) of the first non-empty list in . + /// If none of the lists contain elements, the call blocks on the server until elements + /// become available, or the given expires. A of 0 + /// means to wait indefinitely server-side. Returns null if the server timeout expires. + ///

+ /// When using this, pay attention to the timeout configured in the client, on the + /// , which by default can be too small: + /// + /// ConfigurationOptions configurationOptions = new ConfigurationOptions(); + /// configurationOptions.SyncTimeout = 120000; // set a meaningful value here + /// configurationOptions.EndPoints.Add("localhost"); + /// ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(configurationOptions); + /// + /// If the connection multiplexer timeout expires in the client, a StackExchange.Redis.RedisTimeoutException + /// is thrown. + ///

+ /// This is an extension method added to the class, for convenience. + ///

+ /// The class where this extension method is applied. + /// The keys to check. + /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. + /// A value, together with the key it was popped from, or null if the server timeout + /// expires. + /// + public static Tuple? BRPop(this IDatabase db, RedisKey[] keys, double timeout) + { + var command = CoreCommandBuilder.BRPop(keys, timeout); + return db.Execute(command).ToListPopResult(); + } - /// - /// Syntactic sugar for , - /// where only one key is used. - /// - /// The class where this extension method is applied. - /// The key to check. - /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. - /// A value, together with the key it was popped from, or null if the server timeout - /// expires. - /// - public static Tuple? BRPop(this IDatabase db, RedisKey key, double timeout) - { - return BRPop(db, new[] { key }, timeout); - } + /// + /// Syntactic sugar for , + /// where only one key is used. + /// + /// The class where this extension method is applied. + /// The key to check. + /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. + /// A value, together with the key it was popped from, or null if the server timeout + /// expires. + /// + public static Tuple? BRPop(this IDatabase db, RedisKey key, double timeout) + { + return BRPop(db, new[] { key }, timeout); + } - /// - /// The BLMOVE command. - ///

- /// Atomically returns and removes the first or last element of the list stored at - /// (depending on the value of ), and pushes the element as the first or last - /// element of the list stored at (depending on the value of - /// ). - ///

- /// This is an extension method added to the class, for convenience. - ///

- /// The class where this extension method is applied. - /// The key of the source list. - /// The key of the destination list. - /// What side of the list to remove from. - /// What side of the list to move to. - /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. - /// The element being popped and pushed, or null if the server timeout expires. - /// - public static RedisValue? BLMove(this IDatabase db, RedisKey source, RedisKey destination, ListSide sourceSide, ListSide destinationSide, double timeout) - { - var command = CoreCommandBuilder.BLMove(source, destination, sourceSide, destinationSide, timeout); - return db.Execute(command).ToRedisValue(); - } + /// + /// The BLMOVE command. + ///

+ /// Atomically returns and removes the first or last element of the list stored at + /// (depending on the value of ), and pushes the element as the first or last + /// element of the list stored at (depending on the value of + /// ). + ///

+ /// This is an extension method added to the class, for convenience. + ///

+ /// The class where this extension method is applied. + /// The key of the source list. + /// The key of the destination list. + /// What side of the list to remove from. + /// What side of the list to move to. + /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. + /// The element being popped and pushed, or null if the server timeout expires. + /// + public static RedisValue? BLMove(this IDatabase db, RedisKey source, RedisKey destination, ListSide sourceSide, ListSide destinationSide, double timeout) + { + var command = CoreCommandBuilder.BLMove(source, destination, sourceSide, destinationSide, timeout); + return db.Execute(command).ToRedisValue(); + } - /// - /// The BRPOPLPUSH command. - ///

- /// Atomically returns and removes the last element (tail) of the list stored at source, and pushes the element - /// at the first element (head) of the list stored at destination. - ///

- /// This is an extension method added to the class, for convenience. - ///

- /// The class where this extension method is applied. - /// The key of the source list. - /// The key of the destination list. - /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. - /// The element being popped and pushed, or null if the server timeout expires. - /// - public static RedisValue? BRPopLPush(this IDatabase db, RedisKey source, RedisKey destination, double timeout) - { - var command = CoreCommandBuilder.BRPopLPush(source, destination, timeout); - return db.Execute(command).ToRedisValue(); - } + /// + /// The BRPOPLPUSH command. + ///

+ /// Atomically returns and removes the last element (tail) of the list stored at source, and pushes the element + /// at the first element (head) of the list stored at destination. + ///

+ /// This is an extension method added to the class, for convenience. + ///

+ /// The class where this extension method is applied. + /// The key of the source list. + /// The key of the destination list. + /// Server-side timeout for the wait. A value of 0 means to wait indefinitely. + /// The element being popped and pushed, or null if the server timeout expires. + /// + public static RedisValue? BRPopLPush(this IDatabase db, RedisKey source, RedisKey destination, double timeout) + { + var command = CoreCommandBuilder.BRPopLPush(source, destination, timeout); + return db.Execute(command).ToRedisValue(); } } + diff --git a/src/NRedisStack/Search/AggregationResult.cs b/src/NRedisStack/Search/AggregationResult.cs index c3f55f1c..34ace0f3 100644 --- a/src/NRedisStack/Search/AggregationResult.cs +++ b/src/NRedisStack/Search/AggregationResult.cs @@ -37,7 +37,7 @@ internal AggregationResult(RedisResult result, long cursorId = -1) CursorId = cursorId; } - + /// /// takes a Redis multi-bulk array represented by a RedisResult[] and recursively processes its elements. /// For each element in the array, it checks if it's another multi-bulk array, and if so, it recursively calls itself. From ecf7ae0bf264c3ac2809debf837a1b55cdde34ba Mon Sep 17 00:00:00 2001 From: nima nikoonazar Date: Sun, 3 Mar 2024 22:56:17 +0330 Subject: [PATCH 44/57] Roleback ' List args = [key];' to previous version becuase the old version of .net does not support the .net 8 syntax --- src/NRedisStack/Bloom/BloomCommandBuilder.cs | 2 +- src/NRedisStack/CountMinSketch/CmsCommandBuilder.cs | 6 +++--- src/NRedisStack/Json/JsonCommandBuilder.cs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/NRedisStack/Bloom/BloomCommandBuilder.cs b/src/NRedisStack/Bloom/BloomCommandBuilder.cs index 9af649e2..49544b7c 100644 --- a/src/NRedisStack/Bloom/BloomCommandBuilder.cs +++ b/src/NRedisStack/Bloom/BloomCommandBuilder.cs @@ -47,7 +47,7 @@ public static SerializedCommand MAdd(RedisKey key, params RedisValue[] items) if (items.Length < 1) throw new ArgumentOutOfRangeException(nameof(items)); - List args = [key]; + List args = new List { key }; args.AddRange(items.Cast()); return new SerializedCommand(BF.MADD, args); diff --git a/src/NRedisStack/CountMinSketch/CmsCommandBuilder.cs b/src/NRedisStack/CountMinSketch/CmsCommandBuilder.cs index d5025ce9..e9e0819b 100644 --- a/src/NRedisStack/CountMinSketch/CmsCommandBuilder.cs +++ b/src/NRedisStack/CountMinSketch/CmsCommandBuilder.cs @@ -16,7 +16,7 @@ public static SerializedCommand IncrBy(RedisKey key, Tuple[] i if (itemIncrements.Length < 1) throw new ArgumentOutOfRangeException(nameof(itemIncrements)); - List args = [key]; + List args = new List { key }; foreach (var pair in itemIncrements) { args.Add(pair.Item1); @@ -61,8 +61,8 @@ public static SerializedCommand Query(RedisKey key, params RedisValue[] items) if (items.Length < 1) throw new ArgumentOutOfRangeException(nameof(items)); - List args = [key]; - args.AddRange(items.Cast()); + List args = new List { key }; + foreach (var item in items) args.Add(item); return new SerializedCommand(CMS.QUERY, args); } diff --git a/src/NRedisStack/Json/JsonCommandBuilder.cs b/src/NRedisStack/Json/JsonCommandBuilder.cs index 07a62368..c62c4570 100644 --- a/src/NRedisStack/Json/JsonCommandBuilder.cs +++ b/src/NRedisStack/Json/JsonCommandBuilder.cs @@ -144,7 +144,7 @@ public static SerializedCommand Del(RedisKey key, string? path = null) public static SerializedCommand Get(RedisKey key, RedisValue? indent = null, RedisValue? newLine = null, RedisValue? space = null, RedisValue? path = null) { - List args = [key]; + List args = new List { key }; if (indent != null) { @@ -175,7 +175,7 @@ public static SerializedCommand Get(RedisKey key, RedisValue? indent = null, Red public static SerializedCommand Get(RedisKey key, string[] paths, RedisValue? indent = null, RedisValue? newLine = null, RedisValue? space = null) { - List args = [key]; + List args = new List() { key }; if (indent != null) { From 30ff30bb41e44c6a1d44759bb800ff0f33c25494 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Thu, 7 Mar 2024 14:29:08 +0200 Subject: [PATCH 45/57] fix compilation error --- src/NRedisStack/CoreCommands/CoreCommands.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/NRedisStack/CoreCommands/CoreCommands.cs b/src/NRedisStack/CoreCommands/CoreCommands.cs index bb325d14..9af50645 100644 --- a/src/NRedisStack/CoreCommands/CoreCommands.cs +++ b/src/NRedisStack/CoreCommands/CoreCommands.cs @@ -480,5 +480,4 @@ public static bool ClientSetInfo(this IDatabase db, SetInfoAttr attr, string val return result[0].Entries; } } -} From a3eb2323bd0bc5ed2b47529a6b194367b6f3c98d Mon Sep 17 00:00:00 2001 From: shacharPash Date: Thu, 7 Mar 2024 14:31:45 +0200 Subject: [PATCH 46/57] format --- src/NRedisStack/CountMinSketch/CmsCommandBuilder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NRedisStack/CountMinSketch/CmsCommandBuilder.cs b/src/NRedisStack/CountMinSketch/CmsCommandBuilder.cs index e9e0819b..80da7e79 100644 --- a/src/NRedisStack/CountMinSketch/CmsCommandBuilder.cs +++ b/src/NRedisStack/CountMinSketch/CmsCommandBuilder.cs @@ -16,7 +16,7 @@ public static SerializedCommand IncrBy(RedisKey key, Tuple[] i if (itemIncrements.Length < 1) throw new ArgumentOutOfRangeException(nameof(itemIncrements)); - List args = new List { key }; + List args = new List { key }; foreach (var pair in itemIncrements) { args.Add(pair.Item1); From d35f8665d7b72835c97cca832701ba2a2eeb1226 Mon Sep 17 00:00:00 2001 From: nima nikoonazar Date: Tue, 12 Mar 2024 21:43:06 +0330 Subject: [PATCH 47/57] Fix Indent and Solve Problem of old .net version with feature primary constructor in .net 8 --- src/NRedisStack/Bloom/BloomCommands.cs | 31 ++++--- src/NRedisStack/Bloom/BloomCommandsAsync.cs | 32 ++++--- src/NRedisStack/CountMinSketch/CmsCommands.cs | 24 +++-- .../CountMinSketch/CmsCommandsAsync.cs | 25 +++-- .../Json/DataTypes/KeyValuePath.cs | 15 ++- src/NRedisStack/Json/JsonCommands.cs | 65 +++++++------ src/NRedisStack/Json/JsonCommandsAsync.cs | 91 +++++++++++-------- 7 files changed, 176 insertions(+), 107 deletions(-) diff --git a/src/NRedisStack/Bloom/BloomCommands.cs b/src/NRedisStack/Bloom/BloomCommands.cs index a030a5e8..96a4e2c1 100644 --- a/src/NRedisStack/Bloom/BloomCommands.cs +++ b/src/NRedisStack/Bloom/BloomCommands.cs @@ -1,28 +1,36 @@ using NRedisStack.Bloom.DataTypes; using StackExchange.Redis; + namespace NRedisStack; -public class BloomCommands(IDatabase db) : BloomCommandsAsync(db), IBloomCommands +public class BloomCommands : BloomCommandsAsync, IBloomCommands { + private readonly IDatabase _db; + + public BloomCommands(IDatabase db) : base(db) + { + _db = db; + } + /// - public bool Add(RedisKey key, RedisValue item) => db.Execute(BloomCommandBuilder.Add(key, item)).ToString() == "1"; + public bool Add(RedisKey key, RedisValue item) => _db.Execute(BloomCommandBuilder.Add(key, item)).ToString() == "1"; /// public long Card(RedisKey key) { - return db.Execute(BloomCommandBuilder.Card(key)).ToLong(); + return _db.Execute(BloomCommandBuilder.Card(key)).ToLong(); } /// public bool Exists(RedisKey key, RedisValue item) { - return db.Execute(BloomCommandBuilder.Exists(key, item)).ToString() == "1"; + return _db.Execute(BloomCommandBuilder.Exists(key, item)).ToString() == "1"; } /// public BloomInformation Info(RedisKey key) { - return db.Execute(BloomCommandBuilder.Info(key)).ToBloomInfo(); + return _db.Execute(BloomCommandBuilder.Info(key)).ToBloomInfo(); } /// @@ -30,37 +38,38 @@ public bool[] Insert(RedisKey key, RedisValue[] items, int? capacity = null, double? error = null, int? expansion = null, bool nocreate = false, bool nonscaling = false) { - return db.Execute(BloomCommandBuilder.Insert(key, items, capacity, error, expansion, nocreate, nonscaling)).ToBooleanArray(); + return _db.Execute(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(); + return _db.Execute(BloomCommandBuilder.LoadChunk(key, iterator, data)).OKtoBoolean(); } /// public bool[] MAdd(RedisKey key, params RedisValue[] items) { - return db.Execute(BloomCommandBuilder.MAdd(key, items)).ToBooleanArray(); + return _db.Execute(BloomCommandBuilder.MAdd(key, items)).ToBooleanArray(); } /// public bool[] MExists(RedisKey key, RedisValue[] items) { - return db.Execute(BloomCommandBuilder.MExists(key, items)).ToBooleanArray(); + return _db.Execute(BloomCommandBuilder.MExists(key, items)).ToBooleanArray(); } /// public bool Reserve(RedisKey key, double errorRate, long capacity, int? expansion = null, bool nonscaling = false) { - return db.Execute(BloomCommandBuilder.Reserve(key, errorRate, capacity, expansion, nonscaling)).OKtoBoolean(); + return _db.Execute(BloomCommandBuilder.Reserve(key, errorRate, capacity, expansion, nonscaling)).OKtoBoolean(); } /// public Tuple ScanDump(RedisKey key, long iterator) { - return db.Execute(BloomCommandBuilder.ScanDump(key, iterator)).ToScanDumpTuple(); + return _db.Execute(BloomCommandBuilder.ScanDump(key, iterator)).ToScanDumpTuple(); } } \ No newline at end of file diff --git a/src/NRedisStack/Bloom/BloomCommandsAsync.cs b/src/NRedisStack/Bloom/BloomCommandsAsync.cs index 33d7afb5..11b92336 100644 --- a/src/NRedisStack/Bloom/BloomCommandsAsync.cs +++ b/src/NRedisStack/Bloom/BloomCommandsAsync.cs @@ -1,32 +1,40 @@ using NRedisStack.Bloom.DataTypes; using StackExchange.Redis; + namespace NRedisStack; -public class BloomCommandsAsync(IDatabaseAsync db) : IBloomCommandsAsync +public class BloomCommandsAsync : IBloomCommandsAsync { + private readonly IDatabaseAsync _db; + + public BloomCommandsAsync(IDatabaseAsync db) + { + _db = db; + } + /// public async Task AddAsync(RedisKey key, RedisValue item) { - return (await db.ExecuteAsync(BloomCommandBuilder.Add(key, item))).ToString() == "1"; + return (await _db.ExecuteAsync(BloomCommandBuilder.Add(key, item))).ToString() == "1"; } /// public async Task CardAsync(RedisKey key) { - return (await db.ExecuteAsync(BloomCommandBuilder.Card(key))).ToLong(); + 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"; + return (await _db.ExecuteAsync(BloomCommandBuilder.Exists(key, item))).ToString() == "1"; } /// public async Task InfoAsync(RedisKey key) { - var info = (await db.ExecuteAsync(BloomCommandBuilder.Info(key))); + var info = (await _db.ExecuteAsync(BloomCommandBuilder.Info(key))); return info.ToBloomInfo(); } @@ -35,37 +43,39 @@ public async Task InsertAsync(RedisKey key, RedisValue[] items, int? cap 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(); + 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(); + 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(); + 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(); + 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(); + 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(); + return (await _db.ExecuteAsync(BloomCommandBuilder.ScanDump(key, iterator))).ToScanDumpTuple(); } } \ No newline at end of file diff --git a/src/NRedisStack/CountMinSketch/CmsCommands.cs b/src/NRedisStack/CountMinSketch/CmsCommands.cs index 3a5c1206..a193cd0b 100644 --- a/src/NRedisStack/CountMinSketch/CmsCommands.cs +++ b/src/NRedisStack/CountMinSketch/CmsCommands.cs @@ -1,49 +1,57 @@ using NRedisStack.CountMinSketch.DataTypes; using StackExchange.Redis; + namespace NRedisStack; -public class CmsCommands(IDatabase db) : CmsCommandsAsync(db), ICmsCommands +public class CmsCommands : CmsCommandsAsync, ICmsCommands { + private readonly IDatabase _db; + + public CmsCommands(IDatabase db) : base(db) + { + _db = db; + } + /// public long IncrBy(RedisKey key, RedisValue item, long increment) { - return db.Execute(CmsCommandBuilder.IncrBy(key, item, increment)).ToLong(); + return _db.Execute(CmsCommandBuilder.IncrBy(key, item, increment)).ToLong(); } /// public long[] IncrBy(RedisKey key, Tuple[] itemIncrements) { - return db.Execute(CmsCommandBuilder.IncrBy(key, itemIncrements)).ToLongArray(); + return _db.Execute(CmsCommandBuilder.IncrBy(key, itemIncrements)).ToLongArray(); } /// public CmsInformation Info(RedisKey key) { - var info = db.Execute(CmsCommandBuilder.Info(key)); + var info = _db.Execute(CmsCommandBuilder.Info(key)); return info.ToCmsInfo(); } /// public bool InitByDim(RedisKey key, long width, long depth) { - return db.Execute(CmsCommandBuilder.InitByDim(key, width, depth)).OKtoBoolean(); + return _db.Execute(CmsCommandBuilder.InitByDim(key, width, depth)).OKtoBoolean(); } /// public bool InitByProb(RedisKey key, double error, double probability) { - return db.Execute(CmsCommandBuilder.InitByProb(key, error, probability)).OKtoBoolean(); + return _db.Execute(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(); + return _db.Execute(CmsCommandBuilder.Merge(destination, numKeys, source, weight)).OKtoBoolean(); } /// public long[] Query(RedisKey key, params RedisValue[] items) { - return db.Execute(CmsCommandBuilder.Query(key, items)).ToLongArray(); + return _db.Execute(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 index 489a0b0b..7927a153 100644 --- a/src/NRedisStack/CountMinSketch/CmsCommandsAsync.cs +++ b/src/NRedisStack/CountMinSketch/CmsCommandsAsync.cs @@ -1,50 +1,57 @@ using NRedisStack.CountMinSketch.DataTypes; using StackExchange.Redis; + namespace NRedisStack; -public class CmsCommandsAsync(IDatabaseAsync db) : ICmsCommandsAsync +public class CmsCommandsAsync : ICmsCommandsAsync { + private readonly 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(); + 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(); - + return (await _db.ExecuteAsync(CmsCommandBuilder.IncrBy(key, itemIncrements))).ToLongArray(); } /// public async Task InfoAsync(RedisKey key) { - var info = await db.ExecuteAsync(CmsCommandBuilder.Info(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(); + 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(); + 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(); + 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(); + return (await _db.ExecuteAsync(CmsCommandBuilder.Query(key, items))).ToLongArray(); } } \ No newline at end of file diff --git a/src/NRedisStack/Json/DataTypes/KeyValuePath.cs b/src/NRedisStack/Json/DataTypes/KeyValuePath.cs index 5487c451..302485bb 100644 --- a/src/NRedisStack/Json/DataTypes/KeyValuePath.cs +++ b/src/NRedisStack/Json/DataTypes/KeyValuePath.cs @@ -2,11 +2,18 @@ namespace NRedisStack.Json.DataTypes; -public struct KeyPathValue(string key, string path, object value) +public struct KeyPathValue { - private string Key { get; set; } = key; - private string Path { get; set; } = path; - private object Value { get; set; } = value; + public KeyPathValue(string key, string path, object value) + { + Key = key; + Path = path; + Value = value; + } + + private string Key { get; set; } + private string Path { get; set; } + private object Value { get; set; } public IEnumerable ToArray() { diff --git a/src/NRedisStack/Json/JsonCommands.cs b/src/NRedisStack/Json/JsonCommands.cs index c577e2f1..423272c9 100644 --- a/src/NRedisStack/Json/JsonCommands.cs +++ b/src/NRedisStack/Json/JsonCommands.cs @@ -5,12 +5,19 @@ namespace NRedisStack; -public class JsonCommands(IDatabase db) : JsonCommandsAsync(db), IJsonCommands +public class JsonCommands : JsonCommandsAsync, IJsonCommands { + private readonly IDatabase _db; + + public JsonCommands(IDatabase db) : base(db) + { + _db = db; + } + /// public RedisResult[] Resp(RedisKey key, string? path = null) { - RedisResult result = db.Execute(JsonCommandBuilder.Resp(key, path)); + RedisResult result = _db.Execute(JsonCommandBuilder.Resp(key, path)); if (result.IsNull) { @@ -31,26 +38,26 @@ 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(JsonCommandBuilder.Set(key, path, json, when)).OKtoBoolean(); } /// public bool MSet(KeyPathValue[] KeyPathValueList) { - return db.Execute(JsonCommandBuilder.MSet(KeyPathValueList)).OKtoBoolean(); + return _db.Execute(JsonCommandBuilder.MSet(KeyPathValueList)).OKtoBoolean(); } /// public bool Merge(RedisKey key, RedisValue path, RedisValue json) { - return db.Execute(JsonCommandBuilder.Merge(key, path, json)).OKtoBoolean(); + return _db.Execute(JsonCommandBuilder.Merge(key, path, json)).OKtoBoolean(); } /// public bool Merge(RedisKey key, RedisValue path, object obj, JsonSerializerOptions? serializerOptions = default) { string json = JsonSerializer.Serialize(obj, options: serializerOptions); - return db.Execute(JsonCommandBuilder.Merge(key, path, json)).OKtoBoolean(); + return _db.Execute(JsonCommandBuilder.Merge(key, path, json)).OKtoBoolean(); } /// @@ -88,19 +95,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(JsonCommandBuilder.StrAppend(key, value, path)).ToNullableLongArray(); } /// public long?[] StrLen(RedisKey key, string? path = null) { - return db.Execute(JsonCommandBuilder.StrLen(key, path)).ToNullableLongArray(); + return _db.Execute(JsonCommandBuilder.StrLen(key, path)).ToNullableLongArray(); } /// public bool?[] Toggle(RedisKey key, string? path = null) { - RedisResult result = db.Execute(JsonCommandBuilder.Toggle(key, path)); + RedisResult result = _db.Execute(JsonCommandBuilder.Toggle(key, path)); if (result.IsNull) { @@ -115,7 +122,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(JsonCommandBuilder.Type(key, path)); return result.Type switch { @@ -129,37 +136,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(); + return _db.Execute(JsonCommandBuilder.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(JsonCommandBuilder.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(JsonCommandBuilder.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(JsonCommandBuilder.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(JsonCommandBuilder.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(JsonCommandBuilder.ArrPop(key, path, index)); if (result.Type == ResultType.MultiBulk) { @@ -171,18 +178,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(JsonCommandBuilder.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(JsonCommandBuilder.Clear(key, path)).ToLong(); } /// public long Del(RedisKey key, string? path = null) { - return db.Execute(JsonCommandBuilder.Del(key, path)).ToLong(); + return _db.Execute(JsonCommandBuilder.Del(key, path)).ToLong(); } /// @@ -192,54 +199,56 @@ 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(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(JsonCommandBuilder.Get(key, paths, indent, newLine, space)); + return _db.Execute(JsonCommandBuilder.Get(key, paths, indent, newLine, space)); } /// public T? Get(RedisKey key, string path = "$", JsonSerializerOptions? serializerOptions = default) { - var res = db.Execute(JsonCommandBuilder.Get(key, path)); + var res = _db.Execute(JsonCommandBuilder.Get(key, path)); if (res.Type != ResultType.BulkString || res.IsNull) return default; var arr = JsonSerializer.Deserialize(res.ToString()!); - return arr?.Count > 0 ? JsonSerializer.Deserialize(JsonSerializer.Serialize(arr[0]), serializerOptions) : default; + return arr?.Count > 0 + ? JsonSerializer.Deserialize(JsonSerializer.Serialize(arr[0]), serializerOptions) + : default; } /// public IEnumerable GetEnumerable(RedisKey key, string path = "$") { - RedisResult res = db.Execute(JsonCommandBuilder.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(JsonCommandBuilder.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(JsonCommandBuilder.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(JsonCommandBuilder.ObjKeys(key, path)).ToHashSets(); + return _db.Execute(JsonCommandBuilder.ObjKeys(key, path)).ToHashSets(); } /// public long?[] ObjLen(RedisKey key, string? path = null) { - return db.Execute(JsonCommandBuilder.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 307556c2..ed9ac83d 100644 --- a/src/NRedisStack/Json/JsonCommandsAsync.cs +++ b/src/NRedisStack/Json/JsonCommandsAsync.cs @@ -5,31 +5,40 @@ namespace NRedisStack; -public class JsonCommandsAsync(IDatabaseAsync db) : IJsonCommandsAsync +public class JsonCommandsAsync : IJsonCommandsAsync { + private readonly IDatabaseAsync _db; + + public JsonCommandsAsync(IDatabaseAsync db) + { + _db = db; + } + public async Task ArrAppendAsync(RedisKey key, string? path = null, params object[] values) { - return (await db.ExecuteAsync(JsonCommandBuilder.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) + 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(); + 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(); + 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(); + 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)); + RedisResult result = await _db.ExecuteAsync(JsonCommandBuilder.ArrPop(key, path, index)); return result.Type switch { @@ -40,71 +49,76 @@ public async Task ArrPopAsync(RedisKey key, string? path = null, } public async Task ArrTrimAsync(RedisKey key, string path, long start, long stop) => - (await db.ExecuteAsync(JsonCommandBuilder.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(JsonCommandBuilder.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(JsonCommandBuilder.Del(key, path))).ToLong(); + 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, + 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)); + 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, + 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)); + return await _db.ExecuteAsync(JsonCommandBuilder.Get(key, paths, indent, newLine, space)); } - public async Task GetAsync(RedisKey key, string path = "$", JsonSerializerOptions? serializerOptions = default) + public async Task GetAsync(RedisKey key, string path = "$", + JsonSerializerOptions? serializerOptions = default) { - var res = await db.ExecuteAsync(JsonCommandBuilder.Get(key, path)); + var res = await _db.ExecuteAsync(JsonCommandBuilder.Get(key, path)); if (res.Type != ResultType.BulkString || res.IsNull) return default; var arr = JsonSerializer.Deserialize(res.ToString()!); - return arr?.Count > 0 ? JsonSerializer.Deserialize(JsonSerializer.Serialize(arr[0]), serializerOptions) : default; + return arr?.Count > 0 + ? JsonSerializer.Deserialize(JsonSerializer.Serialize(arr[0]), serializerOptions) + : default; } /// public async Task> GetEnumerableAsync(RedisKey key, string path = "$") { - RedisResult res = await db.ExecuteAsync(JsonCommandBuilder.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(JsonCommandBuilder.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(JsonCommandBuilder.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(JsonCommandBuilder.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(JsonCommandBuilder.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(JsonCommandBuilder.Resp(key, path)); + RedisResult result = await _db.ExecuteAsync(JsonCommandBuilder.Resp(key, path)); if (result.IsNull) { @@ -115,7 +129,8 @@ public async Task RespAsync(RedisKey key, string? path = null) } /// - public Task SetAsync(RedisKey key, RedisValue path, object obj, When when = When.Always, JsonSerializerOptions? serializerOptions = default) + public Task SetAsync(RedisKey key, RedisValue path, object obj, When when = When.Always, + JsonSerializerOptions? serializerOptions = default) { string json = JsonSerializer.Serialize(obj, options: serializerOptions); return SetAsync(key, path, json, when); @@ -123,25 +138,26 @@ 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(JsonCommandBuilder.Set(key, path, json, when))).OKtoBoolean(); + return (await _db.ExecuteAsync(JsonCommandBuilder.Set(key, path, json, when))).OKtoBoolean(); } public async Task MSetAsync(KeyPathValue[] KeyPathValueList) { - return (await db.ExecuteAsync(JsonCommandBuilder.MSet(KeyPathValueList))).OKtoBoolean(); + return (await _db.ExecuteAsync(JsonCommandBuilder.MSet(KeyPathValueList))).OKtoBoolean(); } /// public async Task MergeAsync(RedisKey key, RedisValue path, RedisValue json) { - return (await db.ExecuteAsync(JsonCommandBuilder.Merge(key, path, json))).OKtoBoolean(); + return (await _db.ExecuteAsync(JsonCommandBuilder.Merge(key, path, json))).OKtoBoolean(); } /// - public async Task MergeAsync(RedisKey key, RedisValue path, object obj, JsonSerializerOptions? serializerOptions = default) + public async Task MergeAsync(RedisKey key, RedisValue path, object obj, + JsonSerializerOptions? serializerOptions = default) { string json = JsonSerializer.Serialize(obj, options: serializerOptions); - return (await db.ExecuteAsync(JsonCommandBuilder.Merge(key, path, json))).OKtoBoolean(); + return (await _db.ExecuteAsync(JsonCommandBuilder.Merge(key, path, json))).OKtoBoolean(); } public async Task SetFromFileAsync(RedisKey key, RedisValue path, string filePath, When when = When.Always) @@ -179,17 +195,17 @@ public async Task SetFromDirectoryAsync(RedisValue path, string filesPath, public async Task StrAppendAsync(RedisKey key, string value, string? path = null) { - return (await db.ExecuteAsync(JsonCommandBuilder.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(JsonCommandBuilder.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(JsonCommandBuilder.Toggle(key, path)); + RedisResult result = await _db.ExecuteAsync(JsonCommandBuilder.Toggle(key, path)); if (result.IsNull) { @@ -206,18 +222,21 @@ public async Task SetFromDirectoryAsync(RedisValue path, string filesPath, public async Task TypeAsync(RedisKey key, string? path = null) { - RedisResult result = await db.ExecuteAsync(JsonCommandBuilder.Type(key, path)); + RedisResult result = await _db.ExecuteAsync(JsonCommandBuilder.Type(key, path)); if (result.Type == ResultType.MultiBulk) { - return ((RedisResult[])result!).Select(x => (JsonType)Enum.Parse(typeof(JsonType), x.ToString()!.ToUpper())).ToArray(); + return ((RedisResult[])result!).Select(x => (JsonType)Enum.Parse(typeof(JsonType), x.ToString()!.ToUpper())) + .ToArray(); } - return result.Type == ResultType.BulkString ? [(JsonType)Enum.Parse(typeof(JsonType), result.ToString()!.ToUpper())] : Array.Empty(); + return result.Type == ResultType.BulkString + ? [(JsonType)Enum.Parse(typeof(JsonType), result.ToString()!.ToUpper())] + : Array.Empty(); } public async Task DebugMemoryAsync(string key, string? path = null) { - return (await db.ExecuteAsync(JsonCommandBuilder.DebugMemory(key, path))).ToLong(); + return (await _db.ExecuteAsync(JsonCommandBuilder.DebugMemory(key, path))).ToLong(); } } \ No newline at end of file From 5817619dc24295605a077eefd5899566d3401ef1 Mon Sep 17 00:00:00 2001 From: nima nikoonazar Date: Wed, 13 Mar 2024 00:48:18 +0330 Subject: [PATCH 48/57] Fix Issues for compiler error in .net 8 error CS8652: The feature 'collection literals' --- .../CountMinSketch/CmsCommandBuilder.cs | 17 +++++--- src/NRedisStack/Json/JsonCommands.cs | 40 +++++++++++++------ src/NRedisStack/Json/JsonCommandsAsync.cs | 17 +++++--- 3 files changed, 49 insertions(+), 25 deletions(-) diff --git a/src/NRedisStack/CountMinSketch/CmsCommandBuilder.cs b/src/NRedisStack/CountMinSketch/CmsCommandBuilder.cs index 80da7e79..7e6299ab 100644 --- a/src/NRedisStack/CountMinSketch/CmsCommandBuilder.cs +++ b/src/NRedisStack/CountMinSketch/CmsCommandBuilder.cs @@ -22,6 +22,7 @@ public static SerializedCommand IncrBy(RedisKey key, Tuple[] i args.Add(pair.Item1); args.Add(pair.Item2); } + return new SerializedCommand(CMS.INCRBY, args); } @@ -41,17 +42,21 @@ public static SerializedCommand InitByProb(RedisKey key, double error, double pr return new SerializedCommand(CMS.INITBYPROB, key, error, probability); } - public static SerializedCommand Merge(RedisValue destination, long numKeys, RedisValue[] source, long[]? weight = null) + public static SerializedCommand Merge(RedisValue destination, long numKeys, RedisValue[] source, + long[]? weight = null) { if (source.Length < 1) throw new ArgumentOutOfRangeException(nameof(source)); - List args = [destination, numKeys]; - args.AddRange(source.Cast()); + List args = new List { destination, numKeys }; + + foreach (var s in source) args.Add(s); - if (weight is not { Length: >= 1 }) return new SerializedCommand(CMS.MERGE, args); - args.Add(CmsArgs.WEIGHTS); - args.AddRange(weight.Cast()); + if (weight != null && weight.Length >= 1) + { + args.Add(CmsArgs.WEIGHTS); + foreach (var w in weight) args.Add(w); + } return new SerializedCommand(CMS.MERGE, args); } diff --git a/src/NRedisStack/Json/JsonCommands.cs b/src/NRedisStack/Json/JsonCommands.cs index 423272c9..5271dbe8 100644 --- a/src/NRedisStack/Json/JsonCommands.cs +++ b/src/NRedisStack/Json/JsonCommands.cs @@ -87,8 +87,10 @@ public int SetFromDirectory(RedisValue path, string filesPath, When when = When. } } - inserted += Directory.EnumerateDirectories(filesPath).Sum(dirPath => SetFromDirectory(path, dirPath, when)); - + foreach (var dirPath in Directory.EnumerateDirectories(filesPath)) + { + inserted += SetFromDirectory(path, dirPath, when); + } return inserted; } @@ -114,9 +116,12 @@ public int SetFromDirectory(RedisValue path, string filesPath, When when = When. return Array.Empty(); } - return result.Type == ResultType.Integer - ? [(long)result == 1] - : ((RedisResult[])result!).Select(x => (bool?)((long)x == 1)).ToArray(); + if (result.Type == ResultType.Integer) + { + return new bool?[] { (long)result == 1 }; + } + + return ((RedisResult[])result!).Select(x => (bool?)((long)x == 1)).ToArray(); } /// @@ -124,14 +129,18 @@ public JsonType[] Type(RedisKey key, string? path = null) { RedisResult result = _db.Execute(JsonCommandBuilder.Type(key, path)); - return result.Type switch + if (result.Type == ResultType.MultiBulk) + { + return ((RedisResult[])result!).Select(x => (JsonType)Enum.Parse(typeof(JsonType), x.ToString()!.ToUpper())).ToArray(); + } + + if (result.Type == ResultType.BulkString) { - ResultType.MultiBulk => ((RedisResult[])result!) - .Select(x => (JsonType)Enum.Parse(typeof(JsonType), x.ToString()!.ToUpper())) - .ToArray(), - ResultType.BulkString => [(JsonType)Enum.Parse(typeof(JsonType), result.ToString()!.ToUpper())], - _ => Array.Empty() - }; + return new[] { (JsonType)Enum.Parse(typeof(JsonType), result.ToString()!.ToUpper()) }; + } + + return Array.Empty(); + } public long DebugMemory(string key, string? path = null) @@ -173,7 +182,12 @@ public RedisResult[] ArrPop(RedisKey key, string? path = null, long? index = nul return (RedisResult[])result!; } - return result.Type == ResultType.BulkString ? [result] : Array.Empty(); + if (result.Type == ResultType.BulkString) + { + return new[] { result }; + } + + return Array.Empty(); } /// diff --git a/src/NRedisStack/Json/JsonCommandsAsync.cs b/src/NRedisStack/Json/JsonCommandsAsync.cs index ed9ac83d..cab804d5 100644 --- a/src/NRedisStack/Json/JsonCommandsAsync.cs +++ b/src/NRedisStack/Json/JsonCommandsAsync.cs @@ -40,12 +40,17 @@ public async Task ArrPopAsync(RedisKey key, string? path = null, { RedisResult result = await _db.ExecuteAsync(JsonCommandBuilder.ArrPop(key, path, index)); - return result.Type switch + if (result.Type == ResultType.MultiBulk) + { + return (RedisResult[])result!; + } + + if (result.Type == ResultType.BulkString) { - ResultType.MultiBulk => (RedisResult[])result!, - ResultType.BulkString => [result], - _ => Array.Empty() - }; + return new[] { result }; + } + + return Array.Empty(); } public async Task ArrTrimAsync(RedisKey key, string path, long start, long stop) => @@ -214,7 +219,7 @@ public async Task SetFromDirectoryAsync(RedisValue path, string filesPath, if (result.Type == ResultType.Integer) { - return [(long)result == 1]; + return new bool?[] { (long)result == 1 }; } return ((RedisResult[])result!).Select(x => (bool?)((long)x == 1)).ToArray(); From 496fcc3d62d3cf1267f33c5191bb64b1f0b29f97 Mon Sep 17 00:00:00 2001 From: nima nikoonazar Date: Wed, 13 Mar 2024 19:37:45 +0330 Subject: [PATCH 49/57] Fix Compiler Error in JsonCommandsAsync.cs and JsonCommands.cs for Error : error CS8652: The feature 'collection literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version --- src/NRedisStack/Json/JsonCommands.cs | 15 ++++++++---- src/NRedisStack/Json/JsonCommandsAsync.cs | 30 ++++++++++++++--------- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/NRedisStack/Json/JsonCommands.cs b/src/NRedisStack/Json/JsonCommands.cs index 5271dbe8..fd783737 100644 --- a/src/NRedisStack/Json/JsonCommands.cs +++ b/src/NRedisStack/Json/JsonCommands.cs @@ -227,11 +227,16 @@ public RedisResult Get(RedisKey key, string[] paths, RedisValue? indent = null, public T? Get(RedisKey key, string path = "$", JsonSerializerOptions? serializerOptions = default) { var res = _db.Execute(JsonCommandBuilder.Get(key, path)); - if (res.Type != ResultType.BulkString || res.IsNull) return default; - var arr = JsonSerializer.Deserialize(res.ToString()!); - return arr?.Count > 0 - ? JsonSerializer.Deserialize(JsonSerializer.Serialize(arr[0]), serializerOptions) - : default; + if (res.Type == ResultType.BulkString && !res.IsNull) + { + var arr = JsonSerializer.Deserialize(res.ToString()!); + if (arr?.Count > 0) + { + return JsonSerializer.Deserialize(JsonSerializer.Serialize(arr[0]), serializerOptions); + } + } + + return default; } /// diff --git a/src/NRedisStack/Json/JsonCommandsAsync.cs b/src/NRedisStack/Json/JsonCommandsAsync.cs index cab804d5..ce24f73a 100644 --- a/src/NRedisStack/Json/JsonCommandsAsync.cs +++ b/src/NRedisStack/Json/JsonCommandsAsync.cs @@ -82,15 +82,19 @@ public async Task GetAsync(RedisKey key, string[] paths, RedisValue return await _db.ExecuteAsync(JsonCommandBuilder.Get(key, paths, indent, newLine, space)); } - public async Task GetAsync(RedisKey key, string path = "$", - JsonSerializerOptions? serializerOptions = default) + public async Task GetAsync(RedisKey key, string path = "$", JsonSerializerOptions? serializerOptions = default) { var res = await _db.ExecuteAsync(JsonCommandBuilder.Get(key, path)); - if (res.Type != ResultType.BulkString || res.IsNull) return default; - var arr = JsonSerializer.Deserialize(res.ToString()!); - return arr?.Count > 0 - ? JsonSerializer.Deserialize(JsonSerializer.Serialize(arr[0]), serializerOptions) - : default; + if (res.Type == ResultType.BulkString && !res.IsNull) + { + var arr = JsonSerializer.Deserialize(res.ToString()!); + if (arr?.Count > 0) + { + return JsonSerializer.Deserialize(JsonSerializer.Serialize(arr[0]), serializerOptions); + } + } + + return default; } /// @@ -231,13 +235,15 @@ public async Task TypeAsync(RedisKey key, string? path = null) if (result.Type == ResultType.MultiBulk) { - return ((RedisResult[])result!).Select(x => (JsonType)Enum.Parse(typeof(JsonType), x.ToString()!.ToUpper())) - .ToArray(); + return ((RedisResult[])result!).Select(x => (JsonType)Enum.Parse(typeof(JsonType), x.ToString()!.ToUpper())).ToArray(); + } + + if (result.Type == ResultType.BulkString) + { + return new[] { (JsonType)Enum.Parse(typeof(JsonType), result.ToString()!.ToUpper()) }; } - return result.Type == ResultType.BulkString - ? [(JsonType)Enum.Parse(typeof(JsonType), result.ToString()!.ToUpper())] - : Array.Empty(); + return Array.Empty(); } public async Task DebugMemoryAsync(string key, string? path = null) From 56ca7ae0f943360b59a2b8e4aa004fae124efc36 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Thu, 14 Mar 2024 17:24:07 +0200 Subject: [PATCH 50/57] return ExampleTests's ctor --- tests/NRedisStack.Tests/Examples/ExampleTests.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/NRedisStack.Tests/Examples/ExampleTests.cs b/tests/NRedisStack.Tests/Examples/ExampleTests.cs index 031d297c..22aee9c0 100644 --- a/tests/NRedisStack.Tests/Examples/ExampleTests.cs +++ b/tests/NRedisStack.Tests/Examples/ExampleTests.cs @@ -10,11 +10,14 @@ namespace NRedisStack.Tests; -public class ExampleTests(RedisFixture redisFixture, ITestOutputHelper testOutputHelper) - : AbstractNRedisStackTest(redisFixture), IDisposable +public class ExampleTests : AbstractNRedisStackTest, IDisposable { - private readonly ITestOutputHelper testOutputHelper = testOutputHelper; + private readonly ITestOutputHelper testOutputHelper; // private readonly string key = "EXAMPLES_TESTS"; + public ExampleTests(RedisFixture redisFixture, ITestOutputHelper testOutputHelper) : base(redisFixture) + { + this.testOutputHelper = testOutputHelper; + } [SkipIfRedis(Is.OSSCluster)] public void HSETandSearch() From 1927c871e65f14e1dbf993fb92a15607a00825a7 Mon Sep 17 00:00:00 2001 From: nima nikoonazar Date: Thu, 14 Mar 2024 19:35:03 +0330 Subject: [PATCH 51/57] Fix typo for TransactionsTests.cs in method naming TestModulesTransactionWithoutGraph --- tests/NRedisStack.Tests/TransactionsTests.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/NRedisStack.Tests/TransactionsTests.cs b/tests/NRedisStack.Tests/TransactionsTests.cs index 498ed77c..29a472d3 100644 --- a/tests/NRedisStack.Tests/TransactionsTests.cs +++ b/tests/NRedisStack.Tests/TransactionsTests.cs @@ -9,8 +9,10 @@ namespace NRedisStack.Tests public class TransactionTests : AbstractNRedisStackTest, IDisposable { private readonly string key = "TRX_TESTS"; - public TransactionTests(RedisFixture redisFixture) : base(redisFixture) { } + public TransactionTests(RedisFixture redisFixture) : base(redisFixture) + { + } [Fact] public void TestJsonTransaction() @@ -33,7 +35,7 @@ public void TestJsonTransaction() [SkipIfRedis(Comparison.GreaterThanOrEqual, "7.1.242")] [Obsolete] - public void TestModulsTransaction() + public void TestModulesTransaction() { IDatabase db = redisFixture.Redis.GetDatabase(); db.Execute("FLUSHALL"); @@ -85,7 +87,7 @@ public void TestModulsTransaction() [SkipIfRedis(Is.OSSCluster, Is.Enterprise)] [Obsolete] - public void TestModulsTransactionWithoutGraph() + public void TestModulesTransactionWithoutGraph() { IDatabase db = redisFixture.Redis.GetDatabase(); db.Execute("FLUSHALL"); @@ -131,4 +133,4 @@ public void TestModulsTransactionWithoutGraph() Assert.NotNull(db.TOPK().Info("topk-key")); } } -} +} \ No newline at end of file From e1eacb339ba456dab4de5a59da4c3747d082c426 Mon Sep 17 00:00:00 2001 From: nima nikoonazar Date: Thu, 14 Mar 2024 19:40:34 +0330 Subject: [PATCH 52/57] Fix Typo and namespace also Set Private Access Modifier RedisFixture.cs for readonly strings --- tests/NRedisStack.Tests/RedisFixture.cs | 98 ++++---- tests/NRedisStack.Tests/TransactionsTests.cs | 251 +++++++++---------- 2 files changed, 173 insertions(+), 176 deletions(-) diff --git a/tests/NRedisStack.Tests/RedisFixture.cs b/tests/NRedisStack.Tests/RedisFixture.cs index dac4b6f5..81aca9ab 100644 --- a/tests/NRedisStack.Tests/RedisFixture.cs +++ b/tests/NRedisStack.Tests/RedisFixture.cs @@ -1,68 +1,66 @@ using StackExchange.Redis; -namespace NRedisStack.Tests -{ - public class RedisFixture : IDisposable - { - // Set the enviroment variable to specify your own alternet host and port: - readonly string redisStandalone = Environment.GetEnvironmentVariable("REDIS") ?? "localhost:6379"; - readonly string? redisCluster = Environment.GetEnvironmentVariable("REDIS_CLUSTER"); - readonly string? numRedisClusterNodesEnv = Environment.GetEnvironmentVariable("NUM_REDIS_CLUSTER_NODES"); +namespace NRedisStack.Tests; - public bool isEnterprise = Environment.GetEnvironmentVariable("IS_ENTERPRISE") == "true"; - public bool isOSSCluster; +public class RedisFixture : IDisposable +{ + // Set the environment variable to specify your own alternate host and port: + private readonly string redisStandalone = Environment.GetEnvironmentVariable("REDIS") ?? "localhost:6379"; + private readonly string? redisCluster = Environment.GetEnvironmentVariable("REDIS_CLUSTER"); + private readonly string? numRedisClusterNodesEnv = Environment.GetEnvironmentVariable("NUM_REDIS_CLUSTER_NODES"); + public bool isEnterprise = Environment.GetEnvironmentVariable("IS_ENTERPRISE") == "true"; + public bool isOSSCluster; - public RedisFixture() + public RedisFixture() + { + ConfigurationOptions clusterConfig = new ConfigurationOptions { - ConfigurationOptions clusterConfig = new ConfigurationOptions - { - AsyncTimeout = 10000, - SyncTimeout = 10000 - }; - Redis = Connect(clusterConfig, out isOSSCluster); - } + AsyncTimeout = 10000, + SyncTimeout = 10000 + }; + Redis = Connect(clusterConfig, out isOSSCluster); + } - public void Dispose() - { - Redis.Close(); - } + public void Dispose() + { + Redis.Close(); + } - public ConnectionMultiplexer Redis { get; } + public ConnectionMultiplexer Redis { get; } - public ConnectionMultiplexer CustomRedis(ConfigurationOptions configurationOptions, out bool isOssCluster) - { - return Connect(configurationOptions, out isOssCluster); - } + public ConnectionMultiplexer CustomRedis(ConfigurationOptions configurationOptions, out bool isOssCluster) + { + return Connect(configurationOptions, out isOssCluster); + } - private ConnectionMultiplexer Connect(ConfigurationOptions configurationOptions, out bool isOssCluster) + private ConnectionMultiplexer Connect(ConfigurationOptions configurationOptions, out bool isOssCluster) + { + // Redis Cluster + if (redisCluster != null && numRedisClusterNodesEnv != null) { - // Redis Cluster - if (redisCluster != null && numRedisClusterNodesEnv != null) - { - // Split to host and port - string[] parts = redisCluster!.Split(':'); - string host = parts[0]; - int startPort = int.Parse(parts[1]); - - var endpoints = new EndPointCollection(); // TODO: checl if needed + // Split to host and port + string[] parts = redisCluster!.Split(':'); + string host = parts[0]; + int startPort = int.Parse(parts[1]); - configurationOptions.EndPoints.Clear(); - int numRedisClusterNodes = int.Parse(numRedisClusterNodesEnv!); - for (int i = 0; i < numRedisClusterNodes; i++) - { - configurationOptions.EndPoints.Add(host, startPort + i); - } + var endpoints = new EndPointCollection(); // TODO: check if needed - isOssCluster = true; - return ConnectionMultiplexer.Connect(configurationOptions); - } - - // Redis Standalone configurationOptions.EndPoints.Clear(); - configurationOptions.EndPoints.Add($"{redisStandalone}"); + int numRedisClusterNodes = int.Parse(numRedisClusterNodesEnv!); + for (int i = 0; i < numRedisClusterNodes; i++) + { + configurationOptions.EndPoints.Add(host, startPort + i); + } - isOssCluster = false; + isOssCluster = true; return ConnectionMultiplexer.Connect(configurationOptions); } + + // Redis Standalone + configurationOptions.EndPoints.Clear(); + configurationOptions.EndPoints.Add($"{redisStandalone}"); + + isOssCluster = false; + return ConnectionMultiplexer.Connect(configurationOptions); } } \ No newline at end of file diff --git a/tests/NRedisStack.Tests/TransactionsTests.cs b/tests/NRedisStack.Tests/TransactionsTests.cs index 29a472d3..0883bcf1 100644 --- a/tests/NRedisStack.Tests/TransactionsTests.cs +++ b/tests/NRedisStack.Tests/TransactionsTests.cs @@ -4,133 +4,132 @@ using System.Text.Json; using Xunit; -namespace NRedisStack.Tests +namespace NRedisStack.Tests; + +public class TransactionTests : AbstractNRedisStackTest, IDisposable { - public class TransactionTests : AbstractNRedisStackTest, IDisposable + private readonly string key = "TRX_TESTS"; + + public TransactionTests(RedisFixture redisFixture) : base(redisFixture) + { + } + + [Fact] + public void TestJsonTransaction() + { + IDatabase db = redisFixture.Redis.GetDatabase(); + db.Execute("FLUSHALL"); + var transaction = new Transaction(db); + string jsonPerson = JsonSerializer.Serialize(new Person { Name = "Shachar", Age = 23 }); + var setResponse = transaction.Json.SetAsync(key, "$", jsonPerson); + var getResponse = transaction.Json.GetAsync(key); + + transaction.Execute(); + + setResponse.Wait(); + getResponse.Wait(); + + Assert.True(setResponse.Result); + Assert.Equal("{\"Name\":\"Shachar\",\"Age\":23}", getResponse.Result.ToString()); + } + + [SkipIfRedis(Comparison.GreaterThanOrEqual, "7.1.242")] + [Obsolete] + public void TestModulesTransaction() + { + IDatabase db = redisFixture.Redis.GetDatabase(); + db.Execute("FLUSHALL"); + var tran = new Transaction(db); + + _ = tran.Bf.ReserveAsync("bf-key", 0.001, 100); + _ = tran.Bf.AddAsync("bf-key", "1"); + _ = tran.Cms.InitByDimAsync("cms-key", 100, 5); + _ = tran.Cf.ReserveAsync("cf-key", 100); + _ = tran.Graph.QueryAsync("graph-key", "CREATE ({name:'shachar',age:23})"); + _ = tran.Json.SetAsync("json-key", "$", "{}"); + _ = tran.Ft.CreateAsync("ft-key", new FTCreateParams(), new Schema().AddTextField("txt")); + _ = tran.Tdigest.CreateAsync("tdigest-key", 100); + _ = tran.Ts.CreateAsync("ts-key", 100); + _ = tran.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.Empty(db.FT()._List()); + Assert.False(db.KeyExists("tdigest-key")); + Assert.False(db.KeyExists("ts-key")); + Assert.False(db.KeyExists("topk-key")); + + tran.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")); + } + + [SkipIfRedis(Is.OSSCluster, Is.Enterprise)] + [Obsolete] + public void TestModulesTransactionWithoutGraph() { - private readonly string key = "TRX_TESTS"; - - public TransactionTests(RedisFixture redisFixture) : base(redisFixture) - { - } - - [Fact] - public void TestJsonTransaction() - { - IDatabase db = redisFixture.Redis.GetDatabase(); - db.Execute("FLUSHALL"); - var transaction = new Transaction(db); - string jsonPerson = JsonSerializer.Serialize(new Person { Name = "Shachar", Age = 23 }); - var setResponse = transaction.Json.SetAsync(key, "$", jsonPerson); - var getResponse = transaction.Json.GetAsync(key); - - transaction.Execute(); - - setResponse.Wait(); - getResponse.Wait(); - - Assert.True(setResponse.Result); - Assert.Equal("{\"Name\":\"Shachar\",\"Age\":23}", getResponse.Result.ToString()); - } - - [SkipIfRedis(Comparison.GreaterThanOrEqual, "7.1.242")] - [Obsolete] - public void TestModulesTransaction() - { - IDatabase db = redisFixture.Redis.GetDatabase(); - db.Execute("FLUSHALL"); - var tran = new Transaction(db); - - _ = tran.Bf.ReserveAsync("bf-key", 0.001, 100); - _ = tran.Bf.AddAsync("bf-key", "1"); - _ = tran.Cms.InitByDimAsync("cms-key", 100, 5); - _ = tran.Cf.ReserveAsync("cf-key", 100); - _ = tran.Graph.QueryAsync("graph-key", "CREATE ({name:'shachar',age:23})"); - _ = tran.Json.SetAsync("json-key", "$", "{}"); - _ = tran.Ft.CreateAsync("ft-key", new FTCreateParams(), new Schema().AddTextField("txt")); - _ = tran.Tdigest.CreateAsync("tdigest-key", 100); - _ = tran.Ts.CreateAsync("ts-key", 100); - _ = tran.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.Empty(db.FT()._List()); - Assert.False(db.KeyExists("tdigest-key")); - Assert.False(db.KeyExists("ts-key")); - Assert.False(db.KeyExists("topk-key")); - - tran.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")); - } - - [SkipIfRedis(Is.OSSCluster, Is.Enterprise)] - [Obsolete] - public void TestModulesTransactionWithoutGraph() - { - IDatabase db = redisFixture.Redis.GetDatabase(); - db.Execute("FLUSHALL"); - var tran = new Transaction(db); - - _ = tran.Bf.ReserveAsync("bf-key", 0.001, 100); - _ = tran.Bf.AddAsync("bf-key", "1"); - _ = tran.Cms.InitByDimAsync("cms-key", 100, 5); - _ = tran.Cf.ReserveAsync("cf-key", 100); - _ = tran.Json.SetAsync("json-key", "$", "{}"); - _ = tran.Ft.CreateAsync("ft-key", new FTCreateParams(), new Schema().AddTextField("txt")); - _ = tran.Tdigest.CreateAsync("tdigest-key", 100); - _ = tran.Ts.CreateAsync("ts-key", 100); - _ = tran.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("json-key")); - Assert.Empty(db.FT()._List()); - Assert.False(db.KeyExists("tdigest-key")); - Assert.False(db.KeyExists("ts-key")); - Assert.False(db.KeyExists("topk-key")); - - tran.Execute(); - - Assert.True(db.KeyExists("bf-key")); - Assert.True(db.KeyExists("cms-key")); - Assert.True(db.KeyExists("cf-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.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")); - } + IDatabase db = redisFixture.Redis.GetDatabase(); + db.Execute("FLUSHALL"); + var tran = new Transaction(db); + + _ = tran.Bf.ReserveAsync("bf-key", 0.001, 100); + _ = tran.Bf.AddAsync("bf-key", "1"); + _ = tran.Cms.InitByDimAsync("cms-key", 100, 5); + _ = tran.Cf.ReserveAsync("cf-key", 100); + _ = tran.Json.SetAsync("json-key", "$", "{}"); + _ = tran.Ft.CreateAsync("ft-key", new FTCreateParams(), new Schema().AddTextField("txt")); + _ = tran.Tdigest.CreateAsync("tdigest-key", 100); + _ = tran.Ts.CreateAsync("ts-key", 100); + _ = tran.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("json-key")); + Assert.Empty(db.FT()._List()); + Assert.False(db.KeyExists("tdigest-key")); + Assert.False(db.KeyExists("ts-key")); + Assert.False(db.KeyExists("topk-key")); + + tran.Execute(); + + Assert.True(db.KeyExists("bf-key")); + Assert.True(db.KeyExists("cms-key")); + Assert.True(db.KeyExists("cf-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.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")); } } \ No newline at end of file From d75b17b16c5bf2b4fd19cb5f6d7d16a1d09d2008 Mon Sep 17 00:00:00 2001 From: nima nikoonazar Date: Thu, 14 Mar 2024 19:43:30 +0330 Subject: [PATCH 53/57] Fix Typo and set const for readonly key PipelineTests.cs --- tests/NRedisStack.Tests/PipelineTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/NRedisStack.Tests/PipelineTests.cs b/tests/NRedisStack.Tests/PipelineTests.cs index 6c77b0bf..cf4826fc 100644 --- a/tests/NRedisStack.Tests/PipelineTests.cs +++ b/tests/NRedisStack.Tests/PipelineTests.cs @@ -8,12 +8,12 @@ namespace NRedisStack.Tests; public class PipelineTests : AbstractNRedisStackTest, IDisposable { - private readonly string key = "PIPELINE_TESTS"; + private const string key = "PIPELINE_TESTS"; public PipelineTests(RedisFixture redisFixture) : base(redisFixture) { } [SkipIfRedis(Is.OSSCluster, Comparison.GreaterThanOrEqual, "7.1.242")] [Obsolete] - public void TestModulsPipeline() + public void TestModulesPipeline() { IDatabase db = redisFixture.Redis.GetDatabase(); db.Execute("FLUSHALL"); @@ -65,7 +65,7 @@ public void TestModulsPipeline() [SkipIfRedis(Is.OSSCluster)] [Obsolete] - public void TestModulsPipelineWithotGraph() + public void TestModulesPipelineWithoutGraph() { IDatabase db = redisFixture.Redis.GetDatabase(); db.Execute("FLUSHALL"); From 15e3e441588d9e414c7b4b72cf0eb0cc0eb5d70a Mon Sep 17 00:00:00 2001 From: nima nikoonazar Date: Thu, 14 Mar 2024 19:52:36 +0330 Subject: [PATCH 54/57] Fix Typo and Change Namespace to scoped AbstractNRedisStackTest.cs and Person.cs --- .../AbstractNRedisStackTest.cs | 74 +++++++++---------- tests/NRedisStack.Tests/Person.cs | 13 ++-- 2 files changed, 42 insertions(+), 45 deletions(-) diff --git a/tests/NRedisStack.Tests/AbstractNRedisStackTest.cs b/tests/NRedisStack.Tests/AbstractNRedisStackTest.cs index 3de0168b..e51aa449 100644 --- a/tests/NRedisStack.Tests/AbstractNRedisStackTest.cs +++ b/tests/NRedisStack.Tests/AbstractNRedisStackTest.cs @@ -1,58 +1,56 @@ using NRedisStack.DataTypes; -using StackExchange.Redis; using System.Runtime.CompilerServices; using Xunit; -namespace NRedisStack.Tests +namespace NRedisStack.Tests; + +public abstract class AbstractNRedisStackTest : IClassFixture, IAsyncLifetime { - public abstract class AbstractNRedisStackTest : IClassFixture, IAsyncLifetime - { - protected internal RedisFixture redisFixture; + protected internal RedisFixture redisFixture; - protected internal AbstractNRedisStackTest(RedisFixture redisFixture) => this.redisFixture = redisFixture; + protected internal AbstractNRedisStackTest(RedisFixture redisFixture) => this.redisFixture = redisFixture; - private List keyNames = new List(); + private List keyNames = new List(); - protected internal string CreateKeyName([CallerMemberName] string memberName = "") => CreateKeyNames(1, memberName)[0]; + protected internal string CreateKeyName([CallerMemberName] string memberName = "") => CreateKeyNames(1, memberName)[0]; - protected internal string[] CreateKeyNames(int count, [CallerMemberName] string memberName = "") - { - if (count < 1) throw new ArgumentOutOfRangeException(nameof(count), "Must be greater than zero."); + protected internal string[] CreateKeyNames(int count, [CallerMemberName] string memberName = "") + { + if (count < 1) throw new ArgumentOutOfRangeException(nameof(count), "Must be greater than zero."); - var newKeys = new string[count]; - for (var i = 0; i < count; i++) - { - newKeys[i] = $"{GetType().Name}:{memberName}:{i}"; - } + var newKeys = new string[count]; + for (var i = 0; i < count; i++) + { + newKeys[i] = $"{GetType().Name}:{memberName}:{i}"; + } - keyNames.AddRange(newKeys); + keyNames.AddRange(newKeys); - return newKeys; - } + return newKeys; + } - protected internal static List ReverseData(List data) + protected internal static List ReverseData(List data) + { + var tuples = new List(data.Count); + for (var i = data.Count - 1; i >= 0; i--) { - var tuples = new List(data.Count); - for (var i = data.Count - 1; i >= 0; i--) - { - tuples.Add(data[i]); - } - - return tuples; + tuples.Add(data[i]); } - public Task InitializeAsync() => Task.CompletedTask; + return tuples; + } - public void Dispose() - { - redisFixture.Redis.GetDatabase().ExecuteBroadcast("FLUSHALL"); - } + public Task InitializeAsync() => Task.CompletedTask; - public async Task DisposeAsync() - { - var redis = redisFixture.Redis.GetDatabase(); - // await redis.KeyDeleteAsync(keyNames.Select(i => (RedisKey)i).ToArray()); - await redis.ExecuteBroadcastAsync("FLUSHALL"); - } + public void Dispose() + { + redisFixture.Redis.GetDatabase().ExecuteBroadcast("FLUSHALL"); + } + + public async Task DisposeAsync() + { + var redis = redisFixture.Redis.GetDatabase(); + // await redis.KeyDeleteAsync(keyNames.Select(i => (RedisKey)i).ToArray()); + await redis.ExecuteBroadcastAsync("FLUSHALL"); } } \ No newline at end of file diff --git a/tests/NRedisStack.Tests/Person.cs b/tests/NRedisStack.Tests/Person.cs index eed41b9e..c0f0c4f4 100644 --- a/tests/NRedisStack.Tests/Person.cs +++ b/tests/NRedisStack.Tests/Person.cs @@ -1,9 +1,8 @@ -namespace NRedisStack.Tests +namespace NRedisStack.Tests; + +public class Person { - public class Person - { - public string? Name { get; set; } - public int Age { get; set; } - public DateTime? Birthday; - } + public string? Name { get; set; } + public int Age { get; set; } + public DateTime? Birthday; } \ No newline at end of file From 5bb7d65da3ba50b1248d2539e54a9c9bae0c13fc Mon Sep 17 00:00:00 2001 From: nima nikoonazar Date: Thu, 14 Mar 2024 20:19:07 +0330 Subject: [PATCH 55/57] Return to Collection Initializer for collections in ExampleTests.cs --- .../Examples/ExampleTests.cs | 95 ++++++++++--------- 1 file changed, 51 insertions(+), 44 deletions(-) diff --git a/tests/NRedisStack.Tests/Examples/ExampleTests.cs b/tests/NRedisStack.Tests/Examples/ExampleTests.cs index 22aee9c0..40e9fd21 100644 --- a/tests/NRedisStack.Tests/Examples/ExampleTests.cs +++ b/tests/NRedisStack.Tests/Examples/ExampleTests.cs @@ -191,19 +191,21 @@ public async Task PipelineWithAsync() // Adding multiple sequence of time-series data. List<(string, TimeStamp, double)> sequence1 = - [ - ("temp:TLV", 1000, 30), - ("temp:TLV", 1010, 35), - ("temp:TLV", 1020, 9999), - ("temp:TLV", 1030, 40) - ]; + new() + { + ("temp:TLV", 1000, 30), + ("temp:TLV", 1010, 35), + ("temp:TLV", 1020, 9999), + ("temp:TLV", 1030, 40) + }; List<(string, TimeStamp, double)> sequence2 = - [ - ("temp:JLM", 1005, 30), - ("temp:JLM", 1015, 35), - ("temp:JLM", 1025, 9999), - ("temp:JLM", 1035, 40) - ]; + new() + { + ("temp:JLM", 1005, 30), + ("temp:JLM", 1015, 35), + ("temp:JLM", 1025, 9999), + ("temp:JLM", 1035, 40) + }; // Adding multiple samples to multiple series. _ = pipeline.Ts.MAddAsync(sequence1); @@ -1060,10 +1062,11 @@ public void BasicQueryOperationsTest() res = ft.Search("idx1", new Query("@price:[40,130]")).ToJson(); expectedList = - [ - "{\"id\":59263,\"gender\":\"Women\",\"season\":[\"Fall\",\"Winter\",\"Spring\",\"Summer\"],\"description\":\"Titan Women Silver Watch\",\"price\":129.99,\"city\":\"Dallas\",\"coords\":\"-96.808891, 32.779167\"}", - "{\"id\":46885,\"gender\":\"Boys\",\"season\":[\"Fall\"],\"description\":\"Ben 10 Boys Navy Blue Slippers\",\"price\":45.99,\"city\":\"Denver\",\"coords\":\"-104.991531, 39.742043\"}" - ]; + new List + { + "{\"id\":59263,\"gender\":\"Women\",\"season\":[\"Fall\",\"Winter\",\"Spring\",\"Summer\"],\"description\":\"Titan Women Silver Watch\",\"price\":129.99,\"city\":\"Dallas\",\"coords\":\"-96.808891, 32.779167\"}", + "{\"id\":46885,\"gender\":\"Boys\",\"season\":[\"Fall\"],\"description\":\"Ben 10 Boys Navy Blue Slippers\",\"price\":45.99,\"city\":\"Denver\",\"coords\":\"-104.991531, 39.742043\"}" + }; SortAndCompare(expectedList, res); @@ -1083,10 +1086,11 @@ public void BasicQueryOperationsTest() // Find all documents that either match tag value or text value: res = ft.Search("idx1", new Query("(@gender:{Women})|(@city:Boston)")).ToJson(); expectedList = - [ - "{\"id\":59263,\"gender\":\"Women\",\"season\":[\"Fall\",\"Winter\",\"Spring\",\"Summer\"],\"description\":\"Titan Women Silver Watch\",\"price\":129.99,\"city\":\"Dallas\",\"coords\":\"-96.808891, 32.779167\"}", - "{\"id\":15970,\"gender\":\"Men\",\"season\":[\"Fall\",\"Winter\"],\"description\":\"Turtle Check Men Navy Blue Shirt\",\"price\":34.95,\"city\":\"Boston\",\"coords\":\"-71.057083, 42.361145\"}" - ]; + new List + { + "{\"id\":59263,\"gender\":\"Women\",\"season\":[\"Fall\",\"Winter\",\"Spring\",\"Summer\"],\"description\":\"Titan Women Silver Watch\",\"price\":129.99,\"city\":\"Dallas\",\"coords\":\"-96.808891, 32.779167\"}", + "{\"id\":15970,\"gender\":\"Men\",\"season\":[\"Fall\",\"Winter\"],\"description\":\"Turtle Check Men Navy Blue Shirt\",\"price\":34.95,\"city\":\"Boston\",\"coords\":\"-71.057083, 42.361145\"}" + }; SortAndCompare(expectedList, res); @@ -1094,20 +1098,22 @@ public void BasicQueryOperationsTest() res = ft.Search("idx1", new Query("-(@description:Shirt)")).ToJson(); expectedList = - [ - "{\"id\":59263,\"gender\":\"Women\",\"season\":[\"Fall\",\"Winter\",\"Spring\",\"Summer\"],\"description\":\"Titan Women Silver Watch\",\"price\":129.99,\"city\":\"Dallas\",\"coords\":\"-96.808891, 32.779167\"}", - "{\"id\":46885,\"gender\":\"Boys\",\"season\":[\"Fall\"],\"description\":\"Ben 10 Boys Navy Blue Slippers\",\"price\":45.99,\"city\":\"Denver\",\"coords\":\"-104.991531, 39.742043\"}" - ]; + new List + { + "{\"id\":59263,\"gender\":\"Women\",\"season\":[\"Fall\",\"Winter\",\"Spring\",\"Summer\"],\"description\":\"Titan Women Silver Watch\",\"price\":129.99,\"city\":\"Dallas\",\"coords\":\"-96.808891, 32.779167\"}", + "{\"id\":46885,\"gender\":\"Boys\",\"season\":[\"Fall\"],\"description\":\"Ben 10 Boys Navy Blue Slippers\",\"price\":45.99,\"city\":\"Denver\",\"coords\":\"-104.991531, 39.742043\"}" + }; SortAndCompare(expectedList, res); // Find all documents that have a word that begins with a given prefix value: res = ft.Search("idx1", new Query("@description:Nav*")).ToJson(); expectedList = - [ - "{\"id\":15970,\"gender\":\"Men\",\"season\":[\"Fall\",\"Winter\"],\"description\":\"Turtle Check Men Navy Blue Shirt\",\"price\":34.95,\"city\":\"Boston\",\"coords\":\"-71.057083, 42.361145\"}", - "{\"id\":46885,\"gender\":\"Boys\",\"season\":[\"Fall\"],\"description\":\"Ben 10 Boys Navy Blue Slippers\",\"price\":45.99,\"city\":\"Denver\",\"coords\":\"-104.991531, 39.742043\"}" - ]; + new List + { + "{\"id\":15970,\"gender\":\"Men\",\"season\":[\"Fall\",\"Winter\"],\"description\":\"Turtle Check Men Navy Blue Shirt\",\"price\":34.95,\"city\":\"Boston\",\"coords\":\"-71.057083, 42.361145\"}", + "{\"id\":46885,\"gender\":\"Boys\",\"season\":[\"Fall\"],\"description\":\"Ben 10 Boys Navy Blue Slippers\",\"price\":45.99,\"city\":\"Denver\",\"coords\":\"-104.991531, 39.742043\"}" + }; SortAndCompare(expectedList, res); // Find all documents that contain a word that ends with a given suffix value: @@ -1122,10 +1128,11 @@ public void BasicQueryOperationsTest() expectedList = - [ - "{\"id\":15970,\"gender\":\"Men\",\"season\":[\"Fall\",\"Winter\"],\"description\":\"Turtle Check Men Navy Blue Shirt\",\"price\":34.95,\"city\":\"Boston\",\"coords\":\"-71.057083, 42.361145\"}", - "{\"id\":46885,\"gender\":\"Boys\",\"season\":[\"Fall\"],\"description\":\"Ben 10 Boys Navy Blue Slippers\",\"price\":45.99,\"city\":\"Denver\",\"coords\":\"-104.991531, 39.742043\"}" - ]; + new List + { + "{\"id\":15970,\"gender\":\"Men\",\"season\":[\"Fall\",\"Winter\"],\"description\":\"Turtle Check Men Navy Blue Shirt\",\"price\":34.95,\"city\":\"Boston\",\"coords\":\"-71.057083, 42.361145\"}", + "{\"id\":46885,\"gender\":\"Boys\",\"season\":[\"Fall\"],\"description\":\"Ben 10 Boys Navy Blue Slippers\",\"price\":45.99,\"city\":\"Denver\",\"coords\":\"-104.991531, 39.742043\"}" + }; SortAndCompare(expectedList, res); // Find all documents that have geographic coordinates within a given range of a given coordinate. @@ -1177,9 +1184,9 @@ public void AdvancedQueryOperationsTest() } catch { + //Todo: Check When Exception Catch } - ; Assert.True(ft.Create("vss_idx", new FTCreateParams().On(IndexDataType.HASH).Prefix("vec:"), new Schema() .AddTagField("tag") @@ -1202,7 +1209,7 @@ public void AdvancedQueryOperationsTest() .AddParam("query_vec", vec.SelectMany(BitConverter.GetBytes).ToArray()) .SetSortBy("__vector_score") .Dialect(2)); - HashSet resSet = []; + HashSet resSet = new HashSet(); foreach (var doc in res.Documents) { foreach (var item in doc.GetProperties()) @@ -1214,11 +1221,11 @@ public void AdvancedQueryOperationsTest() } } - HashSet expectedResSet = - [ + HashSet expectedResSet = new HashSet() + { "id: vec:3, score: 1", - "id: vec:2, score: 3" - ]; + "id: vec:2, score: 3", + }; Assert.Equal(expectedResSet, resSet); @@ -1242,10 +1249,11 @@ public void AdvancedQueryOperationsTest() } expectedResSet = - [ - "id: vec:2, score: 3", - "id: vec:4, score: 7" - ]; + new HashSet + { + "id: vec:2, score: 3", + "id: vec:4, score: 7" + }; //Advanced Search Queries: // data load: @@ -1321,10 +1329,9 @@ public void AdvancedQueryOperationsTest() } catch { - // ignored + //Todo: Check When Exception Catch } - ; Assert.True(ft.Create("wh_idx", new FTCreateParams() .On(IndexDataType.JSON) .Prefix("warehouse:"), From ef9ddaa02dc7c903eefa5be98a4040223db30579 Mon Sep 17 00:00:00 2001 From: nima nikoonazar Date: Mon, 18 Mar 2024 10:36:32 +0330 Subject: [PATCH 56/57] Return `ExecuteAsync` method in Auxiliary.cs to original version for sole complexity --- src/NRedisStack/Auxiliary.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/NRedisStack/Auxiliary.cs b/src/NRedisStack/Auxiliary.cs index 8cc96a7e..ffac0e27 100644 --- a/src/NRedisStack/Auxiliary.cs +++ b/src/NRedisStack/Auxiliary.cs @@ -67,9 +67,11 @@ public static RedisResult Execute(this IDatabase db, SerializedCommand command) public static async Task ExecuteAsync(this IDatabaseAsync db, SerializedCommand command) { - if (!_setInfo) return await db.ExecuteAsync(command.Command, command.Args); - _setInfo = false; - ((IDatabase)db).SetInfoInPipeline(); + if (_setInfo) + { + _setInfo = false; + ((IDatabase)db).SetInfoInPipeline(); + } return await db.ExecuteAsync(command.Command, command.Args); } From 4159b238cf8741576d43678221d42e45b654e656 Mon Sep 17 00:00:00 2001 From: Gabriel Erzse Date: Tue, 19 Mar 2024 10:00:35 +0200 Subject: [PATCH 57/57] Revert ToString() in code snippets Trying to keep code snippets as short as possible, since they get published on redis.io as documentation. Hence reverting the addition of the `ToString()` calls in some places. --- tests/Doc/StringSnippets.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/Doc/StringSnippets.cs b/tests/Doc/StringSnippets.cs index 0386c7d4..c7f3bade 100644 --- a/tests/Doc/StringSnippets.cs +++ b/tests/Doc/StringSnippets.cs @@ -27,7 +27,7 @@ public void run() // STEP_START set_get var res1 = db.StringSet("bike:1", "Deimos"); - Console.WriteLine(res1.ToString()); // true + Console.WriteLine(res1); // true var res2 = db.StringGet("bike:1"); Console.WriteLine(res2); // Deimos // STEP_END @@ -39,10 +39,10 @@ public void run() //STEP_START setnx_xx var res3 = db.StringSet("bike:1", "bike", when: When.NotExists); - Console.WriteLine(res3.ToString()); // false + Console.WriteLine(res3); // false Console.WriteLine(db.StringGet("bike:1")); var res4 = db.StringSet("bike:1", "bike", when: When.Exists); - Console.WriteLine(res4.ToString()); // true + Console.WriteLine(res4); // true //STEP_END //REMOVE_START @@ -55,9 +55,9 @@ public void run() { new ("bike:1", "Deimos"), new("bike:2", "Ares"), new("bike:3", "Vanth") }); - Console.WriteLine(res5.ToString()); + Console.WriteLine(res5); var res6 = db.StringGet(new RedisKey[] { "bike:1", "bike:2", "bike:3" }); - Console.WriteLine(res6.ToString()); + Console.WriteLine(res6); //STEP_END //REMOVE_START @@ -68,9 +68,9 @@ public void run() //STEP_START incr db.StringSet("total_crashes", 0); var res7 = db.StringIncrement("total_crashes"); - Console.WriteLine(res7.ToString()); // 1 + Console.WriteLine(res7); // 1 var res8 = db.StringIncrement("total_crashes", 10); - Console.WriteLine(res8.ToString()); + Console.WriteLine(res8); //STEP_END //REMOVE_START