From becd81ee8f6319d2a4517d1a1d9fa9abf9041430 Mon Sep 17 00:00:00 2001 From: Rohan Edman Date: Mon, 12 Dec 2022 07:52:17 -0500 Subject: [PATCH] Added error handling and empty array check (#255) --- src/Redis.OM/RedisConnection.cs | 24 +- src/Redis.OM/Searching/SearchResponse.cs | 16 +- test/Redis.OM.Unit.Tests/CoreTests.cs | 20 +- .../RediSearchTests/SearchTests.cs | 330 +++++++++--------- 4 files changed, 211 insertions(+), 179 deletions(-) diff --git a/src/Redis.OM/RedisConnection.cs b/src/Redis.OM/RedisConnection.cs index 50f6ccf6..997f4ea9 100644 --- a/src/Redis.OM/RedisConnection.cs +++ b/src/Redis.OM/RedisConnection.cs @@ -26,15 +26,29 @@ internal RedisConnection(IDatabase db) /// public RedisReply Execute(string command, params string[] args) { - var result = _db.Execute(command, args); - return new RedisReply(result); + try + { + var result = _db.Execute(command, args); + return new RedisReply(result); + } + catch (Exception ex) + { + throw new Exception($"{ex.Message}{Environment.NewLine}Failed on {command} {string.Join(" ", args)}", ex); + } } /// public async Task ExecuteAsync(string command, params string[] args) { - var result = await _db.ExecuteAsync(command, args); - return new RedisReply(result); + try + { + var result = await _db.ExecuteAsync(command, args); + return new RedisReply(result); + } + catch (Exception ex) + { + throw new Exception($"{ex.Message}{Environment.NewLine}Failed on {command} {string.Join(" ", args)}", ex); + } } /// @@ -72,4 +86,4 @@ public void Dispose() { } } -} +} \ No newline at end of file diff --git a/src/Redis.OM/Searching/SearchResponse.cs b/src/Redis.OM/Searching/SearchResponse.cs index bd7ece2b..5e458fe9 100644 --- a/src/Redis.OM/Searching/SearchResponse.cs +++ b/src/Redis.OM/Searching/SearchResponse.cs @@ -67,6 +67,7 @@ public IDictionary DocumentsAs() /// /// The type. #pragma warning disable SA1402 + public class SearchResponse #pragma warning restore SA1402 where T : notnull @@ -101,13 +102,16 @@ public SearchResponse(RedisReply val) var docId = (string)vals[i]; var documentHash = new Dictionary(); var docArray = vals[i + 1].ToArray(); - for (var j = 0; j < docArray.Length; j += 2) + if (docArray.Length > 1) { - documentHash.Add(docArray[j], docArray[j + 1]); - } + for (var j = 0; j < docArray.Length; j += 2) + { + documentHash.Add(docArray[j], docArray[j + 1]); + } - var obj = RedisObjectHandler.FromHashSet(documentHash); - Documents.Add(docId, obj); + var obj = RedisObjectHandler.FromHashSet(documentHash); + Documents.Add(docId, obj); + } } } } @@ -155,4 +159,4 @@ private static SearchResponse PrimitiveSearchResponse(RedisReply redisReply) return response; } } -} +} \ No newline at end of file diff --git a/test/Redis.OM.Unit.Tests/CoreTests.cs b/test/Redis.OM.Unit.Tests/CoreTests.cs index bb27915e..58d343d9 100644 --- a/test/Redis.OM.Unit.Tests/CoreTests.cs +++ b/test/Redis.OM.Unit.Tests/CoreTests.cs @@ -327,17 +327,15 @@ public async Task SimpleJsonInsertWhenAsync() var host = Environment.GetEnvironmentVariable("STANDALONE_HOST_PORT") ?? "localhost"; var provider = new RedisConnectionProvider($"redis://{host}"); var connection = provider.Connection; - var collection = new RedisCollection(provider.Connection); + var collection = new RedisCollection(provider.Connection); - var obj = new Person { Name = "Steve", Age = 33 }; + var obj = new BasicJsonObject { Name = "Steve" }; var key = await collection.InsertAsync(obj, WhenKey.NotExists); Assert.NotNull(key); var reconstituted = await collection.FindByIdAsync(key); Assert.NotNull(reconstituted); Assert.Equal("Steve", reconstituted.Name); - Assert.Equal(33, reconstituted.Age); obj.Name = "Shachar"; - obj.Age = null; var res = await collection.InsertAsync(obj, WhenKey.NotExists); // this should fail Assert.Null(res); @@ -346,14 +344,17 @@ public async Task SimpleJsonInsertWhenAsync() Assert.Equal(key,res); reconstituted = await collection.FindByIdAsync(key); Assert.NotNull(reconstituted); - Assert.Null(reconstituted.Age); Assert.Equal("Shachar" , reconstituted.Name); await connection.UnlinkAsync(key); - await collection.InsertAsync(obj, WhenKey.NotExists, TimeSpan.FromMilliseconds(5000)); + var k2 = await collection.InsertAsync(obj, WhenKey.NotExists, TimeSpan.FromMilliseconds(5000)); + Assert.NotNull(k2); + Assert.Equal(key, k2); var expiration = (long)await connection.ExecuteAsync("PTTL", key); + Assert.Equal(key.Split(":")[1], obj.Id); Assert.True(expiration>4000); await Task.Delay(1000); + Assert.True(connection.Execute("EXISTS", key) == 1, $"Expected: {key} to exist, it did not."); res = await collection.InsertAsync(obj, WhenKey.NotExists, TimeSpan.FromMilliseconds(5000)); Assert.Null(res); expiration = (long)await connection.ExecuteAsync("PTTL", key); @@ -380,17 +381,15 @@ public void SimpleJsonInsertWhen() var host = Environment.GetEnvironmentVariable("STANDALONE_HOST_PORT") ?? "localhost"; var provider = new RedisConnectionProvider($"redis://{host}"); var connection = provider.Connection; - var collection = new RedisCollection(provider.Connection); + var collection = new RedisCollection(provider.Connection); - var obj = new Person { Name = "Steve", Age = 33 }; + var obj = new BasicJsonObject { Name = "Steve" }; var key = collection.Insert(obj, WhenKey.NotExists); Assert.NotNull(key); var reconstituted = collection.FindById(key); Assert.NotNull(reconstituted); Assert.Equal("Steve", reconstituted.Name); - Assert.Equal(33, reconstituted.Age); obj.Name = "Shachar"; - obj.Age = null; var res = collection.Insert(obj, WhenKey.NotExists); // this should fail Assert.Null(res); @@ -399,7 +398,6 @@ public void SimpleJsonInsertWhen() Assert.Equal(key,res); reconstituted = collection.FindById(key); Assert.NotNull(reconstituted); - Assert.Null(reconstituted.Age); Assert.Equal("Shachar" , reconstituted.Name); connection.Unlink(key); diff --git a/test/Redis.OM.Unit.Tests/RediSearchTests/SearchTests.cs b/test/Redis.OM.Unit.Tests/RediSearchTests/SearchTests.cs index c462a476..faed911e 100644 --- a/test/Redis.OM.Unit.Tests/RediSearchTests/SearchTests.cs +++ b/test/Redis.OM.Unit.Tests/RediSearchTests/SearchTests.cs @@ -9,13 +9,16 @@ using Redis.OM.Searching; using Redis.OM.Common; using Xunit; +using Redis.OM.Searching.Query; +using StackExchange.Redis; namespace Redis.OM.Unit.Tests.RediSearchTests { public class SearchTests { - Mock _mock = new Mock(); - RedisReply _mockReply = new RedisReply[] + private Mock _mock = new Mock(); + + private RedisReply _mockReply = new RedisReply[] { new RedisReply(1), new RedisReply("Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N"), @@ -26,12 +29,12 @@ public class SearchTests }) }; - RedisReply _mockReplyNone = new RedisReply[] + private RedisReply _mockReplyNone = new RedisReply[] { new (0), }; - RedisReply _mockReply2Count = new RedisReply[] + private RedisReply _mockReply2Count = new RedisReply[] { new RedisReply(2), new RedisReply("Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N"), @@ -42,7 +45,7 @@ public class SearchTests }) }; - RedisReply _mockReplySelect = new RedisReply[] + private RedisReply _mockReplySelect = new RedisReply[] { new RedisReply(1), new RedisReply("Person:33b58265-2656-4c5e-8476-7246549797d1"), @@ -109,11 +112,10 @@ public void TestFirstOrDefaultWithMixedLocals() { _mock.Setup(x => x.Execute(It.IsAny(), It.IsAny())) .Returns(_mockReply); - var heightList = new List {70.0, 68.0}; + var heightList = new List { 70.0, 68.0 }; var y = 33; foreach (var height in heightList) { - var collection = new RedisCollection(_mock.Object); var res = collection.FirstOrDefault(x => x.Age == y && x.Height == height); _mock.Verify(x => x.Execute( @@ -123,7 +125,6 @@ public void TestFirstOrDefaultWithMixedLocals() "LIMIT", "0", "1")); - } } @@ -221,7 +222,7 @@ public void TestBasicOrQueryWithNegation() .Returns(_mockReply); var collection = new RedisCollection(_mock.Object); - var res = collection.Where(x => x.Age < 33 || x.TagField != "Steve" || x.Name !="Steve").ToList(); + var res = collection.Where(x => x.Age < 33 || x.TagField != "Steve" || x.Name != "Steve").ToList(); Assert.Equal(32, res[0].Age); _mock.Verify(x => x.Execute( "FT.SEARCH", @@ -235,7 +236,7 @@ public void TestBasicOrQueryWithNegation() [Fact] public void TestBasicAndQuery() { - _mock.Setup(x => x.Execute(It.IsAny(),It.IsAny())) + _mock.Setup(x => x.Execute(It.IsAny(), It.IsAny())) .Returns(_mockReply); var collection = new RedisCollection(_mock.Object); @@ -274,7 +275,7 @@ public void TestBasicThreeCluaseQuery() .Returns(_mockReply); var collection = new RedisCollection(_mock.Object); - var res = collection.Where(x => x.Age < 33 && x.TagField == "Steve" && x.Height>=70).ToList(); + var res = collection.Where(x => x.Age < 33 && x.TagField == "Steve" && x.Height >= 70).ToList(); _mock.Verify(x => x.Execute( "FT.SEARCH", "person-idx", @@ -325,7 +326,7 @@ public void TestBasicQueryFromPropertyOfModel() .Returns(_mockReply); var collection = new RedisCollection(_mock.Object); - var modelObject = new Person() {Name = "Steve"}; + var modelObject = new Person() { Name = "Steve" }; collection.Where(x => x.Name == modelObject.Name).ToList(); _mock.Verify(x => x.Execute( "FT.SEARCH", @@ -343,7 +344,7 @@ public void TestBasicQueryFromPropertyOfModelWithStringInterpolation() .Returns(_mockReply); var collection = new RedisCollection(_mock.Object); - var modelObject = new Person() {Name = "Steve"}; + var modelObject = new Person() { Name = "Steve" }; collection.Where(x => x.Name == $"A {nameof(Person)} named {modelObject.Name}").ToList(); _mock.Verify(x => x.Execute( "FT.SEARCH", @@ -361,7 +362,7 @@ public void TestBasicQueryFromPropertyOfModelWithStringFormatFourArgs() .Returns(_mockReply); var collection = new RedisCollection(_mock.Object); - var modelObject = new Person() {Name = "Steve"}; + var modelObject = new Person() { Name = "Steve" }; var a = "A"; var named = "named"; collection.Where(x => x.Name == string.Format("{0} {1} {2} {3}", a, nameof(Person), named, modelObject.Name)).ToList(); @@ -446,7 +447,7 @@ public void TestGeoFilter() .Returns(_mockReply); var collection = new RedisCollection(_mock.Object); - var res = collection.GeoFilter(x=>x.Home, 5, 6.7, 50, GeoLocDistanceUnit.Kilometers).ToList(); + var res = collection.GeoFilter(x => x.Home, 5, 6.7, 50, GeoLocDistanceUnit.Kilometers).ToList(); Assert.Equal(32, res[0].Age); } @@ -457,7 +458,7 @@ public void TestGeoFilterWithWhereClause() .Returns(_mockReply); var collection = new RedisCollection(_mock.Object); - var res = collection.Where(x=>x.TagField == "Steve").GeoFilter(x => x.Home, 5, 6.7, 50, GeoLocDistanceUnit.Kilometers).ToList(); + var res = collection.Where(x => x.TagField == "Steve").GeoFilter(x => x.Home, 5, 6.7, 50, GeoLocDistanceUnit.Kilometers).ToList(); Assert.Equal(32, res[0].Age); _mock.Verify(x => x.Execute( "FT.SEARCH", @@ -482,7 +483,7 @@ public void TestSelect() .Returns(_mockReplySelect); var collection = new RedisCollection(_mock.Object); - var res = collection.Select(x=>x.Name).ToList(); + var res = collection.Select(x => x.Name).ToList(); _mock.Verify(x => x.Execute( "FT.SEARCH", "person-idx", @@ -555,7 +556,7 @@ public void TestPaginationChunkSizesMultiplePredicates() .Returns(_mockReply); var collection = new RedisCollection(_mock.Object, 1000); - var res = collection.Where(x=>x.TagField == "Steve").GeoFilter(x => x.Home, 5, 6.7, 50, GeoLocDistanceUnit.Kilometers).ToList(); + var res = collection.Where(x => x.TagField == "Steve").GeoFilter(x => x.Home, 5, 6.7, 50, GeoLocDistanceUnit.Kilometers).ToList(); Assert.Equal(32, res[0].Age); _mock.Verify(x => x.Execute( "FT.SEARCH", @@ -580,7 +581,7 @@ public void TestNestedObjectStringSearch() .Returns(_mockReply); var collection = new RedisCollection(_mock.Object, 1000); - var res = collection.Where(x=>x.Address.City == "Newark").ToList(); + var res = collection.Where(x => x.Address.City == "Newark").ToList(); _mock.Verify(x => x.Execute( "FT.SEARCH", "person-idx", @@ -598,7 +599,7 @@ public void TestNestedObjectStringSearchNested2Levels() .Returns(_mockReply); var collection = new RedisCollection(_mock.Object, 1000); - var res = collection.Where(x=>x.Address.ForwardingAddress.City == "Newark").ToList(); + var res = collection.Where(x => x.Address.ForwardingAddress.City == "Newark").ToList(); _mock.Verify(x => x.Execute( "FT.SEARCH", "person-idx", @@ -616,7 +617,7 @@ public void TestNestedObjectNumericSearch() .Returns(_mockReply); var collection = new RedisCollection(_mock.Object, 1000); - var res = collection.Where(x=>x.Address.HouseNumber == 4).ToList(); + var res = collection.Where(x => x.Address.HouseNumber == 4).ToList(); _mock.Verify(x => x.Execute( "FT.SEARCH", "person-idx", @@ -634,7 +635,7 @@ public void TestNestedObjectNumericSearch2Levels() .Returns(_mockReply); var collection = new RedisCollection(_mock.Object, 1000); - var res = collection.Where(x=>x.Address.ForwardingAddress.HouseNumber == 4).ToList(); + var res = collection.Where(x => x.Address.ForwardingAddress.HouseNumber == 4).ToList(); _mock.Verify(x => x.Execute( "FT.SEARCH", "person-idx", @@ -769,7 +770,7 @@ public void TestArrayContainsNested() [Fact] public async Task TestUpdateJson() { - _mock.Setup(x=>x.Execute("FT.SEARCH", It.IsAny())) + _mock.Setup(x => x.Execute("FT.SEARCH", It.IsAny())) .Returns(_mockReply); _mock.Setup(x => x.ExecuteAsync("EVALSHA", It.IsAny())).ReturnsAsync("42"); _mock.Setup(x => x.ExecuteAsync("SCRIPT", It.IsAny())).ReturnsAsync("42"); @@ -777,14 +778,14 @@ public async Task TestUpdateJson() var steve = collection.First(x => x.Name == "Steve"); steve.Age = 33; await collection.UpdateAsync(steve); - _mock.Verify(x=>x.ExecuteAsync("EVALSHA","42","1","Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N", "SET","$.Age","33")); + _mock.Verify(x => x.ExecuteAsync("EVALSHA", "42", "1", "Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N", "SET", "$.Age", "33")); Scripts.ShaCollection.Clear(); } [Fact] public async Task TestUpdateJsonName() { - _mock.Setup(x=>x.Execute("FT.SEARCH", It.IsAny())) + _mock.Setup(x => x.Execute("FT.SEARCH", It.IsAny())) .Returns(_mockReply); _mock.Setup(x => x.ExecuteAsync("EVALSHA", It.IsAny())).ReturnsAsync("42"); _mock.Setup(x => x.ExecuteAsync("SCRIPT", It.IsAny())).ReturnsAsync("42"); @@ -792,28 +793,28 @@ public async Task TestUpdateJsonName() var steve = collection.First(x => x.Name == "Steve"); steve.Name = "Bob"; await collection.UpdateAsync(steve); - _mock.Verify(x=>x.ExecuteAsync("EVALSHA",It.IsAny(),"1","Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N", "SET","$.Name","\"Bob\"")); + _mock.Verify(x => x.ExecuteAsync("EVALSHA", It.IsAny(), "1", "Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N", "SET", "$.Name", "\"Bob\"")); Scripts.ShaCollection.Clear(); } [Fact] public async Task TestUpdateJsonNestedObject() { - _mock.Setup(x=>x.Execute("FT.SEARCH", It.IsAny())) + _mock.Setup(x => x.Execute("FT.SEARCH", It.IsAny())) .Returns(_mockReply); _mock.Setup(x => x.ExecuteAsync("EVALSHA", It.IsAny())).ReturnsAsync("42"); _mock.Setup(x => x.ExecuteAsync("SCRIPT", It.IsAny())).ReturnsAsync("42"); var collection = new RedisCollection(_mock.Object); var steve = collection.First(x => x.Name == "Steve"); - steve.Address = new Address {State = "Florida"}; + steve.Address = new Address { State = "Florida" }; await collection.UpdateAsync(steve); var expected = $"{{{Environment.NewLine} \"State\": \"Florida\"{Environment.NewLine}}}"; - _mock.Verify(x=>x.ExecuteAsync("EVALSHA","42","1","Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N", "SET","$.Address",expected)); + _mock.Verify(x => x.ExecuteAsync("EVALSHA", "42", "1", "Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N", "SET", "$.Address", expected)); steve.Address.City = "Satellite Beach"; await collection.UpdateAsync(steve); expected = "\"Satellite Beach\""; - _mock.Verify(x=>x.ExecuteAsync("EVALSHA","42","1","Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N", "SET","$.Address.City",expected)); + _mock.Verify(x => x.ExecuteAsync("EVALSHA", "42", "1", "Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N", "SET", "$.Address.City", expected)); Scripts.ShaCollection.Clear(); } @@ -821,7 +822,7 @@ public async Task TestUpdateJsonNestedObject() [Fact] public async Task TestUpdateJsonWithDouble() { - _mock.Setup(x=>x.Execute("FT.SEARCH", It.IsAny())) + _mock.Setup(x => x.Execute("FT.SEARCH", It.IsAny())) .Returns(_mockReply); _mock.Setup(x => x.ExecuteAsync("EVALSHA", It.IsAny())).ReturnsAsync("42"); _mock.Setup(x => x.ExecuteAsync("SCRIPT", It.IsAny())).ReturnsAsync("42"); @@ -830,7 +831,7 @@ public async Task TestUpdateJsonWithDouble() steve.Age = 33; steve.Height = 71.5; await collection.UpdateAsync(steve); - _mock.Verify(x=>x.ExecuteAsync("EVALSHA","42","1","Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N", "SET","$.Age","33", "SET","$.Height", "71.5")); + _mock.Verify(x => x.ExecuteAsync("EVALSHA", "42", "1", "Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N", "SET", "$.Age", "33", "SET", "$.Height", "71.5")); Scripts.ShaCollection.Clear(); } @@ -838,7 +839,7 @@ public async Task TestUpdateJsonWithDouble() public async Task TestDeleteAsync() { const string key = "Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N"; - _mock.Setup(x=>x.Execute("FT.SEARCH", It.IsAny())) + _mock.Setup(x => x.Execute("FT.SEARCH", It.IsAny())) .Returns(_mockReply); _mock.Setup(x => x.ExecuteAsync("UNLINK", It.IsAny())).ReturnsAsync("1"); var colleciton = new RedisCollection(_mock.Object); @@ -846,15 +847,16 @@ public async Task TestDeleteAsync() Assert.True(colleciton.StateManager.Data.ContainsKey(key)); Assert.True(colleciton.StateManager.Snapshot.ContainsKey(key)); await colleciton.DeleteAsync(steve); - _mock.Verify(x=>x.ExecuteAsync("UNLINK",key)); + _mock.Verify(x => x.ExecuteAsync("UNLINK", key)); Assert.False(colleciton.StateManager.Data.ContainsKey(key)); Assert.False(colleciton.StateManager.Snapshot.ContainsKey(key)); } + [Fact] public void TestDelete() { const string key = "Redis.OM.Unit.Tests.RediSearchTests.Person:01FVN836BNQGYMT80V7RCVY73N"; - _mock.Setup(x=>x.Execute("FT.SEARCH", It.IsAny())) + _mock.Setup(x => x.Execute("FT.SEARCH", It.IsAny())) .Returns(_mockReply); _mock.Setup(x => x.ExecuteAsync("UNLINK", It.IsAny())).ReturnsAsync("1"); var colleciton = new RedisCollection(_mock.Object); @@ -862,7 +864,7 @@ public void TestDelete() Assert.True(colleciton.StateManager.Data.ContainsKey(key)); Assert.True(colleciton.StateManager.Snapshot.ContainsKey(key)); colleciton.DeleteAsync(steve); - _mock.Verify(x=>x.ExecuteAsync("UNLINK",key)); + _mock.Verify(x => x.ExecuteAsync("UNLINK", key)); Assert.False(colleciton.StateManager.Data.ContainsKey(key)); Assert.False(colleciton.StateManager.Snapshot.ContainsKey(key)); } @@ -875,19 +877,19 @@ public async Task TestFirstAsync(bool useExpression) _mock.Setup(x => x.ExecuteAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(_mockReply); - var expectedPredicate = useExpression ? "(@TagField:{bob})" : "*"; + var expectedPredicate = useExpression ? "(@TagField:{bob})" : "*"; var collection = new RedisCollection(_mock.Object); if (useExpression) { - _ = await collection.FirstAsync( x=> x.TagField == "bob"); + _ = await collection.FirstAsync(x => x.TagField == "bob"); } else { _ = await collection.FirstAsync(); } - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", expectedPredicate, @@ -904,18 +906,18 @@ public async Task TestFirstAsyncNone(bool useExpression) _mock.Setup(x => x.ExecuteAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(_mockReplyNone); - var expectedPredicate = useExpression ? "(@TagField:{bob})" : "*"; + var expectedPredicate = useExpression ? "(@TagField:{bob})" : "*"; var collection = new RedisCollection(_mock.Object); if (useExpression) { - await Assert.ThrowsAsync(async () => await collection.FirstAsync(x=>x.TagField == "bob")); + await Assert.ThrowsAsync(async () => await collection.FirstAsync(x => x.TagField == "bob")); } else { await Assert.ThrowsAsync(async () => await collection.FirstAsync()); } - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", expectedPredicate, @@ -932,13 +934,13 @@ public async Task TestFirstOrDefaultAsync(bool useExpression) _mock.Setup(x => x.ExecuteAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(_mockReply); - var expectedPredicate = useExpression ? "(@TagField:{bob})" : "*"; + var expectedPredicate = useExpression ? "(@TagField:{bob})" : "*"; var collection = new RedisCollection(_mock.Object); Person? res; if (useExpression) { - res = await collection.FirstOrDefaultAsync(x=>x.TagField == "bob"); + res = await collection.FirstOrDefaultAsync(x => x.TagField == "bob"); } else { @@ -946,7 +948,7 @@ public async Task TestFirstOrDefaultAsync(bool useExpression) } Assert.NotNull(res); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", expectedPredicate, @@ -965,12 +967,12 @@ public async Task TestFirstOrDefaultAsyncNone(bool useExpression) var collection = new RedisCollection(_mock.Object); - var expectedPredicate = useExpression ? "(@TagField:{bob})" : "*"; + var expectedPredicate = useExpression ? "(@TagField:{bob})" : "*"; Person? res; if (useExpression) { - res = await collection.FirstOrDefaultAsync(x=>x.TagField == "bob"); + res = await collection.FirstOrDefaultAsync(x => x.TagField == "bob"); } else { @@ -978,7 +980,7 @@ public async Task TestFirstOrDefaultAsyncNone(bool useExpression) } Assert.Null(res); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", expectedPredicate, @@ -995,7 +997,7 @@ public async Task TestSingleAsync(bool useExpression) _mock.Setup(x => x.ExecuteAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(_mockReply); - var expectedPredicate = useExpression ? "(@TagField:{bob})" : "*"; + var expectedPredicate = useExpression ? "(@TagField:{bob})" : "*"; var collection = new RedisCollection(_mock.Object); Person res; if (useExpression) @@ -1007,7 +1009,7 @@ public async Task TestSingleAsync(bool useExpression) res = await collection.SingleAsync(); } Assert.NotNull(res); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", expectedPredicate, @@ -1025,17 +1027,17 @@ public async Task TestSingleAsyncNone(bool useExpression) .ReturnsAsync(_mockReplyNone); var collection = new RedisCollection(_mock.Object); - var expectedPredicate = useExpression ? "(@TagField:{bob})" : "*"; + var expectedPredicate = useExpression ? "(@TagField:{bob})" : "*"; if (useExpression) { - await Assert.ThrowsAsync(async () => await collection.SingleAsync(x=>x.TagField == "bob")); + await Assert.ThrowsAsync(async () => await collection.SingleAsync(x => x.TagField == "bob")); } else { await Assert.ThrowsAsync(async () => await collection.SingleAsync()); } - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", expectedPredicate, @@ -1053,17 +1055,17 @@ public async Task TestSingleAsyncTwo(bool useExpression) .ReturnsAsync(_mockReply2Count); var collection = new RedisCollection(_mock.Object); - var expectedPredicate = useExpression ? "(@TagField:{bob})" : "*"; + var expectedPredicate = useExpression ? "(@TagField:{bob})" : "*"; if (useExpression) { - await Assert.ThrowsAsync(async () => await collection.SingleAsync(x=>x.TagField == "bob")); + await Assert.ThrowsAsync(async () => await collection.SingleAsync(x => x.TagField == "bob")); } else { await Assert.ThrowsAsync(async () => await collection.SingleAsync()); } - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", expectedPredicate, @@ -1082,7 +1084,7 @@ public async Task TestSingleOrDefaultAsync(bool useExpression) var collection = new RedisCollection(_mock.Object); - var expectedPredicate = useExpression ? "(@TagField:{bob})" : "*"; + var expectedPredicate = useExpression ? "(@TagField:{bob})" : "*"; Person? res; if (useExpression) @@ -1095,7 +1097,7 @@ public async Task TestSingleOrDefaultAsync(bool useExpression) } Assert.NotNull(res); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", expectedPredicate, @@ -1114,7 +1116,7 @@ public async Task TestSingleOrDefaultAsyncNone(bool useExpression) var collection = new RedisCollection(_mock.Object); - var expectedPredicate = useExpression ? "(@TagField:{bob})" : "*"; + var expectedPredicate = useExpression ? "(@TagField:{bob})" : "*"; Person? res; if (useExpression) @@ -1127,7 +1129,7 @@ public async Task TestSingleOrDefaultAsyncNone(bool useExpression) } Assert.Null(res); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", expectedPredicate, @@ -1146,7 +1148,7 @@ public async Task TestSingleOrDefaultAsyncTwo(bool useExpression) var collection = new RedisCollection(_mock.Object); - var expectedPredicate = useExpression ? "(@TagField:{bob})" : "*"; + var expectedPredicate = useExpression ? "(@TagField:{bob})" : "*"; Person? res; if (useExpression) @@ -1159,7 +1161,7 @@ public async Task TestSingleOrDefaultAsyncTwo(bool useExpression) } Assert.Null(res); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", expectedPredicate, @@ -1176,13 +1178,13 @@ public async Task TestAnyAsync(bool useExpression) _mock.Setup(x => x.ExecuteAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(_mockReply); - var expectedPredicate = useExpression ? "(@TagField:{bob})" : "*"; + var expectedPredicate = useExpression ? "(@TagField:{bob})" : "*"; var collection = new RedisCollection(_mock.Object); var res = await (useExpression ? collection.AnyAsync(x => x.TagField == "bob") : collection.AnyAsync()); Assert.True(res); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", expectedPredicate, @@ -1201,11 +1203,11 @@ public async Task TestAnyAsyncNone(bool useExpression) var collection = new RedisCollection(_mock.Object); - var expectedPredicate = useExpression ? "(@TagField:{bob})" : "*"; + var expectedPredicate = useExpression ? "(@TagField:{bob})" : "*"; var res = await (useExpression ? collection.AnyAsync(x => x.TagField == "bob") : collection.AnyAsync()); Assert.False(res); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", expectedPredicate, @@ -1224,10 +1226,10 @@ public async Task TestCountAsync(bool useExpression) var collection = new RedisCollection(_mock.Object); - var expectedPredicate = useExpression ? "(@TagField:{bob})" : "*"; + var expectedPredicate = useExpression ? "(@TagField:{bob})" : "*"; var res = await (useExpression ? collection.CountAsync(x => x.TagField == "bob") : collection.CountAsync()); - Assert.Equal(1,res); - _mock.Verify(x=>x.ExecuteAsync( + Assert.Equal(1, res); + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", expectedPredicate, @@ -1245,10 +1247,10 @@ public async Task TestCount2Async(bool useExpression) .ReturnsAsync(_mockReply2Count); var collection = new RedisCollection(_mock.Object); - var expectedPredicate = useExpression ? "(@TagField:{bob})" : "*"; + var expectedPredicate = useExpression ? "(@TagField:{bob})" : "*"; var res = await (useExpression ? collection.CountAsync(x => x.TagField == "bob") : collection.CountAsync()); - Assert.Equal(2,res); - _mock.Verify(x=>x.ExecuteAsync( + Assert.Equal(2, res); + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", expectedPredicate, @@ -1265,7 +1267,7 @@ public async Task TestOrderByWithAsync() var collection = new RedisCollection(_mock.Object); var expectedPredicate = "*"; _ = await collection.OrderBy(x => x.Age).ToListAsync(); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", expectedPredicate, @@ -1285,7 +1287,7 @@ public async Task TestOrderByDescendingWithAsync() var collection = new RedisCollection(_mock.Object); var expectedPredicate = "*"; _ = await collection.OrderByDescending(x => x.Age).ToListAsync(); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", expectedPredicate, @@ -1308,7 +1310,7 @@ public async Task CombinedExpressionsWithFirstOrDefaultAsync() var expectedPredicate = "(@Name:\"Bob\")"; _ = await collection.Where(x => x.Name == "Bob").FirstOrDefaultAsync(); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", expectedPredicate, @@ -1328,7 +1330,7 @@ public async Task CombinedExpressionsWithFirstAsync() var expectedPredicate = "(@Name:\"Bob\")"; _ = await collection.Where(x => x.Name == "Bob").FirstAsync(); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", expectedPredicate, @@ -1348,7 +1350,7 @@ public async Task CombinedExpressionsWithAnyAsync() var expectedPredicate = "(@Name:\"Bob\")"; _ = await collection.Where(x => x.Name == "Bob").AnyAsync(); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", expectedPredicate, @@ -1368,7 +1370,7 @@ public async Task CombinedExpressionsSingleOrDefaultAsync() var expectedPredicate = "(@Name:\"Bob\")"; _ = await collection.Where(x => x.Name == "Bob").SingleOrDefaultAsync(); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", expectedPredicate, @@ -1388,7 +1390,7 @@ public async Task CombinedExpressionsSingleAsync() var expectedPredicate = "(@Name:\"Bob\")"; _ = await collection.Where(x => x.Name == "Bob").SingleAsync(); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", expectedPredicate, @@ -1408,7 +1410,7 @@ public async Task CombinedExpressionsCountAsync() var expectedPredicate = "(@Name:\"Bob\")"; _ = await collection.Where(x => x.Name == "Bob").CountAsync(); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", expectedPredicate, @@ -1426,9 +1428,9 @@ public async Task TestCombinedExpressionWithExpressionFirstOrDefaultAsync() var collection = new RedisCollection(_mock.Object); var expectedPredicate = "(@Name:\"Bob\")"; - _ = await collection.GeoFilter(x => x.Home, 5,5,10,GeoLocDistanceUnit.Miles).FirstOrDefaultAsync(x=>x.Name == "Bob"); + _ = await collection.GeoFilter(x => x.Home, 5, 5, 10, GeoLocDistanceUnit.Miles).FirstOrDefaultAsync(x => x.Name == "Bob"); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", expectedPredicate, @@ -1452,9 +1454,9 @@ public async Task TestCombinedExpressionWithExpressionFirstAsync() var collection = new RedisCollection(_mock.Object); var expectedPredicate = "(@Name:\"Bob\")"; - _ = await collection.GeoFilter(x => x.Home, 5,5,10,GeoLocDistanceUnit.Miles).FirstAsync(x=>x.Name == "Bob"); + _ = await collection.GeoFilter(x => x.Home, 5, 5, 10, GeoLocDistanceUnit.Miles).FirstAsync(x => x.Name == "Bob"); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", expectedPredicate, @@ -1478,9 +1480,9 @@ public async Task TestCombinedExpressionWithExpressionAnyAsync() var collection = new RedisCollection(_mock.Object); var expectedPredicate = "(@Name:\"Bob\")"; - _ = await collection.GeoFilter(x => x.Home, 5,5,10,GeoLocDistanceUnit.Miles).AnyAsync(x=>x.Name == "Bob"); + _ = await collection.GeoFilter(x => x.Home, 5, 5, 10, GeoLocDistanceUnit.Miles).AnyAsync(x => x.Name == "Bob"); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", expectedPredicate, @@ -1504,9 +1506,9 @@ public async Task TestCombinedExpressionWithExpressionSingleAsync() var collection = new RedisCollection(_mock.Object); var expectedPredicate = "(@Name:\"Bob\")"; - _ = await collection.GeoFilter(x => x.Home, 5,5,10,GeoLocDistanceUnit.Miles).SingleAsync(x=>x.Name == "Bob"); + _ = await collection.GeoFilter(x => x.Home, 5, 5, 10, GeoLocDistanceUnit.Miles).SingleAsync(x => x.Name == "Bob"); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", expectedPredicate, @@ -1530,9 +1532,9 @@ public async Task TestCombinedExpressionWithExpressionSingleOrDefaultAsync() var collection = new RedisCollection(_mock.Object); var expectedPredicate = "(@Name:\"Bob\")"; - _ = await collection.GeoFilter(x => x.Home, 5,5,10,GeoLocDistanceUnit.Miles).SingleOrDefaultAsync(x=>x.Name == "Bob"); + _ = await collection.GeoFilter(x => x.Home, 5, 5, 10, GeoLocDistanceUnit.Miles).SingleOrDefaultAsync(x => x.Name == "Bob"); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", expectedPredicate, @@ -1556,9 +1558,9 @@ public async Task TestCombinedExpressionWithExpressionCountAsync() var collection = new RedisCollection(_mock.Object); var expectedPredicate = "(@Name:\"Bob\")"; - _ = await collection.GeoFilter(x => x.Home, 5,5,10,GeoLocDistanceUnit.Miles).CountAsync(x=>x.Name == "Bob"); + _ = await collection.GeoFilter(x => x.Home, 5, 5, 10, GeoLocDistanceUnit.Miles).CountAsync(x => x.Name == "Bob"); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", expectedPredicate, @@ -1581,7 +1583,7 @@ public async Task TestCreateIndexWithNoStopwords() await _mock.Object.CreateIndexAsync(typeof(ObjectWithZeroStopwords)); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.CREATE", $"{nameof(ObjectWithZeroStopwords).ToLower()}-idx", "ON", @@ -1602,7 +1604,7 @@ public async Task TestCreateIndexWithTwoStopwords() await _mock.Object.CreateIndexAsync(typeof(ObjectWithTwoStopwords)); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.CREATE", $"{nameof(ObjectWithTwoStopwords).ToLower()}-idx", "ON", @@ -1622,7 +1624,7 @@ public async Task TestCreateIndexWithStringlikeValueTypes() await _mock.Object.CreateIndexAsync(typeof(ObjectWithStringLikeValueTypes)); - _mock.Verify(x=>x.ExecuteAsync("FT.CREATE", + _mock.Verify(x => x.ExecuteAsync("FT.CREATE", "objectwithstringlikevaluetypes-idx", "ON", "Json", @@ -1634,7 +1636,7 @@ public async Task TestCreateIndexWithStringlikeValueTypes() "$.Boolean", "AS", "Boolean", "TAG", "SEPARATOR", "|", "$.Guid", "AS", "Guid", "TAG", "SEPARATOR", "|", "$.AnEnum", "AS", "AnEnum", "TAG", - "$.AnEnumAsInt", "AS", "AnEnumAsInt","NUMERIC", + "$.AnEnumAsInt", "AS", "AnEnumAsInt", "NUMERIC", "$.Flags", "AS", "Flags", "TAG", "SEPARATOR", "," )); } @@ -1647,7 +1649,7 @@ public async Task TestCreateIndexWithStringlikeValueTypesHash() await _mock.Object.CreateIndexAsync(typeof(ObjectWithStringLikeValueTypesHash)); - _mock.Verify(x=>x.ExecuteAsync("FT.CREATE", + _mock.Verify(x => x.ExecuteAsync("FT.CREATE", "objectwithstringlikevaluetypeshash-idx", "ON", "Hash", @@ -1658,10 +1660,10 @@ public async Task TestCreateIndexWithStringlikeValueTypesHash() "Ulid", "TAG", "SEPARATOR", "|", "Boolean", - "TAG", "SEPARATOR", "|", "Guid", "TAG", "SEPARATOR", "|", "AnEnum","NUMERIC" + "TAG", "SEPARATOR", "|", "Guid", "TAG", "SEPARATOR", "|", "AnEnum", "NUMERIC" )); } - + [Fact] public async Task TestCreateIndexWithDatetimeValue() { @@ -1671,7 +1673,7 @@ public async Task TestCreateIndexWithDatetimeValue() await _mock.Object.CreateIndexAsync(typeof(ObjectWithDateTime)); await _mock.Object.CreateIndexAsync(typeof(ObjectWithDateTimeHash)); - _mock.Verify(x=>x.ExecuteAsync("FT.CREATE", + _mock.Verify(x => x.ExecuteAsync("FT.CREATE", "objectwithdatetime-idx", "ON", "Json", @@ -1682,8 +1684,8 @@ public async Task TestCreateIndexWithDatetimeValue() "$.Timestamp", "AS", "Timestamp", "NUMERIC", "SORTABLE", "$.NullableTimestamp", "AS", "NullableTimestamp", "NUMERIC" )); - - _mock.Verify(x=>x.ExecuteAsync("FT.CREATE", + + _mock.Verify(x => x.ExecuteAsync("FT.CREATE", "objectwithdatetimehash-idx", "ON", "Hash", @@ -1709,7 +1711,7 @@ public async Task TestQueryOfUlid() await collection.Where(x => x.Ulid == ulid).ToListAsync(); var expectedPredicate = $"(@Ulid:{{{ulid}}})"; - _mock.Verify(x=>x.ExecuteAsync("FT.SEARCH", "objectwithstringlikevaluetypes-idx", expectedPredicate, "LIMIT", "0", "100")); + _mock.Verify(x => x.ExecuteAsync("FT.SEARCH", "objectwithstringlikevaluetypes-idx", expectedPredicate, "LIMIT", "0", "100")); } [Fact] @@ -1726,7 +1728,7 @@ public async Task TestQueryOfGuid() var expectedPredicate = $"(@Guid:{{{ExpressionParserUtilities.EscapeTagField(guid.ToString())}}})"; - _mock.Verify(x=>x.ExecuteAsync("FT.SEARCH", "objectwithstringlikevaluetypes-idx", expectedPredicate, "LIMIT", "0", "100")); + _mock.Verify(x => x.ExecuteAsync("FT.SEARCH", "objectwithstringlikevaluetypes-idx", expectedPredicate, "LIMIT", "0", "100")); } [Fact] @@ -1743,7 +1745,7 @@ public async Task TestQueryOfBoolean() var expectedPredicate = $"(@Boolean:{{{true}}})"; - _mock.Verify(x=>x.ExecuteAsync("FT.SEARCH", "objectwithstringlikevaluetypes-idx", expectedPredicate, "LIMIT", "0", "100")); + _mock.Verify(x => x.ExecuteAsync("FT.SEARCH", "objectwithstringlikevaluetypes-idx", expectedPredicate, "LIMIT", "0", "100")); } [Fact] @@ -1760,7 +1762,7 @@ public async Task TestQueryOfEnum() var expectedPredicate = $"((@AnEnum:{{{AnEnum.two}}}) (@AnEnumAsInt:[1 1]))"; - _mock.Verify(x=>x.ExecuteAsync("FT.SEARCH", "objectwithstringlikevaluetypes-idx", expectedPredicate, "LIMIT", "0", "100")); + _mock.Verify(x => x.ExecuteAsync("FT.SEARCH", "objectwithstringlikevaluetypes-idx", expectedPredicate, "LIMIT", "0", "100")); } [Fact] @@ -1777,7 +1779,7 @@ public async Task TestQueryOfEnumHash() var expectedPredicate = $"(@AnEnum:[1 1])"; - _mock.Verify(x=>x.ExecuteAsync("FT.SEARCH", "objectwithstringlikevaluetypeshash-idx", expectedPredicate, "LIMIT", "0", "100")); + _mock.Verify(x => x.ExecuteAsync("FT.SEARCH", "objectwithstringlikevaluetypeshash-idx", expectedPredicate, "LIMIT", "0", "100")); } [Fact] @@ -1790,11 +1792,11 @@ public async Task TestGreaterThanEnumQuery() var anEnum = AnEnum.two; - await collection.Where(x => (int)x.AnEnumAsInt > 1 ).ToListAsync(); + await collection.Where(x => (int)x.AnEnumAsInt > 1).ToListAsync(); var expectedPredicate = "(@AnEnumAsInt:[(1 inf])"; - _mock.Verify(x=>x.ExecuteAsync("FT.SEARCH", "objectwithstringlikevaluetypes-idx", expectedPredicate, "LIMIT", "0", "100")); + _mock.Verify(x => x.ExecuteAsync("FT.SEARCH", "objectwithstringlikevaluetypes-idx", expectedPredicate, "LIMIT", "0", "100")); } [Fact] @@ -1802,7 +1804,7 @@ public async Task TestIndexCreationWithEmbeddedListOfDocuments() { _mock.Setup(x => x.ExecuteAsync("FT.CREATE", It.IsAny())).ReturnsAsync("OK"); await _mock.Object.CreateIndexAsync(typeof(ObjectWithEmbeddedArrayOfObjects)); - _mock.Verify(x=>x.ExecuteAsync("FT.CREATE", + _mock.Verify(x => x.ExecuteAsync("FT.CREATE", "objectwithembeddedarrayofobjects-idx", "ON", "Json", @@ -1832,7 +1834,7 @@ public async Task TestAnyQueryForArrayOfEmbeddedObjects() await collection.Where(x => x.Addresses.Any(a => a.City == "Satellite Beach")).ToListAsync(); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "objectwithembeddedarrayofobjects-idx", "(@Addresses_City:{Satellite\\ Beach})", @@ -1852,7 +1854,7 @@ public async Task TestAnyQueryForArrayOfEmbeddedObjectsEnum() await collection.Where(x => x.Addresses.Any(a => a.AddressType == AddressType.Home)).ToListAsync(); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "objectwithembeddedarrayofobjects-idx", "(@Addresses_AddressType:{Home})", @@ -1872,7 +1874,7 @@ public async Task TestAnyQueryForArrayOfEmbeddedObjectsExtraPredicate() await collection.Where(x => x.Numeric == 100 || x.Name == "Bob" && x.Addresses.Any(a => a.City == "Satellite Beach")).ToListAsync(); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "objectwithembeddedarrayofobjects-idx", "((@Numeric:[100 100]) | ((@Name:{Bob}) (@Addresses_City:{Satellite\\ Beach})))", @@ -1890,9 +1892,9 @@ public async Task TestAnyQueryForArrayOfEmbeddedObjectsMultipleAnys() var collection = new RedisCollection(_mock.Object); await collection.Where(x => - x.Addresses.Any(a => a.City == "Satellite Beach") && x.AddressList.Any(x=>x.City == "Newark")).ToListAsync(); + x.Addresses.Any(a => a.City == "Satellite Beach") && x.AddressList.Any(x => x.City == "Newark")).ToListAsync(); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "objectwithembeddedarrayofobjects-idx", "((@Addresses_City:{Satellite\\ Beach}) (@AddressList_City:{Newark}))", @@ -1912,7 +1914,7 @@ public async Task TestAnyQueryForArrayOfEmbeddedObjectsMultiplePredicatesInsideA await collection.Where(x => x.Addresses.Any(a => a.City == "Satellite Beach" && a.State == "Florida")).ToListAsync(); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "objectwithembeddedarrayofobjects-idx", "((@Addresses_City:{Satellite\\ Beach}) (@Addresses_State:{Florida}))", @@ -1934,9 +1936,9 @@ public async Task TestAnyQueryForArrayOfEmbeddedObjectsOtherTypes() var collection = new RedisCollection(_mock.Object); await collection.Where(x => - x.Addresses.Any(a => a.Ulid == ulid) && x.Addresses.Any(a=>a.Guid == guid) && x.Addresses.Any(a=>a.Boolean == boolean)).ToListAsync(); + x.Addresses.Any(a => a.Ulid == ulid) && x.Addresses.Any(a => a.Guid == guid) && x.Addresses.Any(a => a.Boolean == boolean)).ToListAsync(); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "objectwithembeddedarrayofobjects-idx", $"(((@Addresses_Ulid:{{{ulid}}}) (@Addresses_Guid:{{{ExpressionParserUtilities.EscapeTagField(guid.ToString())}}})) (@Addresses_Boolean:{{{boolean}}}))", @@ -1956,7 +1958,7 @@ public async Task TestAnyQueryForListOfEmbeddedObjects() await collection.Where(x => x.AddressList.Any(a => a.City == "Satellite Beach")).ToListAsync(); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "objectwithembeddedarrayofobjects-idx", "(@AddressList_City:{Satellite\\ Beach})", @@ -1976,7 +1978,7 @@ public async Task TestAnyQueryForArrayOfEmbeddedObjectsMultiVariat() await collection.Where(x => x.Addresses.Any(a => a.City == "Satellite Beach" && a.State == "Florida")).ToListAsync(); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "objectwithembeddedarrayofobjects-idx", "((@Addresses_City:{Satellite\\ Beach}) (@Addresses_State:{Florida}))", @@ -1996,9 +1998,9 @@ public async Task SearchWithMultipleWhereClauses() await collection .Where(x => x.Name == "steve") .Where(x => x.Age == 32) - .Where(x=>x.TagField == "foo").ToListAsync(); + .Where(x => x.TagField == "foo").ToListAsync(); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", "(((@Name:\"steve\") (@Age:[32 32])) (@TagField:{foo}))", @@ -2026,28 +2028,28 @@ public async Task TestAsyncMaterializationMethodsWithComibnedQueries() _ = await collection.Where(x => x.TagField == "FirstOrDefaultAsync") .FirstOrDefaultAsync(x => x.Age == 32); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", "((@TagField:{CountAsync}) (@Age:[32 32]))", "LIMIT", "0", "0")); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", "((@TagField:{AnyAsync}) (@Age:[32 32]))", "LIMIT", "0", "0")); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", "((@TagField:{SingleAsync}) (@Age:[32 32]))", "LIMIT", "0", "1")); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", "((@TagField:{FirstAsync}) (@Age:[32 32]))", @@ -2055,14 +2057,14 @@ public async Task TestAsyncMaterializationMethodsWithComibnedQueries() "0", "1")); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", "((@TagField:{SingleOrDefaultAsync}) (@Age:[32 32]))", "LIMIT", "0", "1")); - _mock.Verify(x=>x.ExecuteAsync( + _mock.Verify(x => x.ExecuteAsync( "FT.SEARCH", "person-idx", "((@TagField:{FirstOrDefaultAsync}) (@Age:[32 32]))", @@ -2084,28 +2086,28 @@ public void TestMaterializationMethodsWithComibnedQueries() _ = collection.First(x => x.TagField == "First"); _ = collection.FirstOrDefault(x => x.TagField == "FirstOrDefault"); - _mock.Verify(x=>x.Execute( + _mock.Verify(x => x.Execute( "FT.SEARCH", "person-idx", "((@Age:[32 32]) (@TagField:{Count}))", "LIMIT", "0", "0")); - _mock.Verify(x=>x.Execute( + _mock.Verify(x => x.Execute( "FT.SEARCH", "person-idx", "((@Age:[32 32]) (@TagField:{Any}))", "LIMIT", "0", "0")); - _mock.Verify(x=>x.Execute( + _mock.Verify(x => x.Execute( "FT.SEARCH", "person-idx", "((@Age:[32 32]) (@TagField:{Single}))", "LIMIT", "0", "1")); - _mock.Verify(x=>x.Execute( + _mock.Verify(x => x.Execute( "FT.SEARCH", "person-idx", "((@Age:[32 32]) (@TagField:{First}))", @@ -2113,14 +2115,14 @@ public void TestMaterializationMethodsWithComibnedQueries() "0", "1")); - _mock.Verify(x=>x.Execute( + _mock.Verify(x => x.Execute( "FT.SEARCH", "person-idx", "((@Age:[32 32]) (@TagField:{SingleOrDefault}))", "LIMIT", "0", "1")); - _mock.Verify(x=>x.Execute( + _mock.Verify(x => x.Execute( "FT.SEARCH", "person-idx", "((@Age:[32 32]) (@TagField:{FirstOrDefault}))", @@ -2132,12 +2134,12 @@ public void TestMaterializationMethodsWithComibnedQueries() [Fact] public void SearchTagFieldContains() { - var potentialTagFieldValues = new string[]{"Steve", "Alice", "Bob"}; + var potentialTagFieldValues = new string[] { "Steve", "Alice", "Bob" }; _mock.Setup(x => x.Execute(It.IsAny(), It.IsAny())) .Returns(_mockReply); var collection = new RedisCollection(_mock.Object).Where(x => potentialTagFieldValues.Contains(x.TagField)); collection.ToList(); - _mock.Verify(x=>x.Execute( + _mock.Verify(x => x.Execute( "FT.SEARCH", "person-idx", "(@TagField:{Steve|Alice|Bob})", @@ -2145,16 +2147,16 @@ public void SearchTagFieldContains() "0", "100")); } - + [Fact] public void SearchTextFieldContains() { - var potentialTextFieldValues = new string[]{"Steve", "Alice", "Bob"}; + var potentialTextFieldValues = new string[] { "Steve", "Alice", "Bob" }; _mock.Setup(x => x.Execute(It.IsAny(), It.IsAny())) .Returns(_mockReply); var collection = new RedisCollection(_mock.Object).Where(x => potentialTextFieldValues.Contains(x.Name)); collection.ToList(); - _mock.Verify(x=>x.Execute( + _mock.Verify(x => x.Execute( "FT.SEARCH", "person-idx", "(@Name:Steve|Alice|Bob)", @@ -2162,16 +2164,16 @@ public void SearchTextFieldContains() "0", "100")); } - + [Fact] public void SearchNumericFieldContains() { - var potentialTagFieldValues = new int?[]{35, 50, 60}; + var potentialTagFieldValues = new int?[] { 35, 50, 60 }; _mock.Setup(x => x.Execute(It.IsAny(), It.IsAny())) .Returns(_mockReply); var collection = new RedisCollection(_mock.Object).Where(x => potentialTagFieldValues.Contains(x.Age)); collection.ToList(); - _mock.Verify(x=>x.Execute( + _mock.Verify(x => x.Execute( "FT.SEARCH", "person-idx", "@Age:[35 35]|@Age:[50 50]|@Age:[60 60]", @@ -2186,10 +2188,10 @@ public void Issue201() _mock.Setup(x => x.Execute(It.IsAny(), It.IsAny())) .Returns(_mockReply); - var p1 = new Person() {Name = "Steve"}; + var p1 = new Person() { Name = "Steve" }; var collection = new RedisCollection(_mock.Object, 1000); - collection.Where(x=>x.NickNames.Contains(p1.Name)).ToList(); - + collection.Where(x => x.NickNames.Contains(p1.Name)).ToList(); + _mock.Verify(x => x.Execute( "FT.SEARCH", "person-idx", @@ -2211,7 +2213,7 @@ public void RangeOnDatetime() var timeAnHourAgoMilliseconds = new DateTimeOffset(timeAnHourAgo).ToUnixTimeMilliseconds(); DateTime? timeTwoHoursAgoNullable = timestamp.Subtract(TimeSpan.FromHours(2)); var timeTwoHoursAgoMilliseconds = new DateTimeOffset(timeTwoHoursAgoNullable.Value).ToUnixTimeMilliseconds(); - + var collection = new RedisCollection(_mock.Object, 1000); var mockObj = new ObjectWithDateTime { Timestamp = timestamp.Subtract(TimeSpan.FromHours(3)) }; @@ -2219,13 +2221,13 @@ public void RangeOnDatetime() collection.Where(x => x.Timestamp == timeAnHourAgo).ToList(); collection.Where(x => x.Timestamp > timeAnHourAgo).ToList(); collection.Where(x => x.NullableTimestamp > timeAnHourAgo).ToList(); - + collection.Where(x => x.Timestamp > timeTwoHoursAgoNullable).ToList(); collection.Where(x => x.NullableTimestamp > timeTwoHoursAgoNullable).ToList(); - + collection.Where(x => x.Timestamp > mockObj.Timestamp).ToList(); collection.Where(x => x.NullableTimestamp > mockObj.Timestamp).ToList(); - + _mock.Verify(x => x.Execute( "FT.SEARCH", "objectwithdatetime-idx", @@ -2234,7 +2236,7 @@ public void RangeOnDatetime() "0", "1000" )); - + _mock.Verify(x => x.Execute( "FT.SEARCH", "objectwithdatetime-idx", @@ -2243,7 +2245,7 @@ public void RangeOnDatetime() "0", "1000" )); - + _mock.Verify(x => x.Execute( "FT.SEARCH", "objectwithdatetime-idx", @@ -2252,7 +2254,7 @@ public void RangeOnDatetime() "0", "1000" )); - + _mock.Verify(x => x.Execute( "FT.SEARCH", "objectwithdatetime-idx", @@ -2261,7 +2263,7 @@ public void RangeOnDatetime() "0", "1000" )); - + _mock.Verify(x => x.Execute( "FT.SEARCH", "objectwithdatetime-idx", @@ -2270,7 +2272,7 @@ public void RangeOnDatetime() "0", "1000" )); - + _mock.Verify(x => x.Execute( "FT.SEARCH", "objectwithdatetime-idx", @@ -2279,7 +2281,7 @@ public void RangeOnDatetime() "0", "1000" )); - + _mock.Verify(x => x.Execute( "FT.SEARCH", "objectwithdatetime-idx", @@ -2395,7 +2397,7 @@ public async Task RangeOnDatetimeAsyncHash() var mockObj = new ObjectWithDateTimeHash { Timestamp = timestamp.Subtract(TimeSpan.FromHours(3)) }; var timeThreeHoursAgoMilliseconds = new DateTimeOffset(mockObj.Timestamp).ToUnixTimeMilliseconds(); await collection.Where(x => x.Timestamp == timeAnHourAgo).ToListAsync(); - await collection.Where(x => x.Timestamp == timeAnHourAgo).OrderBy(x=>x.Timestamp).ToListAsync(); + await collection.Where(x => x.Timestamp == timeAnHourAgo).OrderBy(x => x.Timestamp).ToListAsync(); await collection.Where(x => x.Timestamp > timeAnHourAgo).ToListAsync(); await collection.Where(x => x.NullableTimestamp > timeAnHourAgo).ToListAsync(); @@ -2514,7 +2516,21 @@ public void SearchTagFieldAndTextListContains() "0", "100")); } - + + [Fact] + public void TestNullResponseDoc() + { + int? nullVal = null; + var nullResult = RedisResult.Create(nullVal); + var res = new RedisReply[] { 1, $"foo:{Ulid.NewUlid()}", new(nullResult) }; + + var query = new RedisQuery("fake-idx"); + _mock.Setup(x => x.Execute(It.IsAny(), It.IsAny())) + .Returns(res); + + var result = _mock.Object.Search(query); + } + [Fact] public void SearchTagFieldAndTextListContainsWithEscapes() {