diff --git a/src/NRedisStack/Search/Document.cs b/src/NRedisStack/Search/Document.cs index 3223054f..c8f9dec5 100644 --- a/src/NRedisStack/Search/Document.cs +++ b/src/NRedisStack/Search/Document.cs @@ -31,6 +31,10 @@ public static Document Load(string id, double score, byte[]? payload, RedisValue { Document ret = new Document(id, score, payload); if (fields == null) return ret; + if (fields.Length == 1 && fields[0].IsNull) + { + return ret; + } for (int i = 0; i < fields.Length; i += 2) { string fieldName = fields[i]!; diff --git a/tests/NRedisStack.Tests/Search/SearchTests.cs b/tests/NRedisStack.Tests/Search/SearchTests.cs index a5acfb68..c19c7457 100644 --- a/tests/NRedisStack.Tests/Search/SearchTests.cs +++ b/tests/NRedisStack.Tests/Search/SearchTests.cs @@ -11,7 +11,6 @@ namespace NRedisStack.Tests.Search; - public class SearchTests : AbstractNRedisStackTest, IDisposable { // private readonly string key = "SEARCH_TESTS"; @@ -3313,4 +3312,53 @@ public void TestNumericLogicalOperatorsInDialect4() Assert.Equal(1, ft.Search(index, new Query("@version:[123 123] | @id:[456 7890]")).TotalResults); Assert.Equal(1, ft.Search(index, new Query("@version==123 @id==456").Dialect(4)).TotalResults); } + + [Fact] + public void TestDocumentLoad_Issue352() + { + Document d = Document.Load("1", 0.5, null, new RedisValue[] { RedisValue.Null }); + Assert.Empty(d.GetProperties().ToList()); + } + + [SkipIfRedis(Is.OSSCluster)] + public void TestDocumentLoadWithDB_Issue352() + { + IDatabase db = redisFixture.Redis.GetDatabase(); + db.Execute("FLUSHALL"); + var ft = db.FT(); + + Schema sc = new Schema().AddTextField("first", 1.0).AddTextField("last", 1.0).AddNumericField("age"); + Assert.True(ft.Create(index, FTCreateParams.CreateParams(), sc)); + + Document droppedDocument = null; + int numberOfAttempts = 0; + do + { + db.HashSet("student:1111", new HashEntry[] { new("first", "Joe"), new("last", "Dod"), new("age", 18) }); + + Assert.True(db.KeyExpire("student:1111", TimeSpan.FromMilliseconds(500))); + + Boolean cancelled = false; + Task searchTask = Task.Run(() => + { + for (int i = 0; i < 100000; i++) + { + SearchResult result = ft.Search(index, new Query()); + List docs = result.Documents; + if (docs.Count == 0 || cancelled) + { + break; + } + else if (docs[0].GetProperties().ToList().Count == 0) + { + droppedDocument = docs[0]; + } + } + }); + Task.WhenAny(searchTask, Task.Delay(1000)).GetAwaiter().GetResult(); + Assert.True(searchTask.IsCompleted); + Assert.Null(searchTask.Exception); + cancelled = true; + } while (droppedDocument == null && numberOfAttempts++ < 3); + } }