@@ -0,0 +1,61 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.es.searchrequest; | |||
import java.util.Arrays; | |||
import java.util.Objects; | |||
import javax.annotation.concurrent.Immutable; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.sonar.server.es.searchrequest.TopAggregationDefinition.NestedFieldFilterScope; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static java.util.Objects.requireNonNull; | |||
@Immutable | |||
public class NestedFieldTopAggregationDefinition<T> implements TopAggregationDefinition<NestedFieldFilterScope<T>> { | |||
private final NestedFieldFilterScope<T> filterScope; | |||
private final boolean sticky; | |||
public NestedFieldTopAggregationDefinition(String nestedFieldPath, T value, boolean sticky) { | |||
requireNonNull(nestedFieldPath, "nestedFieldPath can't be null"); | |||
requireNonNull(value, "value can't be null"); | |||
checkArgument(StringUtils.countMatches(nestedFieldPath, ".") == 1, | |||
"Field path should have only one dot: %s", nestedFieldPath); | |||
String[] fullPath = Arrays.stream(StringUtils.split(nestedFieldPath, '.')) | |||
.filter(Objects::nonNull) | |||
.map(String::trim) | |||
.filter(t -> !t.isEmpty()) | |||
.toArray(String[]::new); | |||
checkArgument(fullPath.length == 2, | |||
"field path \"%s\" should have exactly 2 non empty field names, got: %s", nestedFieldPath, Arrays.asList(fullPath)); | |||
this.filterScope = new NestedFieldFilterScope<>(fullPath[0], fullPath[1], value); | |||
this.sticky = sticky; | |||
} | |||
@Override | |||
public NestedFieldFilterScope<T> getFilterScope() { | |||
return filterScope; | |||
} | |||
@Override | |||
public boolean isSticky() { | |||
return sticky; | |||
} | |||
} |
@@ -34,6 +34,7 @@ import javax.annotation.concurrent.Immutable; | |||
import org.elasticsearch.index.query.BoolQueryBuilder; | |||
import org.elasticsearch.index.query.QueryBuilder; | |||
import org.sonar.core.util.stream.MoreCollectors; | |||
import org.sonar.server.es.searchrequest.TopAggregationDefinition.FilterScope; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static com.google.common.base.Preconditions.checkState; | |||
@@ -52,15 +53,15 @@ import static org.elasticsearch.index.query.QueryBuilders.boolQuery; | |||
* </ul> | |||
* <p> | |||
* To be able to provide accurate filters, all {@link TopAggregationDefinition} instances for which | |||
* {@link #getTopAggregationFilter(TopAggregationDefinition)} may be called, must be declared in the constructor. | |||
* {@link #getTopAggregationFilter(TopAggregationDefinition)} may be called, must all be declared in the constructor. | |||
*/ | |||
public class RequestFiltersComputer { | |||
private final Set<TopAggregationDefinition> topAggregations; | |||
private final Map<FilterNameAndFieldName, QueryBuilder> postFilters; | |||
private final Map<FilterNameAndFieldName, QueryBuilder> queryFilters; | |||
private final Set<TopAggregationDefinition<?>> topAggregations; | |||
private final Map<FilterNameAndScope, QueryBuilder> postFilters; | |||
private final Map<FilterNameAndScope, QueryBuilder> queryFilters; | |||
public RequestFiltersComputer(AllFilters allFilters, Set<TopAggregationDefinition> topAggregations) { | |||
public RequestFiltersComputer(AllFilters allFilters, Set<TopAggregationDefinition<?>> topAggregations) { | |||
this.topAggregations = ImmutableSet.copyOf(topAggregations); | |||
this.postFilters = computePostFilters((AllFiltersImpl) allFilters, topAggregations); | |||
this.queryFilters = computeQueryFilter((AllFiltersImpl) allFilters, postFilters); | |||
@@ -73,20 +74,20 @@ public class RequestFiltersComputer { | |||
/** | |||
* Any filter of the query which can not be applied to all top-aggregations must be applied as a PostFilter. | |||
* <p> | |||
* A filter applying to some field can not be applied to the query when at least one sticky top-aggregation is enabled | |||
* which applies to that field <strong>and</strong> a top-aggregation is enabled on that field. | |||
* A filter with a given {@link FilterScope} can not be applied to the query when at least one sticky top-aggregation | |||
* is enabled which has the same {@link FilterScope}. | |||
*/ | |||
private static Map<FilterNameAndFieldName, QueryBuilder> computePostFilters(AllFiltersImpl allFilters, | |||
Set<TopAggregationDefinition> topAggregations) { | |||
Set<String> enabledStickyTopAggregationtedFieldNames = topAggregations.stream() | |||
private static Map<FilterNameAndScope, QueryBuilder> computePostFilters(AllFiltersImpl allFilters, | |||
Set<TopAggregationDefinition<?>> topAggregations) { | |||
Set<FilterScope> enabledStickyTopAggregationtedFieldNames = topAggregations.stream() | |||
.filter(TopAggregationDefinition::isSticky) | |||
.map(TopAggregationDefinition::getFieldName) | |||
.map(TopAggregationDefinition::getFilterScope) | |||
.collect(MoreCollectors.toSet(topAggregations.size())); | |||
// use LinkedHashMap over MoreCollectors.uniqueIndex to preserve order and write UTs more easily | |||
Map<FilterNameAndFieldName, QueryBuilder> res = new LinkedHashMap<>(); | |||
Map<FilterNameAndScope, QueryBuilder> res = new LinkedHashMap<>(); | |||
allFilters.internalStream() | |||
.filter(e -> enabledStickyTopAggregationtedFieldNames.contains(e.getKey().getFieldName())) | |||
.filter(e -> enabledStickyTopAggregationtedFieldNames.contains(e.getKey().getFilterScope())) | |||
.forEach(e -> checkState(res.put(e.getKey(), e.getValue()) == null, "Duplicate: %s", e.getKey())); | |||
return res; | |||
} | |||
@@ -99,12 +100,12 @@ public class RequestFiltersComputer { | |||
* (typical case is a filter on the field aggregated to implement sticky facet behavior), this filter can | |||
* not be applied to the query and therefor must be applied as PostFilter. | |||
*/ | |||
private static Map<FilterNameAndFieldName, QueryBuilder> computeQueryFilter(AllFiltersImpl allFilters, | |||
Map<FilterNameAndFieldName, QueryBuilder> postFilters) { | |||
Set<FilterNameAndFieldName> postFilterKeys = postFilters.keySet(); | |||
private static Map<FilterNameAndScope, QueryBuilder> computeQueryFilter(AllFiltersImpl allFilters, | |||
Map<FilterNameAndScope, QueryBuilder> postFilters) { | |||
Set<FilterNameAndScope> postFilterKeys = postFilters.keySet(); | |||
// use LinkedHashMap over MoreCollectors.uniqueIndex to preserve order and write UTs more easily | |||
Map<FilterNameAndFieldName, QueryBuilder> res = new LinkedHashMap<>(); | |||
Map<FilterNameAndScope, QueryBuilder> res = new LinkedHashMap<>(); | |||
allFilters.internalStream() | |||
.filter(e -> !postFilterKeys.contains(e.getKey())) | |||
.forEach(e -> checkState(res.put(e.getKey(), e.getValue()) == null, "Duplicate: %s", e.getKey())); | |||
@@ -133,26 +134,27 @@ public class RequestFiltersComputer { | |||
} | |||
/** | |||
* The {@link BoolQueryBuilder} to apply to the top aggregation for the specified {@link TopAggregationDef}. | |||
* The {@link BoolQueryBuilder} to apply to the top aggregation for the specified {@link SimpleFieldTopAggregationDefinition}. | |||
* <p> | |||
* The filter of the aggregations for a top-aggregation will either be: | |||
* <ul> | |||
* <li>the same as PostFilter, if the top-aggregation is non-sticky or the field the top-aggregation applies | |||
* to is not being filtered</li> | |||
* <li>or the same as PostFilter minus any filter which applies to the field for the top-aggregation (if it's sticky)</li> | |||
* <li>the same as PostFilter, if the top-aggregation is non-sticky or none have the same FilterScope as | |||
* {@code topAggregation}</li> | |||
* <li>or the same as PostFilter minus any filter which applies to the same {@link FilterScope} of | |||
* {@code topAggregation}for the (<strong>if it's sticky</strong>)</li> | |||
* </ul> | |||
* | |||
* @throws IllegalArgumentException if specified {@link TopAggregationDefinition} has not been specified in the constructor | |||
*/ | |||
public Optional<BoolQueryBuilder> getTopAggregationFilter(TopAggregationDefinition topAggregation) { | |||
public Optional<BoolQueryBuilder> getTopAggregationFilter(TopAggregationDefinition<?> topAggregation) { | |||
checkArgument(topAggregations.contains(topAggregation), "topAggregation must have been declared in constructor"); | |||
return toBoolQuery( | |||
postFilters, | |||
(e, v) -> !topAggregation.isSticky() || !topAggregation.getFieldName().equals(e.getFieldName())); | |||
(e, v) -> !topAggregation.isSticky() || !topAggregation.getFilterScope().intersect(e.getFilterScope())); | |||
} | |||
private static Optional<BoolQueryBuilder> toBoolQuery(Map<FilterNameAndFieldName, QueryBuilder> queryFilters, | |||
BiPredicate<FilterNameAndFieldName, QueryBuilder> predicate) { | |||
private static Optional<BoolQueryBuilder> toBoolQuery(Map<FilterNameAndScope, QueryBuilder> queryFilters, | |||
BiPredicate<FilterNameAndScope, QueryBuilder> predicate) { | |||
if (queryFilters.isEmpty()) { | |||
return empty(); | |||
} | |||
@@ -178,13 +180,7 @@ public class RequestFiltersComputer { | |||
/** | |||
* @throws IllegalArgumentException if a filter with the specified name has already been added | |||
*/ | |||
AllFilters addFilter(String name, String fieldName, @Nullable QueryBuilder filter); | |||
/** | |||
* Convenience method for usage of {@link #addFilter(String, String, QueryBuilder)} when name of the filter is | |||
* the same as the field name. | |||
*/ | |||
AllFilters addFilter(String fieldName, @Nullable QueryBuilder filter); | |||
AllFilters addFilter(String name, FilterScope filterScope, @Nullable QueryBuilder filter); | |||
Stream<QueryBuilder> stream(); | |||
} | |||
@@ -194,24 +190,19 @@ public class RequestFiltersComputer { | |||
* Usage of LinkedHashMap only benefits unit tests by providing predictability of the order of the filters. | |||
* ES doesn't care of the order. | |||
*/ | |||
private final Map<FilterNameAndFieldName, QueryBuilder> filters = new LinkedHashMap<>(); | |||
@Override | |||
public AllFilters addFilter(String fieldName, @Nullable QueryBuilder filter) { | |||
return addFilter(fieldName, fieldName, filter); | |||
} | |||
private final Map<FilterNameAndScope, QueryBuilder> filters = new LinkedHashMap<>(); | |||
@Override | |||
public AllFilters addFilter(String name, String fieldName, @Nullable QueryBuilder filter) { | |||
public AllFilters addFilter(String name, FilterScope filterScope, @Nullable QueryBuilder filter) { | |||
requireNonNull(name, "name can't be null"); | |||
requireNonNull(fieldName, "fieldName can't be null"); | |||
requireNonNull(filterScope, "filterScope can't be null"); | |||
if (filter == null) { | |||
return this; | |||
} | |||
checkArgument( | |||
filters.put(new FilterNameAndFieldName(name, fieldName), filter) == null, | |||
filters.put(new FilterNameAndScope(name, filterScope), filter) == null, | |||
"A filter with name %s has already been added", name); | |||
return this; | |||
} | |||
@@ -221,7 +212,7 @@ public class RequestFiltersComputer { | |||
return filters.values().stream(); | |||
} | |||
private Stream<Map.Entry<FilterNameAndFieldName, QueryBuilder>> internalStream() { | |||
private Stream<Map.Entry<FilterNameAndScope, QueryBuilder>> internalStream() { | |||
return filters.entrySet().stream(); | |||
} | |||
} | |||
@@ -233,17 +224,17 @@ public class RequestFiltersComputer { | |||
* This saves from using two internal maps. | |||
*/ | |||
@Immutable | |||
private static final class FilterNameAndFieldName { | |||
private static final class FilterNameAndScope { | |||
private final String filterName; | |||
private final String fieldName; | |||
private final FilterScope filterScope; | |||
public FilterNameAndFieldName(String filterName, String fieldName) { | |||
private FilterNameAndScope(String filterName, FilterScope filterScope) { | |||
this.filterName = filterName; | |||
this.fieldName = fieldName; | |||
this.filterScope = filterScope; | |||
} | |||
public String getFieldName() { | |||
return fieldName; | |||
public FilterScope getFilterScope() { | |||
return filterScope; | |||
} | |||
@Override | |||
@@ -254,7 +245,7 @@ public class RequestFiltersComputer { | |||
if (o == null || getClass() != o.getClass()) { | |||
return false; | |||
} | |||
FilterNameAndFieldName that = (FilterNameAndFieldName) o; | |||
FilterNameAndScope that = (FilterNameAndScope) o; | |||
return filterName.equals(that.filterName); | |||
} | |||
@@ -20,29 +20,32 @@ | |||
package org.sonar.server.es.searchrequest; | |||
import javax.annotation.concurrent.Immutable; | |||
import org.sonar.server.es.searchrequest.TopAggregationDefinition.FilterScope; | |||
import static java.util.Objects.requireNonNull; | |||
/** | |||
* Default implementation of {@link TopAggregationDefinition}. | |||
* Implementation of {@link TopAggregationDefinition} with a filter scope for a simple field. | |||
*/ | |||
@Immutable | |||
public final class TopAggregationDef implements TopAggregationDefinition { | |||
private final String fieldName; | |||
public final class SimpleFieldTopAggregationDefinition implements TopAggregationDefinition<FilterScope> { | |||
private final FilterScope filterScope; | |||
private final boolean sticky; | |||
public TopAggregationDef(String fieldName, boolean sticky) { | |||
this.fieldName = requireNonNull(fieldName, "fieldName can't be null"); | |||
public SimpleFieldTopAggregationDefinition(String fieldName, boolean sticky) { | |||
requireNonNull(fieldName, "fieldName can't be null"); | |||
this.filterScope = new SimpleFieldFilterScope(fieldName); | |||
this.sticky = sticky; | |||
} | |||
@Override | |||
public String getFieldName() { | |||
return fieldName; | |||
public FilterScope getFilterScope() { | |||
return filterScope; | |||
} | |||
@Override | |||
public boolean isSticky() { | |||
return sticky; | |||
} | |||
} |
@@ -63,9 +63,9 @@ public class SubAggregationHelper { | |||
} | |||
public TermsAggregationBuilder buildTermsAggregation(String name, | |||
TopAggregationDefinition topAggregation, @Nullable Integer numberOfTerms) { | |||
TopAggregationDefinition<?> topAggregation, @Nullable Integer numberOfTerms) { | |||
TermsAggregationBuilder termsAggregation = AggregationBuilders.terms(name) | |||
.field(topAggregation.getFieldName()) | |||
.field(topAggregation.getFilterScope().getFieldName()) | |||
.order(order) | |||
.minDocCount(TERM_AGGREGATION_MIN_DOC_COUNT); | |||
if (numberOfTerms != null) { | |||
@@ -77,7 +77,7 @@ public class SubAggregationHelper { | |||
return termsAggregation; | |||
} | |||
public <T> Optional<TermsAggregationBuilder> buildSelectedItemsAggregation(String name, TopAggregationDefinition topAggregation, T[] selected) { | |||
public <T> Optional<TermsAggregationBuilder> buildSelectedItemsAggregation(String name, TopAggregationDefinition<?> topAggregation, T[] selected) { | |||
if (selected.length <= 0) { | |||
return Optional.empty(); | |||
} | |||
@@ -89,7 +89,7 @@ public class SubAggregationHelper { | |||
TermsAggregationBuilder selectedTerms = AggregationBuilders.terms(name + Facets.SELECTED_SUB_AGG_NAME_SUFFIX) | |||
.size(max(MAXIMUM_NUMBER_OF_SELECTED_ITEMS_WHOSE_DOC_COUNT_WILL_BE_CALCULATED, includes.length())) | |||
.field(topAggregation.getFieldName()) | |||
.field(topAggregation.getFilterScope().getFieldName()) | |||
.includeExclude(new IncludeExclude(includes, null)); | |||
if (subAggregation != null) { | |||
selectedTerms = selectedTerms.subAggregation(subAggregation); |
@@ -19,12 +19,144 @@ | |||
*/ | |||
package org.sonar.server.es.searchrequest; | |||
import java.util.Objects; | |||
import javax.annotation.Nullable; | |||
import javax.annotation.concurrent.Immutable; | |||
import static java.util.Objects.requireNonNull; | |||
/** | |||
* Models a first level aggregation in an Elasticsearch request (aka. top-aggregation) on a unique field and whether | |||
* it is to be used to compute data for a sticky facet (see {@link #isSticky()}). | |||
* Models a first level aggregation in an Elasticsearch request (aka. top-aggregation) with a specific | |||
* {@link FilterScope} and whether it is to be used to compute data for a sticky facet (see {@link #isSticky()}) or not. | |||
*/ | |||
public interface TopAggregationDefinition { | |||
String getFieldName(); | |||
public interface TopAggregationDefinition<S extends TopAggregationDefinition.FilterScope> { | |||
boolean STICKY = true; | |||
boolean NON_STICKY = false; | |||
S getFilterScope(); | |||
boolean isSticky(); | |||
abstract class FilterScope { | |||
public abstract String getFieldName(); | |||
/** | |||
* All implementations must implement {@link Object#equals(Object)} and {@link Object#hashCode()} to be used | |||
* in {@link java.util.Set}. | |||
*/ | |||
public abstract boolean equals(Object other); | |||
public abstract int hashCode(); | |||
/** | |||
* | |||
*/ | |||
public abstract boolean intersect(@Nullable FilterScope other); | |||
} | |||
/** | |||
* Filter applies to a regular first level field. | |||
*/ | |||
@Immutable | |||
final class SimpleFieldFilterScope extends FilterScope { | |||
private final String fieldName; | |||
public SimpleFieldFilterScope(String fieldName) { | |||
this.fieldName = requireNonNull(fieldName, "fieldName can't be null"); | |||
} | |||
@Override | |||
public String getFieldName() { | |||
return fieldName; | |||
} | |||
@Override | |||
public boolean equals(@Nullable Object o) { | |||
if (this == o) { | |||
return true; | |||
} | |||
if (o == null || getClass() != o.getClass()) { | |||
return false; | |||
} | |||
SimpleFieldFilterScope that = (SimpleFieldFilterScope) o; | |||
return fieldName.equals(that.fieldName); | |||
} | |||
@Override | |||
public int hashCode() { | |||
return Objects.hash(fieldName); | |||
} | |||
@Override | |||
public boolean intersect(@Nullable FilterScope other) { | |||
if (this == other) { | |||
return true; | |||
} | |||
if (other == null) { | |||
return false; | |||
} | |||
return fieldName.equals(other.getFieldName()); | |||
} | |||
} | |||
/** | |||
* Filter applies to a first level field holding an array of objects (aka. nested fields) used to store various data | |||
* with similar structure in a single field. Each data is identified by a dedicated field which holds a different value | |||
* for each data: eg. metric key subfield identifies which metric the other subfield(s) are the value of. | |||
* <p> | |||
* This filter scope allows to represent filtering on each type of data in this first-level field, hence the necessity | |||
* to provide both the name of the subfield and the value which identifies that data. | |||
*/ | |||
@Immutable | |||
final class NestedFieldFilterScope<T> extends FilterScope { | |||
private final String fieldName; | |||
private final String nestedFieldName; | |||
private final T value; | |||
public NestedFieldFilterScope(String fieldName, String nestedFieldName, T value) { | |||
this.fieldName = requireNonNull(fieldName, "fieldName can't be null"); | |||
this.nestedFieldName = requireNonNull(nestedFieldName, "nestedFieldName can't be null"); | |||
this.value = requireNonNull(value, "value can't be null"); | |||
} | |||
@Override | |||
public String getFieldName() { | |||
return fieldName; | |||
} | |||
public String getNestedFieldName() { | |||
return nestedFieldName; | |||
} | |||
public T getNestedFieldValue() { | |||
return value; | |||
} | |||
@Override | |||
public boolean equals(@Nullable Object o) { | |||
if (this == o) { | |||
return true; | |||
} | |||
if (o == null || getClass() != o.getClass()) { | |||
return false; | |||
} | |||
NestedFieldFilterScope<?> that = (NestedFieldFilterScope<?>) o; | |||
return fieldName.equals(that.fieldName) && | |||
nestedFieldName.equals(that.nestedFieldName) && | |||
value.equals(that.value); | |||
} | |||
@Override | |||
public int hashCode() { | |||
return Objects.hash(fieldName, nestedFieldName, value); | |||
} | |||
@Override | |||
public boolean intersect(@Nullable FilterScope other) { | |||
if (other instanceof NestedFieldFilterScope) { | |||
return equals(other); | |||
} | |||
return false; | |||
} | |||
} | |||
} |
@@ -62,7 +62,7 @@ public class TopAggregationHelper { | |||
* @throws IllegalStateException if no sub-aggregation has been added | |||
* @return the aggregation, that can be added on top level of the elasticsearch request | |||
*/ | |||
public FilterAggregationBuilder buildTopAggregation(String topAggregationName, TopAggregationDefinition topAggregation, | |||
public FilterAggregationBuilder buildTopAggregation(String topAggregationName, TopAggregationDefinition<?> topAggregation, | |||
Consumer<BoolQueryBuilder> extraFilters, Consumer<FilterAggregationBuilder> subAggregations) { | |||
BoolQueryBuilder filter = filterComputer.getTopAggregationFilter(topAggregation) | |||
.orElseGet(QueryBuilders::boolQuery); | |||
@@ -79,10 +79,11 @@ public class TopAggregationHelper { | |||
/** | |||
* Same as {@link #buildTopAggregation(String, TopAggregationDefinition, Consumer, Consumer)} with built-in addition of a | |||
* top-term sub aggregation based field defined by {@link TopAggregationDefinition#getFieldName()}. | |||
* top-term sub aggregation based field defined by {@link TopAggregationDefinition.FilterScope#getFieldName()} of | |||
* {@link TopAggregationDefinition#getFilterScope()}. | |||
*/ | |||
public FilterAggregationBuilder buildTermTopAggregation(String topAggregationName, | |||
TopAggregationDefinition topAggregation, @Nullable Integer numberOfTerms, | |||
TopAggregationDefinition<?> topAggregation, @Nullable Integer numberOfTerms, | |||
Consumer<BoolQueryBuilder> extraFilters, Consumer<FilterAggregationBuilder> otherSubAggregations) { | |||
Consumer<FilterAggregationBuilder> subAggregations = t -> { | |||
t.subAggregation(subAggregationHelper.buildTermsAggregation(topAggregationName, topAggregation, numberOfTerms)); |
@@ -28,11 +28,13 @@ import org.assertj.core.api.ThrowableAssert.ThrowingCallable; | |||
import org.elasticsearch.index.query.BoolQueryBuilder; | |||
import org.elasticsearch.index.query.QueryBuilder; | |||
import org.junit.Test; | |||
import org.sonar.server.es.searchrequest.TopAggregationDefinition.FilterScope; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | |||
import static org.elasticsearch.index.query.QueryBuilders.boolQuery; | |||
import static org.mockito.Mockito.mock; | |||
public class AllFiltersTest { | |||
@Test | |||
@@ -47,15 +49,12 @@ public class AllFiltersTest { | |||
@Test | |||
public void addFilter_fails_if_name_is_null() { | |||
String fieldName = randomAlphabetic(12); | |||
FilterScope filterScope = mock(FilterScope.class); | |||
RequestFiltersComputer.AllFilters allFilters = RequestFiltersComputer.newAllFilters(); | |||
Stream.<ThrowingCallable>of( | |||
() -> allFilters.addFilter(null, boolQuery()), | |||
() -> allFilters.addFilter(null, fieldName, boolQuery())) | |||
.forEach(t -> assertThatThrownBy(t) | |||
.isInstanceOf(NullPointerException.class) | |||
.hasMessage("name can't be null")); | |||
assertThatThrownBy(() -> allFilters.addFilter(null, filterScope, boolQuery())) | |||
.isInstanceOf(NullPointerException.class) | |||
.hasMessage("name can't be null"); | |||
} | |||
@Test | |||
@@ -65,32 +64,23 @@ public class AllFiltersTest { | |||
assertThatThrownBy(() -> allFilters.addFilter(name, null, boolQuery())) | |||
.isInstanceOf(NullPointerException.class) | |||
.hasMessage("fieldName can't be null"); | |||
.hasMessage("filterScope can't be null"); | |||
} | |||
@Test | |||
public void addFilter_fails_if_field_with_name_already_exists() { | |||
String name1 = randomAlphabetic(12); | |||
String name2 = randomAlphabetic(15); | |||
String fieldName = randomAlphabetic(16); | |||
String fieldName2 = randomAlphabetic(18); | |||
FilterScope filterScope1 = mock(FilterScope.class); | |||
FilterScope filterScope2 = mock(FilterScope.class); | |||
RequestFiltersComputer.AllFilters allFilters = RequestFiltersComputer.newAllFilters(); | |||
allFilters.addFilter(name1, boolQuery()); | |||
allFilters.addFilter(name2, fieldName, boolQuery()); | |||
allFilters.addFilter(name2, filterScope1, boolQuery()); | |||
Stream.<ThrowingCallable>of( | |||
// exact same call | |||
() -> allFilters.addFilter(name1, boolQuery()), | |||
// call with a different fieldName | |||
() -> allFilters.addFilter(name1, fieldName, boolQuery())) | |||
.forEach(t -> assertThatThrownBy(t) | |||
.isInstanceOf(IllegalArgumentException.class) | |||
.hasMessage("A filter with name " + name1 + " has already been added")); | |||
Stream.<ThrowingCallable>of( | |||
// exact same call | |||
() -> allFilters.addFilter(name2, fieldName, boolQuery()), | |||
() -> allFilters.addFilter(name2, filterScope1, boolQuery()), | |||
// call with a different fieldName | |||
() -> allFilters.addFilter(name2, fieldName2, boolQuery())) | |||
() -> allFilters.addFilter(name2, filterScope2, boolQuery())) | |||
.forEach(t -> assertThatThrownBy(t) | |||
.isInstanceOf(IllegalArgumentException.class) | |||
.hasMessage("A filter with name " + name2 + " has already been added")); | |||
@@ -102,8 +92,8 @@ public class AllFiltersTest { | |||
String name2 = randomAlphabetic(14); | |||
RequestFiltersComputer.AllFilters allFilters = RequestFiltersComputer.newAllFilters(); | |||
BoolQueryBuilder query = boolQuery(); | |||
allFilters.addFilter(name, query) | |||
.addFilter(name2, null); | |||
allFilters.addFilter(name, mock(FilterScope.class), query) | |||
.addFilter(name2, mock(FilterScope.class), null); | |||
List<QueryBuilder> all = allFilters.stream().collect(Collectors.toList()); | |||
assertThat(all).hasSize(1); |
@@ -0,0 +1,150 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.es.searchrequest; | |||
import org.junit.Test; | |||
import org.sonar.server.es.searchrequest.TopAggregationDefinition.NestedFieldFilterScope; | |||
import org.sonar.server.es.searchrequest.TopAggregationDefinition.SimpleFieldFilterScope; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | |||
public class NestedFieldFilterScopeTest { | |||
@Test | |||
public void constructor_fails_with_NPE_if_fieldName_is_null() { | |||
String nestedFieldName = randomAlphabetic(11); | |||
String value = randomAlphabetic(12); | |||
assertThatThrownBy(() -> new NestedFieldFilterScope<>(null, nestedFieldName, value)) | |||
.isInstanceOf(NullPointerException.class) | |||
.hasMessage("fieldName can't be null"); | |||
} | |||
@Test | |||
public void constructor_fails_with_NPE_if_nestedFieldName_is_null() { | |||
String fieldName = randomAlphabetic(10); | |||
String value = randomAlphabetic(12); | |||
assertThatThrownBy(() -> new NestedFieldFilterScope<>(fieldName, null, value)) | |||
.isInstanceOf(NullPointerException.class) | |||
.hasMessage("nestedFieldName can't be null"); | |||
} | |||
@Test | |||
public void constructor_fails_with_NPE_if_value_is_null() { | |||
String fieldName = randomAlphabetic(10); | |||
String nestedFieldName = randomAlphabetic(11); | |||
assertThatThrownBy(() -> new NestedFieldFilterScope<>(fieldName, nestedFieldName, null)) | |||
.isInstanceOf(NullPointerException.class) | |||
.hasMessage("value can't be null"); | |||
} | |||
@Test | |||
public void verify_getters() { | |||
String fieldName = randomAlphabetic(10); | |||
String nestedFieldName = randomAlphabetic(11); | |||
Object value = new Object(); | |||
NestedFieldFilterScope<Object> underTest = new NestedFieldFilterScope<>(fieldName, nestedFieldName, value); | |||
assertThat(underTest.getFieldName()).isEqualTo(fieldName); | |||
assertThat(underTest.getNestedFieldName()).isEqualTo(nestedFieldName); | |||
assertThat(underTest.getNestedFieldValue()).isSameAs(value); | |||
} | |||
@Test | |||
public void verify_equals() { | |||
String fieldName = randomAlphabetic(10); | |||
String nestedFieldName = randomAlphabetic(11); | |||
Object value = new Object(); | |||
String fieldName2 = randomAlphabetic(12); | |||
String nestedFieldName2 = randomAlphabetic(13); | |||
Object value2 = new Object(); | |||
NestedFieldFilterScope<Object> underTest = new NestedFieldFilterScope<>(fieldName, nestedFieldName, value); | |||
assertThat(underTest) | |||
.isEqualTo(underTest) | |||
.isEqualTo(new NestedFieldFilterScope<>(fieldName, nestedFieldName, value)); | |||
assertThat(underTest) | |||
.isNotEqualTo(null) | |||
.isNotEqualTo(new Object()) | |||
.isNotEqualTo(new NestedFieldFilterScope<>(fieldName2, nestedFieldName, value)) | |||
.isNotEqualTo(new NestedFieldFilterScope<>(fieldName, nestedFieldName2, value)) | |||
.isNotEqualTo(new NestedFieldFilterScope<>(fieldName, nestedFieldName, value2)) | |||
.isNotEqualTo(new NestedFieldFilterScope<>(fieldName2, nestedFieldName2, value)) | |||
.isNotEqualTo(new NestedFieldFilterScope<>(fieldName, nestedFieldName2, value2)) | |||
.isNotEqualTo(new NestedFieldFilterScope<>(fieldName2, nestedFieldName, value2)) | |||
.isNotEqualTo(new NestedFieldFilterScope<>(fieldName2, nestedFieldName2, value2)) | |||
.isNotEqualTo(new SimpleFieldFilterScope(fieldName)) | |||
.isNotEqualTo(new SimpleFieldFilterScope(fieldName2)); | |||
} | |||
@Test | |||
public void verify_hashcode() { | |||
String fieldName = randomAlphabetic(10); | |||
String nestedFieldName = randomAlphabetic(11); | |||
Object value = new Object(); | |||
String fieldName2 = randomAlphabetic(12); | |||
String nestedFieldName2 = randomAlphabetic(13); | |||
Object value2 = new Object(); | |||
NestedFieldFilterScope<Object> underTest = new NestedFieldFilterScope<>(fieldName, nestedFieldName, value); | |||
assertThat(underTest.hashCode()) | |||
.isEqualTo(underTest.hashCode()) | |||
.isEqualTo(new NestedFieldFilterScope<>(fieldName, nestedFieldName, value).hashCode()); | |||
assertThat(underTest.hashCode()) | |||
.isNotEqualTo(null) | |||
.isNotEqualTo(new Object().hashCode()) | |||
.isNotEqualTo(new NestedFieldFilterScope<>(fieldName2, nestedFieldName, value).hashCode()) | |||
.isNotEqualTo(new NestedFieldFilterScope<>(fieldName, nestedFieldName2, value).hashCode()) | |||
.isNotEqualTo(new NestedFieldFilterScope<>(fieldName, nestedFieldName, value2).hashCode()) | |||
.isNotEqualTo(new NestedFieldFilterScope<>(fieldName2, nestedFieldName2, value).hashCode()) | |||
.isNotEqualTo(new NestedFieldFilterScope<>(fieldName, nestedFieldName2, value2).hashCode()) | |||
.isNotEqualTo(new NestedFieldFilterScope<>(fieldName2, nestedFieldName, value2).hashCode()) | |||
.isNotEqualTo(new NestedFieldFilterScope<>(fieldName2, nestedFieldName2, value2).hashCode()) | |||
.isNotEqualTo(new SimpleFieldFilterScope(fieldName).hashCode()) | |||
.isNotEqualTo(new SimpleFieldFilterScope(fieldName2)).hashCode(); | |||
} | |||
@Test | |||
public void verify_intersect() { | |||
String fieldName = randomAlphabetic(10); | |||
String nestedFieldName = randomAlphabetic(11); | |||
Object value = new Object(); | |||
String fieldName2 = randomAlphabetic(12); | |||
String nestedFieldName2 = randomAlphabetic(13); | |||
Object value2 = new Object(); | |||
NestedFieldFilterScope<Object> underTest = new NestedFieldFilterScope<>(fieldName, nestedFieldName, value); | |||
assertThat(underTest.intersect(underTest)).isTrue(); | |||
assertThat(underTest.intersect(new NestedFieldFilterScope<>(fieldName, nestedFieldName, value))).isTrue(); | |||
assertThat(underTest.intersect(new NestedFieldFilterScope<>(fieldName2, nestedFieldName, value))).isFalse(); | |||
assertThat(underTest.intersect(new NestedFieldFilterScope<>(fieldName, nestedFieldName2, value))).isFalse(); | |||
assertThat(underTest.intersect(new NestedFieldFilterScope<>(fieldName, nestedFieldName, value2))).isFalse(); | |||
assertThat(underTest.intersect(new NestedFieldFilterScope<>(fieldName2, nestedFieldName2, value))).isFalse(); | |||
assertThat(underTest.intersect(new NestedFieldFilterScope<>(fieldName, nestedFieldName2, value2))).isFalse(); | |||
assertThat(underTest.intersect(new NestedFieldFilterScope<>(fieldName2, nestedFieldName, value2))).isFalse(); | |||
assertThat(underTest.intersect(new NestedFieldFilterScope<>(fieldName2, nestedFieldName2, value2))).isFalse(); | |||
assertThat(underTest.intersect(new SimpleFieldFilterScope(fieldName))).isFalse(); | |||
assertThat(underTest.intersect(new SimpleFieldFilterScope(fieldName2))).isFalse(); | |||
} | |||
} |
@@ -0,0 +1,140 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.es.searchrequest; | |||
import com.tngtech.java.junit.dataprovider.DataProvider; | |||
import com.tngtech.java.junit.dataprovider.DataProviderRunner; | |||
import com.tngtech.java.junit.dataprovider.UseDataProvider; | |||
import java.util.List; | |||
import java.util.Random; | |||
import java.util.Set; | |||
import java.util.stream.Collectors; | |||
import java.util.stream.IntStream; | |||
import org.junit.Test; | |||
import org.junit.runner.RunWith; | |||
import static java.util.Collections.emptyList; | |||
import static java.util.Collections.singletonList; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | |||
@RunWith(DataProviderRunner.class) | |||
public class NestedFieldTopAggregationDefinitionTest { | |||
public static final Random RANDOM = new Random(); | |||
@Test | |||
@UseDataProvider("notOneLevelDeepPaths") | |||
public void constructor_supports_nestedFieldPath_only_one_level_deep(String unsupportedPath) { | |||
String value = randomAlphabetic(7); | |||
boolean sticky = RANDOM.nextBoolean(); | |||
assertThatThrownBy(() -> new NestedFieldTopAggregationDefinition<>(unsupportedPath, value, sticky)) | |||
.isInstanceOf(IllegalArgumentException.class) | |||
.hasMessage("Field path should have only one dot: " + unsupportedPath); | |||
} | |||
@DataProvider | |||
public static Object[][] notOneLevelDeepPaths() { | |||
return new Object[][] { | |||
{""}, | |||
{" "}, | |||
{".."}, | |||
{"a.b."}, | |||
{"a.b.c"}, | |||
{".b.c"}, | |||
{"..."} | |||
}; | |||
} | |||
@Test | |||
@UseDataProvider("emptyFieldNames") | |||
public void constructor_fails_with_IAE_if_empty_field_name(String unsupportedPath, List<String> expectedParsedFieldNames) { | |||
String value = randomAlphabetic(7); | |||
assertThatThrownBy(() -> new NestedFieldTopAggregationDefinition<>(unsupportedPath, value, true)) | |||
.isInstanceOf(IllegalArgumentException.class) | |||
.hasMessage("field path \"" + unsupportedPath + "\" should have exactly 2 non empty field names, got: " + expectedParsedFieldNames); | |||
} | |||
@DataProvider | |||
public static Object[][] emptyFieldNames() { | |||
String str1 = randomAlphabetic(6); | |||
return new Object[][] { | |||
{".", emptyList()}, | |||
{" . ", emptyList()}, | |||
{str1 + ".", singletonList(str1)}, | |||
{str1 + ". ", singletonList(str1)}, | |||
{"." + str1, singletonList(str1)}, | |||
{" . " + str1, singletonList(str1)} | |||
}; | |||
} | |||
@Test | |||
public void constructor_parses_nested_field_path() { | |||
String fieldName = randomAlphabetic(5); | |||
String nestedFieldName = randomAlphabetic(6); | |||
String value = randomAlphabetic(7); | |||
boolean sticky = RANDOM.nextBoolean(); | |||
NestedFieldTopAggregationDefinition<String> underTest = new NestedFieldTopAggregationDefinition<>(fieldName + "." + nestedFieldName, value, sticky); | |||
assertThat(underTest.getFilterScope().getFieldName()).isEqualTo(fieldName); | |||
assertThat(underTest.getFilterScope().getNestedFieldName()).isEqualTo(nestedFieldName); | |||
assertThat(underTest.getFilterScope().getNestedFieldValue()).isEqualTo(value); | |||
assertThat(underTest.isSticky()).isEqualTo(sticky); | |||
} | |||
@Test | |||
public void constructor_fails_with_NPE_if_nestedFieldPath_is_null() { | |||
String value = randomAlphabetic(7); | |||
boolean sticky = RANDOM.nextBoolean(); | |||
assertThatThrownBy(() -> new NestedFieldTopAggregationDefinition<>(null, value, sticky)) | |||
.isInstanceOf(NullPointerException.class) | |||
.hasMessage("nestedFieldPath can't be null"); | |||
} | |||
@Test | |||
public void constructor_fails_with_NPE_if_value_is_null() { | |||
String value = randomAlphabetic(7); | |||
boolean sticky = RANDOM.nextBoolean(); | |||
assertThatThrownBy(() -> new NestedFieldTopAggregationDefinition<>(value, null, sticky)) | |||
.isInstanceOf(NullPointerException.class) | |||
.hasMessage("value can't be null"); | |||
} | |||
@Test | |||
public void getFilterScope_always_returns_the_same_instance() { | |||
String fieldName = randomAlphabetic(5); | |||
String nestedFieldName = randomAlphabetic(6); | |||
String value = randomAlphabetic(7); | |||
boolean sticky = RANDOM.nextBoolean(); | |||
NestedFieldTopAggregationDefinition<String> underTest = new NestedFieldTopAggregationDefinition<>(fieldName + "." + nestedFieldName, value, sticky); | |||
Set<TopAggregationDefinition.FilterScope> filterScopes = IntStream.range(0, 2 + RANDOM.nextInt(200)) | |||
.mapToObj(i -> underTest.getFilterScope()) | |||
.collect(Collectors.toSet()); | |||
assertThat(filterScopes).hasSize(1); | |||
} | |||
} |
@@ -31,14 +31,20 @@ import org.elasticsearch.index.query.BoolQueryBuilder; | |||
import org.elasticsearch.index.query.QueryBuilder; | |||
import org.elasticsearch.index.query.QueryBuilders; | |||
import org.junit.Test; | |||
import org.mockito.Mockito; | |||
import org.sonar.server.es.searchrequest.RequestFiltersComputer.AllFilters; | |||
import org.sonar.server.es.searchrequest.TopAggregationDefinition.FilterScope; | |||
import org.sonar.server.es.searchrequest.TopAggregationDefinition.NestedFieldFilterScope; | |||
import org.sonar.server.es.searchrequest.TopAggregationDefinition.SimpleFieldFilterScope; | |||
import static com.google.common.base.Preconditions.checkState; | |||
import static java.util.stream.Collectors.toSet; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | |||
import static org.elasticsearch.index.query.QueryBuilders.boolQuery; | |||
import static org.mockito.Mockito.mock; | |||
import static org.sonar.server.es.searchrequest.RequestFiltersComputer.newAllFilters; | |||
import static org.sonar.server.es.searchrequest.TopAggregationDefinition.NON_STICKY; | |||
import static org.sonar.server.es.searchrequest.TopAggregationDefinition.STICKY; | |||
public class RequestFiltersComputerTest { | |||
@@ -48,25 +54,25 @@ public class RequestFiltersComputerTest { | |||
public void getTopAggregationFilters_fails_with_IAE_when_no_TopAggregation_provided_in_constructor() { | |||
RequestFiltersComputer underTest = new RequestFiltersComputer(newAllFilters(), Collections.emptySet()); | |||
assertThatThrownBy(() -> underTest.getTopAggregationFilter(Mockito.mock(TopAggregationDefinition.class))) | |||
assertThatThrownBy(() -> underTest.getTopAggregationFilter(mock(TopAggregationDefinition.class))) | |||
.isInstanceOf(IllegalArgumentException.class) | |||
.hasMessage("topAggregation must have been declared in constructor"); | |||
} | |||
@Test | |||
public void getTopAggregationFilters_fails_with_IAE_when_TopAggregation_was_not_provided_in_constructor() { | |||
Set<TopAggregationDefinition> atLeastOneTopAggs = randomNonEmptyTopAggregations(RANDOM::nextBoolean); | |||
Set<TopAggregationDefinition<?>> atLeastOneTopAggs = randomNonEmptyTopAggregations(RANDOM::nextBoolean); | |||
RequestFiltersComputer underTest = new RequestFiltersComputer(newAllFilters(), atLeastOneTopAggs); | |||
atLeastOneTopAggs.forEach(underTest::getTopAggregationFilter); | |||
assertThatThrownBy(() -> underTest.getTopAggregationFilter(Mockito.mock(TopAggregationDefinition.class))) | |||
assertThatThrownBy(() -> underTest.getTopAggregationFilter(mock(TopAggregationDefinition.class))) | |||
.isInstanceOf(IllegalArgumentException.class) | |||
.hasMessage("topAggregation must have been declared in constructor"); | |||
} | |||
@Test | |||
public void getQueryFilters_returns_empty_if_AllFilters_is_empty() { | |||
Set<TopAggregationDefinition> atLeastOneTopAggs = randomNonEmptyTopAggregations(RANDOM::nextBoolean); | |||
Set<TopAggregationDefinition<?>> atLeastOneTopAggs = randomNonEmptyTopAggregations(RANDOM::nextBoolean); | |||
RequestFiltersComputer underTest = new RequestFiltersComputer(newAllFilters(), atLeastOneTopAggs); | |||
assertThat(underTest.getQueryFilters()).isEmpty(); | |||
@@ -74,7 +80,7 @@ public class RequestFiltersComputerTest { | |||
@Test | |||
public void getPostFilters_returns_empty_if_AllFilters_is_empty() { | |||
Set<TopAggregationDefinition> atLeastOneTopAggs = randomNonEmptyTopAggregations(RANDOM::nextBoolean); | |||
Set<TopAggregationDefinition<?>> atLeastOneTopAggs = randomNonEmptyTopAggregations(RANDOM::nextBoolean); | |||
RequestFiltersComputer underTest = new RequestFiltersComputer(newAllFilters(), atLeastOneTopAggs); | |||
assertThat(underTest.getPostFilters()).isEmpty(); | |||
@@ -82,7 +88,7 @@ public class RequestFiltersComputerTest { | |||
@Test | |||
public void getTopAggregationFilter_returns_empty_if_AllFilters_is_empty() { | |||
Set<TopAggregationDefinition> atLeastOneTopAggs = randomNonEmptyTopAggregations(RANDOM::nextBoolean); | |||
Set<TopAggregationDefinition<?>> atLeastOneTopAggs = randomNonEmptyTopAggregations(RANDOM::nextBoolean); | |||
RequestFiltersComputer underTest = new RequestFiltersComputer(newAllFilters(), atLeastOneTopAggs); | |||
atLeastOneTopAggs.forEach(topAgg -> assertThat(underTest.getTopAggregationFilter(topAgg)).isEmpty()); | |||
@@ -107,7 +113,7 @@ public class RequestFiltersComputerTest { | |||
@Test | |||
public void getQueryFilters_contains_all_filters_when_no_declared_sticky_topAggregation() { | |||
AllFilters allFilters = randomNonEmptyAllFilters(); | |||
Set<TopAggregationDefinition> atLeastOneNonStickyTopAggs = randomNonEmptyTopAggregations(() -> false); | |||
Set<TopAggregationDefinition<?>> atLeastOneNonStickyTopAggs = randomNonEmptyTopAggregations(() -> false); | |||
RequestFiltersComputer underTest = new RequestFiltersComputer(allFilters, atLeastOneNonStickyTopAggs); | |||
assertThat(underTest.getQueryFilters().get()).isEqualTo(toBoolQuery(allFilters.stream())); | |||
@@ -116,7 +122,7 @@ public class RequestFiltersComputerTest { | |||
@Test | |||
public void getPostFilters_returns_empty_when_no_declared_sticky_topAggregation() { | |||
AllFilters allFilters = randomNonEmptyAllFilters(); | |||
Set<TopAggregationDefinition> atLeastOneNonStickyTopAggs = randomNonEmptyTopAggregations(() -> false); | |||
Set<TopAggregationDefinition<?>> atLeastOneNonStickyTopAggs = randomNonEmptyTopAggregations(() -> false); | |||
RequestFiltersComputer underTest = new RequestFiltersComputer(allFilters, atLeastOneNonStickyTopAggs); | |||
assertThat(underTest.getPostFilters()).isEmpty(); | |||
@@ -125,7 +131,7 @@ public class RequestFiltersComputerTest { | |||
@Test | |||
public void getTopAggregationFilters_return_empty_when_no_declared_sticky_topAggregation() { | |||
AllFilters allFilters = randomNonEmptyAllFilters(); | |||
Set<TopAggregationDefinition> atLeastOneNonStickyTopAggs = randomNonEmptyTopAggregations(() -> false); | |||
Set<TopAggregationDefinition<?>> atLeastOneNonStickyTopAggs = randomNonEmptyTopAggregations(() -> false); | |||
RequestFiltersComputer underTest = new RequestFiltersComputer(allFilters, atLeastOneNonStickyTopAggs); | |||
atLeastOneNonStickyTopAggs.forEach(topAgg -> assertThat(underTest.getTopAggregationFilter(topAgg)).isEmpty()); | |||
@@ -136,32 +142,36 @@ public class RequestFiltersComputerTest { | |||
AllFilters allFilters = newAllFilters(); | |||
// has topAggs and two filters | |||
String field1 = "field1"; | |||
TopAggregationDefinition stickyTopAggField1 = new TopAggregationDef(field1, true); | |||
TopAggregationDefinition nonStickyTopAggField1 = new TopAggregationDef(field1, false); | |||
SimpleFieldFilterScope filterScopeField1 = new SimpleFieldFilterScope(field1); | |||
SimpleFieldTopAggregationDefinition stickyTopAggField1 = new SimpleFieldTopAggregationDefinition(field1, STICKY); | |||
SimpleFieldTopAggregationDefinition nonStickyTopAggField1 = new SimpleFieldTopAggregationDefinition(field1, NON_STICKY); | |||
QueryBuilder filterField1_1 = newQuery(); | |||
QueryBuilder filterField1_2 = newQuery(); | |||
allFilters.addFilter(field1, filterField1_1); | |||
allFilters.addFilter(field1 + "_2", field1, filterField1_2); | |||
allFilters.addFilter("filter_field1_1", filterScopeField1, filterField1_1); | |||
allFilters.addFilter("filter_field1_2", filterScopeField1, filterField1_2); | |||
// has topAggs and one filter | |||
String field2 = "field2"; | |||
TopAggregationDefinition stickyTopAggField2 = new TopAggregationDef(field2, true); | |||
TopAggregationDefinition nonStickyTopAggField2 = new TopAggregationDef(field2, false); | |||
SimpleFieldFilterScope filterScopeField2 = new SimpleFieldFilterScope(field2); | |||
SimpleFieldTopAggregationDefinition stickyTopAggField2 = new SimpleFieldTopAggregationDefinition(field2, STICKY); | |||
SimpleFieldTopAggregationDefinition nonStickyTopAggField2 = new SimpleFieldTopAggregationDefinition(field2, NON_STICKY); | |||
QueryBuilder filterField2 = newQuery(); | |||
allFilters.addFilter(field2, filterField2); | |||
allFilters.addFilter("filter_field2", filterScopeField2, filterField2); | |||
// has only non-sticky top-agg and one filter | |||
String field3 = "field3"; | |||
TopAggregationDefinition nonStickyTopAggField3 = new TopAggregationDef(field3, false); | |||
SimpleFieldFilterScope filterScopeField3 = new SimpleFieldFilterScope(field3); | |||
SimpleFieldTopAggregationDefinition nonStickyTopAggField3 = new SimpleFieldTopAggregationDefinition(field3, NON_STICKY); | |||
QueryBuilder filterField3 = newQuery(); | |||
allFilters.addFilter(field3, filterField3); | |||
allFilters.addFilter("filter_field3", filterScopeField3, filterField3); | |||
// has one filter but no top agg | |||
String field4 = "field4"; | |||
SimpleFieldFilterScope filterScopeField4 = new SimpleFieldFilterScope(field4); | |||
QueryBuilder filterField4 = newQuery(); | |||
allFilters.addFilter(field4, filterField4); | |||
allFilters.addFilter("filter_field4", filterScopeField4, filterField4); | |||
// has top-aggs by no filter | |||
String field5 = "field5"; | |||
TopAggregationDefinition stickyTopAggField5 = new TopAggregationDef(field5, true); | |||
TopAggregationDefinition nonStickyTopAggField5 = new TopAggregationDef(field5, false); | |||
Set<TopAggregationDefinition> declaredTopAggregations = ImmutableSet.of( | |||
SimpleFieldTopAggregationDefinition stickyTopAggField5 = new SimpleFieldTopAggregationDefinition(field5, STICKY); | |||
SimpleFieldTopAggregationDefinition nonStickyTopAggField5 = new SimpleFieldTopAggregationDefinition(field5, NON_STICKY); | |||
Set<TopAggregationDefinition<?>> declaredTopAggregations = ImmutableSet.of( | |||
stickyTopAggField1, nonStickyTopAggField1, | |||
stickyTopAggField2, nonStickyTopAggField2, | |||
nonStickyTopAggField3, | |||
@@ -170,45 +180,240 @@ public class RequestFiltersComputerTest { | |||
RequestFiltersComputer underTest = new RequestFiltersComputer(allFilters, declaredTopAggregations); | |||
assertThat(underTest.getQueryFilters().get()).isEqualTo(toBoolQuery(filterField3, filterField4)); | |||
BoolQueryBuilder postFilterQuery = toBoolQuery(filterField1_1, filterField1_2, filterField2); | |||
assertThat(underTest.getPostFilters().get()).isEqualTo(postFilterQuery); | |||
assertThat(underTest.getTopAggregationFilter(stickyTopAggField1).get()).isEqualTo(toBoolQuery(filterField2)); | |||
assertThat(underTest.getTopAggregationFilter(nonStickyTopAggField1).get()).isEqualTo(postFilterQuery); | |||
assertThat(underTest.getTopAggregationFilter(stickyTopAggField2).get()).isEqualTo(toBoolQuery(filterField1_1, filterField1_2)); | |||
assertThat(underTest.getTopAggregationFilter(nonStickyTopAggField2).get()).isEqualTo(postFilterQuery); | |||
assertThat(underTest.getTopAggregationFilter(nonStickyTopAggField3).get()).isEqualTo(postFilterQuery); | |||
assertThat(underTest.getTopAggregationFilter(stickyTopAggField5).get()).isEqualTo(postFilterQuery); | |||
assertThat(underTest.getTopAggregationFilter(nonStickyTopAggField5).get()).isEqualTo(postFilterQuery); | |||
QueryBuilder[] postFilters = {filterField1_1, filterField1_2, filterField2}; | |||
assertThat(underTest.getPostFilters().get()).isEqualTo(toBoolQuery(postFilters)); | |||
assertTopAggregationFilter(underTest, stickyTopAggField1, filterField2); | |||
assertTopAggregationFilter(underTest, nonStickyTopAggField1, postFilters); | |||
assertTopAggregationFilter(underTest, stickyTopAggField2, filterField1_1, filterField1_2); | |||
assertTopAggregationFilter(underTest, nonStickyTopAggField2, postFilters); | |||
assertTopAggregationFilter(underTest, nonStickyTopAggField3, postFilters); | |||
assertTopAggregationFilter(underTest, stickyTopAggField5, postFilters); | |||
assertTopAggregationFilter(underTest, nonStickyTopAggField5, postFilters); | |||
} | |||
@Test | |||
public void getTopAggregationFilters_returns_empty_on_sticky_TopAgg_when_no_other_sticky_TopAgg() { | |||
public void getTopAggregationFilters_returns_empty_on_sticky_field_TopAgg_when_no_other_sticky_TopAgg() { | |||
AllFilters allFilters = newAllFilters(); | |||
// has topAggs and two filters | |||
String field1 = "field1"; | |||
TopAggregationDefinition stickyTopAggField1 = new TopAggregationDef(field1, true); | |||
TopAggregationDefinition nonStickyTopAggField1 = new TopAggregationDef(field1, false); | |||
SimpleFieldFilterScope filterScopeField1 = new SimpleFieldFilterScope(field1); | |||
SimpleFieldTopAggregationDefinition stickyTopAggField1 = new SimpleFieldTopAggregationDefinition(field1, STICKY); | |||
SimpleFieldTopAggregationDefinition nonStickyTopAggField1 = new SimpleFieldTopAggregationDefinition(field1, NON_STICKY); | |||
QueryBuilder filterField1_1 = newQuery(); | |||
QueryBuilder filterField1_2 = newQuery(); | |||
allFilters.addFilter(field1, filterField1_1); | |||
allFilters.addFilter(field1 + "_2", field1, filterField1_2); | |||
allFilters.addFilter("filter_field1_1", filterScopeField1, filterField1_1); | |||
allFilters.addFilter("filter_field1_2", filterScopeField1, filterField1_2); | |||
// has only non-sticky top-agg and one filter | |||
String field2 = "field2"; | |||
TopAggregationDefinition nonStickyTopAggField2 = new TopAggregationDef(field2, false); | |||
SimpleFieldFilterScope filterScopeField2 = new SimpleFieldFilterScope(field2); | |||
SimpleFieldTopAggregationDefinition nonStickyTopAggField2 = new SimpleFieldTopAggregationDefinition(field2, NON_STICKY); | |||
QueryBuilder filterField2 = newQuery(); | |||
allFilters.addFilter(field2, filterField2); | |||
Set<TopAggregationDefinition> declaredTopAggregations = ImmutableSet.of( | |||
allFilters.addFilter("filter_field2", filterScopeField2, filterField2); | |||
Set<TopAggregationDefinition<?>> declaredTopAggregations = ImmutableSet.of( | |||
stickyTopAggField1, nonStickyTopAggField1, | |||
nonStickyTopAggField2); | |||
RequestFiltersComputer underTest = new RequestFiltersComputer(allFilters, declaredTopAggregations); | |||
assertThat(underTest.getQueryFilters().get()).isEqualTo(toBoolQuery(filterField2)); | |||
BoolQueryBuilder postFilterQuery = toBoolQuery(filterField1_1, filterField1_2); | |||
assertThat(underTest.getPostFilters().get()).isEqualTo(postFilterQuery); | |||
QueryBuilder[] postFilters = {filterField1_1, filterField1_2}; | |||
assertThat(underTest.getPostFilters().get()).isEqualTo(toBoolQuery(postFilters)); | |||
assertThat(underTest.getTopAggregationFilter(stickyTopAggField1)).isEmpty(); | |||
assertThat(underTest.getTopAggregationFilter(nonStickyTopAggField1).get()).isEqualTo(postFilterQuery); | |||
assertThat(underTest.getTopAggregationFilter(nonStickyTopAggField2).get()).isEqualTo(postFilterQuery); | |||
assertTopAggregationFilter(underTest, nonStickyTopAggField1, postFilters); | |||
assertTopAggregationFilter(underTest, nonStickyTopAggField2, postFilters); | |||
} | |||
@Test | |||
public void filters_on_nestedField_of_sticky_TopAggregation_go_to_PostFilters_and_TopAgg_Filters_on_other_values_of_same_nestField() { | |||
String field1 = "field"; | |||
String nestField = "nestedField"; | |||
String nestField_value1 = "nestedField_value1"; | |||
String nestField_value2 = "nestedField_value2"; | |||
String nestField_value3 = "nestedField_value3"; | |||
String nestField_value4 = "nestedField_value4"; | |||
String nestField_value5 = "nestedField_value5"; | |||
AllFilters allFilters = newAllFilters(); | |||
// has topAggs and two filters | |||
NestedFieldFilterScope<String> filterScopeNestField_value1 = new NestedFieldFilterScope<>(field1, nestField, nestField_value1); | |||
NestedFieldTopAggregationDefinition<String> stickyTopAggField1 = newNestedFieldTopAggDef(field1, nestField, nestField_value1, STICKY); | |||
NestedFieldTopAggregationDefinition<String> nonStickyTopAggField1 = newNestedFieldTopAggDef(field1, nestField, nestField_value1, NON_STICKY); | |||
QueryBuilder filterField1_1 = newQuery(); | |||
QueryBuilder filterField1_2 = newQuery(); | |||
allFilters.addFilter("filter_field1_1", filterScopeNestField_value1, filterField1_1); | |||
allFilters.addFilter("filter_field1_2", filterScopeNestField_value1, filterField1_2); | |||
// has topAggs and one filter | |||
NestedFieldFilterScope<String> filterScopeNestField_value2 = new NestedFieldFilterScope<>(field1, nestField, nestField_value2); | |||
NestedFieldTopAggregationDefinition<String> stickyTopAggField2 = newNestedFieldTopAggDef(field1, nestField, nestField_value2, STICKY); | |||
NestedFieldTopAggregationDefinition<String> nonStickyTopAggField2 = newNestedFieldTopAggDef(field1, nestField, nestField_value2, NON_STICKY); | |||
QueryBuilder filterField2 = newQuery(); | |||
allFilters.addFilter("filter_field2", filterScopeNestField_value2, filterField2); | |||
// has only non-sticky top-agg and one filter | |||
NestedFieldFilterScope<String> filterScopeField3 = new NestedFieldFilterScope<>(field1, nestField, nestField_value3); | |||
NestedFieldTopAggregationDefinition<String> nonStickyTopAggField3 = newNestedFieldTopAggDef(field1, nestField, nestField_value3, NON_STICKY); | |||
QueryBuilder filterField3 = newQuery(); | |||
allFilters.addFilter("filter_field3", filterScopeField3, filterField3); | |||
// has one filter but no top agg | |||
NestedFieldFilterScope<String> filterScopeField4 = new NestedFieldFilterScope<>(field1, nestField, nestField_value4); | |||
QueryBuilder filterField4 = newQuery(); | |||
allFilters.addFilter("filter_field4", filterScopeField4, filterField4); | |||
// has top-aggs by no filter | |||
String field5 = "field5"; | |||
NestedFieldTopAggregationDefinition<String> stickyTopAggField5 = newNestedFieldTopAggDef(field1, nestField, nestField_value5, STICKY); | |||
NestedFieldTopAggregationDefinition<String> nonStickyTopAggField5 = newNestedFieldTopAggDef(field1, nestField, nestField_value5, NON_STICKY); | |||
Set<TopAggregationDefinition<?>> declaredTopAggregations = ImmutableSet.of( | |||
stickyTopAggField1, nonStickyTopAggField1, | |||
stickyTopAggField2, nonStickyTopAggField2, | |||
nonStickyTopAggField3, | |||
stickyTopAggField5, nonStickyTopAggField5); | |||
RequestFiltersComputer underTest = new RequestFiltersComputer(allFilters, declaredTopAggregations); | |||
assertThat(underTest.getQueryFilters().get()).isEqualTo(toBoolQuery(filterField3, filterField4)); | |||
QueryBuilder[] postFilters = {filterField1_1, filterField1_2, filterField2}; | |||
assertThat(underTest.getPostFilters().get()).isEqualTo(toBoolQuery(postFilters)); | |||
assertTopAggregationFilter(underTest, stickyTopAggField1, filterField2); | |||
assertTopAggregationFilter(underTest, nonStickyTopAggField1, postFilters); | |||
assertTopAggregationFilter(underTest, stickyTopAggField2, filterField1_1, filterField1_2); | |||
assertTopAggregationFilter(underTest, nonStickyTopAggField2, postFilters); | |||
assertTopAggregationFilter(underTest, nonStickyTopAggField3, postFilters); | |||
assertTopAggregationFilter(underTest, stickyTopAggField5, postFilters); | |||
assertTopAggregationFilter(underTest, nonStickyTopAggField5, postFilters); | |||
} | |||
@Test | |||
public void filters_on_nestedField_of_sticky_TopAggregation_go_to_PostFilters_and_TopAgg_Filters_on_other_fields() { | |||
String field1 = "field1"; | |||
String field2 = "field2"; | |||
String field3 = "field3"; | |||
String nestField = "nestedField"; | |||
String nestField_value1 = "nestedField_value1"; | |||
String nestField_value2 = "nestedField_value2"; | |||
AllFilters allFilters = newAllFilters(); | |||
// filter without top aggregation | |||
QueryBuilder queryFilter = newQuery("query_filter"); | |||
allFilters.addFilter("query_filter", new SimpleFieldFilterScope("text"), queryFilter); | |||
// nestedField of field1 with value1: has topAggs and two filters | |||
NestedFieldFilterScope<String> filterScopeNestField1_value1 = new NestedFieldFilterScope<>(field1, nestField, nestField_value1); | |||
NestedFieldTopAggregationDefinition<String> stickyTopAggNestedField1_value1 = newNestedFieldTopAggDef(field1, nestField, nestField_value1, STICKY); | |||
NestedFieldTopAggregationDefinition<String> nonStickyTopAggNestedField1_value1 = newNestedFieldTopAggDef(field1, nestField, nestField_value1, NON_STICKY); | |||
QueryBuilder filterNestedField1_value1_1 = newQuery("filterNestedField1_value1_1"); | |||
QueryBuilder filterNestedField1_value1_2 = newQuery("filterNestedField1_value1_2"); | |||
allFilters.addFilter("filter_nested_field1_value1_1", filterScopeNestField1_value1, filterNestedField1_value1_1); | |||
allFilters.addFilter("filter_nested_field1_value1_2", filterScopeNestField1_value1, filterNestedField1_value1_2); | |||
// nestedField of field1 with value2: has topAggs and two filters | |||
NestedFieldFilterScope<String> filterScopeNestField1_value2 = new NestedFieldFilterScope<>(field1, nestField, nestField_value2); | |||
NestedFieldTopAggregationDefinition<String> stickyTopAggNestedField1_value2 = newNestedFieldTopAggDef(field1, nestField, nestField_value2, STICKY); | |||
NestedFieldTopAggregationDefinition<String> nonStickyTopAggNestedField1_value2 = newNestedFieldTopAggDef(field1, nestField, nestField_value2, NON_STICKY); | |||
QueryBuilder filterNestedField1_value2_1 = newQuery("filterNestedField1_value2_1"); | |||
QueryBuilder filterNestedField1_value2_2 = newQuery("filterNestedField1_value2_2"); | |||
allFilters.addFilter("filter_nested_field1_value2_1", filterScopeNestField1_value2, filterNestedField1_value2_1); | |||
allFilters.addFilter("filter_nested_field1_value2_2", filterScopeNestField1_value2, filterNestedField1_value2_2); | |||
// [EDGE CASE] topAgg directly on field1: has topAggs and two filters | |||
SimpleFieldFilterScope filterScopeField1 = new SimpleFieldFilterScope(field1); | |||
SimpleFieldTopAggregationDefinition stickyTopAggField1 = new SimpleFieldTopAggregationDefinition(field1, STICKY); | |||
SimpleFieldTopAggregationDefinition nonStickyTopAggField1 = new SimpleFieldTopAggregationDefinition(field1, NON_STICKY); | |||
QueryBuilder filterField1_1 = newQuery("filterField1_1"); | |||
QueryBuilder filterField1_2 = newQuery("filterField1_2"); | |||
allFilters.addFilter("filter_field1_1", filterScopeField1, filterField1_1); | |||
allFilters.addFilter("filter_field1_2", filterScopeField1, filterField1_2); | |||
// other field: has topAggs and two filters too | |||
SimpleFieldFilterScope filterScopeField2 = new SimpleFieldFilterScope(field2); | |||
SimpleFieldTopAggregationDefinition stickyTopAggField2 = new SimpleFieldTopAggregationDefinition(field2, STICKY); | |||
SimpleFieldTopAggregationDefinition nonStickyTopAggField2 = new SimpleFieldTopAggregationDefinition(field2, NON_STICKY); | |||
QueryBuilder filterField2_1 = newQuery("filterField2_1"); | |||
QueryBuilder filterField2_2 = newQuery("filterField2_2"); | |||
allFilters.addFilter("filter_field2_1", filterScopeField2, filterField2_1); | |||
allFilters.addFilter("filter_field2_2", filterScopeField2, filterField2_2); | |||
// nestedField of another field (even though nestedField name and values are the same): has topAggs and two filters | |||
NestedFieldFilterScope<String> filterScopeNestField3_value = new NestedFieldFilterScope<>(field3, nestField, nestField_value1); | |||
NestedFieldTopAggregationDefinition<String> stickyTopAggNestedField3 = newNestedFieldTopAggDef(field3, nestField, nestField_value1, STICKY); | |||
NestedFieldTopAggregationDefinition<String> nonStickyTopAggNestedField3 = newNestedFieldTopAggDef(field3, nestField, nestField_value1, NON_STICKY); | |||
QueryBuilder filterNestedField3_1 = newQuery("filterNestedField3_1"); | |||
QueryBuilder filterNestedField3_2 = newQuery("filterNestedField3_2"); | |||
allFilters.addFilter("filter_nested_field3_1", filterScopeNestField3_value, filterNestedField3_1); | |||
allFilters.addFilter("filter_nested_field3_2", filterScopeNestField3_value, filterNestedField3_2); | |||
Set<TopAggregationDefinition<?>> declaredTopAggregations = ImmutableSet.of( | |||
stickyTopAggNestedField1_value1, nonStickyTopAggNestedField1_value1, | |||
stickyTopAggNestedField1_value2, nonStickyTopAggNestedField1_value2, | |||
stickyTopAggField1, nonStickyTopAggField1, | |||
stickyTopAggField2, nonStickyTopAggField2, | |||
stickyTopAggNestedField3, nonStickyTopAggNestedField3); | |||
RequestFiltersComputer underTest = new RequestFiltersComputer(allFilters, declaredTopAggregations); | |||
assertThat(underTest.getQueryFilters().get()).isEqualTo(toBoolQuery(queryFilter)); | |||
QueryBuilder[] postFilters = { | |||
filterNestedField1_value1_1, filterNestedField1_value1_2, | |||
filterNestedField1_value2_1, filterNestedField1_value2_2, | |||
filterField1_1, filterField1_2, | |||
filterField2_1, filterField2_2, | |||
filterNestedField3_1, filterNestedField3_2}; | |||
assertThat(underTest.getPostFilters().get()).isEqualTo(toBoolQuery(postFilters)); | |||
assertTopAggregationFilter(underTest, stickyTopAggNestedField1_value1, | |||
filterNestedField1_value2_1, filterNestedField1_value2_2, | |||
filterField1_1, filterField1_2, | |||
filterField2_1, filterField2_2, | |||
filterNestedField3_1, filterNestedField3_2); | |||
assertTopAggregationFilter(underTest, nonStickyTopAggNestedField1_value1, postFilters); | |||
assertTopAggregationFilter(underTest, stickyTopAggNestedField1_value2, | |||
filterNestedField1_value1_1, filterNestedField1_value1_2, | |||
filterField1_1, filterField1_2, | |||
filterField2_1, filterField2_2, | |||
filterNestedField3_1, filterNestedField3_2); | |||
assertTopAggregationFilter(underTest, nonStickyTopAggNestedField1_value2, postFilters); | |||
assertTopAggregationFilter(underTest, stickyTopAggField1, | |||
filterField2_1, filterField2_2, | |||
filterNestedField3_1, filterNestedField3_2); | |||
assertTopAggregationFilter(underTest, nonStickyTopAggField1, postFilters); | |||
assertTopAggregationFilter(underTest, stickyTopAggField2, | |||
filterNestedField1_value1_1, filterNestedField1_value1_2, | |||
filterNestedField1_value2_1, filterNestedField1_value2_2, | |||
filterField1_1, filterField1_2, | |||
filterNestedField3_1, filterNestedField3_2); | |||
assertTopAggregationFilter(underTest, nonStickyTopAggField2, postFilters); | |||
assertTopAggregationFilter(underTest, stickyTopAggNestedField3, | |||
filterNestedField1_value1_1, filterNestedField1_value1_2, | |||
filterNestedField1_value2_1, filterNestedField1_value2_2, | |||
filterField1_1, filterField1_2, | |||
filterField2_1, filterField2_2); | |||
assertTopAggregationFilter(underTest, nonStickyTopAggNestedField3, postFilters); | |||
} | |||
@Test | |||
public void getTopAggregationFilters_returns_empty_on_sticky_nestedField_TopAgg_when_no_other_sticky_TopAgg() { | |||
String field1 = "field"; | |||
String nestField = "nestedField"; | |||
String nestField_value1 = "nestedField_value1"; | |||
String nestField_value2 = "nestedField_value2"; | |||
AllFilters allFilters = newAllFilters(); | |||
// has topAggs and two filters | |||
NestedFieldFilterScope<String> filterScopeField1 = new NestedFieldFilterScope<>(field1, nestField, nestField_value1); | |||
NestedFieldTopAggregationDefinition<String> stickyTopAggField1 = newNestedFieldTopAggDef(field1, nestField, nestField_value1, STICKY); | |||
NestedFieldTopAggregationDefinition<String> nonStickyTopAggField1 = newNestedFieldTopAggDef(field1, nestField, nestField_value1, NON_STICKY); | |||
QueryBuilder filterField1_1 = newQuery(); | |||
QueryBuilder filterField1_2 = newQuery(); | |||
allFilters.addFilter("filter_field1_1", filterScopeField1, filterField1_1); | |||
allFilters.addFilter("filter_field1_2", filterScopeField1, filterField1_2); | |||
// has only non-sticky top-agg and one filter | |||
NestedFieldFilterScope<String> filterScopeField2 = new NestedFieldFilterScope<>(field1, nestField, nestField_value2); | |||
NestedFieldTopAggregationDefinition<String> nonStickyTopAggField2 = newNestedFieldTopAggDef(field1, nestField, nestField_value2, NON_STICKY); | |||
QueryBuilder filterField2 = newQuery(); | |||
allFilters.addFilter("filter_field2", filterScopeField2, filterField2); | |||
Set<TopAggregationDefinition<?>> declaredTopAggregations = ImmutableSet.of( | |||
stickyTopAggField1, nonStickyTopAggField1, | |||
nonStickyTopAggField2); | |||
RequestFiltersComputer underTest = new RequestFiltersComputer(allFilters, declaredTopAggregations); | |||
assertThat(underTest.getQueryFilters().get()).isEqualTo(toBoolQuery(filterField2)); | |||
QueryBuilder[] postFilters = {filterField1_1, filterField1_2}; | |||
assertThat(underTest.getPostFilters().get()).isEqualTo(toBoolQuery(postFilters)); | |||
assertThat(underTest.getTopAggregationFilter(stickyTopAggField1)).isEmpty(); | |||
assertTopAggregationFilter(underTest, nonStickyTopAggField1, postFilters); | |||
assertTopAggregationFilter(underTest, nonStickyTopAggField2, postFilters); | |||
} | |||
@Test | |||
@@ -216,34 +421,36 @@ public class RequestFiltersComputerTest { | |||
AllFilters allFilters = newAllFilters(); | |||
// has topAggs and two filters | |||
String field1 = "field1"; | |||
TopAggregationDefinition stickyTopAggField1 = new TopAggregationDef(field1, true); | |||
TopAggregationDefinition nonStickyTopAggField1 = new TopAggregationDef(field1, false); | |||
SimpleFieldFilterScope filterScopeField1 = new SimpleFieldFilterScope(field1); | |||
SimpleFieldTopAggregationDefinition stickyTopAggField1 = new SimpleFieldTopAggregationDefinition(field1, STICKY); | |||
SimpleFieldTopAggregationDefinition nonStickyTopAggField1 = new SimpleFieldTopAggregationDefinition(field1, NON_STICKY); | |||
QueryBuilder filterField1_1 = newQuery(); | |||
QueryBuilder filterField1_2 = newQuery(); | |||
allFilters.addFilter(field1, filterField1_1); | |||
allFilters.addFilter(field1 + "_2", field1, filterField1_2); | |||
allFilters.addFilter("filter_field1_1", filterScopeField1, filterField1_1); | |||
allFilters.addFilter("filter_field1_2", filterScopeField1, filterField1_2); | |||
// has only sticky top-agg and one filter | |||
String field2 = "field2"; | |||
TopAggregationDefinition stickyTopAggField2 = new TopAggregationDef(field2, true); | |||
SimpleFieldFilterScope filterScopeField2 = new SimpleFieldFilterScope(field2); | |||
SimpleFieldTopAggregationDefinition stickyTopAggField2 = new SimpleFieldTopAggregationDefinition(field2, STICKY); | |||
QueryBuilder filterField2 = newQuery(); | |||
allFilters.addFilter(field2, filterField2); | |||
Set<TopAggregationDefinition> declaredTopAggregations = ImmutableSet.of( | |||
allFilters.addFilter("filter_field2", filterScopeField2, filterField2); | |||
Set<TopAggregationDefinition<?>> declaredTopAggregations = ImmutableSet.of( | |||
stickyTopAggField1, nonStickyTopAggField1, | |||
stickyTopAggField2); | |||
RequestFiltersComputer underTest = new RequestFiltersComputer(allFilters, declaredTopAggregations); | |||
assertThat(underTest.getQueryFilters()).isEmpty(); | |||
BoolQueryBuilder postFilterQuery = toBoolQuery(filterField1_1, filterField1_2, filterField2); | |||
assertThat(underTest.getPostFilters().get()).isEqualTo(postFilterQuery); | |||
assertThat(underTest.getTopAggregationFilter(stickyTopAggField1).get()).isEqualTo(toBoolQuery(filterField2)); | |||
assertThat(underTest.getTopAggregationFilter(nonStickyTopAggField1).get()).isEqualTo(postFilterQuery); | |||
assertThat(underTest.getTopAggregationFilter(stickyTopAggField2).get()).isEqualTo(toBoolQuery(filterField1_1, filterField1_2)); | |||
QueryBuilder[] postFilters = {filterField1_1, filterField1_2, filterField2}; | |||
assertThat(underTest.getPostFilters().get()).isEqualTo(toBoolQuery(postFilters)); | |||
assertTopAggregationFilter(underTest, stickyTopAggField1, filterField2); | |||
assertTopAggregationFilter(underTest, nonStickyTopAggField1, postFilters); | |||
assertTopAggregationFilter(underTest, stickyTopAggField2, filterField1_1, filterField1_2); | |||
} | |||
private static Set<TopAggregationDefinition> randomNonEmptyTopAggregations(Supplier<Boolean> isSticky) { | |||
private static Set<TopAggregationDefinition<?>> randomNonEmptyTopAggregations(Supplier<Boolean> isSticky) { | |||
return IntStream.range(0, 1 + RANDOM.nextInt(20)) | |||
.mapToObj(i -> new TopAggregationDef("field_" + i, isSticky.get())) | |||
.mapToObj(i -> new SimpleFieldTopAggregationDefinition("field_" + i, isSticky.get())) | |||
.collect(toSet()); | |||
} | |||
@@ -252,19 +459,28 @@ public class RequestFiltersComputerTest { | |||
Stream.of(first), Arrays.stream(others))); | |||
} | |||
private static BoolQueryBuilder toBoolQuery(QueryBuilder[] subQueries) { | |||
return toBoolQuery(Arrays.stream(subQueries)); | |||
} | |||
private static BoolQueryBuilder toBoolQuery(Stream<QueryBuilder> stream) { | |||
BoolQueryBuilder res = boolQuery(); | |||
stream.forEach(res::must); | |||
checkState(res.hasClauses(), "empty stream is not supported"); | |||
return res; | |||
} | |||
private static AllFilters randomNonEmptyAllFilters() { | |||
AllFilters res = newAllFilters(); | |||
IntStream.range(0, 1 + RANDOM.nextInt(22)) | |||
.forEach(i -> res.addFilter("field_" + i, newQuery())); | |||
.forEach(i -> res.addFilter("filter_" + i, mock(FilterScope.class), newQuery())); | |||
return res; | |||
} | |||
private static NestedFieldTopAggregationDefinition<String> newNestedFieldTopAggDef(String field1, String nestField, String nestField_value1, boolean sticky) { | |||
return new NestedFieldTopAggregationDefinition<>(field1 + "." + nestField, nestField_value1, sticky); | |||
} | |||
private static int queryCounter = 0; | |||
/** | |||
@@ -273,4 +489,18 @@ public class RequestFiltersComputerTest { | |||
private static QueryBuilder newQuery() { | |||
return QueryBuilders.termQuery("query_" + (queryCounter++), "foo"); | |||
} | |||
private static QueryBuilder newQuery(String label) { | |||
return QueryBuilders.termQuery("query_" + label, "foo"); | |||
} | |||
private static void assertTopAggregationFilter(RequestFiltersComputer underTest, | |||
TopAggregationDefinition<?> topAggregation, QueryBuilder firstFilter, QueryBuilder... otherFilters) { | |||
assertThat(underTest.getTopAggregationFilter(topAggregation).get()).isEqualTo(toBoolQuery(firstFilter, otherFilters)); | |||
} | |||
private static void assertTopAggregationFilter(RequestFiltersComputer underTest, | |||
TopAggregationDefinition<?> topAggregation, QueryBuilder[] filters) { | |||
assertThat(underTest.getTopAggregationFilter(topAggregation).get()).isEqualTo(toBoolQuery(filters)); | |||
} | |||
} |
@@ -0,0 +1,92 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.es.searchrequest; | |||
import org.junit.Test; | |||
import org.sonar.server.es.searchrequest.TopAggregationDefinition.NestedFieldFilterScope; | |||
import org.sonar.server.es.searchrequest.TopAggregationDefinition.SimpleFieldFilterScope; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | |||
public class SimpleFieldFilterScopeTest { | |||
@Test | |||
public void constructor_fails_with_NPE_if_fieldName_is_null() { | |||
assertThatThrownBy(() -> new SimpleFieldFilterScope(null)) | |||
.isInstanceOf(NullPointerException.class) | |||
.hasMessage("fieldName can't be null"); | |||
} | |||
@Test | |||
public void getFieldName() { | |||
String fieldName = randomAlphabetic(12); | |||
SimpleFieldFilterScope underTest = new SimpleFieldFilterScope(fieldName); | |||
assertThat(underTest.getFieldName()).isEqualTo(fieldName); | |||
} | |||
@Test | |||
public void verify_equals() { | |||
String fieldName1 = randomAlphabetic(11); | |||
String fieldName2 = randomAlphabetic(12); | |||
SimpleFieldFilterScope underTest = new SimpleFieldFilterScope(fieldName1); | |||
assertThat(underTest) | |||
.isEqualTo(underTest) | |||
.isEqualTo(new SimpleFieldFilterScope(fieldName1)); | |||
assertThat(underTest) | |||
.isNotEqualTo(null) | |||
.isNotEqualTo(new Object()) | |||
.isNotEqualTo(new SimpleFieldFilterScope(fieldName2)) | |||
.isNotEqualTo(new NestedFieldFilterScope<>(fieldName1, "foo", "bar")) | |||
.isNotEqualTo(new NestedFieldFilterScope<>(fieldName2, "foo", "bar")); | |||
} | |||
@Test | |||
public void verify_hashcode() { | |||
String fieldName1 = randomAlphabetic(11); | |||
String fieldName2 = randomAlphabetic(12); | |||
SimpleFieldFilterScope underTest = new SimpleFieldFilterScope(fieldName1); | |||
assertThat(underTest.hashCode()) | |||
.isEqualTo(underTest.hashCode()) | |||
.isEqualTo(new SimpleFieldFilterScope(fieldName1).hashCode()); | |||
assertThat(underTest.hashCode()) | |||
.isNotEqualTo(null) | |||
.isNotEqualTo(new Object().hashCode()) | |||
.isNotEqualTo(new SimpleFieldFilterScope(fieldName2).hashCode()) | |||
.isNotEqualTo(new NestedFieldFilterScope<>(fieldName1, "foo", "bar").hashCode()) | |||
.isNotEqualTo(new NestedFieldFilterScope<>(fieldName1, "foo", "bar").hashCode()); | |||
} | |||
@Test | |||
public void verify_intersect() { | |||
String fieldName1 = randomAlphabetic(11); | |||
String fieldName2 = randomAlphabetic(12); | |||
SimpleFieldFilterScope underTest = new SimpleFieldFilterScope(fieldName1); | |||
assertThat(underTest.intersect(underTest)).isTrue(); | |||
assertThat(underTest.intersect(new SimpleFieldFilterScope(fieldName1))).isTrue(); | |||
assertThat(underTest.intersect(new SimpleFieldFilterScope(fieldName2))).isFalse(); | |||
assertThat(underTest.intersect(new NestedFieldFilterScope<>(fieldName1, "foo", "bar"))).isTrue(); | |||
assertThat(underTest.intersect(new NestedFieldFilterScope<>(fieldName2, "foo", "bar"))).isFalse(); | |||
} | |||
} |
@@ -20,33 +20,52 @@ | |||
package org.sonar.server.es.searchrequest; | |||
import java.util.Random; | |||
import java.util.Set; | |||
import java.util.stream.Collectors; | |||
import java.util.stream.IntStream; | |||
import org.apache.commons.lang.RandomStringUtils; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
public class TopAggregationDefTest { | |||
public class SimpleFieldTopAggregationDefinitionTest { | |||
private static final Random RANDOM = new Random(); | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
@Test | |||
public void fieldName_cannot_be_null() { | |||
boolean sticky = new Random().nextBoolean(); | |||
boolean sticky = RANDOM.nextBoolean(); | |||
expectedException.expect(NullPointerException.class); | |||
expectedException.expectMessage("fieldName can't be null"); | |||
new TopAggregationDef(null, sticky); | |||
new SimpleFieldTopAggregationDefinition(null, sticky); | |||
} | |||
@Test | |||
public void getters() { | |||
String fieldName = RandomStringUtils.randomAlphabetic(12); | |||
boolean sticky = new Random().nextBoolean(); | |||
TopAggregationDef underTest = new TopAggregationDef(fieldName, sticky); | |||
SimpleFieldTopAggregationDefinition underTest = new SimpleFieldTopAggregationDefinition(fieldName, sticky); | |||
assertThat(underTest.getFieldName()).isEqualTo(fieldName); | |||
assertThat(underTest.getFilterScope().getFieldName()).isEqualTo(fieldName); | |||
assertThat(underTest.isSticky()).isEqualTo(sticky); | |||
} | |||
@Test | |||
public void getFilterScope_always_returns_the_same_instance() { | |||
String fieldName = randomAlphabetic(12); | |||
boolean sticky = RANDOM.nextBoolean(); | |||
SimpleFieldTopAggregationDefinition underTest = new SimpleFieldTopAggregationDefinition(fieldName, sticky); | |||
Set<TopAggregationDefinition.FilterScope> filterScopes = IntStream.range(0, 2 + RANDOM.nextInt(200)) | |||
.mapToObj(i -> underTest.getFilterScope()) | |||
.collect(Collectors.toSet()); | |||
assertThat(filterScopes).hasSize(1); | |||
} | |||
} |
@@ -45,7 +45,7 @@ public class SubAggregationHelperTest { | |||
@Test | |||
public void buildTermsAggregation_adds_term_subaggregation_with_minDoc_1_and_default_sort() { | |||
String aggName = randomAlphabetic(10); | |||
TopAggregationDef topAggregation = new TopAggregationDef("bar", false); | |||
SimpleFieldTopAggregationDefinition topAggregation = new SimpleFieldTopAggregationDefinition("bar", false); | |||
Stream.of( | |||
underTest, | |||
@@ -54,7 +54,7 @@ public class SubAggregationHelperTest { | |||
TermsAggregationBuilder agg = t.buildTermsAggregation(aggName, topAggregation, null); | |||
assertThat(agg.getName()).isEqualTo(aggName); | |||
assertThat(agg.field()).isEqualTo(topAggregation.getFieldName()); | |||
assertThat(agg.field()).isEqualTo(topAggregation.getFilterScope().getFieldName()); | |||
assertThat(agg.size()).isEqualTo(DEFAULT_BUCKET_SIZE); | |||
assertThat(agg.minDocCount()).isEqualTo(1); | |||
assertThat(agg.order()).isEqualTo(BucketOrder.compound(SQ_DEFAULT_BUCKET_ORDER, ES_BUILTIN_TIE_BREAKER)); | |||
@@ -64,19 +64,19 @@ public class SubAggregationHelperTest { | |||
@Test | |||
public void buildTermsAggregation_adds_custom_order_from_constructor() { | |||
String aggName = randomAlphabetic(10); | |||
TopAggregationDef topAggregation = new TopAggregationDef("bar", false); | |||
SimpleFieldTopAggregationDefinition topAggregation = new SimpleFieldTopAggregationDefinition("bar", false); | |||
TermsAggregationBuilder agg = underTestWithCustomsSubAggAndOrder.buildTermsAggregation(aggName, topAggregation, null); | |||
assertThat(agg.getName()).isEqualTo(aggName); | |||
assertThat(agg.field()).isEqualTo(topAggregation.getFieldName()); | |||
assertThat(agg.field()).isEqualTo(topAggregation.getFilterScope().getFieldName()); | |||
assertThat(agg.order()).isEqualTo(BucketOrder.compound(customOrder, ES_BUILTIN_TIE_BREAKER)); | |||
} | |||
@Test | |||
public void buildTermsAggregation_adds_custom_sub_agg_from_constructor() { | |||
String aggName = randomAlphabetic(10); | |||
TopAggregationDef topAggregation = new TopAggregationDef("bar", false); | |||
SimpleFieldTopAggregationDefinition topAggregation = new SimpleFieldTopAggregationDefinition("bar", false); | |||
Stream.of( | |||
underTestWithCustomSubAgg, | |||
@@ -85,7 +85,7 @@ public class SubAggregationHelperTest { | |||
TermsAggregationBuilder agg = t.buildTermsAggregation(aggName, topAggregation, null); | |||
assertThat(agg.getName()).isEqualTo(aggName); | |||
assertThat(agg.field()).isEqualTo(topAggregation.getFieldName()); | |||
assertThat(agg.field()).isEqualTo(topAggregation.getFilterScope().getFieldName()); | |||
assertThat(agg.getSubAggregations()).hasSize(1); | |||
assertThat(agg.getSubAggregations().iterator().next()).isSameAs(customSubAgg); | |||
}); | |||
@@ -95,7 +95,7 @@ public class SubAggregationHelperTest { | |||
public void buildTermsAggregation_adds_custom_size_if_TermTopAggregation_specifies_one() { | |||
String aggName = randomAlphabetic(10); | |||
int customSize = 1 + new Random().nextInt(400); | |||
TopAggregationDef topAggregation = new TopAggregationDef("bar", false); | |||
SimpleFieldTopAggregationDefinition topAggregation = new SimpleFieldTopAggregationDefinition("bar", false); | |||
Stream.of( | |||
underTest, | |||
@@ -105,7 +105,7 @@ public class SubAggregationHelperTest { | |||
TermsAggregationBuilder agg = t.buildTermsAggregation(aggName, topAggregation, customSize); | |||
assertThat(agg.getName()).isEqualTo(aggName); | |||
assertThat(agg.field()).isEqualTo(topAggregation.getFieldName()); | |||
assertThat(agg.field()).isEqualTo(topAggregation.getFilterScope().getFieldName()); | |||
assertThat(agg.size()).isEqualTo(customSize); | |||
}); | |||
} | |||
@@ -113,7 +113,7 @@ public class SubAggregationHelperTest { | |||
@Test | |||
public void buildSelectedItemsAggregation_returns_empty_if_no_selected_item() { | |||
String aggName = randomAlphabetic(10); | |||
TopAggregationDef topAggregation = new TopAggregationDef("bar", false); | |||
SimpleFieldTopAggregationDefinition topAggregation = new SimpleFieldTopAggregationDefinition("bar", false); | |||
Stream.of( | |||
underTest, | |||
@@ -125,21 +125,21 @@ public class SubAggregationHelperTest { | |||
@Test | |||
public void buildSelectedItemsAggregation_does_not_add_custom_order_from_constructor() { | |||
String aggName = randomAlphabetic(10); | |||
TopAggregationDef topAggregation = new TopAggregationDef("bar", false); | |||
SimpleFieldTopAggregationDefinition topAggregation = new SimpleFieldTopAggregationDefinition("bar", false); | |||
String[] selected = randomNonEmptySelected(); | |||
TermsAggregationBuilder agg = underTestWithCustomsSubAggAndOrder.buildSelectedItemsAggregation(aggName, topAggregation, selected) | |||
.get(); | |||
assertThat(agg.getName()).isEqualTo(aggName + "_selected"); | |||
assertThat(agg.field()).isEqualTo(topAggregation.getFieldName()); | |||
assertThat(agg.field()).isEqualTo(topAggregation.getFilterScope().getFieldName()); | |||
assertThat(agg.order()).isEqualTo(BucketOrder.compound(SQ_DEFAULT_BUCKET_ORDER, ES_BUILTIN_TIE_BREAKER)); | |||
} | |||
@Test | |||
public void buildSelectedItemsAggregation_adds_custom_sub_agg_from_constructor() { | |||
String aggName = randomAlphabetic(10); | |||
TopAggregationDef topAggregation = new TopAggregationDef("bar", false); | |||
SimpleFieldTopAggregationDefinition topAggregation = new SimpleFieldTopAggregationDefinition("bar", false); | |||
String[] selected = randomNonEmptySelected(); | |||
Stream.of( | |||
@@ -149,7 +149,7 @@ public class SubAggregationHelperTest { | |||
TermsAggregationBuilder agg = t.buildSelectedItemsAggregation(aggName, topAggregation, selected).get(); | |||
assertThat(agg.getName()).isEqualTo(aggName + "_selected"); | |||
assertThat(agg.field()).isEqualTo(topAggregation.getFieldName()); | |||
assertThat(agg.field()).isEqualTo(topAggregation.getFilterScope().getFieldName()); | |||
assertThat(agg.getSubAggregations()).hasSize(1); | |||
assertThat(agg.getSubAggregations().iterator().next()).isSameAs(customSubAgg); | |||
}); |
@@ -1,89 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.es.searchrequest; | |||
import java.util.Random; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
public class TermTopAggregationDefTest { | |||
private static final Random RANDOM = new Random(); | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
@Test | |||
public void fieldName_cannot_be_null() { | |||
boolean sticky = RANDOM.nextBoolean(); | |||
int maxTerms = 10; | |||
expectedException.expect(NullPointerException.class); | |||
expectedException.expectMessage("fieldName can't be null"); | |||
new TermTopAggregationDef(null, sticky, maxTerms); | |||
} | |||
@Test | |||
public void maxTerms_can_be_null() { | |||
String fieldName = randomAlphabetic(12); | |||
boolean sticky = RANDOM.nextBoolean(); | |||
TermTopAggregationDef underTest = new TermTopAggregationDef(fieldName, sticky, null); | |||
assertThat(underTest.getMaxTerms()).isEmpty(); | |||
} | |||
@Test | |||
public void maxTerms_can_be_0() { | |||
String fieldName = randomAlphabetic(12); | |||
boolean sticky = RANDOM.nextBoolean(); | |||
TermTopAggregationDef underTest = new TermTopAggregationDef(fieldName, sticky, 0); | |||
assertThat(underTest.getMaxTerms()).hasValue(0); | |||
} | |||
@Test | |||
public void maxTerms_cant_be_less_than_0() { | |||
String fieldName = randomAlphabetic(12); | |||
boolean sticky = RANDOM.nextBoolean(); | |||
int negativeNumber = -1 - RANDOM.nextInt(200); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("maxTerms can't be < 0"); | |||
new TermTopAggregationDef(fieldName, sticky, negativeNumber); | |||
} | |||
@Test | |||
public void getters() { | |||
String fieldName = randomAlphabetic(12); | |||
boolean sticky = RANDOM.nextBoolean(); | |||
int maxTerms = RANDOM.nextInt(299); | |||
TermTopAggregationDef underTest = new TermTopAggregationDef(fieldName, sticky, maxTerms); | |||
assertThat(underTest.getFieldName()).isEqualTo(fieldName); | |||
assertThat(underTest.isSticky()).isEqualTo(sticky); | |||
assertThat(underTest.getMaxTerms()).hasValue(maxTerms); | |||
} | |||
} |
@@ -52,7 +52,7 @@ public class TopAggregationHelperTest { | |||
@Test | |||
public void buildTopAggregation_fails_with_ISE_if_no_subaggregation_added_by_lambda() { | |||
String aggregationName = "name"; | |||
TopAggregationDefinition topAggregation = new TopAggregationDef("bar", false); | |||
SimpleFieldTopAggregationDefinition topAggregation = new SimpleFieldTopAggregationDefinition("bar", false); | |||
assertThatThrownBy(() -> underTest.buildTopAggregation(aggregationName, topAggregation, NO_EXTRA_FILTER, NO_OTHER_SUBAGGREGATION)) | |||
.isInstanceOf(IllegalStateException.class) | |||
@@ -61,7 +61,7 @@ public class TopAggregationHelperTest { | |||
@Test | |||
public void buildTopAggregation_adds_subAggregation_from_lambda_parameter() { | |||
TopAggregationDefinition topAggregation = new TopAggregationDef("bar", false); | |||
SimpleFieldTopAggregationDefinition topAggregation = new SimpleFieldTopAggregationDefinition("bar", false); | |||
AggregationBuilder[] subAggs = IntStream.range(0, 1 + new Random().nextInt(12)) | |||
.mapToObj(i -> AggregationBuilders.min("subAgg_" + i)) | |||
.toArray(AggregationBuilder[]::new); | |||
@@ -77,8 +77,8 @@ public class TopAggregationHelperTest { | |||
@Test | |||
public void buildTopAggregation_adds_filter_from_FiltersComputer_for_TopAggregation() { | |||
TopAggregationDefinition topAggregation = new TopAggregationDef("bar", false); | |||
TopAggregationDefinition otherTopAggregation = new TopAggregationDef("acme", false); | |||
SimpleFieldTopAggregationDefinition topAggregation = new SimpleFieldTopAggregationDefinition("bar", false); | |||
SimpleFieldTopAggregationDefinition otherTopAggregation = new SimpleFieldTopAggregationDefinition("acme", false); | |||
BoolQueryBuilder computerFilter = boolQuery(); | |||
BoolQueryBuilder otherFilter = boolQuery(); | |||
when(filtersComputer.getTopAggregationFilter(topAggregation)).thenReturn(Optional.of(computerFilter)); | |||
@@ -95,8 +95,8 @@ public class TopAggregationHelperTest { | |||
@Test | |||
public void buildTopAggregation_has_empty_filter_when_FiltersComputer_returns_empty_for_TopAggregation() { | |||
TopAggregationDefinition topAggregation = new TopAggregationDef("bar", false); | |||
TopAggregationDefinition otherTopAggregation = new TopAggregationDef("acme", false); | |||
SimpleFieldTopAggregationDefinition topAggregation = new SimpleFieldTopAggregationDefinition("bar", false); | |||
SimpleFieldTopAggregationDefinition otherTopAggregation = new SimpleFieldTopAggregationDefinition("acme", false); | |||
BoolQueryBuilder otherFilter = boolQuery(); | |||
when(filtersComputer.getTopAggregationFilter(topAggregation)).thenReturn(Optional.empty()); | |||
when(filtersComputer.getTopAggregationFilter(otherTopAggregation)).thenReturn(Optional.of(otherFilter)); | |||
@@ -113,8 +113,8 @@ public class TopAggregationHelperTest { | |||
@Test | |||
public void buildTopAggregation_adds_filter_from_FiltersComputer_for_TopAggregation_and_extra_one() { | |||
String topAggregationName = randomAlphabetic(10); | |||
TopAggregationDefinition topAggregation = new TopAggregationDef("bar", false); | |||
TopAggregationDefinition otherTopAggregation = new TopAggregationDef("acme", false); | |||
SimpleFieldTopAggregationDefinition topAggregation = new SimpleFieldTopAggregationDefinition("bar", false); | |||
SimpleFieldTopAggregationDefinition otherTopAggregation = new SimpleFieldTopAggregationDefinition("acme", false); | |||
BoolQueryBuilder computerFilter = boolQuery(); | |||
BoolQueryBuilder otherFilter = boolQuery(); | |||
BoolQueryBuilder extraFilter = boolQuery(); | |||
@@ -132,7 +132,7 @@ public class TopAggregationHelperTest { | |||
@Test | |||
public void buildTopAggregation_does_not_add_subaggregation_from_subAggregationHelper() { | |||
TopAggregationDefinition topAggregation = new TopAggregationDef("bar", false); | |||
SimpleFieldTopAggregationDefinition topAggregation = new SimpleFieldTopAggregationDefinition("bar", false); | |||
when(filtersComputer.getTopAggregationFilter(topAggregation)).thenReturn(Optional.empty()); | |||
MinAggregationBuilder subAggregation = AggregationBuilders.min("donut"); | |||
String topAggregationName = randomAlphabetic(10); | |||
@@ -145,7 +145,7 @@ public class TopAggregationHelperTest { | |||
@Test | |||
public void buildTermTopAggregation_adds_term_subaggregation_from_subAggregationHelper() { | |||
String topAggregationName = randomAlphabetic(10); | |||
TopAggregationDef topAggregation = new TopAggregationDef("bar", false); | |||
SimpleFieldTopAggregationDefinition topAggregation = new SimpleFieldTopAggregationDefinition("bar", false); | |||
TermsAggregationBuilder termSubAgg = AggregationBuilders.terms("foo"); | |||
when(subAggregationHelper.buildTermsAggregation(topAggregationName, topAggregation, null)).thenReturn(termSubAgg); | |||
@@ -160,7 +160,7 @@ public class TopAggregationHelperTest { | |||
@Test | |||
public void buildTermTopAggregation_adds_subAggregation_from_lambda_parameter() { | |||
TopAggregationDef topAggregation = new TopAggregationDef("bar", false); | |||
SimpleFieldTopAggregationDefinition topAggregation = new SimpleFieldTopAggregationDefinition("bar", false); | |||
AggregationBuilder[] subAggs = IntStream.range(0, 1 + new Random().nextInt(12)) | |||
.mapToObj(i -> AggregationBuilders.min("subAgg_" + i)) | |||
.toArray(AggregationBuilder[]::new); | |||
@@ -180,8 +180,8 @@ public class TopAggregationHelperTest { | |||
@Test | |||
public void buildTermTopAggregation_adds_filter_from_FiltersComputer_for_TopAggregation() { | |||
TopAggregationDef topAggregation = new TopAggregationDef("bar", false); | |||
TopAggregationDef otherTopAggregation = new TopAggregationDef("acme", false); | |||
SimpleFieldTopAggregationDefinition topAggregation = new SimpleFieldTopAggregationDefinition("bar", false); | |||
SimpleFieldTopAggregationDefinition otherTopAggregation = new SimpleFieldTopAggregationDefinition("acme", false); | |||
BoolQueryBuilder computerFilter = boolQuery(); | |||
BoolQueryBuilder otherFilter = boolQuery(); | |||
when(filtersComputer.getTopAggregationFilter(topAggregation)).thenReturn(Optional.of(computerFilter)); | |||
@@ -200,8 +200,8 @@ public class TopAggregationHelperTest { | |||
@Test | |||
public void buildTermTopAggregation_has_empty_filter_when_FiltersComputer_returns_empty_for_TopAggregation() { | |||
TopAggregationDef topAggregation = new TopAggregationDef("bar", false); | |||
TopAggregationDef otherTopAggregation = new TopAggregationDef("acme", false); | |||
SimpleFieldTopAggregationDefinition topAggregation = new SimpleFieldTopAggregationDefinition("bar", false); | |||
SimpleFieldTopAggregationDefinition otherTopAggregation = new SimpleFieldTopAggregationDefinition("acme", false); | |||
BoolQueryBuilder otherFilter = boolQuery(); | |||
when(filtersComputer.getTopAggregationFilter(topAggregation)).thenReturn(Optional.empty()); | |||
when(filtersComputer.getTopAggregationFilter(otherTopAggregation)).thenReturn(Optional.of(otherFilter)); | |||
@@ -220,8 +220,8 @@ public class TopAggregationHelperTest { | |||
@Test | |||
public void buildTermTopAggregation_adds_filter_from_FiltersComputer_for_TopAggregation_and_extra_one() { | |||
String topAggregationName = randomAlphabetic(10); | |||
TopAggregationDef topAggregation = new TopAggregationDef("bar", false); | |||
TopAggregationDef otherTopAggregation = new TopAggregationDef("acme", false); | |||
SimpleFieldTopAggregationDefinition topAggregation = new SimpleFieldTopAggregationDefinition("bar", false); | |||
SimpleFieldTopAggregationDefinition otherTopAggregation = new SimpleFieldTopAggregationDefinition("acme", false); | |||
BoolQueryBuilder computerFilter = boolQuery(); | |||
BoolQueryBuilder otherFilter = boolQuery(); | |||
BoolQueryBuilder extraFilter = boolQuery(); |
@@ -80,9 +80,10 @@ import org.sonar.server.es.SearchOptions; | |||
import org.sonar.server.es.Sorting; | |||
import org.sonar.server.es.searchrequest.RequestFiltersComputer; | |||
import org.sonar.server.es.searchrequest.RequestFiltersComputer.AllFilters; | |||
import org.sonar.server.es.searchrequest.SimpleFieldTopAggregationDefinition; | |||
import org.sonar.server.es.searchrequest.SubAggregationHelper; | |||
import org.sonar.server.es.searchrequest.TopAggregationDef; | |||
import org.sonar.server.es.searchrequest.TopAggregationDefinition; | |||
import org.sonar.server.es.searchrequest.TopAggregationDefinition.SimpleFieldFilterScope; | |||
import org.sonar.server.es.searchrequest.TopAggregationHelper; | |||
import org.sonar.server.issue.index.IssueQuery.PeriodStart; | |||
import org.sonar.server.permission.index.AuthorizationDoc; | |||
@@ -107,6 +108,8 @@ import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex; | |||
import static org.sonar.server.es.BaseDoc.epochMillisToEpochSeconds; | |||
import static org.sonar.server.es.EsUtils.escapeSpecialRegexChars; | |||
import static org.sonar.server.es.IndexType.FIELD_INDEX_TYPE; | |||
import static org.sonar.server.es.searchrequest.TopAggregationDefinition.NON_STICKY; | |||
import static org.sonar.server.es.searchrequest.TopAggregationDefinition.STICKY; | |||
import static org.sonar.server.es.searchrequest.TopAggregationHelper.NO_EXTRA_FILTER; | |||
import static org.sonar.server.es.searchrequest.TopAggregationHelper.NO_OTHER_SUBAGGREGATION; | |||
import static org.sonar.server.issue.index.IssueIndex.Facet.ASSIGNED_TO_ME; | |||
@@ -217,10 +220,8 @@ public class IssueIndex { | |||
.filter(termQuery(FIELD_ISSUE_STATUS, Issue.STATUS_REVIEWED)) | |||
.filter(termQuery(FIELD_ISSUE_RESOLUTION, Issue.RESOLUTION_FIXED)); | |||
private static final boolean STICKY = true; | |||
private static final boolean NON_STICKY = false; | |||
private static final Object[] NO_SELECTED_VALUES = {0}; | |||
private static final TopAggregationDefinition EFFORT_TOP_AGGREGATION = new TopAggregationDef(FIELD_ISSUE_EFFORT, NON_STICKY); | |||
private static final SimpleFieldTopAggregationDefinition EFFORT_TOP_AGGREGATION = new SimpleFieldTopAggregationDefinition(FIELD_ISSUE_EFFORT, NON_STICKY); | |||
public enum Facet { | |||
SEVERITIES(PARAM_SEVERITIES, FIELD_ISSUE_SEVERITY, STICKY, Severity.ALL.size()), | |||
@@ -246,18 +247,18 @@ public class IssueIndex { | |||
SONARSOURCE_SECURITY(PARAM_SONARSOURCE_SECURITY, FIELD_ISSUE_SQ_SECURITY_CATEGORY, STICKY, DEFAULT_FACET_SIZE); | |||
private final String name; | |||
private final TopAggregationDefinition topAggregation; | |||
private final SimpleFieldTopAggregationDefinition topAggregation; | |||
private final Integer numberOfTerms; | |||
Facet(String name, String fieldName, boolean sticky, int numberOfTerms) { | |||
this.name = name; | |||
this.topAggregation = new TopAggregationDef(fieldName, sticky); | |||
this.topAggregation = new SimpleFieldTopAggregationDefinition(fieldName, sticky); | |||
this.numberOfTerms = numberOfTerms; | |||
} | |||
Facet(String name, String fieldName, boolean sticky) { | |||
this.name = name; | |||
this.topAggregation = new TopAggregationDef(fieldName, sticky); | |||
this.topAggregation = new SimpleFieldTopAggregationDefinition(fieldName, sticky); | |||
this.numberOfTerms = null; | |||
} | |||
@@ -266,10 +267,14 @@ public class IssueIndex { | |||
} | |||
public String getFieldName() { | |||
return topAggregation.getFieldName(); | |||
return topAggregation.getFilterScope().getFieldName(); | |||
} | |||
public TopAggregationDefinition getTopAggregationDef() { | |||
public TopAggregationDefinition.FilterScope getFilterScope() { | |||
return topAggregation.getFilterScope(); | |||
} | |||
public SimpleFieldTopAggregationDefinition getTopAggregationDef() { | |||
return topAggregation; | |||
} | |||
@@ -389,41 +394,54 @@ public class IssueIndex { | |||
private AllFilters createAllFilters(IssueQuery query) { | |||
AllFilters filters = RequestFiltersComputer.newAllFilters(); | |||
filters.addFilter("__indexType", FIELD_INDEX_TYPE, termQuery(FIELD_INDEX_TYPE, TYPE_ISSUE.getName())); | |||
filters.addFilter("__authorization", "parent", createAuthorizationFilter()); | |||
filters.addFilter("__indexType", new SimpleFieldFilterScope(FIELD_INDEX_TYPE), termQuery(FIELD_INDEX_TYPE, TYPE_ISSUE.getName())); | |||
filters.addFilter("__authorization", new SimpleFieldFilterScope("parent"), createAuthorizationFilter()); | |||
// Issue is assigned Filter | |||
if (BooleanUtils.isTrue(query.assigned())) { | |||
filters.addFilter(IS_ASSIGNED_FILTER, FIELD_ISSUE_ASSIGNEE_UUID, existsQuery(FIELD_ISSUE_ASSIGNEE_UUID)); | |||
filters.addFilter(IS_ASSIGNED_FILTER, Facet.ASSIGNEES.getFilterScope(), existsQuery(FIELD_ISSUE_ASSIGNEE_UUID)); | |||
} else if (BooleanUtils.isFalse(query.assigned())) { | |||
filters.addFilter(IS_ASSIGNED_FILTER, FIELD_ISSUE_ASSIGNEE_UUID, boolQuery().mustNot(existsQuery(FIELD_ISSUE_ASSIGNEE_UUID))); | |||
filters.addFilter(IS_ASSIGNED_FILTER, ASSIGNEES.getFilterScope(), boolQuery().mustNot(existsQuery(FIELD_ISSUE_ASSIGNEE_UUID))); | |||
} | |||
// Issue is Resolved Filter | |||
if (BooleanUtils.isTrue(query.resolved())) { | |||
filters.addFilter("__isResolved", FIELD_ISSUE_RESOLUTION, existsQuery(FIELD_ISSUE_RESOLUTION)); | |||
filters.addFilter("__isResolved", Facet.RESOLUTIONS.getFilterScope(), existsQuery(FIELD_ISSUE_RESOLUTION)); | |||
} else if (BooleanUtils.isFalse(query.resolved())) { | |||
filters.addFilter("__isResolved", FIELD_ISSUE_RESOLUTION, boolQuery().mustNot(existsQuery(FIELD_ISSUE_RESOLUTION))); | |||
filters.addFilter("__isResolved", Facet.RESOLUTIONS.getFilterScope(), boolQuery().mustNot(existsQuery(FIELD_ISSUE_RESOLUTION))); | |||
} | |||
// Field Filters | |||
filters.addFilter(FIELD_ISSUE_KEY, createTermsFilter(FIELD_ISSUE_KEY, query.issueKeys())); | |||
filters.addFilter(FIELD_ISSUE_ASSIGNEE_UUID, createTermsFilter(FIELD_ISSUE_ASSIGNEE_UUID, query.assignees())); | |||
filters.addFilter(FIELD_ISSUE_LANGUAGE, createTermsFilter(FIELD_ISSUE_LANGUAGE, query.languages())); | |||
filters.addFilter(FIELD_ISSUE_TAGS, createTermsFilter(FIELD_ISSUE_TAGS, query.tags())); | |||
filters.addFilter(FIELD_ISSUE_TYPE, createTermsFilter(FIELD_ISSUE_TYPE, query.types())); | |||
filters.addFilter(FIELD_ISSUE_RESOLUTION, createTermsFilter(FIELD_ISSUE_RESOLUTION, query.resolutions())); | |||
filters.addFilter(FIELD_ISSUE_AUTHOR_LOGIN, createTermsFilter(FIELD_ISSUE_AUTHOR_LOGIN, query.authors())); | |||
filters.addFilter(FIELD_ISSUE_RULE_ID, createTermsFilter( | |||
FIELD_ISSUE_RULE_ID, | |||
query.rules().stream().map(IssueDoc::formatRuleId).collect(toList()))); | |||
filters.addFilter(FIELD_ISSUE_STATUS, createTermsFilter(FIELD_ISSUE_STATUS, query.statuses())); | |||
filters.addFilter(FIELD_ISSUE_ORGANIZATION_UUID, createTermFilter(FIELD_ISSUE_ORGANIZATION_UUID, query.organizationUuid())); | |||
filters.addFilter(FIELD_ISSUE_OWASP_TOP_10, createTermsFilter(FIELD_ISSUE_OWASP_TOP_10, query.owaspTop10())); | |||
filters.addFilter(FIELD_ISSUE_SANS_TOP_25, createTermsFilter(FIELD_ISSUE_SANS_TOP_25, query.sansTop25())); | |||
filters.addFilter(FIELD_ISSUE_CWE, createTermsFilter(FIELD_ISSUE_CWE, query.cwe())); | |||
filters.addFilter(FIELD_ISSUE_KEY, new SimpleFieldFilterScope(FIELD_ISSUE_KEY), createTermsFilter(FIELD_ISSUE_KEY, query.issueKeys())); | |||
filters.addFilter(FIELD_ISSUE_ASSIGNEE_UUID, ASSIGNEES.getFilterScope(), createTermsFilter(FIELD_ISSUE_ASSIGNEE_UUID, query.assignees())); | |||
filters.addFilter(FIELD_ISSUE_LANGUAGE, LANGUAGES.getFilterScope(), createTermsFilter(FIELD_ISSUE_LANGUAGE, query.languages())); | |||
filters.addFilter(FIELD_ISSUE_TAGS, TAGS.getFilterScope(), createTermsFilter(FIELD_ISSUE_TAGS, query.tags())); | |||
filters.addFilter(FIELD_ISSUE_TYPE, TYPES.getFilterScope(), createTermsFilter(FIELD_ISSUE_TYPE, query.types())); | |||
filters.addFilter( | |||
FIELD_ISSUE_RESOLUTION, RESOLUTIONS.getFilterScope(), | |||
createTermsFilter(FIELD_ISSUE_RESOLUTION, query.resolutions())); | |||
filters.addFilter( | |||
FIELD_ISSUE_AUTHOR_LOGIN, AUTHOR.getFilterScope(), | |||
createTermsFilter(FIELD_ISSUE_AUTHOR_LOGIN, query.authors())); | |||
filters.addFilter( | |||
FIELD_ISSUE_RULE_ID, RULES.getFilterScope(), createTermsFilter( | |||
FIELD_ISSUE_RULE_ID, | |||
query.rules().stream().map(IssueDoc::formatRuleId).collect(toList()))); | |||
filters.addFilter(FIELD_ISSUE_STATUS, STATUSES.getFilterScope(), createTermsFilter(FIELD_ISSUE_STATUS, query.statuses())); | |||
filters.addFilter( | |||
FIELD_ISSUE_ORGANIZATION_UUID, new SimpleFieldFilterScope(FIELD_ISSUE_ORGANIZATION_UUID), | |||
createTermFilter(FIELD_ISSUE_ORGANIZATION_UUID, query.organizationUuid())); | |||
filters.addFilter( | |||
FIELD_ISSUE_OWASP_TOP_10, OWASP_TOP_10.getFilterScope(), | |||
createTermsFilter(FIELD_ISSUE_OWASP_TOP_10, query.owaspTop10())); | |||
filters.addFilter( | |||
FIELD_ISSUE_SANS_TOP_25, SANS_TOP_25.getFilterScope(), | |||
createTermsFilter(FIELD_ISSUE_SANS_TOP_25, query.sansTop25())); | |||
filters.addFilter(FIELD_ISSUE_CWE, CWE.getFilterScope(), createTermsFilter(FIELD_ISSUE_CWE, query.cwe())); | |||
addSeverityFilter(query, filters); | |||
filters.addFilter(FIELD_ISSUE_SQ_SECURITY_CATEGORY, createTermsFilter(FIELD_ISSUE_SQ_SECURITY_CATEGORY, query.sonarsourceSecurity())); | |||
filters.addFilter( | |||
FIELD_ISSUE_SQ_SECURITY_CATEGORY, SONARSOURCE_SECURITY.getFilterScope(), | |||
createTermsFilter(FIELD_ISSUE_SQ_SECURITY_CATEGORY, query.sonarsourceSecurity())); | |||
addComponentRelatedFilters(query, filters); | |||
addDatesFilter(filters, query); | |||
@@ -434,10 +452,13 @@ public class IssueIndex { | |||
private static void addSeverityFilter(IssueQuery query, AllFilters allFilters) { | |||
QueryBuilder severityFieldFilter = createTermsFilter(FIELD_ISSUE_SEVERITY, query.severities()); | |||
if (severityFieldFilter != null) { | |||
allFilters.addFilter(FIELD_ISSUE_SEVERITY, boolQuery() | |||
.must(severityFieldFilter) | |||
// Ignore severity of Security HotSpots | |||
.mustNot(termQuery(FIELD_ISSUE_TYPE, SECURITY_HOTSPOT.name()))); | |||
allFilters.addFilter( | |||
FIELD_ISSUE_SEVERITY, | |||
SEVERITIES.getFilterScope(), | |||
boolQuery() | |||
.must(severityFieldFilter) | |||
// Ignore severity of Security HotSpots | |||
.mustNot(termQuery(FIELD_ISSUE_TYPE, SECURITY_HOTSPOT.name()))); | |||
} | |||
} | |||
@@ -455,23 +476,22 @@ public class IssueIndex { | |||
QueryBuilder fileFilter = createTermsFilter(FIELD_ISSUE_COMPONENT_UUID, query.fileUuids()); | |||
if (BooleanUtils.isTrue(query.onComponentOnly())) { | |||
filters.addFilter(FIELD_ISSUE_COMPONENT_UUID, componentFilter); | |||
filters.addFilter(FIELD_ISSUE_COMPONENT_UUID, new SimpleFieldFilterScope(FIELD_ISSUE_COMPONENT_UUID), componentFilter); | |||
} else { | |||
filters.addFilter( | |||
FIELD_ISSUE_PROJECT_UUID, | |||
FIELD_ISSUE_PROJECT_UUID, new SimpleFieldFilterScope(FIELD_ISSUE_PROJECT_UUID), | |||
createTermsFilter(FIELD_ISSUE_PROJECT_UUID, query.projectUuids())); | |||
filters.addFilter( | |||
"__module", | |||
FIELD_ISSUE_MODULE_PATH, | |||
"__module", new SimpleFieldFilterScope(FIELD_ISSUE_MODULE_PATH), | |||
createTermsFilter(FIELD_ISSUE_MODULE_PATH, query.moduleRootUuids())); | |||
filters.addFilter( | |||
FIELD_ISSUE_MODULE_UUID, | |||
FIELD_ISSUE_MODULE_UUID, new SimpleFieldFilterScope(FIELD_ISSUE_MODULE_UUID), | |||
createTermsFilter(FIELD_ISSUE_MODULE_UUID, query.moduleUuids())); | |||
filters.addFilter( | |||
FIELD_ISSUE_DIRECTORY_PATH, | |||
FIELD_ISSUE_DIRECTORY_PATH, new SimpleFieldFilterScope(FIELD_ISSUE_DIRECTORY_PATH), | |||
createTermsFilter(FIELD_ISSUE_DIRECTORY_PATH, query.directories())); | |||
filters.addFilter( | |||
FIELD_ISSUE_COMPONENT_UUID, | |||
FIELD_ISSUE_COMPONENT_UUID, new SimpleFieldFilterScope(FIELD_ISSUE_COMPONENT_UUID), | |||
fileFilter == null ? componentFilter : fileFilter); | |||
} | |||
} | |||
@@ -481,11 +501,10 @@ public class IssueIndex { | |||
return; | |||
} | |||
allFilters.addFilter( | |||
"__is_main_branch", | |||
FIELD_ISSUE_IS_MAIN_BRANCH, | |||
"__is_main_branch", new SimpleFieldFilterScope(FIELD_ISSUE_IS_MAIN_BRANCH), | |||
createTermFilter(FIELD_ISSUE_IS_MAIN_BRANCH, Boolean.toString(query.isMainBranch()))); | |||
allFilters.addFilter( | |||
FIELD_ISSUE_BRANCH_UUID, | |||
FIELD_ISSUE_BRANCH_UUID, new SimpleFieldFilterScope(FIELD_ISSUE_BRANCH_UUID), | |||
createTermFilter(FIELD_ISSUE_BRANCH_UUID, query.branchUuid())); | |||
} | |||
@@ -497,10 +516,10 @@ public class IssueIndex { | |||
String branchUuid = query.branchUuid(); | |||
boolean onApplicationBranch = branchUuid != null && !viewUuids.isEmpty(); | |||
if (onApplicationBranch) { | |||
allFilters.addFilter("__view", createViewFilter(singletonList(query.branchUuid()))); | |||
allFilters.addFilter("__view", new SimpleFieldFilterScope("view"), createViewFilter(singletonList(query.branchUuid()))); | |||
} else { | |||
allFilters.addFilter("__is_main_branch", createTermFilter(FIELD_ISSUE_IS_MAIN_BRANCH, Boolean.toString(true))); | |||
allFilters.addFilter("__view", createViewFilter(viewUuids)); | |||
allFilters.addFilter("__is_main_branch", new SimpleFieldFilterScope(FIELD_ISSUE_IS_MAIN_BRANCH), createTermFilter(FIELD_ISSUE_IS_MAIN_BRANCH, Boolean.toString(true))); | |||
allFilters.addFilter("__view", new SimpleFieldFilterScope("view"), createViewFilter(viewUuids)); | |||
} | |||
} | |||
@@ -525,7 +544,7 @@ public class IssueIndex { | |||
private static RequestFiltersComputer newFilterComputer(SearchOptions options, AllFilters allFilters) { | |||
Collection<String> facetNames = options.getFacets(); | |||
Set<TopAggregationDefinition> facets = Stream.concat( | |||
Set<TopAggregationDefinition<?>> facets = Stream.concat( | |||
Stream.of(EFFORT_TOP_AGGREGATION), | |||
facetNames.stream() | |||
.map(FACETS_BY_NAME::get) | |||
@@ -589,16 +608,14 @@ public class IssueIndex { | |||
if (createdAfter != null) { | |||
filters.addFilter( | |||
"__createdAfter", | |||
FIELD_ISSUE_FUNC_CREATED_AT, | |||
"__createdAfter", CREATED_AT.getFilterScope(), | |||
QueryBuilders | |||
.rangeQuery(FIELD_ISSUE_FUNC_CREATED_AT) | |||
.from(BaseDoc.dateToEpochSeconds(createdAfter.date()), createdAfter.inclusive())); | |||
} | |||
if (createdBefore != null) { | |||
filters.addFilter( | |||
"__createdBefore", | |||
FIELD_ISSUE_FUNC_CREATED_AT, | |||
"__createdBefore", CREATED_AT.getFilterScope(), | |||
QueryBuilders | |||
.rangeQuery(FIELD_ISSUE_FUNC_CREATED_AT) | |||
.lt(BaseDoc.dateToEpochSeconds(createdBefore))); | |||
@@ -606,8 +623,7 @@ public class IssueIndex { | |||
Date createdAt = query.createdAt(); | |||
if (createdAt != null) { | |||
filters.addFilter( | |||
"__createdAt", | |||
FIELD_ISSUE_FUNC_CREATED_AT, | |||
"__createdAt", CREATED_AT.getFilterScope(), | |||
termQuery(FIELD_ISSUE_FUNC_CREATED_AT, BaseDoc.dateToEpochSeconds(createdAt))); | |||
} | |||
} | |||
@@ -618,7 +634,7 @@ public class IssueIndex { | |||
createdAfterByProjectUuids.forEach((projectUuid, createdAfterDate) -> boolQueryBuilder.should(boolQuery() | |||
.filter(termQuery(FIELD_ISSUE_PROJECT_UUID, projectUuid)) | |||
.filter(rangeQuery(FIELD_ISSUE_FUNC_CREATED_AT).from(BaseDoc.dateToEpochSeconds(createdAfterDate.date()), createdAfterDate.inclusive())))); | |||
allFilters.addFilter("createdAfterByProjectUuids", boolQueryBuilder); | |||
allFilters.addFilter("createdAfterByProjectUuids", new SimpleFieldFilterScope("TODO::???"), boolQueryBuilder); | |||
} | |||
private void validateCreationDateBounds(@Nullable Date createdBefore, @Nullable Date createdAfter) { |