Skip to content

Commit cf520a6

Browse files
committed
Adds comprehensive nested field query tests
Updates Foundatio.Parsers.ElasticQueries dependency to support enhanced nested field parsing. Introduces new test cases for various nested query scenarios in FindAsync: - Queries on individual nested fields without group syntax. - Nested range queries. - Nested AND conditions without group syntax. - Queries mixing nested and non-nested fields. - Negated nested group queries. Refactors existing test code for clarity and minor performance improvements.
1 parent 2327ea6 commit cf520a6

2 files changed

Lines changed: 152 additions & 8 deletions

File tree

src/Foundatio.Repositories.Elasticsearch/Foundatio.Repositories.Elasticsearch.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<Compile Include="..\Foundatio.Repositories\Extensions\TaskExtensions.cs" Link="Extensions\TaskExtensions.cs" />
44
</ItemGroup>
55
<ItemGroup>
6-
<PackageReference Include="Foundatio.Parsers.ElasticQueries" Version="7.18.0-beta3" Condition="'$(ReferenceFoundatioRepositoriesSource)' == '' OR '$(ReferenceFoundatioRepositoriesSource)' == 'false'" />
6+
<PackageReference Include="Foundatio.Parsers.ElasticQueries" Version="7.18.0-beta3.nested-tests.16" Condition="'$(ReferenceFoundatioRepositoriesSource)' == '' OR '$(ReferenceFoundatioRepositoriesSource)' == 'false'" />
77
<ProjectReference Include="$(FoundatioProjectsDir)Foundatio.Parsers\src\Foundatio.Parsers.ElasticQueries\Foundatio.Parsers.ElasticQueries.csproj" Condition="'$(ReferenceFoundatioRepositoriesSource)' == 'true'" />
88
<ProjectReference Include="..\Foundatio.Repositories\Foundatio.Repositories.csproj" />
99
</ItemGroup>

tests/Foundatio.Repositories.Elasticsearch.Tests/NestedFieldTests.cs

Lines changed: 151 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
using Foundatio.Repositories.Models;
99
using Newtonsoft.Json;
1010
using Xunit;
11-
using Xunit.Abstractions;
1211

1312
namespace Foundatio.Repositories.Elasticsearch.Tests;
1413

@@ -21,7 +20,7 @@ public NestedFieldTests(ITestOutputHelper output) : base(output)
2120
_employeeRepository = new EmployeeRepository(_configuration);
2221
}
2322

24-
public override async Task InitializeAsync()
23+
public override async ValueTask InitializeAsync()
2524
{
2625
await base.InitializeAsync();
2726
await RemoveDataAsync();
@@ -48,10 +47,9 @@ public async Task FindAsync_WithNestedPeerReviewOrCondition_ReturnsMatchingEmplo
4847
];
4948

5049
await _employeeRepository.AddAsync(employees, o => o.ImmediateConsistency());
51-
var searchRepository = (ISearchableReadOnlyRepository<Employee>)_employeeRepository;
5250

5351
// Act
54-
var results = await searchRepository.FindAsync(q => q.FilterExpression("peerReviews.rating:>=4 OR peerReviews.reviewerEmployeeId:bob_456"));
52+
var results = await _employeeRepository.FindAsync(q => q.FilterExpression("peerReviews.rating:>=4 OR peerReviews.reviewerEmployeeId:bob_456"));
5553

5654
// Assert
5755
Assert.Equal(2, results.Documents.Count);
@@ -90,7 +88,6 @@ public async Task CountAsync_WithNestedPeerReviewAggregation_ReturnsAggregationD
9088
// Assert
9189
Assert.Equal(3, result.Total);
9290
Assert.Single(result.Aggregations);
93-
Assert.NotEmpty(result.Aggregations);
9491

9592
var nestedPeerReviewsAgg = result.Aggregations["nested_peerReviews"] as SingleBucketAggregate;
9693
Assert.NotNull(nestedPeerReviewsAgg);
@@ -119,10 +116,9 @@ public async Task FindAsync_WithNestedFieldInDefaultSearch_ReturnsMatchingEmploy
119116
];
120117

121118
await _employeeRepository.AddAsync(employees, o => o.ImmediateConsistency());
122-
var searchRepository = (ISearchableReadOnlyRepository<Employee>)_employeeRepository;
123119

124120
// Act
125-
var results = await searchRepository.FindAsync(q => q.SearchExpression(specialReviewerId));
121+
var results = await _employeeRepository.FindAsync(q => q.SearchExpression(specialReviewerId));
126122

127123
// Assert
128124
Assert.Single(results.Documents);
@@ -405,4 +401,152 @@ public async Task CountAsync_WithNestedAggregationsSerialization_CanRoundtripBot
405401
bucket = roundTrippedRatingTermsAgg.Buckets.First(f => f.Key == 5);
406402
Assert.Equal(2, bucket.Total);
407403
}
404+
405+
[Fact]
406+
public async Task FindAsync_WithIndividualNestedFieldWithoutGroupSyntax_ReturnsMatchingEmployee()
407+
{
408+
// Arrange
409+
List<Employee> employees =
410+
[
411+
EmployeeGenerator.Generate("alice_123", "Alice", peerReviews:
412+
[
413+
new PeerReview { ReviewerEmployeeId = "bob_456", Rating = 5 }
414+
]),
415+
EmployeeGenerator.Generate("bob_456", "Bob", peerReviews:
416+
[
417+
new PeerReview { ReviewerEmployeeId = "alice_123", Rating = 3 }
418+
])
419+
];
420+
421+
await _employeeRepository.AddAsync(employees, o => o.ImmediateConsistency());
422+
423+
// Act
424+
var results = await _employeeRepository.FindAsync(q => q.FilterExpression("peerReviews.rating:5"));
425+
426+
// Assert
427+
Assert.Single(results.Documents);
428+
Assert.Equal("Alice", results.Documents.Single().Name);
429+
}
430+
431+
[Fact]
432+
public async Task FindAsync_WithNestedRangeQuery_ReturnsMatchingEmployees()
433+
{
434+
// Arrange
435+
List<Employee> employees =
436+
[
437+
EmployeeGenerator.Generate("alice_123", "Alice", peerReviews:
438+
[
439+
new PeerReview { ReviewerEmployeeId = "bob_456", Rating = 5 }
440+
]),
441+
EmployeeGenerator.Generate("bob_456", "Bob", peerReviews:
442+
[
443+
new PeerReview { ReviewerEmployeeId = "alice_123", Rating = 2 }
444+
]),
445+
EmployeeGenerator.Generate("charlie_789", "Charlie", peerReviews:
446+
[
447+
new PeerReview { ReviewerEmployeeId = "alice_123", Rating = 4 }
448+
])
449+
];
450+
451+
await _employeeRepository.AddAsync(employees, o => o.ImmediateConsistency());
452+
453+
// Act
454+
var results = await _employeeRepository.FindAsync(q => q.FilterExpression("peerReviews.rating:[4 TO 5]"));
455+
456+
// Assert
457+
Assert.Equal(2, results.Documents.Count);
458+
Assert.Contains(results.Documents, e => String.Equals(e.Name, "Alice"));
459+
Assert.Contains(results.Documents, e => String.Equals(e.Name, "Charlie"));
460+
}
461+
462+
[Fact]
463+
public async Task FindAsync_WithNestedAndConditionWithoutGroupSyntax_ReturnsMatchingEmployee()
464+
{
465+
// Arrange
466+
List<Employee> employees =
467+
[
468+
EmployeeGenerator.Generate("alice_123", "Alice", peerReviews:
469+
[
470+
new PeerReview { ReviewerEmployeeId = "bob_456", Rating = 5 }
471+
]),
472+
EmployeeGenerator.Generate("bob_456", "Bob", peerReviews:
473+
[
474+
new PeerReview { ReviewerEmployeeId = "alice_123", Rating = 5 }
475+
]),
476+
EmployeeGenerator.Generate("charlie_789", "Charlie", peerReviews:
477+
[
478+
new PeerReview { ReviewerEmployeeId = "alice_123", Rating = 3 }
479+
])
480+
];
481+
482+
await _employeeRepository.AddAsync(employees, o => o.ImmediateConsistency());
483+
484+
// Act
485+
var results = await _employeeRepository.FindAsync(q => q.FilterExpression("peerReviews.rating:5 AND peerReviews.reviewerEmployeeId:bob_456"));
486+
487+
// Assert
488+
Assert.Single(results.Documents);
489+
Assert.Equal("Alice", results.Documents.Single().Name);
490+
}
491+
492+
[Fact]
493+
public async Task FindAsync_WithMixedNestedAndNonNestedFields_ReturnsMatchingEmployee()
494+
{
495+
// Arrange
496+
List<Employee> employees =
497+
[
498+
EmployeeGenerator.Generate("alice_123", "Alice", peerReviews:
499+
[
500+
new PeerReview { ReviewerEmployeeId = "bob_456", Rating = 5 }
501+
]),
502+
EmployeeGenerator.Generate("bob_456", "Bob", peerReviews:
503+
[
504+
new PeerReview { ReviewerEmployeeId = "alice_123", Rating = 5 }
505+
]),
506+
EmployeeGenerator.Generate("charlie_789", "Charlie", peerReviews:
507+
[
508+
new PeerReview { ReviewerEmployeeId = "alice_123", Rating = 3 }
509+
])
510+
];
511+
512+
await _employeeRepository.AddAsync(employees, o => o.ImmediateConsistency());
513+
514+
// Act
515+
var results = await _employeeRepository.FindAsync(q => q.FilterExpression("name:Alice peerReviews.rating:5"));
516+
517+
// Assert
518+
Assert.Single(results.Documents);
519+
Assert.Equal("Alice", results.Documents.Single().Name);
520+
}
521+
522+
[Fact]
523+
public async Task FindAsync_WithNegatedNestedGroup_ExcludesMatchingEmployees()
524+
{
525+
// Arrange
526+
List<Employee> employees =
527+
[
528+
EmployeeGenerator.Generate("alice_123", "Alice", peerReviews:
529+
[
530+
new PeerReview { ReviewerEmployeeId = "bob_456", Rating = 5 }
531+
]),
532+
EmployeeGenerator.Generate("bob_456", "Bob", peerReviews:
533+
[
534+
new PeerReview { ReviewerEmployeeId = "alice_123", Rating = 3 }
535+
]),
536+
EmployeeGenerator.Generate("charlie_789", "Charlie", peerReviews:
537+
[
538+
new PeerReview { ReviewerEmployeeId = "alice_123", Rating = 4 }
539+
])
540+
];
541+
542+
await _employeeRepository.AddAsync(employees, o => o.ImmediateConsistency());
543+
544+
// Act
545+
var results = await _employeeRepository.FindAsync(q => q.FilterExpression("NOT peerReviews.rating:5"));
546+
547+
// Assert
548+
Assert.Equal(2, results.Documents.Count);
549+
Assert.Contains(results.Documents, e => String.Equals(e.Name, "Bob"));
550+
Assert.Contains(results.Documents, e => String.Equals(e.Name, "Charlie"));
551+
}
408552
}

0 commit comments

Comments
 (0)