Skip to content

fix #3505 daterange default DateTime should not serialize #3546

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 20 additions & 6 deletions src/Nest/CommonAbstractions/Infer/Field/Field.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ public class Field : IEquatable<Field>, IUrlParameter
private readonly object _comparisonValue;
private readonly Type _type;

public Field(string name, double? boost = null, string format = null)
public Field(string name, double? boost = null) : this(name, boost, format: null) {}

public Field(string name, double? boost, string format = null)
{
name.ThrowIfNullOrEmpty(nameof(name));
Name = ParseFieldName(name, out var b);
Expand All @@ -27,7 +29,9 @@ public Field(string name, double? boost = null, string format = null)
_comparisonValue = Name;
}

public Field(Expression expression, double? boost = null, string format = null)
public Field(Expression expression, double? boost = null) : this(expression, boost, format: null) { }

public Field(Expression expression, double? boost, string format = null)
{
Expression = expression ?? throw new ArgumentNullException(nameof(expression));
Boost = boost;
Expand All @@ -37,7 +41,9 @@ public Field(Expression expression, double? boost = null, string format = null)
CachableExpression = !new HasVariableExpressionVisitor(expression).Found;
}

public Field(PropertyInfo property, double? boost = null, string format = null)
public Field(PropertyInfo property, double? boost = null) : this(property, boost, format: null) { }

public Field(PropertyInfo property, double? boost, string format = null)
{
Property = property ?? throw new ArgumentNullException(nameof(property));
Boost = boost;
Expand Down Expand Up @@ -98,13 +104,21 @@ string IUrlParameter.GetString(IConnectionConfigurationValues settings)

public Fields And(Field field) => new Fields(new[] { this, field });

public Fields And<T>(Expression<Func<T, object>> field, double? boost = null, string format = null) where T : class =>
public Fields And<T>(Expression<Func<T, object>> field, double? boost = null) where T : class =>
new Fields(new[] { this, new Field(field, boost, format: null) });

public Fields And<T>(Expression<Func<T, object>> field, double? boost, string format = null) where T : class =>
new Fields(new[] { this, new Field(field, boost, format) });

public Fields And(string field, double? boost = null, string format = null) =>
public Fields And(string field, double? boost = null) => new Fields(new[] { this, new Field(field, boost, format: null) });

public Fields And(string field, double? boost, string format = null) =>
new Fields(new[] { this, new Field(field, boost, format) });

public Fields And(PropertyInfo property, double? boost = null, string format = null) =>
public Fields And(PropertyInfo property, double? boost = null) =>
new Fields(new[] { this, new Field(property, boost, format: null) });

public Fields And(PropertyInfo property, double? boost, string format = null) =>
new Fields(new[] { this, new Field(property, boost, format) });

private static string ParseFieldName(string name, out double? boost)
Expand Down
12 changes: 8 additions & 4 deletions src/Nest/CommonAbstractions/Static/Infer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,17 @@ public static Fields Fields<T>(params Expression<Func<T, object>>[] fields) wher
/// Create a strongly typed string field name representation of the path to a property
/// <para>e.g. p => p.Array.First().SubProperty.Field will return 'array.subProperty.field'</para>
/// </summary>
public static Field Field<T>(Expression<Func<T, object>> path, double? boost = null, string format = null)
public static Field Field<T>(Expression<Func<T, object>> path, double? boost = null) where T : class => Field(path, boost, null);

public static Field Field<T>(Expression<Func<T, object>> path, double? boost, string format = null)
where T : class => new Field(path, boost, format);

public static Field Field(string field, double? boost = null, string format = null) =>
new Field(field, boost, format);
public static Field Field(string field, double? boost = null) => Field(field, boost, format: null);

public static Field Field(string field, double? boost, string format = null) => new Field(field, boost, format);

public static Field Field(PropertyInfo property, double? boost = null, string format = null) =>
public static Field Field(PropertyInfo property, double? boost = null) => Field(property, boost, format: null);
public static Field Field(PropertyInfo property, double? boost, string format = null) =>
new Field(property, boost, format);

public static PropertyName Property(string property) => property;
Expand Down
5 changes: 3 additions & 2 deletions src/Nest/CommonOptions/DateMath/DateMath.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,11 @@ public static DateMath FromString(string dateMath)
return math;
}

internal bool IsValid => Self.Anchor.Match(d => d != default, s => !s.IsNullOrEmpty());

public override string ToString()
{
var isValid = Self.Anchor.Match(d => d != default(DateTime), s => !s.IsNullOrEmpty());
if (!isValid) return string.Empty;
if (!IsValid) return string.Empty;

var separator = Self.Round.HasValue || Self.Ranges.HasAny() ? "||" : string.Empty;

Expand Down
8 changes: 4 additions & 4 deletions src/Nest/QueryDsl/TermLevel/Range/DateRangeQuery .cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ public class DateRangeQuery : FieldNameQueryBase, IDateRangeQuery
internal override void InternalWrapInContainer(IQueryContainer c) => c.Range = this;

internal static bool IsConditionless(IDateRangeQuery q) => q.Field.IsConditionless()
|| q.GreaterThanOrEqualTo == null
&& q.LessThanOrEqualTo == null
&& q.GreaterThan == null
&& q.LessThan == null;
|| ((q.GreaterThanOrEqualTo == null || !q.GreaterThanOrEqualTo.IsValid)
&& (q.LessThanOrEqualTo == null || !q.LessThanOrEqualTo.IsValid)
&& (q.GreaterThan == null || !q.GreaterThan.IsValid)
&& (q.LessThan == null || !q.LessThan.IsValid));
}

[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
Expand Down
95 changes: 95 additions & 0 deletions src/Tests/Tests.Reproduce/GithubIssue3538.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading;
using Elastic.Xunit.XunitPlumbing;
using FluentAssertions;
using Nest;
using Nest.JsonNetSerializer;
using Newtonsoft.Json;
using Tests.Core.Client.Settings;

namespace Tests.Reproduce
{
public class GithubIssue3538
{
[U] public void EmptyPolicyCausesNullReferenceException()
{
var converter = new MyPocoJsonConverter();
var connectionSettings = new AlwaysInMemoryConnectionSettings(
sourceSerializerFactory: (builtin, settings) => new JsonNetSerializer(builtin, settings,
() =>
{
var jSettings = new JsonSerializerSettings();
jSettings.Converters.Add(converter);
return jSettings;
}))
.DefaultIndex("blah");

var client = new ElasticClient(connectionSettings);

var result = client.IndexDocument(new MyPoco() { Id = 1, Name = "x" });
converter.CanConvertCallCount.Should().Be(1);

client.Bulk(b => b.Index<MyPoco>(i=>i.Document(new MyPoco { Id = 2, Name = "y" })));
converter.CanConvertCallCount.Should().Be(2);

client.Bulk(b => b.Update<MyPoco>(i=>i.Doc(new MyPoco { Id = 3, Name = "z" })));
converter.CanConvertCallCount.Should().Be(3);

client.Bulk(b => b.Update<MyPoco>(i=>i.Upsert(new MyPoco { Id = 4, Name = "a" })));
converter.CanConvertCallCount.Should().Be(4);

converter.WriteCount.Should().Be(4);
converter.SeenIds.Should().BeEquivalentTo(1, 2, 3, 4);

}

public class MyPoco
{
public int Id { get; set; }
public string Name { get; set; }
}

public class MyPocoJsonConverter : JsonConverter
{
private int _canConvertCallCount;
public int CanConvertCallCount => _canConvertCallCount;

private int _writeCount;
public int WriteCount => _writeCount;

public List<int> SeenIds { get; } = new List<int>();


public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
Interlocked.Increment(ref _writeCount);

if (!(value is MyPoco poco))
{
writer.WriteNull();
return;
}

writer.WriteStartObject();
writer.WritePropertyName("id");
writer.WriteValue(poco.Id);
SeenIds.Add(poco.Id);
writer.WritePropertyName("name");
writer.WriteValue(poco.Name);
writer.WriteEndObject();
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) =>
new MyPoco { };

public override bool CanConvert(Type objectType)
{
Interlocked.Increment(ref _canConvertCallCount);

return objectType == typeof(MyPoco);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,7 @@ public void PrecedenceIsAsExpected()
usingSettings.Expect("data").ForField(Field<Precedence>(p => p.DataMember));
usingSettings.Expect("DEFAULTFIELDNAMEINFERRER").ForField(Field<Precedence>(p => p.DefaultFieldNameInferrer));


var x = Field<Project>(p => p.Name, 1.0);
/** The same naming rules also apply when indexing a document */
usingSettings.Expect(new []
{
Expand Down
12 changes: 12 additions & 0 deletions src/Tests/Tests/CommonOptions/DateMath/DateMathTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,17 @@ public void ImplicitConversionFromNullNullableDateTime()
dateMath.Should().BeNull();
}

[U] // F# backticks would be great in C# :)
public void ImplicitConversionFromDefaultDateTimeIsNotNullButEmptyString()
{
// in 6.x DateMath is backed by a DateTime instance
// for 7.x we will adress this
DateTime nullableDateTime = default;
Nest.DateMath dateMath = nullableDateTime;
dateMath.Should().NotBeNull();
dateMath.ToString().Should().BeEmpty();
}

[U]
public void ImplicitConversionFromDateMathString()
{
Expand All @@ -38,4 +49,5 @@ public void ImplicitConversionFromNullableDateTimeWithValue()
dateMath.Should().NotBeNull();
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ public DateRangeQueryUsageTests(ReadOnlyCluster cluster, EndpointUsage usage) :
q.GreaterThanOrEqualTo = null;
q.LessThan = null;
q.LessThanOrEqualTo = null;
},
q =>
{
q.GreaterThan = default;
q.GreaterThanOrEqualTo = default;
q.LessThan = default;
q.LessThanOrEqualTo = default;
}
};

Expand Down Expand Up @@ -66,4 +73,5 @@ protected override QueryContainer QueryFluent(QueryContainerDescriptor<Project>
.TimeZone("+01:00")
);
}

}
4 changes: 2 additions & 2 deletions src/Tests/Tests/Search/Search/SearchApiTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,8 @@ public SearchApiDocValueFieldsTests(ReadOnlyCluster cluster, EndpointUsage usage
Field = "state",
Value = "Stable"
}),
DocValueFields = Infer.Field<Project>(p => p.Name, format: "use_field_mapping")
.And<Project>(p => p.LastActivity, format: "weekyear")
DocValueFields = Infer.Field<Project>(p => p.Name, boost: null, format: "use_field_mapping")
.And<Project>(p => p.LastActivity, boost: null, format: "weekyear")
};

protected override void ExpectResponse(ISearchResponse<Project> response)
Expand Down