diff --git a/aspnet-core/framework/elasticsearch/LINGYUN.Abp.Elasticsearch/LINGYUN/Abp/Elasticsearch/ExpressionQueryService.cs b/aspnet-core/framework/elasticsearch/LINGYUN.Abp.Elasticsearch/LINGYUN/Abp/Elasticsearch/ExpressionQueryService.cs new file mode 100644 index 000000000..c7f4be8d2 --- /dev/null +++ b/aspnet-core/framework/elasticsearch/LINGYUN.Abp.Elasticsearch/LINGYUN/Abp/Elasticsearch/ExpressionQueryService.cs @@ -0,0 +1,259 @@ +using Elastic.Clients.Elasticsearch; +using Elastic.Clients.Elasticsearch.QueryDsl; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Elasticsearch; + +public class ExpressionQueryService : IExpressionQueryService, ITransientDependency +{ + private readonly IElasticsearchClientFactory _clientFactory; + private readonly IExpressionQueryTranslator _expressionQueryTranslator; + + public ExpressionQueryService( + IElasticsearchClientFactory clientFactory, + IExpressionQueryTranslator expressionQueryTranslator) + { + _clientFactory = clientFactory; + _expressionQueryTranslator = expressionQueryTranslator; + } + + public async virtual Task GetCountAsync( + string indexName, + Expression> expression, + CancellationToken cancellationToken = default) + { + var client = _clientFactory.Create(); + var query = await _expressionQueryTranslator.TranslateAsync(indexName, expression); + + var response = await client.CountAsync(dsl => + dsl.Indices(indexName).Query(query), + cancellationToken); + + return response.Count; + } + + public async virtual Task> GetListAsync( + string indexName, + Expression> expression, + string? sorting = null, + int maxResultCount = 50, + int skipCount = 0, + Fields? sourceExcludes = null, + Fields? sourceIncludes = null, + CancellationToken cancellationToken = default) + { + var client = _clientFactory.Create(); + var query = await _expressionQueryTranslator.TranslateAsync(indexName, expression); + + SortOptions[]? sorts = null; + if (!sorting.IsNullOrWhiteSpace()) + { + var sortOrder = !sorting.IsNullOrWhiteSpace() && sorting.EndsWith("asc", StringComparison.InvariantCultureIgnoreCase) + ? SortOrder.Asc : SortOrder.Desc; + + sorts = new SortOptions[1] + { + new SortOptions + { + Field = new FieldSort(new Field(sorting)), + } + }; + } + + // 数量超过10000且存在排序时才可以使用SearchAfter特性 + return skipCount >= 10000 && sorts != null + ? await SearchAfter( + client, + indexName, + query, + sorts, + maxResultCount, + skipCount, + sourceExcludes, + sourceIncludes, + cancellationToken) + : await SearchFromSize( + client, + indexName, + query, + sorts, + maxResultCount, + skipCount, + sourceExcludes, + sourceIncludes, + cancellationToken); + } + + private async Task> SearchFromSize( + ElasticsearchClient client, + string indexName, + Query query, + SortOptions[]? sorts = null, + int maxResultCount = 50, + int skipCount = 0, + Fields? sourceExcludes = null, + Fields? sourceIncludes = null, + CancellationToken cancellationToken = default) + { + var searchResponse = await client.SearchAsync(dsl => + { + dsl.Indices(indexName) + .Query(query) + .From(skipCount) + .Size(maxResultCount); + if (sorts != null) + { + dsl.Sort(sorts); + } + if (sourceExcludes != null) + { + dsl.SourceExcludes(sourceExcludes); + } + if (sourceIncludes != null) + { + dsl.SourceIncludes(sourceIncludes); + } + }, cancellationToken); + + if (!searchResponse.IsSuccess()) + { + return []; + } + + return searchResponse.Documents.ToList(); + } + + private async Task> SearchAfter( + ElasticsearchClient client, + string indexName, + Query query, + SortOptions[] sorts, + int maxResultCount = 50, + int skipCount = 0, + Fields? sourceExcludes = null, + Fields? sourceIncludes = null, + CancellationToken cancellationToken = default) + { + var searchAfter = await GetSearchAfterValue( + client, + indexName, + query, + sorts, + skipCount, + cancellationToken); + + if (searchAfter == null || !searchAfter.Any()) + { + return []; + } + + var searchResponse = await client.SearchAsync(dsl => + { + dsl.Indices(indexName) + .Query(query) + .Sort(sorts) + .Size(maxResultCount) + .SearchAfter(searchAfter); + if (sourceExcludes != null) + { + dsl.SourceExcludes(sourceExcludes); + } + if (sourceIncludes != null) + { + dsl.SourceIncludes(sourceIncludes); + } + }, cancellationToken); + + if (!searchResponse.IsSuccess()) + { + return []; + } + + return searchResponse.Documents.ToList(); + } + + private async Task?> GetSearchAfterValue( + ElasticsearchClient client, + string indexName, + Query query, + SortOptions[] sorts, + int skipCount, + CancellationToken cancellationToken = default) + { + // 10000以内直接取最后一条数据 + if (skipCount < 10000) + { + var response = await client.SearchAsync( + dsl => dsl.Indices(indexName) + .Query(query) + .Sort(sorts) + .From(skipCount) + .Size(1), + cancellationToken); + + if (!response.IsSuccess() || response.Hits == null || !response.Hits.Any()) + { + return null; + } + + var hit = response.Hits.FirstOrDefault(); + return hit?.Sort?.ToList(); + } + + // 获取第9999条数据Hits作为searchAfter + var firstResponse = await client.SearchAsync( + dsl => dsl.Indices(indexName) + .Query(query) + .Sort(sorts) + .SourceIncludes([]) + .From(9999) + .Size(1), + cancellationToken); + + if (!firstResponse.IsSuccess() || firstResponse.Hits == null || !firstResponse.Hits.Any()) + { + return null; + } + + var firstHit = firstResponse.Hits.FirstOrDefault(); + if (firstHit?.Sort == null || !firstHit.Sort.Any()) + { + return null; + } + + var remaining = skipCount - 10000; + // 获取skipCount最近一条数据作为searchAfter + var secondResponse = await client.SearchAsync( + dsl => dsl.Indices(indexName) + .Query(query) + .Sort(sorts) + .SourceIncludes([]) + .SearchAfter(firstHit.Sort.ToList()) + .Size(remaining), + cancellationToken); + + if (!secondResponse.IsSuccess() || secondResponse.Hits == null || !secondResponse.Hits.Any()) + { + return null; + } + + if (secondResponse.Hits.Count < remaining) + { + return null; + } + + var lastHit = secondResponse.Hits.LastOrDefault(); + if (lastHit?.Sort == null || !lastHit.Sort.Any()) + { + return null; + } + + return lastHit.Sort.ToList(); + } +} diff --git a/aspnet-core/framework/elasticsearch/LINGYUN.Abp.Elasticsearch/LINGYUN/Abp/Elasticsearch/ExpressionQueryTranslator.cs b/aspnet-core/framework/elasticsearch/LINGYUN.Abp.Elasticsearch/LINGYUN/Abp/Elasticsearch/ExpressionQueryTranslator.cs index fff6a0190..15731d7d2 100644 --- a/aspnet-core/framework/elasticsearch/LINGYUN.Abp.Elasticsearch/LINGYUN/Abp/Elasticsearch/ExpressionQueryTranslator.cs +++ b/aspnet-core/framework/elasticsearch/LINGYUN.Abp.Elasticsearch/LINGYUN/Abp/Elasticsearch/ExpressionQueryTranslator.cs @@ -7,38 +7,36 @@ using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Text.Json.Serialization; +using System.Threading.Tasks; using Volo.Abp; +using Volo.Abp.DependencyInjection; namespace LINGYUN.Abp.Elasticsearch; /// /// 表达式查询转换器 - 将 LINQ 表达式转换为 Elasticsearch Query /// -/// 文档类型 -public class ExpressionQueryTranslator +public class ExpressionQueryTranslator : IExpressionQueryTranslator, ISingletonDependency { - private readonly bool _defaultNestedBehavior; - private readonly IndexMappingInfo _mappingInfo; + private readonly IIndexMappingProvider _indexMappingProvider; - /// - /// 构造函数(使用已有的映射信息) - /// public ExpressionQueryTranslator( - IndexMappingInfo mappingInfo, - bool defaultNestedBehavior = false) + IIndexMappingProvider indexMappingProvider) { - _mappingInfo = mappingInfo; - _defaultNestedBehavior = defaultNestedBehavior; + _indexMappingProvider = indexMappingProvider; } /// - /// 同步翻译表达式(需要已加载映射) + /// 翻译表达式 /// - public virtual Query Translate(Expression> expression) + public async virtual Task TranslateAsync(string indexName, Expression> expression) { + Check.NotNullOrWhiteSpace(indexName, nameof(indexName)); Check.NotNull(expression, nameof(expression)); - return TranslateNode(expression.Body, prefix: null, _mappingInfo); + var indexMapping = await _indexMappingProvider.GetMappingAsync(indexName); + + return TranslateNode(expression.Body, prefix: null, indexMapping); } #region 节点翻译 @@ -555,9 +553,7 @@ public class ExpressionQueryTranslator inner = TranslateNode(predicate.Body, prefix: collectionField.Path, mappingInfo); } - var shouldUseNested = collectionField.IsNested || - (mappingInfo?.IsNested(collectionField.Path) ?? false) || - _defaultNestedBehavior; + var shouldUseNested = collectionField.IsNested || (mappingInfo?.IsNested(collectionField.Path) ?? false); return shouldUseNested ? new NestedQuery(collectionField.Path, inner) diff --git a/aspnet-core/framework/elasticsearch/LINGYUN.Abp.Elasticsearch/LINGYUN/Abp/Elasticsearch/IExpressionQueryService.cs b/aspnet-core/framework/elasticsearch/LINGYUN.Abp.Elasticsearch/LINGYUN/Abp/Elasticsearch/IExpressionQueryService.cs new file mode 100644 index 000000000..aef5b89cf --- /dev/null +++ b/aspnet-core/framework/elasticsearch/LINGYUN.Abp.Elasticsearch/LINGYUN/Abp/Elasticsearch/IExpressionQueryService.cs @@ -0,0 +1,46 @@ +using Elastic.Clients.Elasticsearch; +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Threading; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Elasticsearch; + +public interface IExpressionQueryService +{ + /// + /// 查询符合条件的文档数量 + /// + /// 文档类型 + /// 文档索引 + /// 查询表达式树 + /// + /// + Task GetCountAsync( + string indexName, + Expression> expression, + CancellationToken cancellationToken = default); + /// + /// 查询符合条件的文档列表 + /// + /// 文档类型 + /// 文档索引 + /// 查询表达式树 + /// 排序字段 + /// 最大返回数据大小 + /// 跳过数据大小 + /// 包含字段 + /// 忽略字段 + /// + /// + Task> GetListAsync( + string indexName, + Expression> expression, + string? sorting = null, + int maxResultCount = 50, + int skipCount = 0, + Fields? sourceExcludes = null, + Fields? sourceIncludes = null, + CancellationToken cancellationToken = default); +} diff --git a/aspnet-core/framework/elasticsearch/LINGYUN.Abp.Elasticsearch/LINGYUN/Abp/Elasticsearch/IExpressionQueryTranslator.cs b/aspnet-core/framework/elasticsearch/LINGYUN.Abp.Elasticsearch/LINGYUN/Abp/Elasticsearch/IExpressionQueryTranslator.cs new file mode 100644 index 000000000..391739717 --- /dev/null +++ b/aspnet-core/framework/elasticsearch/LINGYUN.Abp.Elasticsearch/LINGYUN/Abp/Elasticsearch/IExpressionQueryTranslator.cs @@ -0,0 +1,11 @@ +using Elastic.Clients.Elasticsearch.QueryDsl; +using System; +using System.Linq.Expressions; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Elasticsearch; + +public interface IExpressionQueryTranslator +{ + Task TranslateAsync(string indexName, Expression> expression); +} diff --git a/aspnet-core/framework/elasticsearch/LINGYUN.Abp.Elasticsearch/LINGYUN/Abp/Elasticsearch/IndexMappingInfo.cs b/aspnet-core/framework/elasticsearch/LINGYUN.Abp.Elasticsearch/LINGYUN/Abp/Elasticsearch/IndexMappingInfo.cs index 46c7c29e1..f0887d72d 100644 --- a/aspnet-core/framework/elasticsearch/LINGYUN.Abp.Elasticsearch/LINGYUN/Abp/Elasticsearch/IndexMappingInfo.cs +++ b/aspnet-core/framework/elasticsearch/LINGYUN.Abp.Elasticsearch/LINGYUN/Abp/Elasticsearch/IndexMappingInfo.cs @@ -107,7 +107,7 @@ public class IndexMappingInfo // 检查路径的父级是否是 Nested var parts = path.Split('.'); - for (int i = 0; i < parts.Length - 1; i++) + for (var i = 0; i < parts.Length - 1; i++) { var parentPath = string.Join(".", parts.Take(i + 1)); if (IsNested(parentPath)) @@ -125,7 +125,7 @@ public class IndexMappingInfo public string? GetNestedParentPath(string path) { var parts = path.Split('.'); - for (int i = parts.Length - 1; i >= 0; i--) + for (var i = parts.Length - 1; i >= 0; i--) { var parentPath = string.Join(".", parts.Take(i + 1)); if (IsNested(parentPath)) diff --git a/aspnet-core/tests/LINGYUN.Abp.Elasticsearch.Tests/LINGYUN/Abp/Elasticsearch/DefaultExpressionQueryTranslatorTests.cs b/aspnet-core/tests/LINGYUN.Abp.Elasticsearch.Tests/LINGYUN/Abp/Elasticsearch/DefaultExpressionQueryTranslatorTests.cs new file mode 100644 index 000000000..3f2dad4bd --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.Elasticsearch.Tests/LINGYUN/Abp/Elasticsearch/DefaultExpressionQueryTranslatorTests.cs @@ -0,0 +1,7 @@ +using LINGYUN.Abp.Elasticsearch.Tests; + +namespace LINGYUN.Abp.Elasticsearch; + +public class DefaultExpressionQueryTranslatorTests : ExpressionQueryTranslatorTests +{ +} diff --git a/aspnet-core/tests/LINGYUN.Abp.Elasticsearch.Tests/LINGYUN/Abp/Elasticsearch/ExpressionQueryTranslator_Tests.cs b/aspnet-core/tests/LINGYUN.Abp.Elasticsearch.Tests/LINGYUN/Abp/Elasticsearch/ExpressionQueryTranslator_Tests.cs index 99163a96f..412c67eb3 100644 --- a/aspnet-core/tests/LINGYUN.Abp.Elasticsearch.Tests/LINGYUN/Abp/Elasticsearch/ExpressionQueryTranslator_Tests.cs +++ b/aspnet-core/tests/LINGYUN.Abp.Elasticsearch.Tests/LINGYUN/Abp/Elasticsearch/ExpressionQueryTranslator_Tests.cs @@ -4,38 +4,29 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Volo.Abp.Modularity; +using Volo.Abp.Testing; using Xunit; namespace LINGYUN.Abp.Elasticsearch.Tests; -public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase +public abstract class ExpressionQueryTranslatorTests : AbpIntegratedTest + where TStartupModule : IAbpModule { - private readonly IIndexMappingProvider _indexMappingProvider; + private readonly IExpressionQueryTranslator _expressionQueryTranslator; public ExpressionQueryTranslatorTests() { - _indexMappingProvider = GetRequiredService(); - } - - private async Task> CreateTranslator( - bool defaultNestedBehavior = false) - { - var indexMapping = await _indexMappingProvider.GetMappingAsync(TestDocumentIndexNames.Index); - return new ExpressionQueryTranslator( - indexMapping, - defaultNestedBehavior); + _expressionQueryTranslator = GetRequiredService(); } #region 基础查询测试 [Fact] - public async Task Translate_ConstantTrue_ReturnsMatchAllQuery() + public async virtual Task Translate_ConstantTrue_ReturnsMatchAllQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => true); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => true); // Assert query.ShouldNotBeNull(); @@ -43,42 +34,26 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_ConstantFalse_ReturnsMatchNoneQuery() + public async virtual Task Translate_ConstantFalse_ReturnsMatchNoneQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => false); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => false); // Assert query.ShouldNotBeNull(); query.MatchNone.ShouldNotBeNull(); } - [Fact] - public async Task Translate_NullExpression_ThrowsArgumentNullException() - { - // Arrange - var translator = await CreateTranslator(); - - // Act & Assert - Should.Throw(() => translator.Translate(null!)); - } - #endregion #region 相等性查询测试 [Fact] - public async Task Translate_Equal_NumericField_ReturnsTermQuery() + public async virtual Task Translate_Equal_NumericField_ReturnsTermQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act var idValue = 100; - var query = translator.Translate(x => x.Id == idValue); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Id == idValue); // Assert query.ShouldNotBeNull(); @@ -88,14 +63,11 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_Equal_StringField_ReturnsTermQueryWithKeyword() + public async virtual Task Translate_Equal_StringField_ReturnsTermQueryWithKeyword() { - // Arrange - var translator = await CreateTranslator(); - // Act var stringValue = "test"; - var query = translator.Translate(x => x.Name == stringValue); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Name == stringValue); // Assert query.ShouldNotBeNull(); @@ -105,14 +77,11 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_Equal_BooleanField_ReturnsTermQuery() + public async virtual Task Translate_Equal_BooleanField_ReturnsTermQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act var boolValue = true; - var query = translator.Translate(x => x.IsActive == boolValue); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.IsActive == boolValue); // Assert query.ShouldNotBeNull(); @@ -122,14 +91,11 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_Equal_EnumField_ReturnsTermQuery() + public async virtual Task Translate_Equal_EnumField_ReturnsTermQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act var enumValue = TestEnum.Active; - var query = translator.Translate(x => x.Status == enumValue); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Status == enumValue); // Assert query.ShouldNotBeNull(); @@ -139,14 +105,11 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_Equal_StringEnumField_ReturnsTermQueryWithString() + public async virtual Task Translate_Equal_StringEnumField_ReturnsTermQueryWithString() { - // Arrange - var translator = await CreateTranslator(); - // Act var enumValue = TestEnum.Pending; - var query = translator.Translate(x => x.StringValueStatus == enumValue); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.StringValueStatus == enumValue); // Assert query.ShouldNotBeNull(); @@ -156,13 +119,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_NotEqual_StringField_ReturnsBoolMustNot() + public async virtual Task Translate_NotEqual_StringField_ReturnsBoolMustNot() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Name != "test"); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Name != "test"); // Assert query.ShouldNotBeNull(); @@ -177,14 +137,11 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_Equal_NullableEnumField_ReturnsTermQuery() + public async virtual Task Translate_Equal_NullableEnumField_ReturnsTermQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act var enumValue = TestEnum.Inactive; - var query = translator.Translate(x => x.NullableStatus == enumValue); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.NullableStatus == enumValue); // Assert query.ShouldNotBeNull(); @@ -194,13 +151,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_Equal_DecimalField_ReturnsTermQuery() + public async virtual Task Translate_Equal_DecimalField_ReturnsTermQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Salary == 5000.50m); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Salary == 5000.50m); // Assert query.ShouldNotBeNull(); @@ -209,14 +163,13 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_Equal_NullableDateField_ReturnsDateRangeQuery() + public async virtual Task Translate_Equal_NullableDateField_ReturnsDateRangeQuery() { // Arrange - var translator = await CreateTranslator(); var date = new DateTime(2024, 3, 15, 10, 30, 0); // Act - var query = translator.Translate(x => x.UpdatedTime == date); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.UpdatedTime == date); // Assert query.ShouldNotBeNull(); @@ -231,13 +184,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase #region Null 比较测试 [Fact] - public async Task Translate_EqualNull_ReturnsMustNotExistsQuery() + public async virtual Task Translate_EqualNull_ReturnsMustNotExistsQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Name == null); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Name == null); // Assert query.ShouldNotBeNull(); @@ -252,13 +202,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_NotEqualNull_ReturnsExistsQuery() + public async virtual Task Translate_NotEqualNull_ReturnsExistsQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Name != null); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Name != null); // Assert query.ShouldNotBeNull(); @@ -267,13 +214,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_NullableType_IsNull_ReturnsMustNotExists() + public async virtual Task Translate_NullableType_IsNull_ReturnsMustNotExists() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.UpdatedTime == null); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.UpdatedTime == null); // Assert query.ShouldNotBeNull(); @@ -284,13 +228,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_NullableType_IsNotNull_ReturnsExistsQuery() + public async virtual Task Translate_NullableType_IsNotNull_ReturnsExistsQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.UpdatedTime != null); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.UpdatedTime != null); // Assert query.ShouldNotBeNull(); @@ -299,13 +240,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_NullableEnum_IsNull_ReturnsMustNotExists() + public async virtual Task Translate_NullableEnum_IsNull_ReturnsMustNotExists() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.NullableStatus == null); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.NullableStatus == null); // Assert query.ShouldNotBeNull(); @@ -320,13 +258,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase #region 逻辑运算测试 [Fact] - public async Task Translate_AndAlso_TwoConditions_ReturnsBoolFilterWithTwoQueries() + public async virtual Task Translate_AndAlso_TwoConditions_ReturnsBoolFilterWithTwoQueries() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Age > 18 && x.IsActive == true); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Age > 18 && x.IsActive == true); // Assert query.ShouldNotBeNull(); @@ -336,13 +271,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_AndAlso_ThreeConditions_ReturnsBoolFilterWithThreeQueries() + public async virtual Task Translate_AndAlso_ThreeConditions_ReturnsBoolFilterWithThreeQueries() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Age > 18 && x.IsActive == true && x.Name != null); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Age > 18 && x.IsActive == true && x.Name != null); // Assert query.ShouldNotBeNull(); @@ -352,13 +284,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_OrElse_TwoConditions_ReturnsBoolShouldWithTwoQueries() + public async virtual Task Translate_OrElse_TwoConditions_ReturnsBoolShouldWithTwoQueries() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Age > 18 || x.IsActive == true); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Age > 18 || x.IsActive == true); // Assert query.ShouldNotBeNull(); @@ -370,13 +299,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_OrElse_ThreeConditions_ReturnsBoolShouldWithThreeQueries() + public async virtual Task Translate_OrElse_ThreeConditions_ReturnsBoolShouldWithThreeQueries() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Age > 18 || x.IsActive == true || x.Name != null); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Age > 18 || x.IsActive == true || x.Name != null); // Assert query.ShouldNotBeNull(); @@ -388,13 +314,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_AndAlsoWithOrElse_ReturnsNestedBoolQuery() + public async virtual Task Translate_AndAlsoWithOrElse_ReturnsNestedBoolQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => (x.Age > 18 || x.IsActive == true) && x.Name != null); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => (x.Age > 18 || x.IsActive == true) && x.Name != null); // Assert query.ShouldNotBeNull(); @@ -411,13 +334,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_Not_ReturnsNegatedBooleanQuery() + public async virtual Task Translate_Not_ReturnsNegatedBooleanQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => !x.IsActive); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => !x.IsActive); // Assert query.ShouldNotBeNull(); @@ -428,13 +348,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_Not_OnComparison_ReturnsMustNotQuery() + public async virtual Task Translate_Not_OnComparison_ReturnsMustNotQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => !(x.Age > 18)); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => !(x.Age > 18)); // Assert query.ShouldNotBeNull(); @@ -449,13 +366,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase #region 范围查询测试 [Fact] - public async Task Translate_GreaterThan_ReturnsRangeQuery() + public async virtual Task Translate_GreaterThan_ReturnsRangeQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Age > 18); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Age > 18); // Assert query.ShouldNotBeNull(); @@ -466,13 +380,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_GreaterThanOrEqual_ReturnsRangeQuery() + public async virtual Task Translate_GreaterThanOrEqual_ReturnsRangeQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Age >= 18); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Age >= 18); // Assert query.ShouldNotBeNull(); @@ -483,13 +394,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_LessThan_ReturnsRangeQuery() + public async virtual Task Translate_LessThan_ReturnsRangeQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Age < 65); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Age < 65); // Assert query.ShouldNotBeNull(); @@ -500,13 +408,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_LessThanOrEqual_ReturnsRangeQuery() + public async virtual Task Translate_LessThanOrEqual_ReturnsRangeQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Age <= 65); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Age <= 65); // Assert query.ShouldNotBeNull(); @@ -517,14 +422,13 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_DateComparison_GreaterThan_ReturnsDateRangeQuery() + public async virtual Task Translate_DateComparison_GreaterThan_ReturnsDateRangeQuery() { // Arrange - var translator = await CreateTranslator(); var date = new DateTime(2024, 1, 15); // Act - var query = translator.Translate(x => x.CreatedTime > date); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.CreatedTime > date); // Assert query.ShouldNotBeNull(); @@ -534,15 +438,14 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_DateComparison_BetweenDates_ReturnsDateRangeQuery() + public async virtual Task Translate_DateComparison_BetweenDates_ReturnsDateRangeQuery() { // Arrange - var translator = await CreateTranslator(); var startDate = new DateTime(2024, 1, 1); var endDate = new DateTime(2024, 12, 31); // Act - var query = translator.Translate(x => x.CreatedTime >= startDate && x.CreatedTime <= endDate); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.CreatedTime >= startDate && x.CreatedTime <= endDate); // Assert query.ShouldNotBeNull(); @@ -555,13 +458,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_DecimalComparison_ReturnsRangeQuery() + public async virtual Task Translate_DecimalComparison_ReturnsRangeQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Salary >= 3000.50m); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Salary >= 3000.50m); // Assert query.ShouldNotBeNull(); @@ -575,13 +475,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase #region 字符串方法测试 [Fact] - public async Task Translate_StringContains_KeywordField_ReturnsWildcardQuery() + public async virtual Task Translate_StringContains_KeywordField_ReturnsWildcardQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Name!.Contains("test")); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Name!.Contains("test")); // Assert query.ShouldNotBeNull(); @@ -591,13 +488,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_StringStartsWith_KeywordField_ReturnsWildcardQuery() + public async virtual Task Translate_StringStartsWith_KeywordField_ReturnsWildcardQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Name!.StartsWith("test")); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Name!.StartsWith("test")); // Assert query.ShouldNotBeNull(); @@ -607,13 +501,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_StringEndsWith_KeywordField_ReturnsWildcardQuery() + public async virtual Task Translate_StringEndsWith_KeywordField_ReturnsWildcardQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Name!.EndsWith("test")); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Name!.EndsWith("test")); // Assert query.ShouldNotBeNull(); @@ -623,13 +514,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_StringContains_WildcardField_ReturnsWildcardQuery() + public async virtual Task Translate_StringContains_WildcardField_ReturnsWildcardQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Exceptions!.Contains("error")); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Exceptions!.Contains("error")); // Assert query.ShouldNotBeNull(); @@ -639,13 +527,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_StringContains_TextWithoutKeyword_ReturnsMatchPhraseQuery() + public async virtual Task Translate_StringContains_TextWithoutKeyword_ReturnsMatchPhraseQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Description!.Contains("hello world")); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Description!.Contains("hello world")); // Assert query.ShouldNotBeNull(); @@ -655,13 +540,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_StringStartsWith_TextWithoutKeyword_ReturnsMatchPhrasePrefixQuery() + public async virtual Task Translate_StringStartsWith_TextWithoutKeyword_ReturnsMatchPhrasePrefixQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Description!.StartsWith("hello")); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Description!.StartsWith("hello")); // Assert query.ShouldNotBeNull(); @@ -671,13 +553,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_StringContains_EscapesWildcardCharacters() + public async virtual Task Translate_StringContains_EscapesWildcardCharacters() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Name!.Contains("test*value")); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Name!.Contains("test*value")); // Assert query.ShouldNotBeNull(); @@ -686,13 +565,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_StringContains_EscapesQuestionMark() + public async virtual Task Translate_StringContains_EscapesQuestionMark() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Name!.Contains("test?value")); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Name!.Contains("test?value")); // Assert query.ShouldNotBeNull(); @@ -701,13 +577,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_StringEquals_ReturnsTermQuery() + public async virtual Task Translate_StringEquals_ReturnsTermQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Name!.Equals("test")); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Name!.Equals("test")); // Assert query.ShouldNotBeNull(); @@ -722,14 +595,13 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase #region 集合方法测试 [Fact] - public async Task Translate_EnumerableContains_Tags_ReturnsTermsQuery() + public async virtual Task Translate_EnumerableContains_Tags_ReturnsTermsQuery() { // Arrange - var translator = await CreateTranslator(); var tags = new List { "tag1", "tag2", "tag3" }; // Act - var query = translator.Translate(x => tags.Contains(x.Name!)); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => tags.Contains(x.Name!)); // Assert query.ShouldNotBeNull(); @@ -738,14 +610,13 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_CollectionContains_SingleItem_ReturnsTermQuery() + public async virtual Task Translate_CollectionContains_SingleItem_ReturnsTermQuery() { // Arrange - var translator = await CreateTranslator(); var tags = new List { "tag1" }; // Act - var query = translator.Translate(x => tags.Contains(x.Name!)); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => tags.Contains(x.Name!)); // Assert query.ShouldNotBeNull(); @@ -754,14 +625,13 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_EnumerableContains_EmptyCollection_ReturnsMatchNoneQuery() + public async virtual Task Translate_EnumerableContains_EmptyCollection_ReturnsMatchNoneQuery() { // Arrange - var translator = await CreateTranslator(); var tags = new List(); // Act - var query = translator.Translate(x => tags.Contains(x.Name!)); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => tags.Contains(x.Name!)); // Assert query.ShouldNotBeNull(); @@ -769,13 +639,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_EnumerableAny_WithoutPredicate_ReturnsNestedExistsQuery() + public async virtual Task Translate_EnumerableAny_WithoutPredicate_ReturnsNestedExistsQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Items!.Any()); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Items!.Any()); // Assert query.ShouldNotBeNull(); @@ -785,13 +652,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_EnumerableAny_WithPredicate_ReturnsNestedQuery() + public async virtual Task Translate_EnumerableAny_WithPredicate_ReturnsNestedQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Items!.Any(i => i.Id == 10)); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Items!.Any(i => i.Id == 10)); // Assert query.ShouldNotBeNull(); @@ -802,13 +666,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_EnumerableAny_WithComplexPredicate_ReturnsNestedBoolQuery() + public async virtual Task Translate_EnumerableAny_WithComplexPredicate_ReturnsNestedBoolQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Items!.Any(i => i.Price > 100 && i.Price < 1000)); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Items!.Any(i => i.Price > 100 && i.Price < 1000)); // Assert query.ShouldNotBeNull(); @@ -820,13 +681,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_EnumerableAll_ReturnsNestedQuery() + public async virtual Task Translate_EnumerableAll_ReturnsNestedQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Items!.All(i => i.Price > 0)); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Items!.All(i => i.Price > 0)); // Assert query.ShouldNotBeNull(); @@ -840,13 +698,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase #region 嵌套属性测试 [Fact] - public async Task Translate_NestedObjectProperty_ReturnsQueryWithNestedPath() + public async virtual Task Translate_NestedObjectProperty_ReturnsQueryWithNestedPath() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Address!.City == "Beijing"); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Address!.City == "Beijing"); // Assert query.ShouldNotBeNull(); @@ -855,13 +710,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_NestedObjectStringContains_ReturnsWildcardQuery() + public async virtual Task Translate_NestedObjectStringContains_ReturnsWildcardQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Address!.City!.Contains("bei")); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Address!.City!.Contains("bei")); // Assert query.ShouldNotBeNull(); @@ -871,13 +723,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_NestedObjectProperty_NotEqualNull_ReturnsExistsQuery() + public async virtual Task Translate_NestedObjectProperty_NotEqualNull_ReturnsExistsQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Address!.City != null); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Address!.City != null); // Assert query.ShouldNotBeNull(); @@ -890,13 +739,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase #region Nullable 属性测试 [Fact] - public async Task Translate_NullableDate_HasValue_ReturnsExistsQuery() + public async virtual Task Translate_NullableDate_HasValue_ReturnsExistsQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.UpdatedTime.HasValue); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.UpdatedTime.HasValue); // Assert query.ShouldNotBeNull(); @@ -909,16 +755,15 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase #region 复杂表达式测试 [Fact] - public async Task Translate_ComplexExpression_ReturnsCorrectQuery() + public async virtual Task Translate_ComplexExpression_ReturnsCorrectQuery() { // Arrange - var translator = await CreateTranslator(); var minAge = 18; var maxAge = 65; var namePrefix = "test"; // Act - var query = translator.Translate(x => + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => (x.Age >= minAge && x.Age <= maxAge) && (x.Name != null && x.Name.StartsWith(namePrefix)) && x.IsActive == true && @@ -976,15 +821,14 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_ExpressionWithCapturedVariable_ReturnsCorrectQuery() + public async virtual Task Translate_ExpressionWithCapturedVariable_ReturnsCorrectQuery() { // Arrange - var translator = await CreateTranslator(); var targetName = "John"; var targetAge = 30; // Act - var query = translator.Translate(x => x.Name == targetName && x.Age == targetAge); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Name == targetName && x.Age == targetAge); // Assert query.ShouldNotBeNull(); @@ -1003,14 +847,13 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_ExpressionWithDateTimeVariable_ReturnsDateRangeQuery() + public async virtual Task Translate_ExpressionWithDateTimeVariable_ReturnsDateRangeQuery() { // Arrange - var translator = await CreateTranslator(); var targetDate = new DateTime(2024, 6, 15); // Act - var query = translator.Translate(x => x.CreatedTime == targetDate); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.CreatedTime == targetDate); // Assert query.ShouldNotBeNull(); @@ -1025,23 +868,18 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase #region 边界情况测试 [Fact] - public async Task Translate_UnsupportedMethod_ThrowsNotSupportedException() + public async virtual Task Translate_UnsupportedMethod_ThrowsNotSupportedException() { - // Arrange - var translator = await CreateTranslator(); - // Act & Assert - Should.Throw(() => translator.Translate(x => x.Name!.ToUpper() == "TEST")); + await Should.ThrowAsync(async () => + await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Name!.ToUpper() == "TEST")); } [Fact] - public async Task Translate_MultipleWhereConditions_ReturnsCorrectQuery() + public async virtual Task Translate_MultipleWhereConditions_ReturnsCorrectQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => (x.Age > 18 || x.Age < 65) && x.Name != null && !x.IsActive); @@ -1054,14 +892,13 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_NestedAnyWithContains_ReturnsNestedTermsQuery() + public async virtual Task Translate_NestedAnyWithContains_ReturnsNestedTermsQuery() { // Arrange - var translator = await CreateTranslator(); var validIds = new List { 1, 2, 3, 4, 5 }; // Act - var query = translator.Translate(x => x.Items!.Any(i => validIds.Contains(i.Id))); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Items!.Any(i => validIds.Contains(i.Id))); // Assert query.ShouldNotBeNull(); @@ -1072,13 +909,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_StringEquals_NullValue_ReturnsMustNotExists() + public async virtual Task Translate_StringEquals_NullValue_ReturnsMustNotExists() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Name!.Equals(null)); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Name!.Equals(null)); // Assert query.ShouldNotBeNull(); @@ -1089,13 +923,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase } [Fact] - public async Task Translate_NotEqual_NullableEnum_ReturnsCorrectQuery() + public async virtual Task Translate_NotEqual_NullableEnum_ReturnsCorrectQuery() { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.NullableStatus != TestEnum.Active); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.NullableStatus != TestEnum.Active); // Assert query.ShouldNotBeNull(); @@ -1116,13 +947,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase [InlineData(TestEnum.Active, 1)] [InlineData(TestEnum.Inactive, 2)] [InlineData(TestEnum.Pending, 3)] - public async Task Translate_Equal_EnumField_ReturnsCorrectValue(TestEnum enumValue, long expectedValue) + public async virtual Task Translate_Equal_EnumField_ReturnsCorrectValue(TestEnum enumValue, long expectedValue) { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Status == enumValue); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Status == enumValue); // Assert query.ShouldNotBeNull(); @@ -1135,13 +963,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase [InlineData(18)] [InlineData(30)] [InlineData(65)] - public async Task Translate_GreaterThan_VariousAges_ReturnsCorrectRange(int age) + public async virtual Task Translate_GreaterThan_VariousAges_ReturnsCorrectRange(int age) { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Age > age); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Age > age); // Assert query.ShouldNotBeNull(); @@ -1155,13 +980,10 @@ public class ExpressionQueryTranslatorTests : AbpElasticsearchTestBase [InlineData("test")] [InlineData("hello")] [InlineData("world")] - public async Task Translate_StringContains_VariousValues_ReturnsCorrectWildcard(string searchValue) + public async virtual Task Translate_StringContains_VariousValues_ReturnsCorrectWildcard(string searchValue) { - // Arrange - var translator = await CreateTranslator(); - // Act - var query = translator.Translate(x => x.Name!.Contains(searchValue)); + var query = await _expressionQueryTranslator.TranslateAsync(TestDocumentIndexNames.Index, x => x.Name!.Contains(searchValue)); // Assert query.ShouldNotBeNull();