From 07a97d14db70595372651465c5958a37ad977130 Mon Sep 17 00:00:00 2001 From: udi Date: Sun, 15 Feb 2015 18:34:28 +0200 Subject: [PATCH] Add support for execution in range filter: http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-range-filter.html#_execution --- src/Nest/DSL/Filter/IFilterContainer.cs | 248 +- src/Nest/DSL/Filter/RangeFilterDescriptor.cs | 407 +-- src/Nest/Nest.csproj | 2275 +++++++++-------- .../Converters/RangeFilterConverter.cs | 130 + .../Search/Filter/RangeFilterTests.cs | 145 +- .../QueryParsers/Filter/RangeFilterTests.cs | 163 +- 6 files changed, 1768 insertions(+), 1600 deletions(-) create mode 100644 src/Nest/Resolvers/Converters/RangeFilterConverter.cs diff --git a/src/Nest/DSL/Filter/IFilterContainer.cs b/src/Nest/DSL/Filter/IFilterContainer.cs index f1fb3f17410..b83178ac834 100644 --- a/src/Nest/DSL/Filter/IFilterContainer.cs +++ b/src/Nest/DSL/Filter/IFilterContainer.cs @@ -1,126 +1,126 @@ -using System; -using System.Collections.Generic; -using Nest.DSL.Visitor; -using Nest.Resolvers.Converters; -using Nest.Resolvers.Converters.Filters; -using Newtonsoft.Json; - -namespace Nest -{ - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - [JsonConverter(typeof(ReadAsTypeConverter))] - public interface IFilterContainer - { - [JsonIgnore] - string FilterName { get; set; } - [JsonIgnore] - string CacheKey { get; set; } - [JsonIgnore] - bool? Cache { get; set; } - - [JsonIgnore] - bool IsConditionless { get; set; } - - [JsonIgnore] - string RawFilter { get; set; } - - [JsonIgnore] - bool IsStrict { get; set; } - - [JsonIgnore] - bool IsVerbatim { get; set; } - - [JsonProperty(PropertyName = "bool")] - IBoolFilter Bool { get; set; } - - [JsonProperty(PropertyName = "exists")] - IExistsFilter Exists { get; set; } - - [JsonProperty(PropertyName = "missing")] - IMissingFilter Missing { get; set; } - - [JsonProperty(PropertyName = "ids")] - IIdsFilter Ids { get; set; } - - [JsonProperty(PropertyName = "geo_bounding_box")] - [JsonConverter(typeof(GeoBoundingFilterConverter))] - IGeoBoundingBoxFilter GeoBoundingBox { get; set; } - - [JsonProperty(PropertyName = "geo_distance")] - [JsonConverter(typeof(GeoDistanceFilterConverter))] - IGeoDistanceFilter GeoDistance { get; set; } - - [JsonProperty(PropertyName = "geohash_cell")] - [JsonConverter(typeof(GeoHashCellFilterConverter))] - IGeoHashCellFilter GeoHashCell { get; set; } - - [JsonProperty(PropertyName = "geo_distance_range")] - [JsonConverter(typeof(GeoDistanceRangeFilterConverter))] - IGeoDistanceRangeFilter GeoDistanceRange { get; set; } - - [JsonProperty(PropertyName = "geo_polygon")] +using Nest.DSL.Visitor; +using Nest.Resolvers.Converters; +using Nest.Resolvers.Converters.Filters; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; + +namespace Nest +{ + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] + [JsonConverter(typeof(ReadAsTypeConverter))] + public interface IFilterContainer + { + [JsonIgnore] + string FilterName { get; set; } + [JsonIgnore] + string CacheKey { get; set; } + [JsonIgnore] + bool? Cache { get; set; } + + [JsonIgnore] + bool IsConditionless { get; set; } + + [JsonIgnore] + string RawFilter { get; set; } + + [JsonIgnore] + bool IsStrict { get; set; } + + [JsonIgnore] + bool IsVerbatim { get; set; } + + [JsonProperty(PropertyName = "bool")] + IBoolFilter Bool { get; set; } + + [JsonProperty(PropertyName = "exists")] + IExistsFilter Exists { get; set; } + + [JsonProperty(PropertyName = "missing")] + IMissingFilter Missing { get; set; } + + [JsonProperty(PropertyName = "ids")] + IIdsFilter Ids { get; set; } + + [JsonProperty(PropertyName = "geo_bounding_box")] + [JsonConverter(typeof(GeoBoundingFilterConverter))] + IGeoBoundingBoxFilter GeoBoundingBox { get; set; } + + [JsonProperty(PropertyName = "geo_distance")] + [JsonConverter(typeof(GeoDistanceFilterConverter))] + IGeoDistanceFilter GeoDistance { get; set; } + + [JsonProperty(PropertyName = "geohash_cell")] + [JsonConverter(typeof(GeoHashCellFilterConverter))] + IGeoHashCellFilter GeoHashCell { get; set; } + + [JsonProperty(PropertyName = "geo_distance_range")] + [JsonConverter(typeof(GeoDistanceRangeFilterConverter))] + IGeoDistanceRangeFilter GeoDistanceRange { get; set; } + + [JsonProperty(PropertyName = "geo_polygon")] [JsonConverter(typeof(CompositeJsonConverter>))] - IGeoPolygonFilter GeoPolygon { get; set; } - - [JsonProperty(PropertyName = "geo_shape")] - [JsonConverter(typeof(CompositeJsonConverter>))] - IGeoShapeBaseFilter GeoShape { get; set; } - - [JsonProperty(PropertyName = "limit")] - ILimitFilter Limit { get; set; } - - [JsonProperty(PropertyName = "indices")] - IIndicesFilter Indices { get; set; } - - [JsonProperty(PropertyName = "type")] - ITypeFilter Type { get; set; } - - [JsonProperty(PropertyName = "match_all")] - IMatchAllFilter MatchAll { get; set; } - - [JsonProperty(PropertyName = "has_child")] - IHasChildFilter HasChild { get; set; } - - [JsonProperty(PropertyName = "has_parent")] - IHasParentFilter HasParent { get; set; } - - [JsonProperty(PropertyName = "range")] - [JsonConverter(typeof(FieldNameFilterConverter))] - IRangeFilter Range { get; set; } - - [JsonProperty(PropertyName = "prefix")] - [JsonConverter(typeof(PrefixFilterConverter))] - IPrefixFilter Prefix { get; set; } - - [JsonProperty(PropertyName = "term")] + IGeoPolygonFilter GeoPolygon { get; set; } + + [JsonProperty(PropertyName = "geo_shape")] + [JsonConverter(typeof(CompositeJsonConverter>))] + IGeoShapeBaseFilter GeoShape { get; set; } + + [JsonProperty(PropertyName = "limit")] + ILimitFilter Limit { get; set; } + + [JsonProperty(PropertyName = "indices")] + IIndicesFilter Indices { get; set; } + + [JsonProperty(PropertyName = "type")] + ITypeFilter Type { get; set; } + + [JsonProperty(PropertyName = "match_all")] + IMatchAllFilter MatchAll { get; set; } + + [JsonProperty(PropertyName = "has_child")] + IHasChildFilter HasChild { get; set; } + + [JsonProperty(PropertyName = "has_parent")] + IHasParentFilter HasParent { get; set; } + + [JsonProperty(PropertyName = "range")] + [JsonConverter(typeof(RangeFilterConverter))] + IRangeFilter Range { get; set; } + + [JsonProperty(PropertyName = "prefix")] + [JsonConverter(typeof(PrefixFilterConverter))] + IPrefixFilter Prefix { get; set; } + + [JsonProperty(PropertyName = "term")] [JsonConverter(typeof (TermFilterConverter))] - ITermFilter Term { get; set; } - - [JsonProperty(PropertyName = "terms")] - ITermsBaseFilter Terms { get; set; } - - [JsonProperty(PropertyName = "fquery")] - IQueryFilter Query { get; set; } - - [JsonProperty(PropertyName = "and")] - IAndFilter And { get; set; } - - [JsonProperty(PropertyName = "or")] - IOrFilter Or { get; set; } - - [JsonProperty(PropertyName = "not")] - INotFilter Not { get; set; } - - [JsonProperty(PropertyName = "script")] - IScriptFilter Script { get; set; } - - [JsonProperty(PropertyName = "nested")] - INestedFilter Nested { get; set; } - - [JsonProperty(PropertyName = "regexp")] - [JsonConverter(typeof(FieldNameFilterConverter))] - IRegexpFilter Regexp { get; set; } - - void Accept(IQueryVisitor visitor); - } -} + ITermFilter Term { get; set; } + + [JsonProperty(PropertyName = "terms")] + ITermsBaseFilter Terms { get; set; } + + [JsonProperty(PropertyName = "fquery")] + IQueryFilter Query { get; set; } + + [JsonProperty(PropertyName = "and")] + IAndFilter And { get; set; } + + [JsonProperty(PropertyName = "or")] + IOrFilter Or { get; set; } + + [JsonProperty(PropertyName = "not")] + INotFilter Not { get; set; } + + [JsonProperty(PropertyName = "script")] + IScriptFilter Script { get; set; } + + [JsonProperty(PropertyName = "nested")] + INestedFilter Nested { get; set; } + + [JsonProperty(PropertyName = "regexp")] + [JsonConverter(typeof(FieldNameFilterConverter))] + IRegexpFilter Regexp { get; set; } + + void Accept(IQueryVisitor visitor); + } +} \ No newline at end of file diff --git a/src/Nest/DSL/Filter/RangeFilterDescriptor.cs b/src/Nest/DSL/Filter/RangeFilterDescriptor.cs index cc7e812930a..42e6a00ac31 100644 --- a/src/Nest/DSL/Filter/RangeFilterDescriptor.cs +++ b/src/Nest/DSL/Filter/RangeFilterDescriptor.cs @@ -1,197 +1,218 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using Nest.Resolvers.Converters; -using Newtonsoft.Json; -using System.Linq.Expressions; - -namespace Nest -{ - [JsonObject(MemberSerialization = MemberSerialization.OptIn)] - public interface IRangeFilter : IFieldNameFilter - { - [JsonProperty("gte")] +using Nest.Resolvers.Converters; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using System; +using System.Globalization; +using System.Linq.Expressions; +using System.Runtime.Serialization; + +namespace Nest +{ + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] + public interface IRangeFilter : IFieldNameFilter + { + [JsonProperty("gte")] [JsonConverter(typeof(ForceStringReader))] - string GreaterThanOrEqualTo { get; set; } - - [JsonProperty("lte")] + string GreaterThanOrEqualTo { get; set; } + + [JsonProperty("lte")] [JsonConverter(typeof(ForceStringReader))] - string LowerThanOrEqualTo { get; set; } - - [JsonProperty("gt")] + string LowerThanOrEqualTo { get; set; } + + [JsonProperty("gt")] [JsonConverter(typeof(ForceStringReader))] - string GreaterThan { get; set; } - - [JsonProperty("lt")] + string GreaterThan { get; set; } + + [JsonProperty("lt")] [JsonConverter(typeof(ForceStringReader))] - string LowerThan { get; set; } - - [JsonProperty("time_zone")] - string TimeZone { get; set; } - } - - public class RangeFilter : PlainFilter, IRangeFilter - { - protected internal override void WrapInContainer(IFilterContainer container) - { - container.Range = this; - } - public string GreaterThanOrEqualTo { get; set; } - public string LowerThanOrEqualTo { get; set; } - public string GreaterThan { get; set; } - public string LowerThan { get; set; } - public string TimeZone { get; set; } - public PropertyPathMarker Field { get; set; } - } - - public class RangeFilterDescriptor : FilterBase, IRangeFilter where T : class - { - string IRangeFilter.GreaterThanOrEqualTo { get; set; } - - string IRangeFilter.LowerThanOrEqualTo { get; set; } - - string IRangeFilter.GreaterThan { get; set; } - - string IRangeFilter.LowerThan { get; set; } - - string IRangeFilter.TimeZone { get; set; } - - PropertyPathMarker IFieldNameFilter.Field { get; set; } - - private IRangeFilter Self { get { return this; } } - - bool IFilter.IsConditionless - { - get - { - return this.Self.Field.IsConditionless() || - ( this.Self.GreaterThanOrEqualTo.IsNullOrEmpty() - && this.Self.LowerThanOrEqualTo.IsNullOrEmpty() - && this.Self.LowerThan.IsNullOrEmpty() - && this.Self.GreaterThan.IsNullOrEmpty() - ); - } - } - - public RangeFilterDescriptor OnField(string field) - { - this.Self.Field = field; - return this; - } - public RangeFilterDescriptor OnField(Expression> objectPath) - { - this.Self.Field = objectPath; - return this; - } - - public RangeFilterDescriptor Greater(long? from) - { - this.Self.GreaterThan = from.HasValue ? from.Value.ToString(CultureInfo.InvariantCulture) : null; - return this; - } - - public RangeFilterDescriptor GreaterOrEquals(long? from) - { - this.Self.GreaterThanOrEqualTo = from.HasValue ? from.Value.ToString(CultureInfo.InvariantCulture) : null; - return this; - } - - public RangeFilterDescriptor Lower(long? to) - { - this.Self.LowerThan = to.HasValue ? to.Value.ToString(CultureInfo.InvariantCulture) : null; - return this; - } - - public RangeFilterDescriptor LowerOrEquals(long? to) - { - this.Self.LowerThanOrEqualTo = to.HasValue ? to.Value.ToString(CultureInfo.InvariantCulture) : null; - return this; - } - - public RangeFilterDescriptor Greater(double? from) - { - this.Self.GreaterThan = from.HasValue ? from.Value.ToString(CultureInfo.InvariantCulture) : null; - return this; - } - - public RangeFilterDescriptor GreaterOrEquals(double? from) - { - this.Self.GreaterThanOrEqualTo = from.HasValue ? from.Value.ToString(CultureInfo.InvariantCulture) : null; - return this; - } - - public RangeFilterDescriptor Lower(double? to) - { - this.Self.LowerThan = to.HasValue ? to.Value.ToString(CultureInfo.InvariantCulture) : null; - return this; - } - /// - /// Same as setting to and include_upper to true. - /// - public RangeFilterDescriptor LowerOrEquals(double? to) - { - this.Self.LowerThanOrEqualTo = to.HasValue ? to.Value.ToString(CultureInfo.InvariantCulture) : null; - return this; - } - - - public RangeFilterDescriptor Greater(string from) - { - this.Self.GreaterThan = from; - return this; - } - - public RangeFilterDescriptor GreaterOrEquals(string from) - { - this.Self.GreaterThanOrEqualTo = from; - return this; - } - - public RangeFilterDescriptor Lower(string to) - { - this.Self.LowerThan = to; - return this; - } - - public RangeFilterDescriptor LowerOrEquals(string to) - { - this.Self.LowerThanOrEqualTo = to; - return this; - } - - public RangeFilterDescriptor Greater(DateTime? from, string format = "yyyy-MM-dd'T'HH:mm:ss.fff") - { - if (!from.HasValue) return this; - this.Self.GreaterThan = from.Value.ToString(format, CultureInfo.InvariantCulture); - return this; - } - - public RangeFilterDescriptor GreaterOrEquals(DateTime? from, string format = "yyyy-MM-dd'T'HH:mm:ss.fff") - { - if (!from.HasValue) return this; - this.Self.GreaterThanOrEqualTo = from.Value.ToString(format, CultureInfo.InvariantCulture); - return this; - } - - public RangeFilterDescriptor Lower(DateTime? to, string format = "yyyy-MM-dd'T'HH:mm:ss.fff") - { - if (!to.HasValue) return this; - this.Self.LowerThan = to.Value.ToString(format, CultureInfo.InvariantCulture); - return this; - } - - public RangeFilterDescriptor LowerOrEquals(DateTime? to, string format = "yyyy-MM-dd'T'HH:mm:ss.fff") - { - if (!to.HasValue) return this; - this.Self.LowerThanOrEqualTo = to.Value.ToString(format, CultureInfo.InvariantCulture); - return this; - } - - public RangeFilterDescriptor TimeZone(string timeZone) - { - this.Self.TimeZone = timeZone; - return this; - } - } -} + string LowerThan { get; set; } + + [JsonProperty("time_zone")] + string TimeZone { get; set; } + + FilterRangeExecutionType? ExecutionType { get; set; } + } + + public class RangeFilter : PlainFilter, IRangeFilter + { + protected internal override void WrapInContainer(IFilterContainer container) + { + container.Range = this; + } + + public string GreaterThanOrEqualTo { get; set; } + public string LowerThanOrEqualTo { get; set; } + public string GreaterThan { get; set; } + public string LowerThan { get; set; } + public string TimeZone { get; set; } + public FilterRangeExecutionType? ExecutionType { get; set; } + public PropertyPathMarker Field { get; set; } + } + + public class RangeFilterDescriptor : FilterBase, IRangeFilter where T : class + { + string IRangeFilter.GreaterThanOrEqualTo { get; set; } + + string IRangeFilter.LowerThanOrEqualTo { get; set; } + + string IRangeFilter.GreaterThan { get; set; } + + string IRangeFilter.LowerThan { get; set; } + + string IRangeFilter.TimeZone { get; set; } + + PropertyPathMarker IFieldNameFilter.Field { get; set; } + + FilterRangeExecutionType? IRangeFilter.ExecutionType { get; set; } + + private IRangeFilter Self + { + get { return this; } + } + + bool IFilter.IsConditionless + { + get + { + return this.Self.Field.IsConditionless() || + (this.Self.GreaterThanOrEqualTo.IsNullOrEmpty() + && this.Self.LowerThanOrEqualTo.IsNullOrEmpty() + && this.Self.LowerThan.IsNullOrEmpty() + && this.Self.GreaterThan.IsNullOrEmpty() + ); + } + } + + public RangeFilterDescriptor OnField(string field, FilterRangeExecutionType? executionType = null) + { + this.Self.Field = field; + this.Self.ExecutionType = executionType; + return this; + } + + public RangeFilterDescriptor OnField(Expression> objectPath, + FilterRangeExecutionType? executionType = null) + { + this.Self.Field = objectPath; + this.Self.ExecutionType = executionType; + return this; + } + + public RangeFilterDescriptor Greater(long? from) + { + this.Self.GreaterThan = from.HasValue ? from.Value.ToString(CultureInfo.InvariantCulture) : null; + return this; + } + + public RangeFilterDescriptor GreaterOrEquals(long? from) + { + this.Self.GreaterThanOrEqualTo = from.HasValue ? from.Value.ToString(CultureInfo.InvariantCulture) : null; + return this; + } + + public RangeFilterDescriptor Lower(long? to) + { + this.Self.LowerThan = to.HasValue ? to.Value.ToString(CultureInfo.InvariantCulture) : null; + return this; + } + + public RangeFilterDescriptor LowerOrEquals(long? to) + { + this.Self.LowerThanOrEqualTo = to.HasValue ? to.Value.ToString(CultureInfo.InvariantCulture) : null; + return this; + } + + public RangeFilterDescriptor Greater(double? from) + { + this.Self.GreaterThan = from.HasValue ? from.Value.ToString(CultureInfo.InvariantCulture) : null; + return this; + } + + public RangeFilterDescriptor GreaterOrEquals(double? from) + { + this.Self.GreaterThanOrEqualTo = from.HasValue ? from.Value.ToString(CultureInfo.InvariantCulture) : null; + return this; + } + + public RangeFilterDescriptor Lower(double? to) + { + this.Self.LowerThan = to.HasValue ? to.Value.ToString(CultureInfo.InvariantCulture) : null; + return this; + } + + /// + /// Same as setting to and include_upper to true. + /// + public RangeFilterDescriptor LowerOrEquals(double? to) + { + this.Self.LowerThanOrEqualTo = to.HasValue ? to.Value.ToString(CultureInfo.InvariantCulture) : null; + return this; + } + + public RangeFilterDescriptor Greater(string from) + { + this.Self.GreaterThan = from; + return this; + } + + public RangeFilterDescriptor GreaterOrEquals(string from) + { + this.Self.GreaterThanOrEqualTo = from; + return this; + } + + public RangeFilterDescriptor Lower(string to) + { + this.Self.LowerThan = to; + return this; + } + + public RangeFilterDescriptor LowerOrEquals(string to) + { + this.Self.LowerThanOrEqualTo = to; + return this; + } + + public RangeFilterDescriptor Greater(DateTime? from, string format = "yyyy-MM-dd'T'HH:mm:ss.fff") + { + if (!from.HasValue) return this; + this.Self.GreaterThan = from.Value.ToString(format, CultureInfo.InvariantCulture); + return this; + } + + public RangeFilterDescriptor GreaterOrEquals(DateTime? from, string format = "yyyy-MM-dd'T'HH:mm:ss.fff") + { + if (!from.HasValue) return this; + this.Self.GreaterThanOrEqualTo = from.Value.ToString(format, CultureInfo.InvariantCulture); + return this; + } + + public RangeFilterDescriptor Lower(DateTime? to, string format = "yyyy-MM-dd'T'HH:mm:ss.fff") + { + if (!to.HasValue) return this; + this.Self.LowerThan = to.Value.ToString(format, CultureInfo.InvariantCulture); + return this; + } + + public RangeFilterDescriptor LowerOrEquals(DateTime? to, string format = "yyyy-MM-dd'T'HH:mm:ss.fff") + { + if (!to.HasValue) return this; + this.Self.LowerThanOrEqualTo = to.Value.ToString(format, CultureInfo.InvariantCulture); + return this; + } + + public RangeFilterDescriptor TimeZone(string timeZone) + { + this.Self.TimeZone = timeZone; + return this; + } + } + + [JsonConverter(typeof (StringEnumConverter))] + public enum FilterRangeExecutionType + { + [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..a5a7cb3b3f3 100644 --- a/src/Nest/Nest.csproj +++ b/src/Nest/Nest.csproj @@ -1,1144 +1,1145 @@ - - - - - Debug - AnyCPU - {072BA7DA-7B60-407D-8B6E-95E3186BE70C} - Library - Properties - Nest - Nest - v4.0 - 512 - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - BasicCorrectnessRules.ruleset - AnyCPU - bin\Debug\Nest.XML - false - 1591,1572,1571,1573,1587,1570 - - - pdbonly - True - bin\Release\ - TRACE - prompt - 4 - AllRules.ruleset - bin\Release\Nest.XML - 1591,1572,1571,1573,1587,1570 - - - true - bin\Debug - Generator\ - DEBUG;TRACE - bin\Debug\Nest.XML - full - AnyCPU - prompt - BasicCorrectnessRules.ruleset - - - true - - - ..\..\build\keys\keypair.snk - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Code - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Code - - - Code - - - - - - Code - - - Code - - - - Code - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - - - {e97ccf40-0ba6-43fe-9f2d-58d454134088} - Elasticsearch.Net - - - - - - - + + + + + Debug + AnyCPU + {072BA7DA-7B60-407D-8B6E-95E3186BE70C} + Library + Properties + Nest + Nest + v4.0 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + BasicCorrectnessRules.ruleset + AnyCPU + bin\Debug\Nest.XML + false + 1591,1572,1571,1573,1587,1570 + + + pdbonly + True + bin\Release\ + TRACE + prompt + 4 + AllRules.ruleset + bin\Release\Nest.XML + 1591,1572,1571,1573,1587,1570 + + + true + bin\Debug - Generator\ + DEBUG;TRACE + bin\Debug\Nest.XML + full + AnyCPU + prompt + BasicCorrectnessRules.ruleset + + + true + + + ..\..\build\keys\keypair.snk + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Code + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Code + + + Code + + + + + + Code + + + Code + + + + Code + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + {e97ccf40-0ba6-43fe-9f2d-58d454134088} + Elasticsearch.Net + + + + + + + - - - - - - ..\..\packages\Newtonsoft.Json\lib\netcore45\Newtonsoft.Json.dll - True - True - - - - - - - ..\..\packages\Newtonsoft.Json\lib\net35\Newtonsoft.Json.dll - True - True - - - - - - - ..\..\packages\Newtonsoft.Json\lib\net20\Newtonsoft.Json.dll - True - True - - - - - - - ..\..\packages\Newtonsoft.Json\lib\net40\Newtonsoft.Json.dll - True - True - - - - - - - ..\..\packages\Newtonsoft.Json\lib\net45\Newtonsoft.Json.dll - True - True - - - - - - - ..\..\packages\Newtonsoft.Json\lib\portable-net40+sl5+wp80+win8+monotouch+monoandroid\Newtonsoft.Json.dll - True - True - - - - - - - ..\..\packages\Newtonsoft.Json\lib\portable-net45+wp80+win8\Newtonsoft.Json.dll - True - True - - - - + --> + + + + + + ..\..\packages\Newtonsoft.Json\lib\netcore45\Newtonsoft.Json.dll + True + True + + + + + + + ..\..\packages\Newtonsoft.Json\lib\net35\Newtonsoft.Json.dll + True + True + + + + + + + ..\..\packages\Newtonsoft.Json\lib\net20\Newtonsoft.Json.dll + True + True + + + + + + + ..\..\packages\Newtonsoft.Json\lib\net40\Newtonsoft.Json.dll + True + True + + + + + + + ..\..\packages\Newtonsoft.Json\lib\net45\Newtonsoft.Json.dll + True + True + + + + + + + ..\..\packages\Newtonsoft.Json\lib\portable-net40+sl5+wp80+win8+monotouch+monoandroid\Newtonsoft.Json.dll + True + True + + + + + + + ..\..\packages\Newtonsoft.Json\lib\portable-net45+wp80+win8\Newtonsoft.Json.dll + True + True + + + + \ No newline at end of file diff --git a/src/Nest/Resolvers/Converters/RangeFilterConverter.cs b/src/Nest/Resolvers/Converters/RangeFilterConverter.cs new file mode 100644 index 00000000000..bcbd955fe18 --- /dev/null +++ b/src/Nest/Resolvers/Converters/RangeFilterConverter.cs @@ -0,0 +1,130 @@ +using Nest.Resolvers; +using Nest.Resolvers.Converters; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Nest +{ + public class RangeFilterConverter : JsonConverter + where T : class, new() + { + private readonly ReadAsTypeConverter _reader; + + public RangeFilterConverter() + { + this._reader = new ReadAsTypeConverter(); + } + + public override bool CanConvert(Type objectType) + { + return typeof (IRangeFilter).IsAssignableFrom(objectType); + } + + public override bool CanRead + { + get { return true; } + } + + public override bool CanWrite + { + get { return true; } + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var depth = reader.Depth; + if (reader.TokenType != JsonToken.StartObject) + return null; + + var r = JObject.Load(reader); + var dict = r.Properties().ToDictionary(p => p.Name); + + var name = GetValue("_name", dict); + var cache = GetValue("_cache", dict); + var cacheKey = GetValue("_cacheKey", dict) ?? GetValue("_cache_key", dict); + var executionStr = GetValue("execution", dict); + FilterRangeExecutionType execution; + var foundExecution = Enum.TryParse(executionStr, true, out execution); + + if (dict.Count == 0) return null; + + var remainingProperty = dict.First(); + + var filter = this._reader.ReadJson(remainingProperty.Value.First().CreateReader(), objectType, existingValue, + serializer); + var setter = filter as IRangeFilter; + if (setter != null) + { + setter.Field = remainingProperty.Key; + if (foundExecution) + setter.ExecutionType = execution; + } + var f = filter as IFilter; + if (f == null) return filter; + f.Cache = cache; + f.FilterName = name; + f.CacheKey = cacheKey; + return filter; + } + + private static TValue GetValue(string name, Dictionary dict) + { + JProperty prop; + if (dict.TryGetValue(name, out prop)) + { + dict.Remove(name); + return prop.Value.Value(); + } + return default(TValue); + } + + private static void WriteProperty(JsonWriter writer, IFilter filter, string field, object value) + { + if ((field.IsNullOrEmpty() || value == null)) + return; + writer.WritePropertyName(field); + writer.WriteValue(value); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var v = value as IRangeFilter; + if (v == null) return; + + var fieldName = v.Field; + if (fieldName == null) + return; + + var contract = serializer.ContractResolver as SettingsContractResolver; + if (contract == null) + return; + + var field = contract.Infer.PropertyPath(fieldName); + if (field.IsNullOrEmpty()) + return; + + var cache = v.Cache; + var cacheKey = v.CacheKey; + var name = v.FilterName; + + v.Cache = null; + v.CacheKey = null; + v.FilterName = null; + + writer.WriteStartObject(); + { + writer.WritePropertyName(field); + serializer.Serialize(writer, value); + if (v.ExecutionType.HasValue) + WriteProperty(writer, v, "execution", v.ExecutionType.Value.GetStringValue()); + WriteProperty(writer, v, "_cache", cache); + WriteProperty(writer, v, "_cache_key", cacheKey); + WriteProperty(writer, v, "_name", name); + } + writer.WriteEndObject(); + } + } +} \ No newline at end of file diff --git a/src/Tests/Nest.Tests.Integration/Search/Filter/RangeFilterTests.cs b/src/Tests/Nest.Tests.Integration/Search/Filter/RangeFilterTests.cs index de94968be9f..e9b403c75e0 100644 --- a/src/Tests/Nest.Tests.Integration/Search/Filter/RangeFilterTests.cs +++ b/src/Tests/Nest.Tests.Integration/Search/Filter/RangeFilterTests.cs @@ -1,67 +1,82 @@ -using System.Linq; -using Elasticsearch.Net; -using NUnit.Framework; -using Nest.Tests.MockData; -using Nest.Tests.MockData.Domain; - -namespace Nest.Tests.Integration.Search.Filter -{ - /// - /// Integrated tests of RangeFilter with elasticsearch. - /// - [TestFixture] - public class RangeFilterTests : IntegrationTests - { - /// - /// Document used in test. - /// - private ElasticsearchProject _LookFor; - - [TestFixtureSetUp] - public void Initialize() - { - _LookFor = NestTestData.Session.Single().Get(); - _LookFor.Name = "mmm"; - var status = this.Client.Index(_LookFor, i=>i.Refresh()).ConnectionStatus; - Assert.True(status.Success, status.ResponseRaw.Utf8String()); - } - - - - /// - /// Set of filters that should not filter de documento _LookFor. - /// - [Test] - public void TestNotFiltered() - { - var name = _LookFor.Name; - +using Elasticsearch.Net; +using Nest.Tests.MockData; +using Nest.Tests.MockData.Domain; +using NUnit.Framework; +using System.Linq; + +namespace Nest.Tests.Integration.Search.Filter +{ + /// + /// Integrated tests of RangeFilter with elasticsearch. + /// + [TestFixture] + public class RangeFilterTests : IntegrationTests + { + /// + /// Document used in test. + /// + private ElasticsearchProject _LookFor; + + [TestFixtureSetUp] + public void Initialize() + { + _LookFor = NestTestData.Session.Single().Get(); + _LookFor.Name = "mmm"; + _LookFor.LOC = 9; + var status = this.Client.Index(_LookFor, i => i.Refresh()).ConnectionStatus; + Assert.True(status.Success, status.ResponseRaw.Utf8String()); + } + + /// + /// Set of filters that should not filter de documento _LookFor. + /// + [Test] + public void TestNotFiltered() + { + var name = _LookFor.Name; + this.DoFilterTest(f => f.Range(range => range.OnField(e => e.Name).GreaterOrEquals(name).LowerOrEquals(name)), _LookFor, true); - + this.DoFilterTest(f => f.Range(range => range.OnField(e => e.Name).GreaterOrEquals("aaa").LowerOrEquals("zzz")), _LookFor, true); - - this.DoFilterTest(f => f.Range(range => range.OnField(e => e.Name).GreaterOrEquals(name)), _LookFor, true); - - this.DoFilterTest(f => f.Range(range => range.OnField(e => e.Name).LowerOrEquals(name)), _LookFor, true); - - } - - /// - /// Set of filters that should filter de documento _LookFor. - /// - [Test] - public void TestFiltered() - { - var name = _LookFor.Name; - - this.DoFilterTest(f => f.Range(range => range.OnField(e => e.Name).GreaterOrEquals("zzz")), _LookFor, false); - - this.DoFilterTest(f => f.Range(range => range.OnField(e => e.Name).LowerOrEquals("aaa")), _LookFor, false); - - this.DoFilterTest(f => f.Range(range => range.OnField(e => e.Name).GreaterOrEquals(name)), _LookFor, true); - - 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.Name).GreaterOrEquals(name)), _LookFor, true); + + this.DoFilterTest(f => f.Range(range => range.OnField(e => e.Name).LowerOrEquals(name)), _LookFor, true); + + } + + /// + /// Set of filters that should filter de documento _LookFor. + /// + [Test] + public void TestFiltered() + { + var name = _LookFor.Name; + + this.DoFilterTest(f => f.Range(range => range.OnField(e => e.Name).GreaterOrEquals("zzz")), _LookFor, false); + + this.DoFilterTest(f => f.Range(range => range.OnField(e => e.Name).LowerOrEquals("aaa")), _LookFor, false); + + this.DoFilterTest(f => f.Range(range => range.OnField(e => e.Name).GreaterOrEquals(name)), _LookFor, true); + + this.DoFilterTest(f => f.Range(range => range.OnField(e => e.Name).LowerOrEquals(name)), _LookFor, true); + } + + /// + /// Set of filters that should filter de documento _LookFor. + /// + [Test] + public void TestNumericFiltered() + { + var name = _LookFor.Id; + + this.DoFilterTest( + f => f.Range(range => range.OnField(e => e.LOC, FilterRangeExecutionType.FieldData).GreaterOrEquals(2)), _LookFor, + true); + + this.DoFilterTest( + f => f.Range(range => range.OnField(e => e.LOC, FilterRangeExecutionType.FieldData).Lower(2)), _LookFor, + false); + } + } +} \ No newline at end of file diff --git a/src/Tests/Nest.Tests.Unit/QueryParsers/Filter/RangeFilterTests.cs b/src/Tests/Nest.Tests.Unit/QueryParsers/Filter/RangeFilterTests.cs index 2b75b7b8914..ec42254cec1 100644 --- a/src/Tests/Nest.Tests.Unit/QueryParsers/Filter/RangeFilterTests.cs +++ b/src/Tests/Nest.Tests.Unit/QueryParsers/Filter/RangeFilterTests.cs @@ -1,82 +1,83 @@ -using System; -using System.Globalization; -using FluentAssertions; -using NUnit.Framework; - -namespace Nest.Tests.Unit.QueryParsers.Filter -{ - [TestFixture] - public class RangeFilterTests : ParseFilterTestsBase - { - [Test] - [TestCase("cacheName", "cacheKey", true)] - public void Range_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("10") - .LowerOrEquals("20") - ) - ); - - rangeFilter.Field.Should().Be("loc"); - rangeFilter.LowerThanOrEqualTo.Should().Be("20"); - rangeFilter.GreaterThanOrEqualTo.Should().Be("10"); - - } - - [Test] - [TestCase("cacheName", "cacheKey", true)] - public void Range_Long_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(10) - .LowerOrEquals(20) - ) - ); - - rangeFilter.GreaterThanOrEqualTo.Should().Be("10"); - rangeFilter.LowerThanOrEqualTo.Should().Be("20"); - } - - [Test] - [TestCase("cacheName", "cacheKey", true)] - public void Range_DateTime_Deserializes(string cacheName, string cacheKey, bool cache) - { - var dateFrom = DateTime.UtcNow.AddDays(-1); - var dateTo = DateTime.UtcNow.AddDays(1); - var rangeFilter = this.SerializeThenDeserialize(cacheName, cacheKey, cache, - f=>f.Range, - f=>f.Range(n => n - .OnField(p=>p.LOC) - .GreaterOrEquals(dateFrom) - .LowerOrEquals(dateTo) - ) - ); - rangeFilter.GreaterThanOrEqualTo.Should().Be(dateFrom.ToString("yyyy-MM-dd'T'HH:mm:ss.fff", CultureInfo.InvariantCulture)); - rangeFilter.LowerThanOrEqualTo.Should().Be(dateTo.ToString("yyyy-MM-dd'T'HH:mm:ss.fff", CultureInfo.InvariantCulture)); - } - - [Test] - [TestCase("cacheName", "cacheKey", true)] - public void Range_Double_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) - ) - ); - rangeFilter.GreaterThanOrEqualTo.Should().Be("20.1"); - rangeFilter.LowerThanOrEqualTo.Should().Be("20.22"); - } - - } +using FluentAssertions; +using NUnit.Framework; +using System; +using System.Globalization; + +namespace Nest.Tests.Unit.QueryParsers.Filter +{ + [TestFixture] + public class RangeFilterTests : ParseFilterTestsBase + { + [Test] + [TestCase("cacheName", "cacheKey", true)] + public void Range_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("10") + .LowerOrEquals("20") + ) + ); + + rangeFilter.Field.Should().Be("loc"); + rangeFilter.LowerThanOrEqualTo.Should().Be("20"); + rangeFilter.GreaterThanOrEqualTo.Should().Be("10"); + } + + [Test] + [TestCase("cacheName", "cacheKey", true)] + public void Range_Long_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, FilterRangeExecutionType.FieldData) + .GreaterOrEquals(10) + .LowerOrEquals(20) + ) + ); + + rangeFilter.GreaterThanOrEqualTo.Should().Be("10"); + rangeFilter.LowerThanOrEqualTo.Should().Be("20"); + rangeFilter.ExecutionType.Should().Be(FilterRangeExecutionType.FieldData); + } + + [Test] + [TestCase("cacheName", "cacheKey", true)] + public void Range_DateTime_Deserializes(string cacheName, string cacheKey, bool cache) + { + var dateFrom = DateTime.UtcNow.AddDays(-1); + var dateTo = DateTime.UtcNow.AddDays(1); + var rangeFilter = this.SerializeThenDeserialize(cacheName, cacheKey, cache, + f => f.Range, + f => f.Range(n => n + .OnField(p => p.LOC) + .GreaterOrEquals(dateFrom) + .LowerOrEquals(dateTo) + ) + ); + rangeFilter.GreaterThanOrEqualTo.Should() + .Be(dateFrom.ToString("yyyy-MM-dd'T'HH:mm:ss.fff", CultureInfo.InvariantCulture)); + rangeFilter.LowerThanOrEqualTo.Should() + .Be(dateTo.ToString("yyyy-MM-dd'T'HH:mm:ss.fff", CultureInfo.InvariantCulture)); + } + + [Test] + [TestCase("cacheName", "cacheKey", true)] + public void Range_Double_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) + ) + ); + rangeFilter.GreaterThanOrEqualTo.Should().Be("20.1"); + rangeFilter.LowerThanOrEqualTo.Should().Be("20.22"); + } + } } \ No newline at end of file