Skip to content

Commit 10ee84a

Browse files
committed
Merge branch 'fix/bool-composition-pure'
2 parents a250374 + c5e6bea commit 10ee84a

File tree

8 files changed

+56
-82
lines changed

8 files changed

+56
-82
lines changed

src/Nest/QueryDsl/Abstractions/Container/QueryContainer-Dsl.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ private static bool IfEitherIsEmptyReturnTheOtherOrEmpty(QueryContainer leftCont
6868
if (!leftWritable && !rightWritable) return true;
6969

7070
queryContainer = leftWritable ? leftContainer : rightContainer;
71-
return !leftWritable || !rightWritable;
71+
return true;
7272
}
7373

7474
public static QueryContainer operator !(QueryContainer queryContainer) => queryContainer == null || (!queryContainer.IsWritable)

src/Nest/QueryDsl/Abstractions/Query/BoolQueryAndExtensions.cs

Lines changed: 19 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ internal static QueryContainer CombineAsMust(this QueryContainer leftContainer,
2626
var filterClauses = OrphanFilters(leftContainer).EagerConcat(OrphanFilters(rightContainer));
2727
var mustClauses = OrphanMusts(leftContainer).EagerConcat(OrphanMusts(rightContainer));
2828

29-
var reuseContainer = ContainerContainingBool(leftContainer, rightContainer);
30-
var container = CreateMustContainer(mustClauses, mustNotClauses, filterClauses, reuseContainer);
29+
var container = CreateMustContainer(mustClauses, mustNotClauses, filterClauses);
3130
return container;
3231
}
3332

@@ -79,66 +78,41 @@ private static bool TryHandleBoolsWithOnlyShouldClauses(
7978
c = null;
8079
var leftHasOnlyShoulds = leftBool.HasOnlyShouldClauses();
8180
var rightHasOnlyShoulds = rightBool.HasOnlyShouldClauses();
82-
if (leftHasOnlyShoulds || rightHasOnlyShoulds)
81+
if (!leftHasOnlyShoulds && !rightHasOnlyShoulds) return false;
82+
if (leftContainer.HoldsOnlyShouldMusts && rightHasOnlyShoulds)
8383
{
84-
if (leftContainer.HoldsOnlyShouldMusts && rightHasOnlyShoulds)
85-
{
86-
leftBool.Must = leftBool.Must.AddIfNotNull(rightContainer);
87-
c = leftContainer;
88-
}
89-
else if (rightContainer.HoldsOnlyShouldMusts && leftHasOnlyShoulds)
90-
{
91-
rightBool.Must = rightBool.Must.AddIfNotNull(leftContainer);
92-
c = rightContainer;
93-
}
94-
else
95-
{
96-
//c = CreateMustContainer(leftContainer, rightContainer);
97-
c = CreateMustContainer(new Containers { leftContainer, rightContainer }, null);
98-
c.HoldsOnlyShouldMusts = rightHasOnlyShoulds && leftHasOnlyShoulds;
99-
}
84+
leftBool.Must = leftBool.Must.AddIfNotNull(rightContainer);
85+
c = leftContainer;
10086
}
101-
return c != null;
87+
else if (rightContainer.HoldsOnlyShouldMusts && leftHasOnlyShoulds)
88+
{
89+
rightBool.Must = rightBool.Must.AddIfNotNull(leftContainer);
90+
c = rightContainer;
91+
}
92+
else
93+
{
94+
c = CreateMustContainer(new Containers { leftContainer, rightContainer }, null);
95+
c.HoldsOnlyShouldMusts = rightHasOnlyShoulds && leftHasOnlyShoulds;
96+
}
97+
return true;
10298
}
10399

104100
private static QueryContainer CreateMustContainer(QueryContainer left, QueryContainer right)
105101
{
106-
return CreateMustContainer(new Containers { left, right }, ContainerContainingBool(left, right));
107-
}
108-
109-
private static QueryContainer ContainerContainingBool(QueryContainer left, QueryContainer right)
110-
{
111-
var l = (left?.Self().Bool?.CreatedByBoolDsl).GetValueOrDefault();
112-
var r = (right?.Self().Bool?.CreatedByBoolDsl).GetValueOrDefault();
113-
return l ? left : r ? right : null;
102+
return CreateMustContainer(new Containers { left, right }, null);
114103
}
115104

116105
private static QueryContainer CreateMustContainer(List<QueryContainer> mustClauses, QueryContainer reuse)
117106
{
118-
var existingBool = reuse?.Self().Bool;
119-
if (existingBool != null && existingBool.CreatedByBoolDsl)
120-
{
121-
existingBool.Must = mustClauses.ToListOrNullIfEmpty();
122-
return reuse;
123-
}
124-
return new QueryContainer(new BoolQuery(createdByBoolDsl: true) { Must = mustClauses.ToListOrNullIfEmpty() });
107+
return new QueryContainer(new BoolQuery() { Must = mustClauses.ToListOrNullIfEmpty() });
125108
}
126109

127110
private static QueryContainer CreateMustContainer(
128111
List<QueryContainer> mustClauses,
129112
List<QueryContainer> mustNotClauses,
130-
List<QueryContainer> filters,
131-
QueryContainer reuse
113+
List<QueryContainer> filters
132114
)
133115
{
134-
var existingBool = reuse?.Self().Bool;
135-
if (existingBool != null && existingBool.CreatedByBoolDsl)
136-
{
137-
existingBool.Must = mustClauses.ToListOrNullIfEmpty();
138-
existingBool.MustNot = mustNotClauses.ToListOrNullIfEmpty();
139-
existingBool.Filter = filters.ToListOrNullIfEmpty();
140-
return reuse;
141-
}
142116
return new QueryContainer(new BoolQuery
143117
{
144118
Must = mustClauses.ToListOrNullIfEmpty(),
@@ -148,11 +122,8 @@ QueryContainer reuse
148122
}
149123

150124
private static bool CanMergeAnd(this IBoolQuery boolQuery) =>
151-
//boolQuery != null && boolQuery.IsWritable && !boolQuery.Locked && !boolQuery.Should.HasAny();
152125
boolQuery != null && !boolQuery.Locked && !boolQuery.Should.HasAny();
153126

154-
private static bool CanMergeAnd(this IQueryContainer container) => container.Bool.CanMergeAnd();
155-
156127
private static IEnumerable<QueryContainer> OrphanMusts(QueryContainer container)
157128
{
158129
var lBoolQuery = container.Self().Bool;

src/Nest/QueryDsl/Abstractions/Query/BoolQueryOrExtensions.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ private static bool CanMergeShould(this IBoolQuery boolQuery) =>
5656
boolQuery != null && boolQuery.IsWritable && !boolQuery.Locked && boolQuery.HasOnlyShouldClauses();
5757

5858
private static QueryContainer CreateShouldContainer(List<QueryContainer> shouldClauses) =>
59-
new BoolQuery(createdByBoolDsl: true)
59+
//new BoolQuery(createdByBoolDsl: true)
60+
new BoolQuery()
6061
{
6162
Should = shouldClauses.ToListOrNullIfEmpty()
6263
};

src/Nest/QueryDsl/Abstractions/Query/QueryBase.cs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,8 @@ private static bool IfEitherIsEmptyReturnTheOtherOrEmpty(QueryBase leftQuery, Qu
8282
return anyEmpty;
8383
}
8484

85-
public static implicit operator QueryContainer(QueryBase query)
86-
{
87-
if (query == null)
88-
return null;
89-
return new QueryContainer(query);
90-
91-
92-
}
85+
public static implicit operator QueryContainer(QueryBase query) =>
86+
query == null ? null : new QueryContainer(query);
9387

9488
internal void WrapInContainer(IQueryContainer container)
9589
{

src/Nest/QueryDsl/Abstractions/Query/QueryDescriptorBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,6 @@ public abstract class QueryDescriptorBase<TDescriptor, TInterface>
2323

2424
public TDescriptor Strict(bool strict = true) => Assign(a => a.IsStrict = strict);
2525

26-
bool IQuery.IsWritable { get { return Self.IsVerbatim || !Self.Conditionless; } }
26+
bool IQuery.IsWritable => Self.IsVerbatim || !Self.Conditionless;
2727
}
2828
}

src/Nest/QueryDsl/Compound/Bool/BoolQuery.cs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -51,15 +51,12 @@ public interface IBoolQuery : IQuery
5151
bool? DisableCoord { get; set; }
5252

5353
bool Locked { get; }
54-
bool CreatedByBoolDsl { get; }
5554
}
5655

5756
public class BoolQuery : QueryBase, IBoolQuery
5857
{
5958
internal static bool Locked(IBoolQuery q) => !q.Name.IsNullOrEmpty() || q.Boost.HasValue || q.DisableCoord.HasValue || q.MinimumShouldMatch != null;
6059
bool IBoolQuery.Locked => BoolQuery.Locked(this);
61-
private readonly bool _createdByBoolDsl;
62-
bool IBoolQuery.CreatedByBoolDsl => _createdByBoolDsl;
6360

6461
private IList<QueryContainer> _must;
6562
private IList<QueryContainer> _mustNot;
@@ -68,16 +65,6 @@ public class BoolQuery : QueryBase, IBoolQuery
6865

6966
public BoolQuery() { }
7067

71-
/// <summary>
72-
/// Internal constructor which we use internally in the bool dsl so we know its safe to reuse a boolean query instance
73-
/// </summary>
74-
/// <param name="createdByBoolDsl">ignored</param>
75-
internal BoolQuery(bool createdByBoolDsl)
76-
{
77-
this._createdByBoolDsl = true;
78-
}
79-
80-
8168
/// <summary>
8269
/// The clause(s) that must appear in matching documents
8370
/// </summary>
@@ -137,7 +124,6 @@ public class BoolQueryDescriptor<T>
137124
, IBoolQuery where T : class
138125
{
139126
bool IBoolQuery.Locked => BoolQuery.Locked(this);
140-
bool IBoolQuery.CreatedByBoolDsl { get; } = false;
141127

142128
protected override bool Conditionless => BoolQuery.IsConditionless(this);
143129
private IList<QueryContainer> _must;

src/Tests/QueryDsl/BoolDsl/BoolDsl.doc.cs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,33 @@ private static void AssertDoesNotJoinOntoLockedBool(IQueryContainer c, string fi
336336
nestedBool.Bool.Name.Should().Be(firstName);
337337
}
338338

339+
//hide
340+
[U] public void AndShouldNotBeViralAnyWayYouComposeIt()
341+
{
342+
QueryContainer andAssign = new TermQuery { Field = "a", Value = "a" };
343+
andAssign &= new TermQuery { Field = "b", Value = "b" };
344+
345+
AssertAndIsNotViral(andAssign, "&=");
346+
347+
QueryContainer andOperator =
348+
new TermQuery { Field = "a", Value = "a" } && new TermQuery { Field = "b", Value = "b" };
349+
350+
AssertAndIsNotViral(andOperator, "&&");
351+
}
352+
353+
//hide
354+
private static void AssertAndIsNotViral(QueryContainer query, string origin)
355+
{
356+
IQueryContainer original = query;
357+
original.Bool.Must.Should().HaveCount(2, $"query composed using {origin} should have 2 must clauses before");
358+
IQueryContainer result = query && new TermQuery { Field = "c", Value = "c" };
359+
result.Bool.Must.Should().HaveCount(3, $"query composed using {origin} combined with && should have 3 must clauses");
360+
original.Bool.Must.Should().HaveCount(2, $"query composed using {origin} should still have 2 must clauses after composition");
361+
}
362+
363+
364+
365+
339366
/** === Perfomance considerations
340367
*
341368
* If you have a requirement of combining many many queries using the bool dsl please take the following into account.
@@ -349,8 +376,10 @@ private static void SlowCombine()
349376
var c = new QueryContainer();
350377
var q = new TermQuery { Field = "x", Value = "x" };
351378

352-
for (var i=0;i<1000;i++)
379+
for (var i = 0; i < 1000; i++)
380+
{
353381
c &= q;
382+
}
354383
}
355384
/**
356385
*....

src/Tests/tests.yaml

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,12 @@
11
# mode either u (unit test), i (integration test) or m (mixed mode)
2-
mode: i
3-
2+
mode: m
43
# the elasticsearch version that should be started
54
# Can be a snapshot version of sonatype or "latest" to get the latest snapshot of sonatype
65
elasticsearch_version: 5.0.2
7-
86
# cluster filter allows you to only run the integration tests of a particular cluster (cluster suffix not needed)
97
# cluster_filter:
10-
11-
# test filter allows you to only run the integration tests matching the filter (using a simple contains)
12-
# cluster_filter:
13-
148
# whether we want to forcefully reseed on the node, if you are starting the tests with a node already running
159
force_reseed: true
16-
1710
# do not spawn nodes as part of the test setup if we find a node is already running
1811
# this is opt in during development in CI we never want to see our tests running against an already running node
1912
test_against_already_running_elasticsearch: true

0 commit comments

Comments
 (0)