/** * Creates a new ApiFilter based on this ApiFilter, except with the new set of filter values replacing this * ApiFilter's filter values. * * @param values The new set of values to use in the new ApiFilter * * @return the new ApiFilter object */ public ApiFilter withValues(Collection<String> values) { return new ApiFilter(dimension, dimensionField, operation, values); }
/** * Validity rules for non-aggregatable dimensions that are only referenced in filters. * A query that references a non-aggregatable dimension in a filter without grouping by this dimension, is valid * only if the requested dimension field is a key for this dimension and only a single value is requested * with an inclusive operator ('in' or 'eq'). * * @return A predicate that determines a given dimension is non aggregatable and also not constrained to one row * per result */ protected static Predicate<ApiFilter> isNonAggregatableInFilter() { return apiFilter -> !apiFilter.getDimensionField().equals(apiFilter.getDimension().getKey()) || apiFilter.getValues().size() != 1 || !( apiFilter.getOperation().equals(DefaultFilterOperation.in) || apiFilter.getOperation().equals(DefaultFilterOperation.eq) ); }
/** * Constructor. * * Parses the URL filter Query and generates the ApiFilter object. * * @param filterQuery Expects a URL filter query String in the format: * <code>(dimension name)|(field name)-(operation)[?(value or comma separated values)]?</code> * @param dimensionDictionary cache containing all the valid dimension objects. * * @throws BadFilterException Exception when filter pattern is not matched or when any of its properties are not * @deprecated use {@link ApiFilterGenerator} build method instead */ @Deprecated public ApiFilter( @NotNull String filterQuery, DimensionDictionary dimensionDictionary ) throws BadFilterException { ApiFilter filter = ApiFilterGenerator.build(filterQuery, dimensionDictionary); this.dimension = filter.getDimension(); this.dimensionField = filter.getDimensionField(); this.operation = filter.getOperation(); this.values = filter.getValuesList(); }
@Override public TreeSet<DimensionRow> notinFilterOperation(TreeSet<DimensionRow> dimensionRows, ApiFilter filter) { TreeSet<DimensionRow> filteredDimensionRows = new TreeSet<>(dimensionRows); for (DimensionRow dimensionRow : dimensionRows) { String value = dimensionRow.get(filter.getDimensionField()); if (filter.getValues().contains(value)) { filteredDimensionRows.remove(dimensionRow); } } return filteredDimensionRows; }
new ImmutableTriple<>(filter.getDimension(), filter.getDimensionField(), filter.getOperation()); .map(it -> new ApiFilter( it.getKey().getLeft(), it.getKey().getMiddle(),
ApiFilter inProgressApiFilter = new ApiFilter(null, null, null, new LinkedHashSet<>()); throw new BadFilterException(FILTER_DIMENSION_UNDEFINED.format(filterDimensionName)); inProgressApiFilter = inProgressApiFilter.withDimension(dimension); inProgressApiFilter = inProgressApiFilter.withDimensionField(dimensionField); } catch (IllegalArgumentException ignored) { LOG.debug(FILTER_FIELD_NOT_IN_DIMENSIONS.logFormat(dimensionFieldName, filterDimensionName)); try { FilterOperation operation = DefaultFilterOperation.fromString(operationName); inProgressApiFilter = inProgressApiFilter.withOperation(operation); } catch (IllegalArgumentException ignored) { LOG.debug(FILTER_OPERATOR_INVALID.logFormat(operationName)); inProgressApiFilter = inProgressApiFilter.withValues(values); } catch (IllegalArgumentException e) { LOG.debug(FILTER_ERROR.logFormat(filterQuery, e.getMessage()), e);
List<String> values = filter.getValuesList(); Dimension dimension = filter.getDimension(); DefaultFilterOperation filterOperation = (DefaultFilterOperation) filter.getOperation(); switch (filterOperation) { case lte:
if (!table.getDimensions().contains(newFilter.getDimension())) { String filterDimensionName = newFilter.getDimension().getApiName(); LOG.debug(FILTER_DIMENSION_NOT_IN_TABLE.logFormat(filterDimensionName, table)); String errorMessage = FILTER_DIMENSION_NOT_IN_TABLE.format( FilterOperation filterOperation = newFilter.getOperation(); if (filterOperation.equals(DefaultFilterOperation.startswith) || filterOperation.equals(DefaultFilterOperation.contains) Dimension dim = newFilter.getDimension(); if (!generated.containsKey(dim)) { generated.put(dim, new LinkedHashSet<>());
boolean hasPositive = false; for (ApiFilter filter : filters) { FilterOperation op = filter.getOperation(); if (!(op instanceof DefaultFilterOperation)) { LOG.error("Illegal Filter operation : {}, only default filter ops supported", filter.getOperation()); throw new IllegalArgumentException( "Only supports default filter operations: in, notin, startswith, contains, eq" String luceneFieldName = DimensionStoreKeyUtils.getColumnKey(filter.getDimensionField().getName()); switch (defaultFilterOp) { case eq: break; default: LOG.debug("Illegal Filter operation : {}", filter.getOperation()); throw new IllegalArgumentException("Invalid Filter Operation.");
/** * Negates a collection of negative filters, i.e. {@link DefaultFilterOperation#notin} {@code =>} * {@link DefaultFilterOperation#in}, and returns a stream of the negated filters. * <p> * This method throws {@link IllegalArgumentException} if any one of the filter collection passed in is not a * negative filter, i.e. {@link DefaultFilterOperation#notin}. * * @param negativeFilters The collection of filters to be negated * * @return a stream of the negated filters */ protected Set<ApiFilter> negateNegativeFilters(Collection<ApiFilter> negativeFilters) { return negativeFilters.stream() // TODO - refactor this and next map when more than 1 not* FilterOperations are supported. .peek(filter -> { if (!DefaultFilterOperation.notin.equals(filter.getOperation())) { String message = String.format(NON_NEGATIVE_FILTER_ERROR_FORMAT, filter); LOG.error(message); throw new IllegalArgumentException(message); } }) .map(filter -> filter.withOperation(DefaultFilterOperation.in)) .collect(Collectors.toSet()); }
if (DefaultFilterOperation.notin.equals(filter.getOperation())) {
if (!requestedDimensions.contains(filter.getDimension())) { Dimension filterDimension = filter.getDimension(); String msg; if (requestedDimensions.size() == 1) {
/** * Given an ApiFilter, returns a stream of term queries, one for each value in the filter. * * @param luceneFieldName Name of the lucene field to filter on * @param filter The filter to be turned into term queries * * @return A stream of term queries */ private Stream<TermQuery> filterToTermQueries(String luceneFieldName, ApiFilter filter) { return filter.getValues().stream() .map(value -> new Term(luceneFieldName, value)) .map(TermQuery::new); }
.map(filter -> filter.withOperation(DefaultFilterOperation.in)) .collect(Collectors.toCollection(LinkedHashSet::new));
@Override public TreeSet<DimensionRow> inFilterOperation(TreeSet<DimensionRow> dimensionRows, ApiFilter filter) { return dimensionRows.stream() .filter(row -> filter.getValues().contains(row.get(filter.getDimensionField()))) .collect(Collectors.toCollection(TreeSet<DimensionRow>::new)); }
@Override protected Filter buildDimensionFilter(Dimension dimension, Set<ApiFilter> filters) throws DimensionRowNotFoundException { LOG.trace("Building dimension filter using dimension: {} \n\n and set of filter: {}", dimension, filters); List<Filter> orFilters = new ArrayList<>(); for (ApiFilter filter : filters) { ApiFilter normalizedFilter = filter; if (normalizedFilter.getOperation().equals(DefaultFilterOperation.notin)) { normalizedFilter = filter.withOperation(DefaultFilterOperation.in); } Filter disjunction = new OrFilter(buildSelectorFilters( dimension, getFilteredDimensionRows(dimension, Collections.singleton(normalizedFilter)) )); orFilters.add(normalizedFilter == filter ? disjunction : new NotFilter(disjunction)); } Filter newFilter = orFilters.size() == 1 ? orFilters.get(0) : new AndFilter(orFilters); LOG.trace("Filter: {}", newFilter); return newFilter; } }
FilterOperation op = filter.getOperation(); if (!(op instanceof DefaultFilterOperation)) { LOG.error("Illegal Filter operation : {}, only default filter ops supported", filter.getOperation()); throw new IllegalArgumentException( "Only supports default filter operations: in, notin, startswith, contains, eq" break; default: LOG.error("Illegal Filter operation : {}", filter.getOperation()); throw new IllegalArgumentException("Invalid Filter Operation.");
@Override public Pagination<DimensionRow> findFilteredDimensionRowsPaged( Set<ApiFilter> filters, PaginationParameters paginationParameters ) { return new AllPagesPagination<>( filters.stream() .flatMap(f -> f.getValues().stream()) .map(this::makeDimensionRow) .collect(Collectors.toCollection(TreeSet::new)), paginationParameters ); } }
/** * Constructor. * * @param filter The filter being recorded */ public Filter(ApiFilter filter) { this.dimension = filter.getDimension().getApiName(); this.field = filter.getDimensionField().getName(); this.operator = filter.getOperation().getName(); this.numberOfValues = filter.getValues().size(); }
@Override public TreeSet<DimensionRow> startswithFilterOperation( TreeSet<DimensionRow> dimensionRows, ApiFilter filter ) { TreeSet<DimensionRow> filteredDimensionRows = new TreeSet<>(); // regex string containing all starts with filter values StringBuilder startsWithRegex = new StringBuilder("("); for (String filterValue : filter.getValues()) { startsWithRegex.append(filterValue).append("|"); } startsWithRegex.replace(startsWithRegex.length() - 1, startsWithRegex.length(), ").*"); String startsWithRegexString = startsWithRegex.toString(); for (DimensionRow dimensionRow : dimensionRows) { String value = dimensionRow.get(filter.getDimensionField()); if (value.matches(startsWithRegexString)) { filteredDimensionRows.add(dimensionRow); } } return filteredDimensionRows; }