Skip to content

Commit

Permalink
#1081 add exists to filter functions
Browse files Browse the repository at this point in the history
Signed-off-by: Vadim Guenther <vadim.guenther@bosch.io>
  • Loading branch information
VadimGue committed Jun 2, 2021
1 parent 1d0997d commit d0616a7
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.concurrent.Immutable;

Expand Down Expand Up @@ -52,11 +54,9 @@ public PipelineElement apply(final PipelineElement value, final String paramsInc

final Optional<FilterFunction> rqlFunctionOpt =
FilterFunctions.fromName(parameters.get(RqlFunctionParam.NAME));
final boolean shouldKeepValue = rqlFunctionOpt.map(rqlFunction -> {
final String filterValue = parameters.get(FilterValueParam.NAME);
final String comparedValue = parameters.get(ComparedValueParam.NAME);
return rqlFunction.apply(filterValue, comparedValue);
}).orElse(false);
final boolean shouldKeepValue = rqlFunctionOpt
.map(rqlFunction -> applyRqlFunction(parameters, rqlFunction))
.orElse(false);


if (shouldKeepValue) {
Expand All @@ -68,32 +68,63 @@ public PipelineElement apply(final PipelineElement value, final String paramsInc
});
}

private Boolean applyRqlFunction(final Map<String, String> parameters, final FilterFunction rqlFunction) {
if (rqlFunction == FilterFunctions.EXISTS) {
final String filterValue = parameters.get(FilterValueParam.NAME);
return rqlFunction.apply(filterValue);
} else {
final String filterValue = parameters.get(FilterValueParam.NAME);
final String comparedValue = parameters.get(ComparedValueParam.NAME);
return rqlFunction.apply(filterValue, comparedValue);
}
}

private Map<String, String> parseAndResolve(final String paramsIncludingParentheses,
final ExpressionResolver expressionResolver) {

final List<PipelineElement> parameterElements =
PipelineFunctionParameterResolverFactory.forTripleStringOrPlaceholderParameter()
.apply(paramsIncludingParentheses, expressionResolver, this);
final boolean hasComparedValue = hasComparedValue(paramsIncludingParentheses);
final List<PipelineElement> parameterElements = getPipelineElements(paramsIncludingParentheses,
expressionResolver, hasComparedValue);

final PipelineElement filterValueParamElement = parameterElements.get(0);
final PipelineElement rqlFunctionParamElement = parameterElements.get(1);
final PipelineElement comparedValueParamElement = parameterElements.get(2);
final Map<String, String> parameters = new HashMap<>();

final PipelineElement filterValueParamElement = parameterElements.get(0);
final String filterValueParam = filterValueParamElement.toOptional().orElse("");
parameters.put(FilterValueParam.NAME, filterValueParam);

final PipelineElement rqlFunctionParamElement = parameterElements.get(1);
final String rqlFunctionParam = rqlFunctionParamElement.toOptional().orElseThrow(() ->
PlaceholderFunctionSignatureInvalidException.newBuilder(paramsIncludingParentheses, this)
.build());
final String comparedValueParam = comparedValueParamElement.toOptional().orElse("");

final Map<String, String> parameters = new HashMap<>();

parameters.put(FilterValueParam.NAME, filterValueParam);
parameters.put(RqlFunctionParam.NAME, rqlFunctionParam);
parameters.put(ComparedValueParam.NAME, comparedValueParam);

if (hasComparedValue) {
final PipelineElement comparedValueParamElement = parameterElements.get(2);
final String comparedValueParam = comparedValueParamElement.toOptional().orElse("");
parameters.put(ComparedValueParam.NAME, comparedValueParam);
}

return parameters;
}

private boolean hasComparedValue(final String paramsIncludingParentheses) {
final Pattern pattern =
Pattern.compile(PipelineFunctionParameterResolverFactory.ParameterResolver.EXISTS_FUNCTION);
final Matcher matcher = pattern.matcher(paramsIncludingParentheses);
return !matcher.matches();
}

private List<PipelineElement> getPipelineElements(final String paramsIncludingParentheses,
final ExpressionResolver expressionResolver, final boolean hasComparedValue) {
if (hasComparedValue) {
return PipelineFunctionParameterResolverFactory.forTripleStringOrPlaceholderParameter()
.apply(paramsIncludingParentheses, expressionResolver, this);
} else {
return PipelineFunctionParameterResolverFactory.forDoubleStringOrPlaceholderParameter()
.apply(paramsIncludingParentheses, expressionResolver, this);
}
}

/**
* Describes the signature of the {@code filter(filterValue, rqlFunction, comparedValue)} function.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ final class PipelineFunctionParameterResolverFactory {
private static final ParameterResolver TRIPLE_STRING_OR_PLACEHOLDER_PARAMETER_RESOLVER =
new ParameterResolver(3, true);

private static final ParameterResolver DOUBLE_STRING_OR_PLACEHOLDER_PARAMETER_RESOLVER =
new ParameterResolver(2, true);


/**
* Get a parameter resolver that validates for empty parameters.
Expand Down Expand Up @@ -90,6 +93,18 @@ static ParameterResolver forTripleStringOrPlaceholderParameter() {
return TRIPLE_STRING_OR_PLACEHOLDER_PARAMETER_RESOLVER;
}

/**
* Get a parameter resolver that resolves 2 parameters that each could be either a string constant or a placeholder.
* <p>
* E.g.
* <ul>
* <li>("value", 'otherValue')</li>
* </ul>
*/
static ParameterResolver forDoubleStringOrPlaceholderParameter() {
return DOUBLE_STRING_OR_PLACEHOLDER_PARAMETER_RESOLVER;
}

private PipelineFunctionParameterResolverFactory() {
throw new AssertionError();
}
Expand Down Expand Up @@ -128,6 +143,9 @@ static class ParameterResolver {
private static final String OPEN_PARENTHESIS = "\\(";
private static final String CLOSED_PARENTHESIS = "\\)";

static final String EXISTS_FUNCTION =
OPEN_PARENTHESIS + ".*"+ PARAMETER_SEPARATOR + "\\s*'exists'\\s*" + CLOSED_PARENTHESIS;

private final Pattern pattern;
private final int numberOfParameters;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2021 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.ditto.internal.models.placeholders.filter;

/**
* Keeps the value if passed parameters is not empty.
*/
final class ExistsFunction implements FilterFunction {

@Override
public String getName() {
return "exists";
}

@Override
public boolean apply(final String... parameters) {
if (parameters.length != 1) {
return false;
}
final String toMatch = parameters[0];
return !toMatch.isEmpty();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,13 @@ public enum FilterFunctions implements FilterFunction {
* the second parameter, where {@code ?} matches a character and {@code *} matches 0 or more characters.
* Consult the documentation about the RQL expression {@code like} for pattern examples.
*/
LIKE(new LikeFunction());
LIKE(new LikeFunction()),

/**
* The {@code 'exists'} function keeps the value if passed parameter is not empty.
* Consult the documentation about the RQL expression {@code exists} for pattern examples.
*/
EXISTS(new ExistsFunction());

private final FilterFunction rqlFunction;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ public final class PipelineFunctionFilterTest {

private static final String KNOWN_VALUE = "some value";
private static final PipelineElement KNOWN_INPUT = PipelineElement.resolved(KNOWN_VALUE);
private static final String KNOWN_BOOLEAN = "true";
private static final PipelineElement KNOWN_INPUT_BOOLEAN = PipelineElement.resolved(KNOWN_BOOLEAN);

private final PipelineFunctionFilter underTest = new PipelineFunctionFilter();

Expand Down Expand Up @@ -180,6 +182,23 @@ public void filterFailsWithOneUnresolvedValue() {
assertThat(underTest.apply(KNOWN_INPUT, params, expressionResolver)).isEmpty();
}


@Test
public void existsSucceedsWithValueResolved() {
when(expressionResolver.resolveAsPipelineElement("header:reply-to"))
.thenReturn(PipelineElement.resolved("true"));
final String params = String.format("(%s,'%s')", "header:reply-to", "exists");
assertThat(underTest.apply(KNOWN_INPUT_BOOLEAN, params, expressionResolver)).contains(KNOWN_BOOLEAN);
}

@Test
public void existsFailsWithValueUnresolved() {
when(expressionResolver.resolveAsPipelineElement("header:reply-to"))
.thenReturn(PipelineElement.unresolved());
final String params = String.format("(%s,'%s')", "header:reply-to", "exists");
assertThat(underTest.apply(KNOWN_INPUT_BOOLEAN, params, expressionResolver)).isEmpty();
}

private void testPatternMatching(final String arg, final String pattern, final boolean shouldMatch) {
final String params = String.format("('%s','like','%s')", arg, pattern);
assertThat(underTest.apply(KNOWN_INPUT, params, expressionResolver))
Expand Down

0 comments on commit d0616a7

Please sign in to comment.