diff --git a/CHANGELOG.md b/CHANGELOG.md index 772cf5df87..e9740a05b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,12 +6,18 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Removed support for the `net461` target ([#256](https://github.com/opensearch-project/opensearch-net/pull/256)) - Fixed naming of `ClusterManagerTimeout` and `MasterTimeout` properties from `*TimeSpanout` in the low-level client ([#332](https://github.com/opensearch-project/opensearch-net/pull/332)) + +### Added +- Added `.Strict(bool)` and `.Verbatim(bool)` methods on `QueryContainer` that recursively apply the respective attribute to all subqueries. Also added a `.Name(string)` method on `QueryContainer` that names the (root) contained query. + ### Removed - Removed the `Features` API which is not supported by OpenSearch from the low-level client ([#331](https://github.com/opensearch-project/opensearch-net/pull/331)) - Removed the deprecated low-level `IndexTemplateV2` APIs in favour of the `ComposableIndexTemplate` APIs ([#437](https://github.com/opensearch-project/opensearch-net/pull/437)) ### Fixed - Fix `HttpConnection.ConvertHttpMethod` to support `Patch` method ([#489](https://github.com/opensearch-project/opensearch-net/pull/489)) +- Fixed `IEnumerable` property mapping. ([#503](https://github.com/opensearch-project/opensearch-net/pull/503)) + ### Fixed diff --git a/src/OpenSearch.Client/QueryDsl/Abstractions/Container/QueryContainer-Dsl.cs b/src/OpenSearch.Client/QueryDsl/Abstractions/Container/QueryContainer-Dsl.cs index 2d4221d6e4..532570d1c3 100644 --- a/src/OpenSearch.Client/QueryDsl/Abstractions/Container/QueryContainer-Dsl.cs +++ b/src/OpenSearch.Client/QueryDsl/Abstractions/Container/QueryContainer-Dsl.cs @@ -131,5 +131,42 @@ out QueryContainer queryContainer // ReSharper disable once UnusedMember.Global internal bool ShouldSerialize(IJsonFormatterResolver formatterResolver) => IsWritable; + + + public QueryContainer Name(string name) + { + ContainedQuery.Name = name; + return this; + } + + /// + /// Applies or removes the `strict` attribute to the query container and all child sub-queries. + /// + /// When null, the value is taken from the root query. + /// + public QueryContainer Strict(bool? strict = true) + { + if (!strict.HasValue) + strict = ContainedQuery.IsStrict; + + var visitor = new QueryNodeModifierVisitor((query, ctx) => query.IsStrict = strict.Value); + Accept(visitor); + return this; + } + + /// + /// Applies or removes the `verbatim` attribute to the query container and all child sub-queries. + /// + /// When null, the value is taken from the root query. + /// + public QueryContainer Verbatim(bool? verbatim = true) + { + if (!verbatim.HasValue) + verbatim = ContainedQuery.IsVerbatim; + + var visitor = new QueryNodeModifierVisitor((query, ctx) => query.IsVerbatim = verbatim.Value); + Accept(visitor); + return this; + } } } diff --git a/src/OpenSearch.Client/QueryDsl/Visitor/QueryNodeModifierVisitor.cs b/src/OpenSearch.Client/QueryDsl/Visitor/QueryNodeModifierVisitor.cs new file mode 100644 index 0000000000..8bba8b6e3b --- /dev/null +++ b/src/OpenSearch.Client/QueryDsl/Visitor/QueryNodeModifierVisitor.cs @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: Apache-2.0 +* +* The OpenSearch Contributors require contributions made to +* this file be licensed under the Apache-2.0 license or a +* compatible open source license. +*/ + +using System; + +namespace OpenSearch.Client +{ + public class QueryNodeModifierVisitor : QueryVisitor + { + private readonly Action action; + private QueryNodeModifierVisitorContext context; + + public QueryNodeModifierVisitor(Action action) + { + this.action = action; + context = new QueryNodeModifierVisitorContext(); + } + + public override void Visit(IQuery query) + { + context.Depth = Depth; + context.Scope = Scope; + + action(query, context); + base.Visit(query); + } + } +} diff --git a/src/OpenSearch.Client/QueryDsl/Visitor/QueryNodeModifierVisitorContext.cs b/src/OpenSearch.Client/QueryDsl/Visitor/QueryNodeModifierVisitorContext.cs new file mode 100644 index 0000000000..9623385ab8 --- /dev/null +++ b/src/OpenSearch.Client/QueryDsl/Visitor/QueryNodeModifierVisitorContext.cs @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: Apache-2.0 +* +* The OpenSearch Contributors require contributions made to +* this file be licensed under the Apache-2.0 license or a +* compatible open source license. +*/ + +namespace OpenSearch.Client +{ + public struct QueryNodeModifierVisitorContext + { + public int Depth { get; internal set; } + public VisitorScope Scope { get; internal set; } + } +} diff --git a/tests/Tests/QueryDsl/Container/QueryContainerTests.cs b/tests/Tests/QueryDsl/Container/QueryContainerTests.cs new file mode 100644 index 0000000000..7db7980770 --- /dev/null +++ b/tests/Tests/QueryDsl/Container/QueryContainerTests.cs @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: Apache-2.0 +* +* The OpenSearch Contributors require contributions made to +* this file be licensed under the Apache-2.0 license or a +* compatible open source license. +*/ + +using FluentAssertions; +using OpenSearch.Client; +using OpenSearch.OpenSearch.Xunit.XunitPlumbing; +using Xunit; + +namespace Tests.QueryDsl.Container +{ + public class QueryContainerTests + { + [TU] + [InlineData(false, false)] + [InlineData(false, true)] + [InlineData(true, false)] + [InlineData(true, true)] + public void StrictAndVerbatimAttributesAreRecursivelySetCorrectly(bool targetStrict, bool targetVerbatim) + { + // Arrange + var query0 = new TermQuery { Field = "field", Value = 1, IsStrict = !targetStrict, IsVerbatim = !targetVerbatim }; + var query1 = new BoolQuery { MustNot = new QueryContainer[] { query0 } }; + var query2 = new TermQuery { Field = "field2", Value = 7, IsStrict = !targetStrict, IsVerbatim = !targetVerbatim }; + var query3 = new BoolQuery { Must = new QueryContainer[] { query1, query2 } }; + var queryContainer = new QueryContainer(query3); + + // Act + queryContainer.Strict(targetStrict); + queryContainer.Verbatim(targetVerbatim); + + // Assert + query0.IsStrict.Should().Be(targetStrict); + query0.IsVerbatim.Should().Be(targetVerbatim); + query1.IsStrict.Should().Be(targetStrict); + query1.IsVerbatim.Should().Be(targetVerbatim); + query2.IsStrict.Should().Be(targetStrict); + query2.IsVerbatim.Should().Be(targetVerbatim); + query3.IsStrict.Should().Be(targetStrict); + query3.IsVerbatim.Should().Be(targetVerbatim); + } + + [TU] + [InlineData("name1")] + [InlineData("a name")] + [InlineData(null)] + public void SettingTheNameOnTheQueryContainerSetTheNameOnTheContainedQuery(string name) + { + // Arrange + var query0 = new TermQuery { Name = "a", Field = "field", Value = 1 }; + var query1 = new BoolQuery { Name = "b", MustNot = new QueryContainer[] { query0 } }; + var query2 = new TermQuery { Name = "c", Field = "field2", Value = 7 }; + var query3 = new BoolQuery { Name = "d", Must = new QueryContainer[] { query1, query2 } }; + var queryContainer = new QueryContainer(query3); + + // Act + queryContainer.Name(name); + + // Assert + query3.Name.Should().Be(name); + queryContainer.ContainedQuery.Name.Should().Be(name); + query0.Name.Should().Be("a"); + query1.Name.Should().Be("b"); + query2.Name.Should().Be("c"); + } + + + } +}