Skip to content

Commit 7bbb3fa

Browse files
committed
Merge branch 'fix/1880'
2 parents 04e3396 + d103a6b commit 7bbb3fa

File tree

5 files changed

+163
-61
lines changed

5 files changed

+163
-61
lines changed

src/Nest/CommonAbstractions/Extensions/Extensions.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ internal static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> items, Fu
7272
}
7373

7474
internal static ConcurrentDictionary<string, object> _enumCache = new ConcurrentDictionary<string, object>();
75-
internal static T? ToEnum<T>(this string str) where T : struct
75+
internal static T? ToEnum<T>(this string str, StringComparison comparison = StringComparison.OrdinalIgnoreCase) where T : struct
7676
{
7777
var enumType = typeof(T);
7878
var key = $"{enumType.Name}.{str}";
@@ -82,7 +82,7 @@ internal static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> items, Fu
8282

8383
foreach (var name in Enum.GetNames(enumType))
8484
{
85-
if (name.Equals(str, StringComparison.OrdinalIgnoreCase))
85+
if (name.Equals(str, comparison))
8686
{
8787
var v = (T)Enum.Parse(enumType, name, true);
8888
_enumCache.TryAdd(key, v);
@@ -99,7 +99,6 @@ internal static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> items, Fu
9999
}
100100

101101
var alternativeEnumMemberAttribute = enumFieldInfo.GetCustomAttribute<AlternativeEnumMemberAttribute>();
102-
103102
if (alternativeEnumMemberAttribute?.Value == str)
104103
{
105104
var v = (T) Enum.Parse(enumType, name);

src/Nest/CommonOptions/DateMath/DateMath.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public static DateMath FromString(string dateMath)
7171

7272
if (match.Groups["rounding"].Success)
7373
{
74-
var rounding = match.Groups["rounding"].Value.Substring(1).ToEnum<TimeUnit>();
74+
var rounding = match.Groups["rounding"].Value.Substring(1).ToEnum<TimeUnit>(StringComparison.Ordinal);
7575
if (rounding.HasValue)
7676
return math.RoundTo(rounding.Value);
7777
}

src/Nest/CommonOptions/TimeUnit/Time.cs

Lines changed: 73 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ namespace Nest
88
[JsonConverter(typeof(TimeJsonConverter))]
99
public class Time : IComparable<Time>, IEquatable<Time>
1010
{
11-
private static readonly Regex _expressionRegex = new Regex(@"^(?<factor>\d+(?:\.\d+)?)(?<interval>(?:y|M|w|d|h|m|s|ms))?$", RegexOptions.Compiled | RegexOptions.ExplicitCapture);
11+
private static readonly Regex _expressionRegex = new Regex(@"^(?<factor>[-+]?\d+(?:\.\d+)?)(?<interval>(?:y|M|w|d|h|m|s|ms))?$", RegexOptions.Compiled | RegexOptions.ExplicitCapture);
1212

13-
private static readonly double _year = TimeSpan.FromDays(365).TotalMilliseconds;
13+
private static readonly double _yearApproximate = TimeSpan.FromDays(365).TotalMilliseconds;
14+
private static readonly double _monthApproximate = TimeSpan.FromDays(30).TotalMilliseconds;
1415
private static readonly double _week = TimeSpan.FromDays(7).TotalMilliseconds;
1516
private static readonly double _day = TimeSpan.FromDays(1).TotalMilliseconds;
1617
private static readonly double _hour = TimeSpan.FromHours(1).TotalMilliseconds;
@@ -19,33 +20,15 @@ public class Time : IComparable<Time>, IEquatable<Time>
1920

2021
public double? Factor { get; private set; }
2122
public TimeUnit? Interval { get; private set; }
23+
24+
// TODO make nullable in 3.0
2225
public double Milliseconds { get; private set; }
26+
private double ApproximateMilliseconds { get; set; }
2327

2428
public static implicit operator Time(TimeSpan span) => new Time(span);
2529
public static implicit operator Time(double milliseconds) => new Time(milliseconds);
2630
public static implicit operator Time(string expression) => new Time(expression);
2731

28-
public Time(double factor, TimeUnit interval)
29-
{
30-
this.Factor = factor;
31-
this.Interval = interval;
32-
33-
if (interval == TimeUnit.Year)
34-
Milliseconds = (long)factor * _year;
35-
else if (interval == TimeUnit.Week)
36-
Milliseconds = (long)factor * _week;
37-
else if (interval == TimeUnit.Day)
38-
Milliseconds = (long)factor * _day;
39-
else if (interval == TimeUnit.Hour)
40-
Milliseconds = (long)factor * _hour;
41-
else if (interval == TimeUnit.Minute)
42-
Milliseconds = (long)factor * _minute;
43-
else if (interval == TimeUnit.Second)
44-
Milliseconds = (long)factor * _second;
45-
else //ms
46-
Milliseconds = (long)factor;
47-
}
48-
4932
public Time(TimeSpan timeSpan)
5033
{
5134
Reduce(timeSpan.TotalMilliseconds);
@@ -56,38 +39,36 @@ public Time(double milliseconds)
5639
Reduce(milliseconds);
5740
}
5841

42+
public Time(double factor, TimeUnit interval)
43+
{
44+
this.Factor = factor;
45+
this.Interval = interval;
46+
SetMilliseconds(this.Interval, this.Factor.Value);
47+
}
48+
5949
public Time(string timeUnit)
6050
{
6151
if (timeUnit.IsNullOrEmpty()) throw new ArgumentException("Time expression string is empty", nameof(timeUnit));
6252
var match = _expressionRegex.Match(timeUnit);
6353
if (!match.Success) throw new ArgumentException($"Time expression '{timeUnit}' string is invalid", nameof(timeUnit));
6454

6555
this.Factor = double.Parse(match.Groups["factor"].Value, CultureInfo.InvariantCulture);
66-
this.Interval = match.Groups["interval"].Success
67-
? match.Groups["interval"].Value.ToEnum<TimeUnit>()
68-
: TimeUnit.Millisecond;
69-
70-
if (this.Interval == TimeUnit.Year)
71-
Milliseconds = (long)(this.Factor * _year);
72-
else if (this.Interval == TimeUnit.Week)
73-
Milliseconds = (long)(this.Factor * _week);
74-
else if (this.Interval == TimeUnit.Day)
75-
Milliseconds = (long)(this.Factor * _day);
76-
else if (this.Interval == TimeUnit.Hour)
77-
Milliseconds = (long)(this.Factor * _hour);
78-
else if (this.Interval == TimeUnit.Minute)
79-
Milliseconds = (long)(this.Factor * _minute);
80-
else if (this.Interval == TimeUnit.Second)
81-
Milliseconds = (long)(this.Factor * _second);
82-
else //ms
83-
Milliseconds = (long)this.Factor;
56+
57+
if (this.Factor > 0)
58+
{
59+
this.Interval = match.Groups["interval"].Success
60+
? match.Groups["interval"].Value.ToEnum<TimeUnit>(StringComparison.Ordinal)
61+
: TimeUnit.Millisecond;
62+
}
63+
64+
SetMilliseconds(this.Interval, this.Factor.Value);
8465
}
8566

8667
public int CompareTo(Time other)
8768
{
8869
if (other == null) return 1;
89-
if (this.Milliseconds == other.Milliseconds) return 0;
90-
if (this.Milliseconds < other.Milliseconds) return -1;
70+
if (this.ApproximateMilliseconds == other.ApproximateMilliseconds) return 0;
71+
if (this.ApproximateMilliseconds < other.ApproximateMilliseconds) return -1;
9172
return 1;
9273
}
9374

@@ -115,7 +96,7 @@ public bool Equals(Time other)
11596
{
11697
if (ReferenceEquals(null, other)) return false;
11798
if (ReferenceEquals(this, other)) return true;
118-
return Milliseconds == other.Milliseconds;
99+
return (this.ApproximateMilliseconds == other.ApproximateMilliseconds);
119100
}
120101

121102
public override bool Equals(object obj)
@@ -126,18 +107,57 @@ public override bool Equals(object obj)
126107
return Equals((Time)obj);
127108
}
128109

129-
public override int GetHashCode() => this.Milliseconds.GetHashCode();
110+
public override int GetHashCode() => this.ApproximateMilliseconds.GetHashCode();
130111

131-
private void Reduce(double ms)
112+
private void SetMilliseconds(TimeUnit? interval, double factor)
132113
{
133-
this.Milliseconds = ms;
114+
this.Milliseconds = interval.HasValue ? GetExactMilliseconds(interval.Value, factor) : factor;
115+
this.ApproximateMilliseconds = interval.HasValue ? GetApproximateMilliseconds(interval.Value, factor) : factor;
116+
}
134117

135-
if (ms >= _year)
118+
private double GetExactMilliseconds(TimeUnit interval, double factor)
119+
{
120+
switch (interval)
136121
{
137-
Factor = ms / _year;
138-
Interval = TimeUnit.Year;
122+
123+
case TimeUnit.Week:
124+
return factor * _week;
125+
case TimeUnit.Day:
126+
return factor * _day;
127+
case TimeUnit.Hour:
128+
return factor * _hour;
129+
case TimeUnit.Minute:
130+
return factor * _minute;
131+
case TimeUnit.Second:
132+
return factor * _second;
133+
case TimeUnit.Year:
134+
case TimeUnit.Month:
135+
// Cannot calculate exact milliseconds for non-fixed intervals
136+
return -1;
137+
default: // ms
138+
return factor;
139139
}
140-
else if (ms >= _week)
140+
}
141+
142+
private double GetApproximateMilliseconds(TimeUnit interval, double factor)
143+
{
144+
switch (interval)
145+
{
146+
case TimeUnit.Year:
147+
return factor * _yearApproximate;
148+
case TimeUnit.Month:
149+
return factor * _monthApproximate;
150+
default:
151+
return GetExactMilliseconds(interval, factor);
152+
}
153+
}
154+
155+
private void Reduce(double ms)
156+
{
157+
this.Milliseconds = ms;
158+
this.ApproximateMilliseconds = ms;
159+
160+
if (ms >= _week)
141161
{
142162
Factor = ms / _week;
143163
Interval = TimeUnit.Week;
@@ -165,10 +185,9 @@ private void Reduce(double ms)
165185
else
166186
{
167187
Factor = ms;
168-
// If milliseconds is < 0 then don't set an interval.
188+
// If milliseconds is <= 0 then don't set an interval.
169189
// This is used when setting things like index.refresh_interval = -1 (the only case where a unit isn't required)
170-
if (ms > 0)
171-
Interval = TimeUnit.Millisecond;
190+
Interval = (ms > 0) ? (TimeUnit?)TimeUnit.Millisecond : null;
172191
}
173192
}
174193
}

src/Tests/CommonOptions/TimeUnit/TimeUnits.doc.cs

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,20 @@ public void EqualityAndComparable()
6969
Time oneAndHalfYear = "1.5y";
7070
Time twoWeeks = TimeSpan.FromDays(14);
7171
Time twoDays = 1000*60*60*24*2;
72-
72+
7373
/**
7474
* Milliseconds are calculated even when values are not passed as long
7575
*/
76-
oneAndHalfYear.Milliseconds.Should().BeGreaterThan(1);
7776
twoWeeks.Milliseconds.Should().BeGreaterThan(1);
7877

78+
/**
79+
* Except when dealing with years or months, whose millsecond value cannot
80+
* be calculated *accurately*, since they are not fixed durations. For instance,
81+
* 30 vs 31 vs 28 days in a month, or 366 vs 365 days in a year.
82+
* In this instance, Milliseconds will be -1.
83+
*/
84+
oneAndHalfYear.Milliseconds.Should().Be(-1);
85+
7986
/**
8087
* This allows you to do comparisons on the expressions
8188
*/
@@ -96,6 +103,8 @@ public void EqualityAndComparable()
96103
(twoDays == new Time("2d")).Should().BeTrue();
97104
(twoDays != new Time("2.1d")).Should().BeTrue();
98105
(new Time("2.1d") == new Time(TimeSpan.FromDays(2.1))).Should().BeTrue();
106+
(new Time("1") == new Time(1)).Should().BeTrue();
107+
(new Time("-1") == new Time(-1)).Should().BeTrue();
99108
}
100109

101110
[U]
@@ -117,5 +126,80 @@ public void UsingInterval()
117126
Expect("2d").WhenSerializing<Union<DateInterval, Time>>((Time)"2d");
118127
Expect("1.16w").WhenSerializing<Union<DateInterval, Time>>((Time)TimeSpan.FromDays(8.1));
119128
}
129+
130+
[U]
131+
public void MillisecondsNeverSerializeToMonthsOrYears()
132+
{
133+
double millisecondsInAMonth = 2592000000;
134+
Expect("4.29w").WhenSerializing(new Time(millisecondsInAMonth));
135+
Expect("8.57w").WhenSerializing(new Time(millisecondsInAMonth * 2));
136+
Expect("51.43w").WhenSerializing(new Time(millisecondsInAMonth * 12));
137+
Expect("102.86w").WhenSerializing(new Time(millisecondsInAMonth * 24));
138+
}
139+
140+
[U]
141+
public void ExpectedValues()
142+
{
143+
Expect("-1").WhenSerializing(new Time(-1));
144+
Expect("-1").WhenSerializing(new Time("-1"));
145+
146+
Assert(
147+
1, Nest.TimeUnit.Year, -1, "1y",
148+
new Time(1, Nest.TimeUnit.Year),
149+
new Time("1y")
150+
);
151+
152+
Assert(
153+
1, Nest.TimeUnit.Month, -1, "1M",
154+
new Time(1, Nest.TimeUnit.Month),
155+
new Time("1M")
156+
);
157+
158+
Assert(
159+
1, Nest.TimeUnit.Week, TimeSpan.FromDays(7).TotalMilliseconds, "1w",
160+
new Time(1, Nest.TimeUnit.Week),
161+
new Time("1w"),
162+
new Time(TimeSpan.FromDays(7).TotalMilliseconds)
163+
);
164+
165+
Assert(
166+
1, Nest.TimeUnit.Day, TimeSpan.FromDays(1).TotalMilliseconds, "1d",
167+
new Time(1, Nest.TimeUnit.Day),
168+
new Time("1d"),
169+
new Time(TimeSpan.FromDays(1).TotalMilliseconds)
170+
);
171+
172+
Assert(
173+
1, Nest.TimeUnit.Hour, TimeSpan.FromHours(1).TotalMilliseconds, "1h",
174+
new Time(1, Nest.TimeUnit.Hour),
175+
new Time("1h"),
176+
new Time(TimeSpan.FromHours(1).TotalMilliseconds)
177+
);
178+
179+
Assert(
180+
1, Nest.TimeUnit.Minute, TimeSpan.FromMinutes(1).TotalMilliseconds, "1m",
181+
new Time(1, Nest.TimeUnit.Minute),
182+
new Time("1m"),
183+
new Time(TimeSpan.FromMinutes(1).TotalMilliseconds)
184+
);
185+
186+
Assert(
187+
1, Nest.TimeUnit.Second, TimeSpan.FromSeconds(1).TotalMilliseconds, "1s",
188+
new Time(1, Nest.TimeUnit.Second),
189+
new Time("1s"),
190+
new Time(TimeSpan.FromSeconds(1).TotalMilliseconds)
191+
);
192+
}
193+
194+
private void Assert(double expectedFactor, Nest.TimeUnit expectedInterval, double expectedMilliseconds, string expectedSerialized, params Time[] times)
195+
{
196+
foreach (var time in times)
197+
{
198+
time.Factor.Should().Be(expectedFactor);
199+
time.Interval.Should().Be(expectedInterval);
200+
time.Milliseconds.Should().Be(expectedMilliseconds);
201+
Expect(expectedSerialized).WhenSerializing(time);
202+
}
203+
}
120204
}
121205
}

src/Tests/tests.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# mode either u (unit test), i (integration test) or m (mixed mode)
2-
mode: m
2+
mode: u
33
# the elasticsearch version that should be started
44
elasticsearch_version: 2.2.0
55
# whether we want to forcefully reseed on the node, if you are starting the tests with a node already running

0 commit comments

Comments
 (0)