Skip to content

Commit 5a859b9

Browse files
committed
Fix double evaluation of IEnumerable methods
The ToListOrNullIfEmpty() extension method called .Any() and .ToList() which both evaluate the IEnumerable. This caused funcs to be executed twice when applied to an IEnumerable<Func<>>. Closes #2101
1 parent 914f366 commit 5a859b9

File tree

4 files changed

+58
-3
lines changed

4 files changed

+58
-3
lines changed

src/Nest/CommonAbstractions/Extensions/Extensions.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,11 @@ internal static void ForEach<T>(this IEnumerable<T> enumerable, Action<T> handle
161161
foreach (T item in enumerable) handler(item);
162162
}
163163

164-
internal static List<T> ToListOrNullIfEmpty<T>(this IEnumerable<T> enumerable) =>
165-
enumerable.HasAny() ? enumerable.ToList() : null;
164+
internal static List<T> ToListOrNullIfEmpty<T>(this IEnumerable<T> enumerable)
165+
{
166+
var list = enumerable?.ToList();
167+
return list.HasAny() ? list : null;
168+
}
166169

167170
internal static void AddIfNotNull<T>(this IList<T> list, T item) where T : class
168171
{
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using Elasticsearch.Net;
6+
using Nest;
7+
using FluentAssertions;
8+
using Tests.Framework;
9+
10+
namespace Tests.Reproduce
11+
{
12+
public class GithubIssue2101
13+
{
14+
15+
[U]
16+
public void BoolClausesShouldEvaluateOnlyOnce()
17+
{
18+
var must = 0;
19+
var mustNot = 0;
20+
var should = 0;
21+
var filter = 0;
22+
23+
new BoolQueryDescriptor<object>()
24+
.Must(m =>
25+
{
26+
must++;
27+
return m;
28+
})
29+
.MustNot(mn =>
30+
{
31+
mustNot++;
32+
return mn;
33+
})
34+
.Should(sh =>
35+
{
36+
should++;
37+
return sh;
38+
})
39+
.Filter(f =>
40+
{
41+
filter++;
42+
return f;
43+
});
44+
45+
filter.Should().Be(1);
46+
should.Should().Be(1);
47+
must.Should().Be(1);
48+
mustNot.Should().Be(1);
49+
}
50+
}
51+
}

src/Tests/Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,7 @@
560560
<Compile Include="Framework\Integration\Process\ElasticsearchNodeInfo.cs" />
561561
<Compile Include="Framework\Integration\Process\ElasticsearchVersionInfo.cs" />
562562
<Compile Include="QueryDsl\Verbatim\VerbatimAndStrictQueryUsageTests.cs" />
563+
<Compile Include="Reproduce\GithubIssue2101.cs" />
563564
<Compile Include="Search\Search\Rescoring\RescoreUsageTests.cs" />
564565
<Compile Include="XPack\Security\ClearCachedRealms\ClearCachedRealmsApiTests.cs" />
565566
<Compile Include="XPack\Security\ClearCachedRealms\ClearCachedRealmsUrlTests.cs" />

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.3.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)