From f887be7ec8915a064471f362ffc483e12b8532e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20=C5=81yso=C5=84?= Date: Sat, 14 Feb 2015 16:32:12 +0100 Subject: [PATCH] RangeFilter has been changed to handle execution parameter RangeFilterJsonReader -> RangeFilterJsonConverter --- src/Nest/DSL/Filter/FilterDescriptor.cs | 5 +- src/Nest/DSL/Filter/IFilterContainer.cs | 2 +- src/Nest/DSL/Filter/RangeFilterDescriptor.cs | 16 ++- src/Nest/Domain/DSL/Filter.cs | 4 +- src/Nest/Enums/RangeExecution.cs | 15 ++ src/Nest/Nest.csproj | 3 +- .../Filters/RangeFilterJsonConverter.cs | 132 ++++++++++++++++++ .../Filters/RangeFilterJsonReader.cs | 76 ---------- .../Search/Filter/RangeFilterTests.cs | 3 + .../QueryParsers/Filter/RangeFilterTests.cs | 17 +++ .../Search/Filter/Singles/RangeFilterJson.cs | 60 ++++++++ 11 files changed, 250 insertions(+), 83 deletions(-) create mode 100644 src/Nest/Enums/RangeExecution.cs create mode 100644 src/Nest/Resolvers/Converters/Filters/RangeFilterJsonConverter.cs delete mode 100644 src/Nest/Resolvers/Converters/Filters/RangeFilterJsonReader.cs diff --git a/src/Nest/DSL/Filter/FilterDescriptor.cs b/src/Nest/DSL/Filter/FilterDescriptor.cs index 32e15cef96a..37bbc13b438 100644 --- a/src/Nest/DSL/Filter/FilterDescriptor.cs +++ b/src/Nest/DSL/Filter/FilterDescriptor.cs @@ -660,12 +660,13 @@ public FilterContainer MatchAll() /// Filters documents with fields that have terms within a certain range. /// Similar to range query, except that it acts as a filter. /// - public FilterContainer Range(Action> rangeSelector) + public FilterContainer Range(Action> rangeSelector, RangeExecution? execution = null) { var filter = new RangeFilterDescriptor(); if (rangeSelector != null) rangeSelector(filter); - + filter.Execution(execution); + return this.New(filter, f=>f.Range = filter); } /// diff --git a/src/Nest/DSL/Filter/IFilterContainer.cs b/src/Nest/DSL/Filter/IFilterContainer.cs index f1fb3f17410..6367b0294ed 100644 --- a/src/Nest/DSL/Filter/IFilterContainer.cs +++ b/src/Nest/DSL/Filter/IFilterContainer.cs @@ -85,7 +85,7 @@ public interface IFilterContainer IHasParentFilter HasParent { get; set; } [JsonProperty(PropertyName = "range")] - [JsonConverter(typeof(FieldNameFilterConverter))] + [JsonConverter(typeof(RangeFilterJsonConverter))] IRangeFilter Range { get; set; } [JsonProperty(PropertyName = "prefix")] diff --git a/src/Nest/DSL/Filter/RangeFilterDescriptor.cs b/src/Nest/DSL/Filter/RangeFilterDescriptor.cs index cc7e812930a..18d66a926f3 100644 --- a/src/Nest/DSL/Filter/RangeFilterDescriptor.cs +++ b/src/Nest/DSL/Filter/RangeFilterDescriptor.cs @@ -3,11 +3,13 @@ using System.Globalization; using System.Linq; using Nest.Resolvers.Converters; +using Nest.Resolvers.Converters.Filters; using Newtonsoft.Json; using System.Linq.Expressions; namespace Nest { + [JsonConverter(typeof(RangeFilterJsonConverter))] [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public interface IRangeFilter : IFieldNameFilter { @@ -29,6 +31,9 @@ public interface IRangeFilter : IFieldNameFilter [JsonProperty("time_zone")] string TimeZone { get; set; } + + [JsonProperty("execution")] + RangeExecution? Execution { get; set; } } public class RangeFilter : PlainFilter, IRangeFilter @@ -42,6 +47,7 @@ protected internal override void WrapInContainer(IFilterContainer container) public string GreaterThan { get; set; } public string LowerThan { get; set; } public string TimeZone { get; set; } + public RangeExecution? Execution { get; set; } public PropertyPathMarker Field { get; set; } } @@ -57,6 +63,8 @@ public class RangeFilterDescriptor : FilterBase, IRangeFilter where T : class string IRangeFilter.TimeZone { get; set; } + RangeExecution? IRangeFilter.Execution { get; set; } + PropertyPathMarker IFieldNameFilter.Field { get; set; } private IRangeFilter Self { get { return this; } } @@ -73,7 +81,7 @@ bool IFilter.IsConditionless ); } } - + public RangeFilterDescriptor OnField(string field) { this.Self.Field = field; @@ -193,5 +201,11 @@ public RangeFilterDescriptor TimeZone(string timeZone) this.Self.TimeZone = timeZone; return this; } + + public RangeFilterDescriptor Execution(RangeExecution? execution) + { + this.Self.Execution = execution; + return this; + } } } diff --git a/src/Nest/Domain/DSL/Filter.cs b/src/Nest/Domain/DSL/Filter.cs index a5361642e80..f06ce8a8c59 100644 --- a/src/Nest/Domain/DSL/Filter.cs +++ b/src/Nest/Domain/DSL/Filter.cs @@ -135,9 +135,9 @@ public static FilterContainer Query(Func, QueryContainer> que { return new FilterDescriptor().Query(querySelector); } - public static FilterContainer Range(Action> rangeSelector) + public static FilterContainer Range(Action> rangeSelector, RangeExecution? execution = null) { - return new FilterDescriptor().Range(rangeSelector); + return new FilterDescriptor().Range(rangeSelector, execution); } public static FilterContainer Script(Action scriptSelector) { diff --git a/src/Nest/Enums/RangeExecution.cs b/src/Nest/Enums/RangeExecution.cs new file mode 100644 index 00000000000..099a4fc7aac --- /dev/null +++ b/src/Nest/Enums/RangeExecution.cs @@ -0,0 +1,15 @@ +using System.Runtime.Serialization; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Nest +{ + [JsonConverter(typeof(StringEnumConverter))] + public enum RangeExecution + { + [EnumMember(Value = "index")] + Index, + [EnumMember(Value = "fielddata")] + FieldData + } +} \ No newline at end of file diff --git a/src/Nest/Nest.csproj b/src/Nest/Nest.csproj index 799e1c26c66..d44dde07e69 100644 --- a/src/Nest/Nest.csproj +++ b/src/Nest/Nest.csproj @@ -392,6 +392,7 @@ + @@ -864,7 +865,7 @@ - + diff --git a/src/Nest/Resolvers/Converters/Filters/RangeFilterJsonConverter.cs b/src/Nest/Resolvers/Converters/Filters/RangeFilterJsonConverter.cs new file mode 100644 index 00000000000..fd564899361 --- /dev/null +++ b/src/Nest/Resolvers/Converters/Filters/RangeFilterJsonConverter.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Nest.Resolvers.Converters.Filters +{ + public class RangeFilterJsonConverter : JsonConverter + { + public override bool CanRead { get { return true; } } + public override bool CanWrite { get { return true; } } + + public override bool CanConvert(Type objectType) + { + return true; //only to be used with attribute or contract registration. + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var f = value as IRangeFilter; + if (f == null || (f.IsConditionless && !f.IsVerbatim)) return; + + var contract = serializer.ContractResolver as SettingsContractResolver; + if (contract == null) + return; + + var field = contract.Infer.PropertyPath(f.Field); + if (field.IsNullOrEmpty()) + return; + + writer.WriteStartObject(); + { + writer.WritePropertyName(field); + writer.WriteStartObject(); + { + SerializeProperty(writer, serializer, "lt", f.LowerThan); + SerializeProperty(writer, serializer, "lte", f.LowerThanOrEqualTo); + SerializeProperty(writer, serializer, "gt", f.GreaterThan); + SerializeProperty(writer, serializer, "gte", f.GreaterThanOrEqualTo); + SerializeProperty(writer, serializer, "time_zone", f.TimeZone); + } + writer.WriteEndObject(); + + if (f.Execution.HasValue) + { + writer.WritePropertyName("execution"); + serializer.Serialize(writer, f.Execution.Value); + } + WriteProperty(writer, "_cache", f.Cache); + WriteProperty(writer, "_cache_key", f.CacheKey); + WriteProperty(writer, "_name", f.FilterName); + } + writer.WriteEndObject(); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var j = JObject.Load(reader); + if (j == null || !j.HasValues) + return null; + IRangeFilter filter = new RangeFilterDescriptor(); + foreach (var jv in j) + { + switch (jv.Key) + { + case "execution": + var execution = jv.Value.Value(); + if(!string.IsNullOrEmpty(execution)) filter.Execution = execution.ToEnum(); + break; + case "_cache": + filter.Cache = jv.Value.Value(); + break; + case "_cache_key": + filter.CacheKey = jv.Value.Value(); + break; + case "_name": + filter.FilterName = jv.Value.Value(); + break; + default: + filter.Field = jv.Key; + + var gte = jv.Value["gte"]; + if (gte != null) + filter.GreaterThanOrEqualTo = ToString(gte); + + var gt = jv.Value["gt"]; + if (gt != null) + filter.GreaterThanOrEqualTo = ToString(gt); + + var lte = jv.Value["lte"]; + if (lte != null) + filter.LowerThanOrEqualTo = ToString(lte); + + var lt = jv.Value["lt"]; + if (lt != null) + filter.LowerThanOrEqualTo = ToString(lt); + + break; + } + } + + return filter; + + } + + private static void SerializeProperty(JsonWriter writer, JsonSerializer serializer, string field, object value) + { + if ((field.IsNullOrEmpty() || value == null)) + return; + writer.WritePropertyName(field); + serializer.Serialize(writer, value); + } + + private static void WriteProperty(JsonWriter writer, string field, object value) + { + if ((field.IsNullOrEmpty() || value == null)) + return; + writer.WritePropertyName(field); + writer.WriteValue(value); + } + + private static string ToString(JToken token) + { + if (token.Type == JTokenType.Date) + return token.Value().ToString("yyyy-MM-dd'T'HH:mm:ss.fff", CultureInfo.InvariantCulture); + return token.Value(); + } + } + +} diff --git a/src/Nest/Resolvers/Converters/Filters/RangeFilterJsonReader.cs b/src/Nest/Resolvers/Converters/Filters/RangeFilterJsonReader.cs deleted file mode 100644 index bfde8486e3b..00000000000 --- a/src/Nest/Resolvers/Converters/Filters/RangeFilterJsonReader.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace Nest.Resolvers.Converters.Filters -{ - public class RangeFilterJsonReader : JsonConverter - { - public override bool CanRead { get { return true; } } - public override bool CanWrite { get { return false; } } - - public override bool CanConvert(Type objectType) - { - return true; //only to be used with attribute or contract registration. - } - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - var j = JObject.Load(reader); - if (j == null || !j.HasValues) - return null; - IRangeFilter filter = new RangeFilterDescriptor(); - foreach (var jv in j) - { - switch (jv.Key) - { - case "_cache": - filter.Cache = jv.Value.Value(); - break; - case "_cache_key": - filter.CacheKey = jv.Value.Value(); - break; - case "_name": - filter.FilterName = jv.Value.Value(); - break; - default: - filter.Field = jv.Key; - - var gte = jv.Value["gte"]; - if (gte != null) - filter.GreaterThanOrEqualTo = ToString(gte); - - var gt = jv.Value["gt"]; - if (gt != null) - filter.GreaterThanOrEqualTo = ToString(gt); - - var lte = jv.Value["lte"]; - if (lte != null) - filter.LowerThanOrEqualTo = ToString(lte); - - var lt = jv.Value["lt"]; - if (lt != null) - filter.LowerThanOrEqualTo = ToString(lt); - - break; - } - } - - return filter; - - } - - private static string ToString(JToken token) - { - if (token.Type == JTokenType.Date) - return token.Value().ToString("yyyy-MM-dd'T'HH:mm:ss.fff", CultureInfo.InvariantCulture); - return token.Value(); - } - } - -} diff --git a/src/Tests/Nest.Tests.Integration/Search/Filter/RangeFilterTests.cs b/src/Tests/Nest.Tests.Integration/Search/Filter/RangeFilterTests.cs index de94968be9f..72c8154d936 100644 --- a/src/Tests/Nest.Tests.Integration/Search/Filter/RangeFilterTests.cs +++ b/src/Tests/Nest.Tests.Integration/Search/Filter/RangeFilterTests.cs @@ -44,6 +44,9 @@ public void TestNotFiltered() this.DoFilterTest(f => f.Range(range => range.OnField(e => e.Name).LowerOrEquals(name)), _LookFor, true); + this.DoFilterTest(f => f.Range(range => range.OnField(e => e.Id).GreaterOrEquals(1), RangeExecution.FieldData), _LookFor, true); + + this.DoFilterTest(f => f.Range(range => range.OnField(e => e.Name).LowerOrEquals(name), RangeExecution.Index), _LookFor, true); } /// diff --git a/src/Tests/Nest.Tests.Unit/QueryParsers/Filter/RangeFilterTests.cs b/src/Tests/Nest.Tests.Unit/QueryParsers/Filter/RangeFilterTests.cs index 2b75b7b8914..eca56a56959 100644 --- a/src/Tests/Nest.Tests.Unit/QueryParsers/Filter/RangeFilterTests.cs +++ b/src/Tests/Nest.Tests.Unit/QueryParsers/Filter/RangeFilterTests.cs @@ -78,5 +78,22 @@ public void Range_Double_Deserializes(string cacheName, string cacheKey, bool ca rangeFilter.LowerThanOrEqualTo.Should().Be("20.22"); } + + [Test] + [TestCase("cacheName", "cacheKey", true)] + public void Range_Execution_Deserializes(string cacheName, string cacheKey, bool cache) + { + var rangeFilter = this.SerializeThenDeserialize(cacheName, cacheKey, cache, + f => f.Range, + f => f.Range(n => n + .OnField(p => p.LOC) + .GreaterOrEquals(20.1) + .LowerOrEquals(20.22), RangeExecution.FieldData) + ); + + rangeFilter.GreaterThanOrEqualTo.Should().Be("20.1"); + rangeFilter.LowerThanOrEqualTo.Should().Be("20.22"); + rangeFilter.Execution.Should().Be(RangeExecution.FieldData); + } } } \ No newline at end of file diff --git a/src/Tests/Nest.Tests.Unit/Search/Filter/Singles/RangeFilterJson.cs b/src/Tests/Nest.Tests.Unit/Search/Filter/Singles/RangeFilterJson.cs index 8227487c103..ab42361fc07 100644 --- a/src/Tests/Nest.Tests.Unit/Search/Filter/Singles/RangeFilterJson.cs +++ b/src/Tests/Nest.Tests.Unit/Search/Filter/Singles/RangeFilterJson.cs @@ -159,5 +159,65 @@ public void RangeDatesCustom() }"; Assert.True(json.JsonEquals(expected), json); } + + [Test] + public void Execution_FieldData() + { + var s = new SearchDescriptor() + .From(0) + .Size(10) + .Filter(ff => ff + .Cache(true) + .Range(n => n + .OnField(f => f.LOC) + .GreaterOrEquals(10) + .LowerOrEquals(20), RangeExecution.FieldData)); + + var json = TestElasticClient.Serialize(s); + var expected = @"{ from: 0, size: 10, + filter : { + range: { + ""execution"" : ""fielddata"", + ""loc"": { + gte: ""10"", + lte: ""20"", + }, + ""_cache"" : true + } + } + }"; + + Assert.True(json.JsonEquals(expected), json); + } + + [Test] + public void Execution_Index() + { + var s = new SearchDescriptor() + .From(0) + .Size(10) + .Filter(ff => ff + .Cache(true) + .Range(n => n + .OnField(f => f.LOC) + .GreaterOrEquals(10) + .LowerOrEquals(20), RangeExecution.Index)); + + var json = TestElasticClient.Serialize(s); + var expected = @"{ from: 0, size: 10, + filter : { + range: { + ""execution"" : ""index"", + ""loc"": { + gte: ""10"", + lte: ""20"", + }, + ""_cache"" : true + } + } + }"; + + Assert.True(json.JsonEquals(expected), json); + } } }