diff --git a/src/Nest/QueryDsl/Abstractions/Container/QueryContainerDescriptor.cs b/src/Nest/QueryDsl/Abstractions/Container/QueryContainerDescriptor.cs index d34a000d865..40c880d03d1 100644 --- a/src/Nest/QueryDsl/Abstractions/Container/QueryContainerDescriptor.cs +++ b/src/Nest/QueryDsl/Abstractions/Container/QueryContainerDescriptor.cs @@ -138,6 +138,9 @@ public QueryContainer Conditionless(Func, ICondi public QueryContainer Range(Func, INumericRangeQuery> selector) => WrapInContainer(selector, (query, container) => container.Range = query); + public QueryContainer LongRange(Func, ILongRangeQuery> selector) => + WrapInContainer(selector, (query, container) => container.Range = query); + /// /// Matches documents with fields that have terms within a certain date range. /// diff --git a/src/Nest/QueryDsl/Query.cs b/src/Nest/QueryDsl/Query.cs index 4afdff2c3e6..ce6289aff73 100644 --- a/src/Nest/QueryDsl/Query.cs +++ b/src/Nest/QueryDsl/Query.cs @@ -125,6 +125,9 @@ public static QueryContainer QueryString(Func, IQu public static QueryContainer Range(Func, INumericRangeQuery> selector) => new QueryContainerDescriptor().Range(selector); + public static QueryContainer LongRange(Func, ILongRangeQuery> selector) => + new QueryContainerDescriptor().LongRange(selector); + public static QueryContainer Regexp(Func, IRegexpQuery> selector) => new QueryContainerDescriptor().Regexp(selector); diff --git a/src/Nest/QueryDsl/TermLevel/Range/LongRangeQuery.cs b/src/Nest/QueryDsl/TermLevel/Range/LongRangeQuery.cs new file mode 100644 index 00000000000..640345d9a0f --- /dev/null +++ b/src/Nest/QueryDsl/TermLevel/Range/LongRangeQuery.cs @@ -0,0 +1,67 @@ +using Newtonsoft.Json; + +namespace Nest +{ + public interface ILongRangeQuery : IRangeQuery + { + [JsonProperty("gte")] + long? GreaterThanOrEqualTo { get; set; } + + [JsonProperty("lte")] + long? LessThanOrEqualTo { get; set; } + + [JsonProperty("gt")] + long? GreaterThan { get; set; } + + [JsonProperty("lt")] + long? LessThan { get; set; } + + [JsonProperty("relation")] + RangeRelation? Relation { get; set; } + } + + public class LongRangeQuery : FieldNameQueryBase, ILongRangeQuery + { + protected override bool Conditionless => IsConditionless(this); + public long? GreaterThanOrEqualTo { get; set; } + public long? LessThanOrEqualTo { get; set; } + public long? GreaterThan { get; set; } + public long? LessThan { get; set; } + + public RangeRelation? Relation { get; set; } + + internal override void InternalWrapInContainer(IQueryContainer c) => c.Range = this; + + internal static bool IsConditionless(ILongRangeQuery q) + { + return q.Field.IsConditionless() + || (q.GreaterThanOrEqualTo == null + && q.LessThanOrEqualTo == null + && q.GreaterThan == null + && q.LessThan == null); + } + } + + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] + public class LongRangeQueryDescriptor + : FieldNameQueryDescriptorBase, ILongRangeQuery, T> + , ILongRangeQuery where T : class + { + protected override bool Conditionless => LongRangeQuery.IsConditionless(this); + long? ILongRangeQuery.GreaterThanOrEqualTo { get; set; } + long? ILongRangeQuery.LessThanOrEqualTo { get; set; } + long? ILongRangeQuery.GreaterThan { get; set; } + long? ILongRangeQuery.LessThan { get; set; } + RangeRelation? ILongRangeQuery.Relation { get; set; } + + public LongRangeQueryDescriptor Relation(RangeRelation? relation) => Assign(a => a.Relation = relation); + + public LongRangeQueryDescriptor GreaterThan(long? from) => Assign(a => a.GreaterThan = from); + + public LongRangeQueryDescriptor GreaterThanOrEquals(long? from) => Assign(a => a.GreaterThanOrEqualTo = from); + + public LongRangeQueryDescriptor LessThan(long? to) => Assign(a => a.LessThan = to); + + public LongRangeQueryDescriptor LessThanOrEquals(long? to) => Assign(a => a.LessThanOrEqualTo = to); + } +} diff --git a/src/Nest/QueryDsl/TermLevel/Range/NumericRangeQuery.cs b/src/Nest/QueryDsl/TermLevel/Range/NumericRangeQuery.cs index 40d61e526cd..be86363fd2e 100644 --- a/src/Nest/QueryDsl/TermLevel/Range/NumericRangeQuery.cs +++ b/src/Nest/QueryDsl/TermLevel/Range/NumericRangeQuery.cs @@ -52,6 +52,7 @@ public class NumericRangeQueryDescriptor double? INumericRangeQuery.LessThanOrEqualTo { get; set; } double? INumericRangeQuery.GreaterThan { get; set; } double? INumericRangeQuery.LessThan { get; set; } + RangeRelation? INumericRangeQuery.Relation{ get; set; } public NumericRangeQueryDescriptor GreaterThan(double? from) => Assign(a => a.GreaterThan = from); diff --git a/src/Nest/QueryDsl/TermLevel/Range/RangeQueryJsonConverter.cs b/src/Nest/QueryDsl/TermLevel/Range/RangeQueryJsonConverter.cs index b30ea6a9779..1f5aa9dc11b 100644 --- a/src/Nest/QueryDsl/TermLevel/Range/RangeQueryJsonConverter.cs +++ b/src/Nest/QueryDsl/TermLevel/Range/RangeQueryJsonConverter.cs @@ -26,20 +26,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist var jo = firstProp.Value.Value(); if (jo == null) return null; - - var isNumeric = !jo.Properties().Any(p=>p.Name == "format" || p.Name == "time_zone") - && jo.Properties().Any(p=> _rangeKeys.Contains(p.Name) && (p.Value.Type == JTokenType.Integer || p.Value.Type == JTokenType.Float)); - - - IRangeQuery fq; - if (isNumeric) - { - fq = FromJson.ReadAs(jo.CreateReader(), serializer); - } - else - { - fq = FromJson.ReadAs(jo.CreateReader(), serializer); - } + var fq = GetRangeQuery(serializer, jo); fq.Name = GetPropValue(jo, "_name"); fq.Boost = GetPropValue(jo, "boost"); @@ -48,6 +35,31 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist return fq; } + private static IRangeQuery GetRangeQuery(JsonSerializer serializer, JObject jo) + { + var isNumeric = false; + var isLong = false; + + foreach (var property in jo.Properties()) + { + if (property.Name == "format" || property.Name == "time_zone") + return FromJson.ReadAs(jo.CreateReader(), serializer); + if (_rangeKeys.Contains(property.Name)) + { + if (property.Value.Type == JTokenType.Float) + isNumeric = true; + else if (property.Value.Type == JTokenType.Integer) + isLong = true; + } + } + if (isNumeric) + return FromJson.ReadAs(jo.CreateReader(), serializer); + if (isLong) + return FromJson.ReadAs(jo.CreateReader(), serializer); + + return FromJson.ReadAs(jo.CreateReader(), serializer); + } + private static TReturn GetPropValue(JObject jObject, string field) { JToken jToken = null; diff --git a/src/Nest/QueryDsl/Visitor/DslPrettyPrintVisitor.cs b/src/Nest/QueryDsl/Visitor/DslPrettyPrintVisitor.cs index 9e1cea4039e..35f3012e561 100644 --- a/src/Nest/QueryDsl/Visitor/DslPrettyPrintVisitor.cs +++ b/src/Nest/QueryDsl/Visitor/DslPrettyPrintVisitor.cs @@ -79,7 +79,9 @@ private void Write(string queryType, Field field = null) public virtual void Visit(INumericRangeQuery query) => Write("numeric_range"); - public virtual void Visit(ITermRangeQuery query) => Write("term_range"); + public virtual void Visit(ILongRangeQuery query) => Write("long_range"); + + public virtual void Visit(ITermRangeQuery query) => Write("term_range"); public virtual void Visit(IFunctionScoreQuery query) => Write("function_core"); diff --git a/src/Nest/QueryDsl/Visitor/QueryVisitor.cs b/src/Nest/QueryDsl/Visitor/QueryVisitor.cs index 7174f4fca99..1f4c1d8c74a 100644 --- a/src/Nest/QueryDsl/Visitor/QueryVisitor.cs +++ b/src/Nest/QueryDsl/Visitor/QueryVisitor.cs @@ -61,6 +61,7 @@ public interface IQueryVisitor void Visit(IExistsQuery query); void Visit(IDateRangeQuery query); void Visit(INumericRangeQuery query); + void Visit(ILongRangeQuery query); void Visit(ITermRangeQuery query); void Visit(ISpanFirstQuery query); void Visit(ISpanNearQuery query); @@ -123,7 +124,9 @@ public virtual void Visit(IDateRangeQuery query) { } public virtual void Visit(INumericRangeQuery query) { } - public virtual void Visit(ITermRangeQuery query) { } + public virtual void Visit(ILongRangeQuery query) { } + + public virtual void Visit(ITermRangeQuery query) { } public virtual void Visit(IFunctionScoreQuery query) { } diff --git a/src/Nest/QueryDsl/Visitor/QueryWalker.cs b/src/Nest/QueryDsl/Visitor/QueryWalker.cs index 2ea529727d9..284fd984e0f 100644 --- a/src/Nest/QueryDsl/Visitor/QueryWalker.cs +++ b/src/Nest/QueryDsl/Visitor/QueryWalker.cs @@ -26,6 +26,7 @@ public void Walk(IQueryContainer qd, IQueryVisitor visitor) v.Visit(d); VisitQuery(d as IDateRangeQuery, visitor, (vv, dd) => v.Visit(dd)); VisitQuery(d as INumericRangeQuery, visitor, (vv, dd) => v.Visit(dd)); + VisitQuery(d as ILongRangeQuery, visitor, (vv, dd) => v.Visit(dd)); VisitQuery(d as ITermRangeQuery, visitor, (vv, dd) => v.Visit(dd)); }); VisitQuery(qd.GeoShape, visitor, (v, d) => diff --git a/src/Tests/QueryDsl/TermLevel/Range/LongRangeQueryUsageTests.cs b/src/Tests/QueryDsl/TermLevel/Range/LongRangeQueryUsageTests.cs new file mode 100644 index 00000000000..dc313e36fbe --- /dev/null +++ b/src/Tests/QueryDsl/TermLevel/Range/LongRangeQueryUsageTests.cs @@ -0,0 +1,65 @@ +using Nest; +using Tests.Framework.Integration; +using Tests.Framework.ManagedElasticsearch.Clusters; +using Tests.Framework.MockData; + +namespace Tests.QueryDsl.TermLevel.Range +{ + public class LongRangeQueryUsageTests : QueryDslUsageTestsBase + { + public LongRangeQueryUsageTests(ReadOnlyCluster cluster, EndpointUsage usage) : base(cluster, usage) {} + + protected override object QueryJson => new + { + range = new + { + description = new + { + _name = "named_query", + boost = 1.1, + gt = 636634079999999999, + gte = 636634080000000000, + lt = 636634080000000000, + lte = 636634079999999999, + relation = "within" + } + } + }; + + protected override QueryContainer QueryInitializer => new LongRangeQuery + { + Name = "named_query", + Boost = 1.1, + Field = "description", + GreaterThan = 636634079999999999, + GreaterThanOrEqualTo = 636634080000000000, + LessThan = 636634080000000000, + LessThanOrEqualTo = 636634079999999999, + Relation = RangeRelation.Within + }; + + protected override QueryContainer QueryFluent(QueryContainerDescriptor q) => q + .LongRange(c => c + .Name("named_query") + .Boost(1.1) + .Field(p => p.Description) + .GreaterThan(636634079999999999) + .GreaterThanOrEquals(636634080000000000) + .LessThan(636634080000000000) + .LessThanOrEquals(636634079999999999) + .Relation(RangeRelation.Within) + ); + + protected override ConditionlessWhen ConditionlessWhen => new ConditionlessWhen(q => q.Range as ILongRangeQuery) + { + q=> q.Field = null, + q=> + { + q.GreaterThan = null; + q.GreaterThanOrEqualTo = null; + q.LessThan = null; + q.LessThanOrEqualTo = null; + } + }; + } +}