From 703af0bd3ac13c72b3f6d240a556d95a1eff66ff Mon Sep 17 00:00:00 2001 From: Steve Gordon Date: Thu, 28 Oct 2021 09:51:31 +0100 Subject: [PATCH] Support deprecated range query properties (#6042) * Initial work to support deprecated properties * Support additional deprecated properties on range query * Allow skipping some checks in code standards (cherry picked from commit 4125cf9108675168719999e68ac62b7da45713a9) --- .../Extensions/ArraySegmentBytesExtensions.cs | 2 +- .../TermLevel/Range/DateRangeQuery.cs | 73 ++++++++++++++++--- .../TermLevel/Range/LongRangeQuery.cs | 68 +++++++++++++++-- .../TermLevel/Range/NumericRangeQuery.cs | 73 ++++++++++++++++--- .../QueryDsl/TermLevel/Range/RangeQuery.cs | 4 +- .../TermLevel/Range/RangeQueryFormatter.cs | 16 +++- .../TermLevel/Range/TermRangeQuery.cs | 72 +++++++++++++++--- tests/Tests/CodeStandards/Descriptors.doc.cs | 15 ++++ .../Range/RangeSerialisationTests.cs | 57 +++++++++++++++ .../Wildcard/WildcardSerialisationTests.cs | 4 +- 10 files changed, 342 insertions(+), 42 deletions(-) create mode 100644 tests/Tests/QueryDsl/TermLevel/Range/RangeSerialisationTests.cs diff --git a/src/Elasticsearch.Net/Extensions/ArraySegmentBytesExtensions.cs b/src/Elasticsearch.Net/Extensions/ArraySegmentBytesExtensions.cs index b13b82eef78..601df8c7306 100644 --- a/src/Elasticsearch.Net/Extensions/ArraySegmentBytesExtensions.cs +++ b/src/Elasticsearch.Net/Extensions/ArraySegmentBytesExtensions.cs @@ -103,7 +103,7 @@ public static bool IsDateTime(this ref ArraySegment arraySegment, IJsonFor dateTime = default; // TODO: Nicer way to do this - var reader = new JsonReader(arraySegment.Array, arraySegment.Offset - 1); // include opening quote " + var reader = new JsonReader(arraySegment.Array, arraySegment.Offset > 0 ? arraySegment.Offset - 1: arraySegment.Offset); // try to include opening quote " try { dateTime = ISO8601DateTimeFormatter.Default.Deserialize(ref reader, formatterResolver); diff --git a/src/Nest/QueryDsl/TermLevel/Range/DateRangeQuery.cs b/src/Nest/QueryDsl/TermLevel/Range/DateRangeQuery.cs index 571d0fb1df6..055a4a21361 100644 --- a/src/Nest/QueryDsl/TermLevel/Range/DateRangeQuery.cs +++ b/src/Nest/QueryDsl/TermLevel/Range/DateRangeQuery.cs @@ -2,6 +2,7 @@ // 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 System; using System.Runtime.Serialization; using Elasticsearch.Net.Utf8Json; @@ -31,18 +32,67 @@ public interface IDateRangeQuery : IRangeQuery [DataMember(Name = "time_zone")] string TimeZone { get; set; } + + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + [DataMember(Name = "from")] + DateMath From { get; set; } + + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + [DataMember(Name = "to")] + DateMath To { get; set; } + + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + [DataMember(Name = "include_lower")] + bool? IncludeLower { get; set; } + + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + [DataMember(Name = "include_upper")] + bool? IncludeUpper { get; set; } } public class DateRangeQuery : FieldNameQueryBase, IDateRangeQuery { public string Format { get; set; } public DateMath GreaterThan { get; set; } - public DateMath GreaterThanOrEqualTo { get; set; } public DateMath LessThan { get; set; } public DateMath LessThanOrEqualTo { get; set; } public RangeRelation? Relation { get; set; } public string TimeZone { get; set; } + + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + public DateMath From { get; set; } + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + public DateMath To { get; set; } + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + public bool? IncludeLower { get; set; } + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + public bool? IncludeUpper { get; set; } + protected override bool Conditionless => IsConditionless(this); internal override void InternalWrapInContainer(IQueryContainer c) => c.Range = this; @@ -51,13 +101,16 @@ internal static bool IsConditionless(IDateRangeQuery q) => q.Field.IsConditionle || ((q.GreaterThanOrEqualTo == null || !q.GreaterThanOrEqualTo.IsValid) && (q.LessThanOrEqualTo == null || !q.LessThanOrEqualTo.IsValid) && (q.GreaterThan == null || !q.GreaterThan.IsValid) - && (q.LessThan == null || !q.LessThan.IsValid)); + && (q.LessThan == null || !q.LessThan.IsValid) +#pragma warning disable CS0618 // Type or member is obsolete + && (q.From == null || !q.From.IsValid) + && (q.To == null || !q.To.IsValid)); +#pragma warning restore CS0618 // Type or member is obsolete } [DataContract] public class DateRangeQueryDescriptor - : FieldNameQueryDescriptorBase, IDateRangeQuery, T> - , IDateRangeQuery where T : class + : FieldNameQueryDescriptorBase, IDateRangeQuery, T>, IDateRangeQuery where T : class { protected override bool Conditionless => DateRangeQuery.IsConditionless(this); string IDateRangeQuery.Format { get; set; } @@ -68,18 +121,18 @@ public class DateRangeQueryDescriptor RangeRelation? IDateRangeQuery.Relation { get; set; } string IDateRangeQuery.TimeZone { get; set; } - public DateRangeQueryDescriptor GreaterThan(DateMath from) => Assign(from, (a, v) => a.GreaterThan = v); + // From, To, IncludeLower and IncludeUpper are not exposed as methods as they are considered deprecated and legacy. + DateMath IDateRangeQuery.From { get; set; } + DateMath IDateRangeQuery.To { get; set; } + bool? IDateRangeQuery.IncludeLower { get; set; } + bool? IDateRangeQuery.IncludeUpper { get; set; } + public DateRangeQueryDescriptor GreaterThan(DateMath from) => Assign(from, (a, v) => a.GreaterThan = v); public DateRangeQueryDescriptor GreaterThanOrEquals(DateMath from) => Assign(from, (a, v) => a.GreaterThanOrEqualTo = v); - public DateRangeQueryDescriptor LessThan(DateMath to) => Assign(to, (a, v) => a.LessThan = v); - public DateRangeQueryDescriptor LessThanOrEquals(DateMath to) => Assign(to, (a, v) => a.LessThanOrEqualTo = v); - public DateRangeQueryDescriptor TimeZone(string timeZone) => Assign(timeZone, (a, v) => a.TimeZone = v); - public DateRangeQueryDescriptor Format(string format) => Assign(format, (a, v) => a.Format = v); - public DateRangeQueryDescriptor Relation(RangeRelation? relation) => Assign(relation, (a, v) => a.Relation = v); } } diff --git a/src/Nest/QueryDsl/TermLevel/Range/LongRangeQuery.cs b/src/Nest/QueryDsl/TermLevel/Range/LongRangeQuery.cs index 5ae798e38a4..2d50251282f 100644 --- a/src/Nest/QueryDsl/TermLevel/Range/LongRangeQuery.cs +++ b/src/Nest/QueryDsl/TermLevel/Range/LongRangeQuery.cs @@ -2,6 +2,7 @@ // 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 System; using System.Runtime.Serialization; using Elasticsearch.Net.Utf8Json; @@ -23,8 +24,33 @@ public interface ILongRangeQuery : IRangeQuery [DataMember(Name ="lte")] long? LessThanOrEqualTo { get; set; } - [DataMember(Name ="relation")] + [DataMember(Name = "relation")] RangeRelation? Relation { get; set; } + + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + [DataMember(Name = "from")] + long? From { get; set; } + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + [DataMember(Name = "to")] + long? To { get; set; } + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + [DataMember(Name = "include_lower")] + bool? IncludeLower { get; set; } + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + [DataMember(Name = "include_upper")] + bool? IncludeUpper { get; set; } } public class LongRangeQuery : FieldNameQueryBase, ILongRangeQuery @@ -34,6 +60,27 @@ public class LongRangeQuery : FieldNameQueryBase, ILongRangeQuery public long? LessThan { get; set; } public long? LessThanOrEqualTo { get; set; } + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + public long? From { get; set; } + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + public long? To { get; set; } + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + public bool? IncludeLower { get; set; } + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + public bool? IncludeUpper { get; set; } + public RangeRelation? Relation { get; set; } protected override bool Conditionless => IsConditionless(this); @@ -43,13 +90,16 @@ internal static bool IsConditionless(ILongRangeQuery q) => q.Field.IsConditionle || q.GreaterThanOrEqualTo == null && q.LessThanOrEqualTo == null && q.GreaterThan == null - && q.LessThan == null; + && q.LessThan == null +#pragma warning disable CS0618 // Type or member is obsolete + && q.From == null + && q.To == null; +#pragma warning restore CS0618 // Type or member is obsolete } [DataContract] public class LongRangeQueryDescriptor - : FieldNameQueryDescriptorBase, ILongRangeQuery, T> - , ILongRangeQuery where T : class + : FieldNameQueryDescriptorBase, ILongRangeQuery, T>, ILongRangeQuery where T : class { protected override bool Conditionless => LongRangeQuery.IsConditionless(this); long? ILongRangeQuery.GreaterThan { get; set; } @@ -58,14 +108,16 @@ public class LongRangeQueryDescriptor long? ILongRangeQuery.LessThanOrEqualTo { get; set; } RangeRelation? ILongRangeQuery.Relation { get; set; } - public LongRangeQueryDescriptor Relation(RangeRelation? relation) => Assign(relation, (a, v) => a.Relation = v); + // From, To, IncludeLower and IncludeUpper are not exposed as methods as they are considered deprecated and legacy. + long? ILongRangeQuery.From { get; set; } + long? ILongRangeQuery.To { get; set; } + bool? ILongRangeQuery.IncludeLower { get; set; } + bool? ILongRangeQuery.IncludeUpper { get; set; } + public LongRangeQueryDescriptor Relation(RangeRelation? relation) => Assign(relation, (a, v) => a.Relation = v); public LongRangeQueryDescriptor GreaterThan(long? from) => Assign(from, (a, v) => a.GreaterThan = v); - public LongRangeQueryDescriptor GreaterThanOrEquals(long? from) => Assign(from, (a, v) => a.GreaterThanOrEqualTo = v); - public LongRangeQueryDescriptor LessThan(long? to) => Assign(to, (a, v) => a.LessThan = v); - public LongRangeQueryDescriptor LessThanOrEquals(long? to) => Assign(to, (a, v) => a.LessThanOrEqualTo = v); } } diff --git a/src/Nest/QueryDsl/TermLevel/Range/NumericRangeQuery.cs b/src/Nest/QueryDsl/TermLevel/Range/NumericRangeQuery.cs index 99c4c1613bd..9869d1819fb 100644 --- a/src/Nest/QueryDsl/TermLevel/Range/NumericRangeQuery.cs +++ b/src/Nest/QueryDsl/TermLevel/Range/NumericRangeQuery.cs @@ -2,6 +2,7 @@ // 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 System; using System.Runtime.Serialization; using Elasticsearch.Net.Utf8Json; @@ -25,6 +26,34 @@ public interface INumericRangeQuery : IRangeQuery [DataMember(Name = "relation")] RangeRelation? Relation { get; set; } + + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + [DataMember(Name = "from")] + double? From { get; set; } + + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + [DataMember(Name = "to")] + double? To { get; set; } + + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + [DataMember(Name = "include_lower")] + bool? IncludeLower { get; set; } + + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + [DataMember(Name = "include_upper")] + bool? IncludeUpper { get; set; } } public class NumericRangeQuery : FieldNameQueryBase, INumericRangeQuery @@ -33,8 +62,29 @@ public class NumericRangeQuery : FieldNameQueryBase, INumericRangeQuery public double? GreaterThanOrEqualTo { get; set; } public double? LessThan { get; set; } public double? LessThanOrEqualTo { get; set; } - public RangeRelation? Relation { get; set; } + + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + public double? From { get; set; } + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + public double? To { get; set; } + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + public bool? IncludeLower { get; set; } + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + public bool? IncludeUpper { get; set; } + protected override bool Conditionless => IsConditionless(this); internal override void InternalWrapInContainer(IQueryContainer c) => c.Range = this; @@ -43,30 +93,35 @@ internal static bool IsConditionless(INumericRangeQuery q) => q.Field.IsConditio || q.GreaterThanOrEqualTo == null && q.LessThanOrEqualTo == null && q.GreaterThan == null - && q.LessThan == null; + && q.LessThan == null +#pragma warning disable CS0618 // Type or member is obsolete + && q.From == null + && q.To == null; +#pragma warning restore CS0618 // Type or member is obsolete } [DataContract] public class NumericRangeQueryDescriptor - : FieldNameQueryDescriptorBase, INumericRangeQuery, T> - , INumericRangeQuery where T : class + : FieldNameQueryDescriptorBase, INumericRangeQuery, T>, INumericRangeQuery where T : class { protected override bool Conditionless => NumericRangeQuery.IsConditionless(this); + double? INumericRangeQuery.GreaterThan { get; set; } double? INumericRangeQuery.GreaterThanOrEqualTo { get; set; } double? INumericRangeQuery.LessThan { get; set; } double? INumericRangeQuery.LessThanOrEqualTo { get; set; } - RangeRelation? INumericRangeQuery.Relation { get; set; } - public NumericRangeQueryDescriptor GreaterThan(double? from) => Assign(from, (a, v) => a.GreaterThan = v); + // From, To, IncludeLower and IncludeUpper are not exposed as methods as they are considered deprecated and legacy. + double? INumericRangeQuery.From { get; set; } + double? INumericRangeQuery.To { get; set; } + bool? INumericRangeQuery.IncludeLower { get; set; } + bool? INumericRangeQuery.IncludeUpper { get; set; } + public NumericRangeQueryDescriptor GreaterThan(double? from) => Assign(from, (a, v) => a.GreaterThan = v); public NumericRangeQueryDescriptor GreaterThanOrEquals(double? from) => Assign(from, (a, v) => a.GreaterThanOrEqualTo = v); - public NumericRangeQueryDescriptor LessThan(double? to) => Assign(to, (a, v) => a.LessThan = v); - public NumericRangeQueryDescriptor LessThanOrEquals(double? to) => Assign(to, (a, v) => a.LessThanOrEqualTo = v); - public NumericRangeQueryDescriptor Relation(RangeRelation? relation) => Assign(relation, (a, v) => a.Relation = v); } } diff --git a/src/Nest/QueryDsl/TermLevel/Range/RangeQuery.cs b/src/Nest/QueryDsl/TermLevel/Range/RangeQuery.cs index c459795a5e1..7dff36c1793 100644 --- a/src/Nest/QueryDsl/TermLevel/Range/RangeQuery.cs +++ b/src/Nest/QueryDsl/TermLevel/Range/RangeQuery.cs @@ -8,5 +8,7 @@ namespace Nest { [InterfaceDataContract] [JsonFormatter(typeof(RangeQueryFormatter))] - public interface IRangeQuery : IFieldNameQuery { } + public interface IRangeQuery : IFieldNameQuery + { + } } diff --git a/src/Nest/QueryDsl/TermLevel/Range/RangeQueryFormatter.cs b/src/Nest/QueryDsl/TermLevel/Range/RangeQueryFormatter.cs index 3cd1724d3ad..985fb393cc2 100644 --- a/src/Nest/QueryDsl/TermLevel/Range/RangeQueryFormatter.cs +++ b/src/Nest/QueryDsl/TermLevel/Range/RangeQueryFormatter.cs @@ -18,7 +18,11 @@ internal class RangeQueryFormatter : IJsonFormatter { "gt", 2 }, { "gte", 3 }, { "lte", 4 }, - { "lt", 5 } + { "lt", 5 }, + { "from", 6 }, + { "to", 7 }, + { "include_lower", 8 }, + { "include_upper", 9 } }; public IRangeQuery Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) @@ -53,11 +57,12 @@ public IRangeQuery Deserialize(ref JsonReader reader, IJsonFormatterResolver for case 3: case 4: case 5: + case 6: + case 7: var token = segmentReader.GetCurrentJsonToken(); switch (token) { case JsonToken.String: - case JsonToken.Null: if (!isDate) { var valueSegment = segmentReader.ReadStringSegmentUnsafe(); @@ -75,8 +80,15 @@ public IRangeQuery Deserialize(ref JsonReader reader, IJsonFormatterResolver for isLong = true; } break; + case JsonToken.Null: + segmentReader.ReadIsNull(); + break; } break; + case 8: + case 9: + segmentReader.ReadBoolean(); + break; } } else diff --git a/src/Nest/QueryDsl/TermLevel/Range/TermRangeQuery.cs b/src/Nest/QueryDsl/TermLevel/Range/TermRangeQuery.cs index 1b46c7462a2..f6d93281707 100644 --- a/src/Nest/QueryDsl/TermLevel/Range/TermRangeQuery.cs +++ b/src/Nest/QueryDsl/TermLevel/Range/TermRangeQuery.cs @@ -2,6 +2,7 @@ // 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 System; using System.Runtime.Serialization; using Elasticsearch.Net.Utf8Json; @@ -13,15 +14,40 @@ public interface ITermRangeQuery : IRangeQuery { [DataMember(Name = "gt")] string GreaterThan { get; set; } - [DataMember(Name = "gte")] string GreaterThanOrEqualTo { get; set; } - [DataMember(Name = "lt")] string LessThan { get; set; } - [DataMember(Name = "lte")] string LessThanOrEqualTo { get; set; } + + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + [DataMember(Name = "from")] + string From { get; set; } + + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + [DataMember(Name = "to")] + string To { get; set; } + + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + [DataMember(Name = "include_lower")] + bool? IncludeLower { get; set; } + + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + [DataMember(Name = "include_upper")] + bool? IncludeUpper { get; set; } } public class TermRangeQuery : FieldNameQueryBase, ITermRangeQuery @@ -30,6 +56,28 @@ public class TermRangeQuery : FieldNameQueryBase, ITermRangeQuery public string GreaterThanOrEqualTo { get; set; } public string LessThan { get; set; } public string LessThanOrEqualTo { get; set; } + + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + public string From { get; set; } + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + public string To { get; set; } + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + public bool? IncludeLower { get; set; } + /// + /// WARNING: This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead. + /// + [Obsolete("This property is considered deprecated and will be removed in the next major release. Range queries should prefer the gt, lt, gte and lte properties instead.")] + public bool? IncludeUpper { get; set; } + protected override bool Conditionless => IsConditionless(this); internal override void InternalWrapInContainer(IQueryContainer c) => c.Range = this; @@ -38,13 +86,16 @@ internal static bool IsConditionless(ITermRangeQuery q) => q.Field.IsConditionle || q.GreaterThanOrEqualTo.IsNullOrEmpty() && q.LessThanOrEqualTo.IsNullOrEmpty() && q.GreaterThan.IsNullOrEmpty() - && q.LessThan.IsNullOrEmpty(); + && q.LessThan.IsNullOrEmpty() +#pragma warning disable CS0618 // Type or member is obsolete + && q.From.IsNullOrEmpty() + && q.To.IsNullOrEmpty(); +#pragma warning restore CS0618 // Type or member is obsolete } [DataContract] public class TermRangeQueryDescriptor - : FieldNameQueryDescriptorBase, ITermRangeQuery, T> - , ITermRangeQuery where T : class + : FieldNameQueryDescriptorBase, ITermRangeQuery, T>, ITermRangeQuery where T : class { protected override bool Conditionless => TermRangeQuery.IsConditionless(this); string ITermRangeQuery.GreaterThan { get; set; } @@ -52,12 +103,15 @@ public class TermRangeQueryDescriptor string ITermRangeQuery.LessThan { get; set; } string ITermRangeQuery.LessThanOrEqualTo { get; set; } - public TermRangeQueryDescriptor GreaterThan(string from) => Assign(from, (a, v) => a.GreaterThan = v); + // From, To, IncludeLower and IncludeUpper are not exposed as methods as they are considered deprecated and legacy. + string ITermRangeQuery.From { get; set; } + string ITermRangeQuery.To { get; set; } + bool? ITermRangeQuery.IncludeLower { get; set; } + bool? ITermRangeQuery.IncludeUpper { get; set; } + public TermRangeQueryDescriptor GreaterThan(string from) => Assign(from, (a, v) => a.GreaterThan = v); public TermRangeQueryDescriptor GreaterThanOrEquals(string from) => Assign(from, (a, v) => a.GreaterThanOrEqualTo = v); - public TermRangeQueryDescriptor LessThan(string to) => Assign(to, (a, v) => a.LessThan = v); - public TermRangeQueryDescriptor LessThanOrEquals(string to) => Assign(to, (a, v) => a.LessThanOrEqualTo = v); } } diff --git a/tests/Tests/CodeStandards/Descriptors.doc.cs b/tests/Tests/CodeStandards/Descriptors.doc.cs index b96afa64715..d5ddb05219b 100644 --- a/tests/Tests/CodeStandards/Descriptors.doc.cs +++ b/tests/Tests/CodeStandards/Descriptors.doc.cs @@ -121,6 +121,15 @@ where lastArgIsNotInterface selectorMethods.Should().BeEmpty(); } + private readonly Dictionary> _descriptorPropertySkipList = new() + { + // Range queries opt to not expose some legacy properties via assignment methods on the descriptor + { "DateRangeQueryDescriptor`1", new[] { "IncludeLower", "IncludeUpper" } }, + { "LongRangeQueryDescriptor`1", new[] { "IncludeLower", "IncludeUpper" } }, + { "NumericRangeQueryDescriptor`1", new[] { "IncludeLower", "IncludeUpper" } }, + { "TermRangeQueryDescriptor`1", new[] { "IncludeLower", "IncludeUpper" } } + }; + /** * Descriptor methods that assign to a nullable bool property should accept * a nullable bool with a default value @@ -147,6 +156,12 @@ where t.GetInterfaces().Intersect(queries).Any() var descriptor = descriptors.First(d => query.IsAssignableFrom(d)); foreach (var boolProperty in query.GetProperties().Where(p => p.PropertyType == typeof(bool?))) { + if (_descriptorPropertySkipList.TryGetValue(descriptor.Name, out var skips)) + { + if (skips.Contains(boolProperty.Name)) + continue; + } + var descriptorMethod = descriptor.GetMethod(boolProperty.Name); if (descriptorMethod == null) throw new Exception($"No method for property {boolProperty.Name} on {descriptor.Name}"); diff --git a/tests/Tests/QueryDsl/TermLevel/Range/RangeSerialisationTests.cs b/tests/Tests/QueryDsl/TermLevel/Range/RangeSerialisationTests.cs new file mode 100644 index 00000000000..2453f9d285a --- /dev/null +++ b/tests/Tests/QueryDsl/TermLevel/Range/RangeSerialisationTests.cs @@ -0,0 +1,57 @@ +// 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 System; +using System.IO; +using System.Linq; +using System.Text; +using Elastic.Elasticsearch.Xunit.XunitPlumbing; +using Elasticsearch.Net; +using FluentAssertions; +using Nest; + +namespace Tests.QueryDsl.TermLevel.Wildcard +{ + public class RangeSerialisationTests + { + [U] + public void DeserialisesAndSerialises() + { + // This test validates that a response from SQL translate can be used in the seubsequent query + // The RangeQueryBuilder currently returns from, to, include_lower and include_upper which are considered deprecated internally, but we have to handle them until the builder is revised. + // See: https://github.com/elastic/elasticsearch/issues/48538 + + var translateResponse = @"{""size"":1000,""query"":{""bool"":{""must"":[{""range"":{""customer_id"":{""from"":""1"",""to"":null,""include_lower"":false,""include_upper"":false,""boost"":1}}}],""adjust_pure_negative"":true,""boost"":1}}}"; + + var pool = new SingleNodeConnectionPool(new Uri($"http://localhost:9200")); + var settings = new ConnectionSettings(pool, new InMemoryConnection(Encoding.UTF8.GetBytes(translateResponse))); + var client = new ElasticClient(settings); + + var response = client.Sql.Translate(); + + IQueryContainer queryContainer = response.Result.Query; + + queryContainer.Bool.Should().NotBeNull(); + var clauses = queryContainer.Bool.Must.ToList(); + queryContainer = clauses.Single(); + var rangeQuery = queryContainer.Range.Should().BeOfType().Subject; // Expecting term query since the `from` value is provided within quotes. + +#pragma warning disable CS0618 // Type or member is obsolete + rangeQuery.From.Should().Be("1"); + rangeQuery.To.Should().BeNull(); + rangeQuery.IncludeLower.Should().Be(false); + rangeQuery.IncludeUpper.Should().Be(false); +#pragma warning restore CS0618 // Type or member is obsolete + + var stream = new MemoryStream(); + client.ConnectionSettings.RequestResponseSerializer.Serialize(response.Result, stream); + stream.Position = 0; + var reader = new StreamReader(stream); + var json = reader.ReadToEnd(); + + // note: adjust_pure_negative is not recommended + json.Should().Be(@"{""query"":{""bool"":{""must"":[{""range"":{""customer_id"":{""from"":""1"",""include_lower"":false,""include_upper"":false,""boost"":1.0}}}],""boost"":1.0}},""size"":1000}"); + } + } +} diff --git a/tests/Tests/QueryDsl/TermLevel/Wildcard/WildcardSerialisationTests.cs b/tests/Tests/QueryDsl/TermLevel/Wildcard/WildcardSerialisationTests.cs index 841bc7246b3..903d591b9cf 100644 --- a/tests/Tests/QueryDsl/TermLevel/Wildcard/WildcardSerialisationTests.cs +++ b/tests/Tests/QueryDsl/TermLevel/Wildcard/WildcardSerialisationTests.cs @@ -21,7 +21,7 @@ public void DeserialisesAndSerialises() // This test validates that a response from SQL translate can be used in the seubsequent query // The WildcardQueryBuilder prefers the `wildcard` field over the `value` field. - var translateResponse = @"{""size"":1000,""query"":{""bool"":{""must"":[{""wildcard"":{""customershortnm.keyword"":{""wildcard"":""*B*"",""boost"":1}}}],""adjust_pure_negative"":true,""boost"":1}}}"; + var translateResponse = @"{""size"":1000,""query"":{""bool"":{""must"":[{""wildcard"":{""customer.keyword"":{""wildcard"":""*B*"",""boost"":1}}}],""adjust_pure_negative"":true,""boost"":1}}}"; var pool = new SingleNodeConnectionPool(new Uri($"http://localhost:9200")); var settings = new ConnectionSettings(pool, new InMemoryConnection(Encoding.UTF8.GetBytes(translateResponse))); @@ -43,7 +43,7 @@ public void DeserialisesAndSerialises() var json = reader.ReadToEnd(); // note: adjust_pure_negative is not recommended - json.Should().Be(@"{""query"":{""bool"":{""must"":[{""wildcard"":{""customershortnm.keyword"":{""wildcard"":""*B*"",""boost"":1.0}}}],""boost"":1.0}},""size"":1000}"); + json.Should().Be(@"{""query"":{""bool"":{""must"":[{""wildcard"":{""customer.keyword"":{""wildcard"":""*B*"",""boost"":1.0}}}],""boost"":1.0}},""size"":1000}"); } } }