From c9039584fd4a3aa2b9d4acb14b3b0afc0c2249aa Mon Sep 17 00:00:00 2001 From: Steve Gordon Date: Wed, 5 Apr 2023 10:24:03 +0100 Subject: [PATCH] Add support for pinned query (#7576) * Generate pinned query * Add tests --- .../_Generated/Types/QueryDsl/PinnedDoc.g.cs | 70 +++ .../Types/QueryDsl/PinnedQuery.g.cs | 407 ++++++++++++++++++ .../_Generated/Types/QueryDsl/Query.g.cs | 16 + .../Specialized/PinnedQueryUsageTests.cs | 43 ++ ...ageTests.VerifyDescriptorJson.verified.txt | 18 + ...geTests.VerifyInitializerJson.verified.txt | 18 + 6 files changed, 572 insertions(+) create mode 100644 src/Elastic.Clients.Elasticsearch/_Generated/Types/QueryDsl/PinnedDoc.g.cs create mode 100644 src/Elastic.Clients.Elasticsearch/_Generated/Types/QueryDsl/PinnedQuery.g.cs create mode 100644 tests/Tests/QueryDsl/Specialized/PinnedQueryUsageTests.cs create mode 100644 tests/Tests/_VerifySnapshots/PinnedQueryUsageTests.VerifyDescriptorJson.verified.txt create mode 100644 tests/Tests/_VerifySnapshots/PinnedQueryUsageTests.VerifyInitializerJson.verified.txt diff --git a/src/Elastic.Clients.Elasticsearch/_Generated/Types/QueryDsl/PinnedDoc.g.cs b/src/Elastic.Clients.Elasticsearch/_Generated/Types/QueryDsl/PinnedDoc.g.cs new file mode 100644 index 00000000000..c6396626291 --- /dev/null +++ b/src/Elastic.Clients.Elasticsearch/_Generated/Types/QueryDsl/PinnedDoc.g.cs @@ -0,0 +1,70 @@ +// Licensed to Elasticsearch B.V under one or more agreements. +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information. +// +// ███╗ ██╗ ██████╗ ████████╗██╗ ██████╗███████╗ +// ████╗ ██║██╔═══██╗╚══██╔══╝██║██╔════╝██╔════╝ +// ██╔██╗ ██║██║ ██║ ██║ ██║██║ █████╗ +// ██║╚██╗██║██║ ██║ ██║ ██║██║ ██╔══╝ +// ██║ ╚████║╚██████╔╝ ██║ ██║╚██████╗███████╗ +// ╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝╚══════╝ +// ------------------------------------------------ +// +// This file is automatically generated. +// Please do not edit these files manually. +// +// ------------------------------------------------ + +#nullable restore + +using Elastic.Clients.Elasticsearch.Fluent; +using Elastic.Clients.Elasticsearch.Serialization; +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Elastic.Clients.Elasticsearch.QueryDsl; + +public sealed partial class PinnedDoc +{ + [JsonInclude, JsonPropertyName("_id")] + public Elastic.Clients.Elasticsearch.Id Id { get; set; } + [JsonInclude, JsonPropertyName("_index")] + public Elastic.Clients.Elasticsearch.IndexName Index { get; set; } +} + +public sealed partial class PinnedDocDescriptor : SerializableDescriptor +{ + internal PinnedDocDescriptor(Action configure) => configure.Invoke(this); + + public PinnedDocDescriptor() : base() + { + } + + private Elastic.Clients.Elasticsearch.Id IdValue { get; set; } + private Elastic.Clients.Elasticsearch.IndexName IndexValue { get; set; } + + public PinnedDocDescriptor Id(Elastic.Clients.Elasticsearch.Id id) + { + IdValue = id; + return Self; + } + + public PinnedDocDescriptor Index(Elastic.Clients.Elasticsearch.IndexName index) + { + IndexValue = index; + return Self; + } + + protected override void Serialize(Utf8JsonWriter writer, JsonSerializerOptions options, IElasticsearchClientSettings settings) + { + writer.WriteStartObject(); + writer.WritePropertyName("_id"); + JsonSerializer.Serialize(writer, IdValue, options); + writer.WritePropertyName("_index"); + JsonSerializer.Serialize(writer, IndexValue, options); + writer.WriteEndObject(); + } +} \ No newline at end of file diff --git a/src/Elastic.Clients.Elasticsearch/_Generated/Types/QueryDsl/PinnedQuery.g.cs b/src/Elastic.Clients.Elasticsearch/_Generated/Types/QueryDsl/PinnedQuery.g.cs new file mode 100644 index 00000000000..11aa01d3e47 --- /dev/null +++ b/src/Elastic.Clients.Elasticsearch/_Generated/Types/QueryDsl/PinnedQuery.g.cs @@ -0,0 +1,407 @@ +// Licensed to Elasticsearch B.V under one or more agreements. +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information. +// +// ███╗ ██╗ ██████╗ ████████╗██╗ ██████╗███████╗ +// ████╗ ██║██╔═══██╗╚══██╔══╝██║██╔════╝██╔════╝ +// ██╔██╗ ██║██║ ██║ ██║ ██║██║ █████╗ +// ██║╚██╗██║██║ ██║ ██║ ██║██║ ██╔══╝ +// ██║ ╚████║╚██████╔╝ ██║ ██║╚██████╗███████╗ +// ╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝╚══════╝ +// ------------------------------------------------ +// +// This file is automatically generated. +// Please do not edit these files manually. +// +// ------------------------------------------------ + +#nullable restore + +using Elastic.Clients.Elasticsearch.Fluent; +using Elastic.Clients.Elasticsearch.Serialization; +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Elastic.Clients.Elasticsearch.QueryDsl; + +[JsonConverter(typeof(PinnedQueryConverter))] +public sealed partial class PinnedQuery : SearchQuery +{ + internal PinnedQuery(string variantName, object variant) + { + if (variantName is null) + throw new ArgumentNullException(nameof(variantName)); + if (variant is null) + throw new ArgumentNullException(nameof(variant)); + if (string.IsNullOrWhiteSpace(variantName)) + throw new ArgumentException("Variant name must not be empty or whitespace."); + VariantName = variantName; + Variant = variant; + } + + internal object Variant { get; } + internal string VariantName { get; } + + public static PinnedQuery Docs(ICollection variant) => new PinnedQuery("docs", variant); + public static PinnedQuery Ids(ICollection variant) => new PinnedQuery("ids", variant); + + [JsonInclude, JsonPropertyName("_name")] + public string? QueryName { get; set; } + [JsonInclude, JsonPropertyName("boost")] + public float? Boost { get; set; } + [JsonInclude, JsonPropertyName("organic")] + public Elastic.Clients.Elasticsearch.QueryDsl.Query Organic { get; set; } + + public static implicit operator Query(PinnedQuery pinnedQuery) => QueryDsl.Query.Pinned(pinnedQuery); +} + +internal sealed partial class PinnedQueryConverter : JsonConverter +{ + public override PinnedQuery Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType != JsonTokenType.StartObject) + { + throw new JsonException("Expected start token."); + } + + object? variantValue = default; + string? variantNameValue = default; + string? nameValue = default; + float? boostValue = default; + Elastic.Clients.Elasticsearch.QueryDsl.Query organicValue = default; + while (reader.Read() && reader.TokenType != JsonTokenType.EndObject) + { + if (reader.TokenType != JsonTokenType.PropertyName) + { + throw new JsonException("Expected a property name token."); + } + + if (reader.TokenType != JsonTokenType.PropertyName) + { + throw new JsonException("Expected a property name token representing the name of an Elasticsearch field."); + } + + var propertyName = reader.GetString(); + reader.Read(); + if (propertyName == "_name") + { + nameValue = JsonSerializer.Deserialize(ref reader, options); + continue; + } + + if (propertyName == "boost") + { + boostValue = JsonSerializer.Deserialize(ref reader, options); + continue; + } + + if (propertyName == "organic") + { + organicValue = JsonSerializer.Deserialize(ref reader, options); + continue; + } + + if (propertyName == "docs") + { + variantValue = JsonSerializer.Deserialize?>(ref reader, options); + variantNameValue = propertyName; + continue; + } + + if (propertyName == "ids") + { + variantValue = JsonSerializer.Deserialize?>(ref reader, options); + variantNameValue = propertyName; + continue; + } + + throw new JsonException($"Unknown property name '{propertyName}' received while deserializing the 'PinnedQuery' from the response."); + } + + reader.Read(); + var result = new PinnedQuery(variantNameValue, variantValue); + result.QueryName = nameValue; + result.Boost = boostValue; + result.Organic = organicValue; + return result; + } + + public override void Write(Utf8JsonWriter writer, PinnedQuery value, JsonSerializerOptions options) + { + writer.WriteStartObject(); + if (!string.IsNullOrEmpty(value.QueryName)) + { + writer.WritePropertyName("_name"); + writer.WriteStringValue(value.QueryName); + } + + if (value.Boost.HasValue) + { + writer.WritePropertyName("boost"); + writer.WriteNumberValue(value.Boost.Value); + } + + writer.WritePropertyName("organic"); + JsonSerializer.Serialize(writer, value.Organic, options); + if (value.VariantName is not null & value.Variant is not null) + { + writer.WritePropertyName(value.VariantName); + switch (value.VariantName) + { + case "docs": + JsonSerializer.Serialize>(writer, (ICollection)value.Variant, options); + break; + case "ids": + JsonSerializer.Serialize>(writer, (ICollection)value.Variant, options); + break; + } + } + + writer.WriteEndObject(); + } +} + +public sealed partial class PinnedQueryDescriptor : SerializableDescriptor> +{ + internal PinnedQueryDescriptor(Action> configure) => configure.Invoke(this); + + public PinnedQueryDescriptor() : base() + { + } + + private bool ContainsVariant { get; set; } + private string ContainedVariantName { get; set; } + private object Variant { get; set; } + private Descriptor Descriptor { get; set; } + + private PinnedQueryDescriptor Set(Action descriptorAction, string variantName) where T : Descriptor + { + ContainedVariantName = variantName; + ContainsVariant = true; + var descriptor = (T)Activator.CreateInstance(typeof(T), true); + descriptorAction?.Invoke(descriptor); + Descriptor = descriptor; + return Self; + } + + private PinnedQueryDescriptor Set(object variant, string variantName) + { + Variant = variant; + ContainedVariantName = variantName; + ContainsVariant = true; + return Self; + } + + private Elastic.Clients.Elasticsearch.QueryDsl.Query OrganicValue { get; set; } + private QueryDescriptor OrganicDescriptor { get; set; } + private Action> OrganicDescriptorAction { get; set; } + private string? QueryNameValue { get; set; } + private float? BoostValue { get; set; } + + public PinnedQueryDescriptor Organic(Elastic.Clients.Elasticsearch.QueryDsl.Query organic) + { + OrganicDescriptor = null; + OrganicDescriptorAction = null; + OrganicValue = organic; + return Self; + } + + public PinnedQueryDescriptor Organic(QueryDescriptor descriptor) + { + OrganicValue = null; + OrganicDescriptorAction = null; + OrganicDescriptor = descriptor; + return Self; + } + + public PinnedQueryDescriptor Organic(Action> configure) + { + OrganicValue = null; + OrganicDescriptor = null; + OrganicDescriptorAction = configure; + return Self; + } + + public PinnedQueryDescriptor QueryName(string? queryName) + { + QueryNameValue = queryName; + return Self; + } + + public PinnedQueryDescriptor Boost(float? boost) + { + BoostValue = boost; + return Self; + } + + protected override void Serialize(Utf8JsonWriter writer, JsonSerializerOptions options, IElasticsearchClientSettings settings) + { + writer.WriteStartObject(); + if (OrganicDescriptor is not null) + { + writer.WritePropertyName("organic"); + JsonSerializer.Serialize(writer, OrganicDescriptor, options); + } + else if (OrganicDescriptorAction is not null) + { + writer.WritePropertyName("organic"); + JsonSerializer.Serialize(writer, new QueryDescriptor(OrganicDescriptorAction), options); + } + else + { + writer.WritePropertyName("organic"); + JsonSerializer.Serialize(writer, OrganicValue, options); + } + + if (!string.IsNullOrEmpty(QueryNameValue)) + { + writer.WritePropertyName("_name"); + writer.WriteStringValue(QueryNameValue); + } + + if (BoostValue.HasValue) + { + writer.WritePropertyName("boost"); + writer.WriteNumberValue(BoostValue.Value); + } + + if (!string.IsNullOrEmpty(ContainedVariantName)) + { + writer.WritePropertyName(ContainedVariantName); + if (Variant is not null) + { + JsonSerializer.Serialize(writer, Variant, Variant.GetType(), options); + writer.WriteEndObject(); + return; + } + + JsonSerializer.Serialize(writer, Descriptor, Descriptor.GetType(), options); + } + + writer.WriteEndObject(); + } +} + +public sealed partial class PinnedQueryDescriptor : SerializableDescriptor +{ + internal PinnedQueryDescriptor(Action configure) => configure.Invoke(this); + + public PinnedQueryDescriptor() : base() + { + } + + private bool ContainsVariant { get; set; } + private string ContainedVariantName { get; set; } + private object Variant { get; set; } + private Descriptor Descriptor { get; set; } + + private PinnedQueryDescriptor Set(Action descriptorAction, string variantName) where T : Descriptor + { + ContainedVariantName = variantName; + ContainsVariant = true; + var descriptor = (T)Activator.CreateInstance(typeof(T), true); + descriptorAction?.Invoke(descriptor); + Descriptor = descriptor; + return Self; + } + + private PinnedQueryDescriptor Set(object variant, string variantName) + { + Variant = variant; + ContainedVariantName = variantName; + ContainsVariant = true; + return Self; + } + + private Elastic.Clients.Elasticsearch.QueryDsl.Query OrganicValue { get; set; } + private QueryDescriptor OrganicDescriptor { get; set; } + private Action OrganicDescriptorAction { get; set; } + private string? QueryNameValue { get; set; } + private float? BoostValue { get; set; } + + public PinnedQueryDescriptor Organic(Elastic.Clients.Elasticsearch.QueryDsl.Query organic) + { + OrganicDescriptor = null; + OrganicDescriptorAction = null; + OrganicValue = organic; + return Self; + } + + public PinnedQueryDescriptor Organic(QueryDescriptor descriptor) + { + OrganicValue = null; + OrganicDescriptorAction = null; + OrganicDescriptor = descriptor; + return Self; + } + + public PinnedQueryDescriptor Organic(Action configure) + { + OrganicValue = null; + OrganicDescriptor = null; + OrganicDescriptorAction = configure; + return Self; + } + + public PinnedQueryDescriptor QueryName(string? queryName) + { + QueryNameValue = queryName; + return Self; + } + + public PinnedQueryDescriptor Boost(float? boost) + { + BoostValue = boost; + return Self; + } + + protected override void Serialize(Utf8JsonWriter writer, JsonSerializerOptions options, IElasticsearchClientSettings settings) + { + writer.WriteStartObject(); + if (OrganicDescriptor is not null) + { + writer.WritePropertyName("organic"); + JsonSerializer.Serialize(writer, OrganicDescriptor, options); + } + else if (OrganicDescriptorAction is not null) + { + writer.WritePropertyName("organic"); + JsonSerializer.Serialize(writer, new QueryDescriptor(OrganicDescriptorAction), options); + } + else + { + writer.WritePropertyName("organic"); + JsonSerializer.Serialize(writer, OrganicValue, options); + } + + if (!string.IsNullOrEmpty(QueryNameValue)) + { + writer.WritePropertyName("_name"); + writer.WriteStringValue(QueryNameValue); + } + + if (BoostValue.HasValue) + { + writer.WritePropertyName("boost"); + writer.WriteNumberValue(BoostValue.Value); + } + + if (!string.IsNullOrEmpty(ContainedVariantName)) + { + writer.WritePropertyName(ContainedVariantName); + if (Variant is not null) + { + JsonSerializer.Serialize(writer, Variant, Variant.GetType(), options); + writer.WriteEndObject(); + return; + } + + JsonSerializer.Serialize(writer, Descriptor, Descriptor.GetType(), options); + } + + writer.WriteEndObject(); + } +} \ No newline at end of file diff --git a/src/Elastic.Clients.Elasticsearch/_Generated/Types/QueryDsl/Query.g.cs b/src/Elastic.Clients.Elasticsearch/_Generated/Types/QueryDsl/Query.g.cs index 0228934442d..99fc0055b3d 100644 --- a/src/Elastic.Clients.Elasticsearch/_Generated/Types/QueryDsl/Query.g.cs +++ b/src/Elastic.Clients.Elasticsearch/_Generated/Types/QueryDsl/Query.g.cs @@ -72,6 +72,7 @@ internal Query(string variantName, object variant) public static Query Nested(Elastic.Clients.Elasticsearch.QueryDsl.NestedQuery nestedQuery) => new Query("nested", nestedQuery); public static Query ParentId(Elastic.Clients.Elasticsearch.QueryDsl.ParentIdQuery parentIdQuery) => new Query("parent_id", parentIdQuery); public static Query Percolate(Elastic.Clients.Elasticsearch.QueryDsl.PercolateQuery percolateQuery) => new Query("percolate", percolateQuery); + public static Query Pinned(Elastic.Clients.Elasticsearch.QueryDsl.PinnedQuery pinnedQuery) => new Query("pinned", pinnedQuery); public static Query Prefix(Elastic.Clients.Elasticsearch.QueryDsl.PrefixQuery prefixQuery) => new Query("prefix", prefixQuery); public static Query QueryString(Elastic.Clients.Elasticsearch.QueryDsl.QueryStringQuery queryStringQuery) => new Query("query_string", queryStringQuery); public static Query Range(Elastic.Clients.Elasticsearch.QueryDsl.RangeQuery rangeQuery) => new Query("range", rangeQuery); @@ -302,6 +303,13 @@ public override Query Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSe return new Query(propertyName, variant); } + if (propertyName == "pinned") + { + var variant = JsonSerializer.Deserialize(ref reader, options); + reader.Read(); + return new Query(propertyName, variant); + } + if (propertyName == "prefix") { var variant = JsonSerializer.Deserialize(ref reader, options); @@ -554,6 +562,9 @@ public override void Write(Utf8JsonWriter writer, Query value, JsonSerializerOpt case "percolate": JsonSerializer.Serialize(writer, (Elastic.Clients.Elasticsearch.QueryDsl.PercolateQuery)value.Variant, options); break; + case "pinned": + JsonSerializer.Serialize(writer, (Elastic.Clients.Elasticsearch.QueryDsl.PinnedQuery)value.Variant, options); + break; case "prefix": JsonSerializer.Serialize(writer, (Elastic.Clients.Elasticsearch.QueryDsl.PrefixQuery)value.Variant, options); break; @@ -712,6 +723,8 @@ private QueryDescriptor Set(object variant, string variantName) public QueryDescriptor ParentId(Action configure) => Set(configure, "parent_id"); public QueryDescriptor Percolate(PercolateQuery percolateQuery) => Set(percolateQuery, "percolate"); public QueryDescriptor Percolate(Action> configure) => Set(configure, "percolate"); + public QueryDescriptor Pinned(PinnedQuery pinnedQuery) => Set(pinnedQuery, "pinned"); + public QueryDescriptor Pinned(Action> configure) => Set(configure, "pinned"); public QueryDescriptor Prefix(PrefixQuery prefixQuery) => Set(prefixQuery, "prefix"); public QueryDescriptor Prefix(Action> configure) => Set(configure, "prefix"); public QueryDescriptor QueryString(QueryStringQuery queryStringQuery) => Set(queryStringQuery, "query_string"); @@ -892,6 +905,9 @@ private QueryDescriptor Set(object variant, string variantName) public QueryDescriptor Percolate(PercolateQuery percolateQuery) => Set(percolateQuery, "percolate"); public QueryDescriptor Percolate(Action configure) => Set(configure, "percolate"); public QueryDescriptor Percolate(Action> configure) => Set(configure, "percolate"); + public QueryDescriptor Pinned(PinnedQuery pinnedQuery) => Set(pinnedQuery, "pinned"); + public QueryDescriptor Pinned(Action configure) => Set(configure, "pinned"); + public QueryDescriptor Pinned(Action> configure) => Set(configure, "pinned"); public QueryDescriptor Prefix(PrefixQuery prefixQuery) => Set(prefixQuery, "prefix"); public QueryDescriptor Prefix(Action configure) => Set(configure, "prefix"); public QueryDescriptor Prefix(Action> configure) => Set(configure, "prefix"); diff --git a/tests/Tests/QueryDsl/Specialized/PinnedQueryUsageTests.cs b/tests/Tests/QueryDsl/Specialized/PinnedQueryUsageTests.cs new file mode 100644 index 00000000000..d8e32be2fa1 --- /dev/null +++ b/tests/Tests/QueryDsl/Specialized/PinnedQueryUsageTests.cs @@ -0,0 +1,43 @@ +// Licensed to Elasticsearch B.V under one or more agreements. +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information. + +using Elastic.Clients.Elasticsearch.QueryDsl; +using Tests.Core.ManagedElasticsearch.Clusters; +using Tests.Domain; +using Tests.Framework.EndpointTests.TestState; + +namespace Tests.QueryDsl.Specialized; + +public class PinnedQueryUsageTests : QueryDslUsageTestsBase +{ + public PinnedQueryUsageTests(ReadOnlyCluster i, EndpointUsage usage) : base(i, usage) { } + + protected override Query QueryInitializer + { + get + { + var query = PinnedQuery.Ids(new Id[] { 1, 11, 22 }); + + query.QueryName = "named_query"; + query.Boost = 1.1f; + query.Organic = new MatchAllQuery { QueryName = "organic_query" }; + + return query; + } + } + + protected override QueryDescriptor QueryFluent(QueryDescriptor queryDescriptor) + { + // The descriptor for the pinned query is not complete as it doesn't support setting the variant (ids/docs). + // For now, we workaround this by passing in the PinnedQuery directly to the supported overload. + + var query = PinnedQuery.Ids(new Id[] { 1, 11, 22 }); + + query.QueryName = "named_query"; + query.Boost = 1.1f; + query.Organic = new MatchAllQuery { QueryName = "organic_query" }; + + return queryDescriptor.Pinned(query); + } +} diff --git a/tests/Tests/_VerifySnapshots/PinnedQueryUsageTests.VerifyDescriptorJson.verified.txt b/tests/Tests/_VerifySnapshots/PinnedQueryUsageTests.VerifyDescriptorJson.verified.txt new file mode 100644 index 00000000000..fd32b258b9b --- /dev/null +++ b/tests/Tests/_VerifySnapshots/PinnedQueryUsageTests.VerifyDescriptorJson.verified.txt @@ -0,0 +1,18 @@ +{ + query: { + pinned: { + boost: 1.1, + ids: [ + 1, + 11, + 22 + ], + organic: { + match_all: { + _name: organic_query + } + }, + _name: named_query + } + } +} \ No newline at end of file diff --git a/tests/Tests/_VerifySnapshots/PinnedQueryUsageTests.VerifyInitializerJson.verified.txt b/tests/Tests/_VerifySnapshots/PinnedQueryUsageTests.VerifyInitializerJson.verified.txt new file mode 100644 index 00000000000..fd32b258b9b --- /dev/null +++ b/tests/Tests/_VerifySnapshots/PinnedQueryUsageTests.VerifyInitializerJson.verified.txt @@ -0,0 +1,18 @@ +{ + query: { + pinned: { + boost: 1.1, + ids: [ + 1, + 11, + 22 + ], + organic: { + match_all: { + _name: organic_query + } + }, + _name: named_query + } + } +} \ No newline at end of file