From 88ab929a3a4471022d851f6cc384fbb186f899f5 Mon Sep 17 00:00:00 2001 From: Kostas Date: Tue, 6 Feb 2024 18:28:23 +0200 Subject: [PATCH] Fix for #375 - Added `.Strict(...)`, `.Verbatim(...)`, `.Name(...)` methods on `QueryContainer` to help modify contained query attributes. Signed-off-by: Kostas --- CHANGELOG.md | 7 +- .../Container/QueryContainer-Dsl.cs | 53 +++++++++ .../Visitor/StrictnessPropagatingVisitor.cs | 24 +++++ .../Visitor/VerbatimPropagatingVisitor.cs | 22 ++++ .../QueryDsl/Container/QueryContainerTests.cs | 101 ++++++++++++++++++ 5 files changed, 203 insertions(+), 4 deletions(-) create mode 100644 src/OpenSearch.Client/QueryDsl/Visitor/StrictnessPropagatingVisitor.cs create mode 100644 src/OpenSearch.Client/QueryDsl/Visitor/VerbatimPropagatingVisitor.cs create mode 100644 tests/Tests/QueryDsl/Container/QueryContainerTests.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 772cf5df87..93f07ef2ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,18 +6,17 @@ 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(...)`, `.Verbatim(...)`, `.Name(...)` methods on `QueryContainer` to help modify contained query attributes. + ### 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 - Fixed `IEnumerable` property mapping. ([#503](https://github.com/opensearch-project/opensearch-net/pull/503)) - ### Dependencies - Bumps `Microsoft.CodeAnalysis.CSharp` from 4.2.0 to 4.6.0 - Bumps `NSwag.Core.Yaml` from 13.19.0 to 13.20.0 diff --git a/src/OpenSearch.Client/QueryDsl/Abstractions/Container/QueryContainer-Dsl.cs b/src/OpenSearch.Client/QueryDsl/Abstractions/Container/QueryContainer-Dsl.cs index 2d4221d6e4..e7504c8591 100644 --- a/src/OpenSearch.Client/QueryDsl/Abstractions/Container/QueryContainer-Dsl.cs +++ b/src/OpenSearch.Client/QueryDsl/Abstractions/Container/QueryContainer-Dsl.cs @@ -131,5 +131,58 @@ out QueryContainer queryContainer // ReSharper disable once UnusedMember.Global internal bool ShouldSerialize(IJsonFormatterResolver formatterResolver) => IsWritable; + + /// + /// Assigns a name to the contained query. + /// + /// + /// + public QueryContainer Name(string name) + { + ContainedQuery.Name = name; + return this; + } + + /// + /// Applies or removes the `strict` attribute to the contained query and optionally to all child sub-queries. + /// + /// + /// When true, it applies the attribute to all child sub-queries. + /// + public QueryContainer Strict(bool strict = true, bool recurse = false) + { + if (recurse) + { + var visitor = new StrictnessPropagatingVisitor(strict); + Accept(visitor); + } + else + { + ContainedQuery.IsStrict = strict; + } + + return this; + } + + /// + /// Applies or removes the `verbatim` attribute to the contained query and optionally to all child sub-queries. + /// + /// + /// When true, it applies the attribute to all child sub-queries. + /// + public QueryContainer Verbatim(bool verbatim = true, bool recurse = false) + { + if (recurse) + { + var visitor = new VerbatimPropagatingVisitor(verbatim); + Accept(visitor); + } + else + { + ContainedQuery.IsVerbatim = verbatim; + } + + return this; + } } } diff --git a/src/OpenSearch.Client/QueryDsl/Visitor/StrictnessPropagatingVisitor.cs b/src/OpenSearch.Client/QueryDsl/Visitor/StrictnessPropagatingVisitor.cs new file mode 100644 index 0000000000..c97703c6d4 --- /dev/null +++ b/src/OpenSearch.Client/QueryDsl/Visitor/StrictnessPropagatingVisitor.cs @@ -0,0 +1,24 @@ +/* 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 StrictnessPropagatingVisitor : QueryVisitor + { + private readonly bool _strict; + + public StrictnessPropagatingVisitor(bool strict) => _strict = strict; + + public override void Visit(IQuery query) + { + query.IsStrict = _strict; + base.Visit(query); + } + } +} diff --git a/src/OpenSearch.Client/QueryDsl/Visitor/VerbatimPropagatingVisitor.cs b/src/OpenSearch.Client/QueryDsl/Visitor/VerbatimPropagatingVisitor.cs new file mode 100644 index 0000000000..c8daa65d21 --- /dev/null +++ b/src/OpenSearch.Client/QueryDsl/Visitor/VerbatimPropagatingVisitor.cs @@ -0,0 +1,22 @@ +/* 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 class VerbatimPropagatingVisitor : QueryVisitor + { + private readonly bool _verbatim; + + public VerbatimPropagatingVisitor(bool verbatim) => _verbatim = verbatim; + + public override void Visit(IQuery query) + { + query.IsVerbatim = _verbatim; + base.Visit(query); + } + } +} diff --git a/tests/Tests/QueryDsl/Container/QueryContainerTests.cs b/tests/Tests/QueryDsl/Container/QueryContainerTests.cs new file mode 100644 index 0000000000..c2cb5bc1a8 --- /dev/null +++ b/tests/Tests/QueryDsl/Container/QueryContainerTests.cs @@ -0,0 +1,101 @@ +/* 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, recurse: true); + queryContainer.Verbatim(targetVerbatim, recurse: true); + + // 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(false, false)] + [InlineData(false, true)] + [InlineData(true, false)] + [InlineData(true, true)] + public void StrictAndVerbatimAttributesAreSetCorrectly(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, recurse: false); + queryContainer.Verbatim(targetVerbatim, recurse: false); + + // Assert + query0.IsStrict.Should().Be(false); + query0.IsVerbatim.Should().Be(false); + query1.IsStrict.Should().Be(false); + query1.IsVerbatim.Should().Be(false); + query2.IsStrict.Should().Be(false); + query2.IsVerbatim.Should().Be(false); + 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"); + } + + + } +}