Fix not equal operator (#935)
* Use nested query in getNotEqual Predicate * Refactor RSQL Utility + use identifierField for field enums * Don't join in case of not equal rsql operator * Bugfix for automatic cross join + small refactoring * Fix rsql out operator * Fix tests for out-operator + extend TargetFieldTest * Use inner join for subquery * Don't use subquery for simple rsql queries * Refactor RSQLUtility * Change some methods to static * Only use outer joins when they are needed * Add tests for empty tag names * Minor changes and refactoring for RSQLUtility * Refactor methods to remove duplications Signed-off-by: Sebastian Firsching <sebastian.firsching@bosch-si.com>
This commit is contained in:
committed by
GitHub
parent
6df1e934ee
commit
0d52524202
@@ -36,4 +36,9 @@ public enum DistributionSetMetadataFields implements FieldNameProvider {
|
||||
public String getFieldName() {
|
||||
return fieldName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String identifierFieldName() {
|
||||
return KEY.getFieldName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,4 +81,13 @@ public interface FieldNameProvider {
|
||||
default boolean isMap() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the field, that identifies the entity.
|
||||
*
|
||||
* @return the name of the identifier, by default 'id'
|
||||
*/
|
||||
default String identifierFieldName() {
|
||||
return "id";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,4 +41,9 @@ public enum SoftwareModuleMetadataFields implements FieldNameProvider {
|
||||
public String getFieldName() {
|
||||
return fieldName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String identifierFieldName() {
|
||||
return KEY.getFieldName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,4 +33,9 @@ public enum TargetMetadataFields implements FieldNameProvider {
|
||||
public String getFieldName() {
|
||||
return fieldName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String identifierFieldName() {
|
||||
return KEY.getFieldName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
@@ -31,6 +33,7 @@ import javax.persistence.criteria.Path;
|
||||
import javax.persistence.criteria.PluralJoin;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
import javax.persistence.criteria.Subquery;
|
||||
|
||||
import org.apache.commons.lang3.text.StrLookup;
|
||||
import org.eclipse.hawkbit.repository.FieldNameProvider;
|
||||
@@ -48,6 +51,8 @@ import org.springframework.orm.jpa.vendor.Database;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import cz.jirutka.rsql.parser.RSQLParser;
|
||||
import cz.jirutka.rsql.parser.RSQLParserException;
|
||||
import cz.jirutka.rsql.parser.ast.AndNode;
|
||||
@@ -180,7 +185,7 @@ public final class RSQLUtility {
|
||||
query.distinct(true);
|
||||
|
||||
final JpqQueryRSQLVisitor<A, T> jpqQueryRSQLVisitor = new JpqQueryRSQLVisitor<>(root, cb, enumType,
|
||||
virtualPropertyReplacer, database);
|
||||
virtualPropertyReplacer, database, query);
|
||||
final List<Predicate> accept = rootNode.<List<Predicate>, String> accept(jpqQueryRSQLVisitor);
|
||||
|
||||
if (!CollectionUtils.isEmpty(accept)) {
|
||||
@@ -206,29 +211,35 @@ public final class RSQLUtility {
|
||||
private static final class JpqQueryRSQLVisitor<A extends Enum<A> & FieldNameProvider, T>
|
||||
implements RSQLVisitor<List<Predicate>, String> {
|
||||
private static final char ESCAPE_CHAR = '\\';
|
||||
private static final List<String> NO_JOINS_OPERATOR = Lists.newArrayList("!=", "=out=");
|
||||
|
||||
public static final Character LIKE_WILDCARD = '*';
|
||||
|
||||
private final Root<T> root;
|
||||
private final CriteriaBuilder cb;
|
||||
private final CriteriaQuery<?> query;
|
||||
private final Class<A> enumType;
|
||||
private final VirtualPropertyReplacer virtualPropertyReplacer;
|
||||
private int level;
|
||||
private boolean isOrLevel;
|
||||
private final Map<Integer, Set<Join<Object, Object>>> joinsInLevel = new HashMap<>(3);
|
||||
private boolean joinsNeeded;
|
||||
|
||||
private final SimpleTypeConverter simpleTypeConverter;
|
||||
|
||||
private final Database database;
|
||||
|
||||
private JpqQueryRSQLVisitor(final Root<T> root, final CriteriaBuilder cb, final Class<A> enumType,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final Database database) {
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final Database database,
|
||||
final CriteriaQuery<?> query) {
|
||||
this.root = root;
|
||||
this.cb = cb;
|
||||
this.query = query;
|
||||
this.enumType = enumType;
|
||||
this.virtualPropertyReplacer = virtualPropertyReplacer;
|
||||
simpleTypeConverter = new SimpleTypeConverter();
|
||||
this.simpleTypeConverter = new SimpleTypeConverter();
|
||||
this.database = database;
|
||||
this.joinsNeeded = false;
|
||||
}
|
||||
|
||||
private void beginLevel(final boolean isOr) {
|
||||
@@ -288,7 +299,7 @@ public final class RSQLUtility {
|
||||
|
||||
private String getAndValidatePropertyFieldName(final A propertyEnum, final ComparisonNode node) {
|
||||
|
||||
final String[] graph = node.getSelector().split("\\" + FieldNameProvider.SUB_ATTRIBUTE_SEPERATOR);
|
||||
final String[] graph = getSubAttributesFrom(node.getSelector());
|
||||
|
||||
validateMapParameter(propertyEnum, node, graph);
|
||||
|
||||
@@ -363,33 +374,40 @@ public final class RSQLUtility {
|
||||
* dot notated field path
|
||||
* @return the Path for a field
|
||||
*/
|
||||
private Path<Object> getFieldPath(final A enumField, final String finalProperty) {
|
||||
Path<Object> fieldPath = null;
|
||||
final String[] split = finalProperty.split("\\" + FieldNameProvider.SUB_ATTRIBUTE_SEPERATOR);
|
||||
|
||||
private Path<Object> getFieldPath(final A enumField, final String finalProperty) {
|
||||
return (Path<Object>) getFieldPath(root, getSubAttributesFrom(finalProperty), enumField.isMap(),
|
||||
this::getJoinFieldPath);
|
||||
}
|
||||
|
||||
private Path<?> getJoinFieldPath(final Path<?> fieldPath, final String fieldNameSplit) {
|
||||
if (fieldPath instanceof PluralJoin) {
|
||||
final Join<Object, ?> join = (Join<Object, ?>) fieldPath;
|
||||
final From<?, Object> joinParent = join.getParent();
|
||||
final Optional<Join<Object, Object>> currentJoinOfType = findCurrentJoinOfType(join.getJavaType());
|
||||
if (currentJoinOfType.isPresent() && isOrLevel) {
|
||||
// remove the additional join and use the existing one
|
||||
joinParent.getJoins().remove(join);
|
||||
return currentJoinOfType.get();
|
||||
} else {
|
||||
final Join<Object, Object> newJoin = joinParent.join(fieldNameSplit, JoinType.LEFT);
|
||||
addCurrentJoin(newJoin);
|
||||
return newJoin;
|
||||
}
|
||||
}
|
||||
return fieldPath;
|
||||
}
|
||||
|
||||
private static Path<?> getFieldPath(final Root<?> root, final String[] split, final boolean isMapKeyField,
|
||||
final BiFunction<Path<?>, String, Path<?>> joinFieldPathProvider) {
|
||||
Path<?> fieldPath = null;
|
||||
for (int i = 0; i < split.length; i++) {
|
||||
final boolean isMapKeyField = enumField.isMap() && i == (split.length - 1);
|
||||
if (isMapKeyField) {
|
||||
if (isMapKeyField && i == (split.length - 1)) {
|
||||
return fieldPath;
|
||||
}
|
||||
|
||||
final String fieldNameSplit = split[i];
|
||||
fieldPath = (fieldPath != null) ? fieldPath.get(fieldNameSplit) : root.get(fieldNameSplit);
|
||||
if (fieldPath instanceof PluralJoin) {
|
||||
final Join<Object, ?> join = (Join<Object, ?>) fieldPath;
|
||||
final From<?, Object> joinParent = join.getParent();
|
||||
final Optional<Join<Object, Object>> currentJoinOfType = findCurrentJoinOfType(join.getJavaType());
|
||||
if (currentJoinOfType.isPresent() && isOrLevel) {
|
||||
// remove the additional join and use the existing one
|
||||
joinParent.getJoins().remove(join);
|
||||
fieldPath = currentJoinOfType.get();
|
||||
} else {
|
||||
final Join<Object, Object> newJoin = joinParent.join(fieldNameSplit, JoinType.LEFT);
|
||||
addCurrentJoin(newJoin);
|
||||
fieldPath = newJoin;
|
||||
}
|
||||
|
||||
}
|
||||
fieldPath = joinFieldPathProvider.apply(fieldPath, fieldNameSplit);
|
||||
}
|
||||
return fieldPath;
|
||||
}
|
||||
@@ -413,14 +431,20 @@ public final class RSQLUtility {
|
||||
final String finalProperty = getAndValidatePropertyFieldName(fieldName, node);
|
||||
|
||||
final List<String> values = node.getArguments();
|
||||
final List<Object> transformedValue = new ArrayList<>();
|
||||
final List<Object> transformedValues = new ArrayList<>();
|
||||
final Path<Object> fieldPath = getFieldPath(fieldName, finalProperty);
|
||||
|
||||
for (final String value : values) {
|
||||
transformedValue.add(convertValueIfNecessary(node, fieldName, value, fieldPath));
|
||||
transformedValues.add(convertValueIfNecessary(node, fieldName, value, fieldPath));
|
||||
}
|
||||
|
||||
return mapToPredicate(node, fieldPath, node.getArguments(), transformedValue, fieldName, database);
|
||||
this.joinsNeeded = this.joinsNeeded || areJoinsNeeded(node);
|
||||
|
||||
return mapToPredicate(node, fieldPath, node.getArguments(), transformedValues, fieldName, finalProperty);
|
||||
}
|
||||
|
||||
private static boolean areJoinsNeeded(final ComparisonNode node) {
|
||||
return !NO_JOINS_OPERATOR.contains(node.getOperator().getSymbol());
|
||||
}
|
||||
|
||||
// Exception squid:S2095 - see
|
||||
@@ -453,7 +477,7 @@ public final class RSQLUtility {
|
||||
|
||||
private A getFieldEnumByName(final ComparisonNode node) {
|
||||
String enumName = node.getSelector();
|
||||
final String[] graph = enumName.split("\\" + FieldNameProvider.SUB_ATTRIBUTE_SEPERATOR);
|
||||
final String[] graph = getSubAttributesFrom(enumName);
|
||||
if (graph.length != 0) {
|
||||
enumName = graph[0];
|
||||
}
|
||||
@@ -484,8 +508,7 @@ public final class RSQLUtility {
|
||||
return value;
|
||||
}
|
||||
|
||||
private Object convertBooleanValue(final ComparisonNode node, final String value,
|
||||
final Class<?> javaType) {
|
||||
private Object convertBooleanValue(final ComparisonNode node, final String value, final Class<?> javaType) {
|
||||
try {
|
||||
return simpleTypeConverter.convertIfNecessary(value, javaType);
|
||||
} catch (final TypeMismatchException e) {
|
||||
@@ -533,11 +556,7 @@ public final class RSQLUtility {
|
||||
|
||||
private List<Predicate> mapToPredicate(final ComparisonNode node, final Path<Object> fieldPath,
|
||||
final List<String> values, final List<Object> transformedValues, final A enumField,
|
||||
final Database database) {
|
||||
// only 'equal' and 'notEqual' can handle transformed value like
|
||||
// enums. The JPA API cannot handle object types for greaterThan etc
|
||||
// methods.
|
||||
final Object transformedValue = transformedValues.get(0);
|
||||
final String finalProperty) {
|
||||
|
||||
String value = values.get(0);
|
||||
// if lookup is available, replace macros ...
|
||||
@@ -548,19 +567,26 @@ public final class RSQLUtility {
|
||||
final Predicate mapPredicate = mapToMapPredicate(node, fieldPath, enumField);
|
||||
|
||||
final Predicate valuePredicate = addOperatorPredicate(node, getMapValueFieldPath(enumField, fieldPath),
|
||||
transformedValues, transformedValue, value, database);
|
||||
transformedValues, value, finalProperty, enumField);
|
||||
|
||||
return toSingleList(mapPredicate != null ? cb.and(mapPredicate, valuePredicate) : valuePredicate);
|
||||
}
|
||||
|
||||
private Predicate addOperatorPredicate(final ComparisonNode node, final Path<Object> fieldPath,
|
||||
final List<Object> transformedValues, final Object transformedValue, final String value,
|
||||
final Database database) {
|
||||
switch (node.getOperator().getSymbol()) {
|
||||
final List<Object> transformedValues, final String value, final String finalProperty,
|
||||
final A enumField) {
|
||||
|
||||
// only 'equal' and 'notEqual' can handle transformed value like
|
||||
// enums. The JPA API cannot handle object types for greaterThan etc
|
||||
// methods.
|
||||
final Object transformedValue = transformedValues.get(0);
|
||||
final String operator = node.getOperator().getSymbol();
|
||||
|
||||
switch (operator) {
|
||||
case "==":
|
||||
return getEqualToPredicate(transformedValue, fieldPath, database);
|
||||
return getEqualToPredicate(transformedValue, fieldPath);
|
||||
case "!=":
|
||||
return getNotEqualToPredicate(transformedValue, fieldPath, database);
|
||||
return getNotEqualToPredicate(transformedValue, fieldPath, finalProperty, enumField);
|
||||
case "=gt=":
|
||||
return cb.greaterThan(pathOfString(fieldPath), value);
|
||||
case "=ge=":
|
||||
@@ -572,10 +598,10 @@ public final class RSQLUtility {
|
||||
case "=in=":
|
||||
return getInPredicate(transformedValues, fieldPath);
|
||||
case "=out=":
|
||||
return getOutPredicate(transformedValues, fieldPath);
|
||||
return getOutPredicate(transformedValues, finalProperty, enumField, fieldPath);
|
||||
default:
|
||||
throw new RSQLParameterSyntaxException("operator symbol {" + node.getOperator().getSymbol()
|
||||
+ "} is either not supported or not implemented");
|
||||
throw new RSQLParameterSyntaxException(
|
||||
"operator symbol {" + operator + "} is either not supported or not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -594,19 +620,38 @@ public final class RSQLUtility {
|
||||
}
|
||||
}
|
||||
|
||||
private Predicate getOutPredicate(final List<Object> transformedValues, final Path<Object> fieldPath) {
|
||||
final List<String> outParams = new ArrayList<>();
|
||||
for (final Object param : transformedValues) {
|
||||
if (param instanceof String) {
|
||||
outParams.add(((String) param).toUpperCase());
|
||||
}
|
||||
}
|
||||
if (!outParams.isEmpty()) {
|
||||
return cb.not(cb.upper(pathOfString(fieldPath)).in(outParams));
|
||||
} else {
|
||||
return cb.not(fieldPath.in(transformedValues));
|
||||
private Predicate getOutPredicate(final List<Object> transformedValues, final String finalProperty,
|
||||
final A enumField, final Path<Object> fieldPath) {
|
||||
|
||||
final String[] fieldNames = getSubAttributesFrom(finalProperty);
|
||||
final List<String> outParams = transformedValues.stream().filter(String.class::isInstance)
|
||||
.map(String.class::cast).map(String::toUpperCase).collect(Collectors.toList());
|
||||
|
||||
if (isSimpleField(fieldNames, enumField.isMap())) {
|
||||
return toNullOrNotInPredicate(fieldPath, transformedValues, outParams);
|
||||
}
|
||||
|
||||
clearOuterJoinsIfNotNeeded();
|
||||
|
||||
return toOutWithSubQueryPredicate(fieldNames, transformedValues, enumField, outParams);
|
||||
}
|
||||
|
||||
private Predicate toNullOrNotInPredicate(final Path<Object> fieldPath, final List<Object> transformedValues,
|
||||
final List<String> outParams) {
|
||||
|
||||
final Path<String> pathOfString = pathOfString(fieldPath);
|
||||
final Predicate inPredicate = outParams.isEmpty() ? fieldPath.in(transformedValues)
|
||||
: cb.upper(pathOfString).in(outParams);
|
||||
|
||||
return cb.or(cb.isNull(pathOfString), cb.not(inPredicate));
|
||||
}
|
||||
|
||||
private Predicate toOutWithSubQueryPredicate(final String[] fieldNames, final List<Object> transformedValues,
|
||||
final A enumField, final List<String> outParams) {
|
||||
final Function<Expression<String>, Predicate> inPredicateProvider = expressionToCompare -> outParams
|
||||
.isEmpty() ? cb.upper(expressionToCompare).in(transformedValues)
|
||||
: cb.upper(expressionToCompare).in(outParams);
|
||||
return toNotExistsSubQueryPredicate(fieldNames, enumField, inPredicateProvider);
|
||||
}
|
||||
|
||||
private Path<Object> getMapValueFieldPath(final A enumField, final Path<Object> fieldPath) {
|
||||
@@ -625,7 +670,9 @@ public final class RSQLUtility {
|
||||
if (!enumField.isMap()) {
|
||||
return null;
|
||||
}
|
||||
final String[] graph = node.getSelector().split("\\" + FieldNameProvider.SUB_ATTRIBUTE_SEPERATOR);
|
||||
|
||||
final String[] graph = getSubAttributesFrom(node.getSelector());
|
||||
|
||||
final String keyValue = graph[graph.length - 1];
|
||||
if (fieldPath instanceof MapJoin) {
|
||||
// Currently we support only string key .So below cast is safe.
|
||||
@@ -640,15 +687,14 @@ public final class RSQLUtility {
|
||||
return cb.equal(cb.upper(fieldPath.get(keyFieldName)), keyValue.toUpperCase());
|
||||
}
|
||||
|
||||
private Predicate getEqualToPredicate(final Object transformedValue, final Path<Object> fieldPath,
|
||||
final Database database) {
|
||||
private Predicate getEqualToPredicate(final Object transformedValue, final Path<Object> fieldPath) {
|
||||
if (transformedValue instanceof String) {
|
||||
if (StringUtils.isEmpty(transformedValue)) {
|
||||
return cb.or(cb.isNull(pathOfString(fieldPath)), cb.equal(pathOfString(fieldPath), ""));
|
||||
}
|
||||
|
||||
final String preFormattedValue = escapeValueToSQL((String) transformedValue, database, ESCAPE_CHAR);
|
||||
return cb.like(cb.upper(pathOfString(fieldPath)), preFormattedValue.toUpperCase(), ESCAPE_CHAR);
|
||||
final String sqlValue = toSQL((String) transformedValue);
|
||||
return cb.like(cb.upper(pathOfString(fieldPath)), sqlValue, ESCAPE_CHAR);
|
||||
}
|
||||
|
||||
if (transformedValue == null) {
|
||||
@@ -659,34 +705,124 @@ public final class RSQLUtility {
|
||||
}
|
||||
|
||||
private Predicate getNotEqualToPredicate(final Object transformedValue, final Path<Object> fieldPath,
|
||||
final Database database) {
|
||||
if (transformedValue instanceof String) {
|
||||
if (StringUtils.isEmpty(transformedValue)) {
|
||||
return cb.and(cb.isNotNull(pathOfString(fieldPath)), cb.notEqual(pathOfString(fieldPath), ""));
|
||||
}
|
||||
|
||||
final String preFormattedValue = escapeValueToSQL((String) transformedValue, database, ESCAPE_CHAR);
|
||||
return cb.notLike(cb.upper(pathOfString(fieldPath)), preFormattedValue.toUpperCase(), ESCAPE_CHAR);
|
||||
}
|
||||
final String finalProperty, final A enumField) {
|
||||
|
||||
if (transformedValue == null) {
|
||||
return cb.isNotNull(pathOfString(fieldPath));
|
||||
return toNotNullPredicate(fieldPath);
|
||||
}
|
||||
|
||||
if (transformedValue instanceof String) {
|
||||
if (StringUtils.isEmpty(transformedValue)) {
|
||||
return toNotNullAndNotEmptyPredicate(fieldPath);
|
||||
}
|
||||
|
||||
final String sqlValue = toSQL((String) transformedValue);
|
||||
final String[] fieldNames = getSubAttributesFrom(finalProperty);
|
||||
|
||||
if (isSimpleField(fieldNames, enumField.isMap())) {
|
||||
return toNullOrNotLikePredicate(fieldPath, sqlValue);
|
||||
}
|
||||
|
||||
clearOuterJoinsIfNotNeeded();
|
||||
|
||||
return toNotEqualWithSubQueryPredicate(enumField, sqlValue, fieldNames);
|
||||
}
|
||||
|
||||
return toNotEqualPredicate(fieldPath, transformedValue);
|
||||
}
|
||||
|
||||
private void clearOuterJoinsIfNotNeeded() {
|
||||
if (!joinsNeeded) {
|
||||
root.getJoins().clear();
|
||||
}
|
||||
}
|
||||
|
||||
private Predicate toNotNullPredicate(final Path<Object> fieldPath) {
|
||||
return cb.isNotNull(pathOfString(fieldPath));
|
||||
}
|
||||
|
||||
private Predicate toNotEqualPredicate(final Path<Object> fieldPath, final Object transformedValue) {
|
||||
return cb.notEqual(fieldPath, transformedValue);
|
||||
}
|
||||
|
||||
private static String escapeValueToSQL(final String transformedValue, final Database database,
|
||||
final char escapeChar) {
|
||||
private Predicate toNullOrNotLikePredicate(final Path<Object> fieldPath, final String sqlValue) {
|
||||
return cb.or(cb.isNull(pathOfString(fieldPath)),
|
||||
cb.notLike(cb.upper(pathOfString(fieldPath)), sqlValue, ESCAPE_CHAR));
|
||||
}
|
||||
|
||||
private Predicate toNotNullAndNotEmptyPredicate(final Path<Object> fieldPath) {
|
||||
return cb.and(cb.isNotNull(pathOfString(fieldPath)), cb.notEqual(pathOfString(fieldPath), ""));
|
||||
}
|
||||
|
||||
private Predicate toNotEqualWithSubQueryPredicate(final A enumField, final String sqlValue,
|
||||
final String[] fieldNames) {
|
||||
final Function<Expression<String>, Predicate> likePredicateProvider = expressionToCompare -> cb
|
||||
.like(cb.upper(expressionToCompare), sqlValue);
|
||||
return toNotExistsSubQueryPredicate(fieldNames, enumField, likePredicateProvider);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private Predicate toNotExistsSubQueryPredicate(final String[] fieldNames, final A enumField,
|
||||
final Function<Expression<String>, Predicate> subQueryPredicateProvider) {
|
||||
final Class<?> javaType = root.getJavaType();
|
||||
final Subquery<?> subquery = query.subquery(javaType);
|
||||
final Root subqueryRoot = subquery.from(javaType);
|
||||
final Predicate equalPredicate = cb.equal(root.get(enumField.identifierFieldName()),
|
||||
subqueryRoot.get(enumField.identifierFieldName()));
|
||||
final Path innerFieldPath = getInnerFieldPath(subqueryRoot, fieldNames, enumField.isMap());
|
||||
final Expression<String> expressionToCompare = getExpressionToCompare(innerFieldPath, enumField);
|
||||
final Predicate subQueryPredicate = subQueryPredicateProvider.apply(expressionToCompare);
|
||||
subquery.select(subqueryRoot).where(cb.and(equalPredicate, subQueryPredicate));
|
||||
return cb.not(cb.exists(subquery));
|
||||
}
|
||||
|
||||
private static String[] getSubAttributesFrom(final String property) {
|
||||
return property.split("\\" + FieldNameProvider.SUB_ATTRIBUTE_SEPERATOR);
|
||||
}
|
||||
|
||||
private static boolean isSimpleField(final String[] split, final boolean isMapKeyField) {
|
||||
return split.length == 1 || (split.length == 2 && isMapKeyField);
|
||||
}
|
||||
|
||||
private Expression<String> getExpressionToCompare(final Path innerFieldPath, final A enumField) {
|
||||
if (!enumField.isMap()) {
|
||||
return pathOfString(innerFieldPath);
|
||||
}
|
||||
if (innerFieldPath instanceof MapJoin) {
|
||||
// Currently we support only string key .So below cast
|
||||
// is safe.
|
||||
return (Expression<String>) (((MapJoin<?, ?, ?>) pathOfString(innerFieldPath)).value());
|
||||
}
|
||||
final String valueFieldName = enumField.getSubEntityMapTuple().map(Entry::getValue)
|
||||
.orElseThrow(() -> new UnsupportedOperationException(
|
||||
"For the fields, defined as Map, only Map java type or tuple in the form of SimpleImmutableEntry are allowed. Neither of those could be found!"));
|
||||
return pathOfString(innerFieldPath).get(valueFieldName);
|
||||
}
|
||||
|
||||
private static Path<?> getInnerFieldPath(final Root<?> subqueryRoot, final String[] split,
|
||||
final boolean isMapKeyField) {
|
||||
return getFieldPath(subqueryRoot, split, isMapKeyField,
|
||||
(fieldPath, fieldNameSplit) -> getInnerJoinFieldPath(subqueryRoot, fieldPath, fieldNameSplit));
|
||||
}
|
||||
|
||||
private static Path<?> getInnerJoinFieldPath(final Root<?> subqueryRoot, final Path<?> fieldPath,
|
||||
final String fieldNameSplit) {
|
||||
if (fieldPath instanceof Join) {
|
||||
return subqueryRoot.join(fieldNameSplit, JoinType.INNER);
|
||||
}
|
||||
return fieldPath;
|
||||
}
|
||||
|
||||
private String toSQL(final String transformedValue) {
|
||||
final String escaped;
|
||||
|
||||
if (database == Database.SQL_SERVER) {
|
||||
escaped = transformedValue.replace("%", "[%]").replace("_", "[_]");
|
||||
} else {
|
||||
escaped = transformedValue.replace("%", escapeChar + "%").replace("_", escapeChar + "_");
|
||||
escaped = transformedValue.replace("%", ESCAPE_CHAR + "%").replace("_", ESCAPE_CHAR + "_");
|
||||
}
|
||||
|
||||
return escaped.replace(LIKE_WILDCARD, '%');
|
||||
return escaped.replace(LIKE_WILDCARD, '%').toUpperCase();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@@ -79,12 +79,13 @@ public class RSQLDistributionSetFieldTest extends AbstractJpaIntegrationTest {
|
||||
assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "==''", 1);
|
||||
assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "!=''", 4);
|
||||
assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "==DS", 1);
|
||||
assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "!=DS", 3);
|
||||
assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "!=DS*", 3);
|
||||
assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "!=DS", 4);
|
||||
assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "==DS*", 2);
|
||||
assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "==DS%", 1);
|
||||
assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "==noExist*", 0);
|
||||
assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "=in=(DS,notexist)", 1);
|
||||
assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "=out=(DS,notexist)", 3);
|
||||
assertRSQLQuery(DistributionSetFields.DESCRIPTION.name() + "=out=(DS,notexist)", 4);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -115,12 +116,11 @@ public class RSQLDistributionSetFieldTest extends AbstractJpaIntegrationTest {
|
||||
@Description("Test filter distribution set by tag name")
|
||||
public void testFilterByTag() {
|
||||
assertRSQLQuery(DistributionSetFields.TAG.name() + "==Tag1", 2);
|
||||
// does not include untagged sets
|
||||
assertRSQLQuery(DistributionSetFields.TAG.name() + "!=Tag1", 0);
|
||||
assertRSQLQuery(DistributionSetFields.TAG.name() + "!=Tag1", 3);
|
||||
assertRSQLQuery(DistributionSetFields.TAG.name() + "==T*", 2);
|
||||
assertRSQLQuery(DistributionSetFields.TAG.name() + "==noExist*", 0);
|
||||
assertRSQLQuery(DistributionSetFields.TAG.name() + "=in=(Tag1,notexist)", 2);
|
||||
assertRSQLQuery(DistributionSetFields.TAG.name() + "=out=(null)", 2);
|
||||
assertRSQLQuery(DistributionSetFields.TAG.name() + "=out=(null)", 5);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -65,9 +65,9 @@ public class RSQLDistributionSetMetadataFieldsTest extends AbstractJpaIntegratio
|
||||
assertRSQLQuery(DistributionSetMetadataFields.VALUE.name() + "==''", 1);
|
||||
assertRSQLQuery(DistributionSetMetadataFields.VALUE.name() + "!=''", 5);
|
||||
assertRSQLQuery(DistributionSetMetadataFields.VALUE.name() + "==1", 1);
|
||||
assertRSQLQuery(DistributionSetMetadataFields.VALUE.name() + "!=1", 4);
|
||||
assertRSQLQuery(DistributionSetMetadataFields.VALUE.name() + "!=1", 5);
|
||||
assertRSQLQuery(DistributionSetMetadataFields.VALUE.name() + "=in=(1,2)", 2);
|
||||
assertRSQLQuery(DistributionSetMetadataFields.VALUE.name() + "=out=(1,2)", 3);
|
||||
assertRSQLQuery(DistributionSetMetadataFields.VALUE.name() + "=out=(1,2)", 4);
|
||||
}
|
||||
|
||||
private void assertRSQLQuery(final String rsqlParam, final long expectedEntities) {
|
||||
|
||||
@@ -76,10 +76,10 @@ public class RSQLSoftwareModuleFieldTest extends AbstractJpaIntegrationTest {
|
||||
assertRSQLQuery(SoftwareModuleFields.DESCRIPTION.name() + "==''", 1);
|
||||
assertRSQLQuery(SoftwareModuleFields.DESCRIPTION.name() + "!=''", 4);
|
||||
assertRSQLQuery(SoftwareModuleFields.DESCRIPTION.name() + "==agent-hub", 1);
|
||||
assertRSQLQuery(SoftwareModuleFields.DESCRIPTION.name() + "!=agent-hub", 3);
|
||||
assertRSQLQuery(SoftwareModuleFields.DESCRIPTION.name() + "!=agent-hub", 4);
|
||||
assertRSQLQuery(SoftwareModuleFields.DESCRIPTION.name() + "==noExist*", 0);
|
||||
assertRSQLQuery(SoftwareModuleFields.DESCRIPTION.name() + "=in=(agent-hub,notexist)", 1);
|
||||
assertRSQLQuery(SoftwareModuleFields.DESCRIPTION.name() + "=out=(agent-hub,notexist)", 3);
|
||||
assertRSQLQuery(SoftwareModuleFields.DESCRIPTION.name() + "=out=(agent-hub,notexist)", 4);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -71,9 +71,9 @@ public class RSQLSoftwareModuleMetadataFieldsTest extends AbstractJpaIntegration
|
||||
assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "==''", 1);
|
||||
assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "!=''", 6);
|
||||
assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "==1", 1);
|
||||
assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "!=1", 5);
|
||||
assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "!=1", 6);
|
||||
assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "=in=(1,2)", 2);
|
||||
assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "=out=(1,2)", 4);
|
||||
assertRSQLQuery(SoftwareModuleMetadataFields.VALUE.name() + "=out=(1,2)", 5);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -37,6 +37,9 @@ public class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
|
||||
private Target target;
|
||||
private Target target2;
|
||||
|
||||
private static final String OR = ",";
|
||||
private static final String AND = ";";
|
||||
|
||||
@Before
|
||||
public void setupBeforeTest() throws InterruptedException {
|
||||
|
||||
@@ -73,7 +76,8 @@ public class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
targetManagement.assignTag(Arrays.asList(target3.getControllerId(), target4.getControllerId()),
|
||||
targetTag2.getId());
|
||||
targetManagement.assignTag(Arrays.asList(target3.getControllerId(), target4.getControllerId()),
|
||||
targetManagement.assignTag(
|
||||
Arrays.asList(target.getControllerId(), target3.getControllerId(), target4.getControllerId()),
|
||||
targetTag3.getId());
|
||||
|
||||
assignDistributionSet(ds.getId(), target.getControllerId());
|
||||
@@ -85,6 +89,7 @@ public class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
|
||||
assertRSQLQuery(TargetFields.ID.name() + "==targetId123", 1);
|
||||
assertRSQLQuery(TargetFields.ID.name() + "==target*", 5);
|
||||
assertRSQLQuery(TargetFields.ID.name() + "==noExist*", 0);
|
||||
assertRSQLQuery(TargetFields.ID.name() + "!=targetId123", 4);
|
||||
assertRSQLQuery(TargetFields.ID.name() + "=in=(targetId123,notexist)", 1);
|
||||
assertRSQLQuery(TargetFields.ID.name() + "=out=(targetId123,notexist)", 4);
|
||||
}
|
||||
@@ -95,6 +100,7 @@ public class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
|
||||
assertRSQLQuery(TargetFields.NAME.name() + "==targetName123", 1);
|
||||
assertRSQLQuery(TargetFields.NAME.name() + "==target*", 5);
|
||||
assertRSQLQuery(TargetFields.NAME.name() + "==noExist*", 0);
|
||||
assertRSQLQuery(TargetFields.NAME.name() + "!=targetName123", 4);
|
||||
assertRSQLQuery(TargetFields.NAME.name() + "=in=(targetName123,notexist)", 1);
|
||||
assertRSQLQuery(TargetFields.NAME.name() + "=out=(targetName123,notexist)", 4);
|
||||
}
|
||||
@@ -105,10 +111,11 @@ public class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
|
||||
assertRSQLQuery(TargetFields.DESCRIPTION.name() + "==''", 3);
|
||||
assertRSQLQuery(TargetFields.DESCRIPTION.name() + "!=''", 2);
|
||||
assertRSQLQuery(TargetFields.DESCRIPTION.name() + "==targetDesc123", 1);
|
||||
assertRSQLQuery(TargetFields.DESCRIPTION.name() + "!=targetDesc123", 4);
|
||||
assertRSQLQuery(TargetFields.DESCRIPTION.name() + "==target*", 2);
|
||||
assertRSQLQuery(TargetFields.DESCRIPTION.name() + "==noExist*", 0);
|
||||
assertRSQLQuery(TargetFields.DESCRIPTION.name() + "=in=(targetDesc123,notexist)", 1);
|
||||
assertRSQLQuery(TargetFields.DESCRIPTION.name() + "=out=(targetDesc123,notexist)", 1);
|
||||
assertRSQLQuery(TargetFields.DESCRIPTION.name() + "=out=(targetDesc123,notexist)", 4);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -117,6 +124,7 @@ public class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
|
||||
assertRSQLQuery(TargetFields.CONTROLLERID.name() + "==targetId123", 1);
|
||||
assertRSQLQuery(TargetFields.CONTROLLERID.name() + "==target*", 5);
|
||||
assertRSQLQuery(TargetFields.CONTROLLERID.name() + "==noExist*", 0);
|
||||
assertRSQLQuery(TargetFields.CONTROLLERID.name() + "!=targetId123", 4);
|
||||
assertRSQLQuery(TargetFields.CONTROLLERID.name() + "=in=(targetId123,notexist)", 1);
|
||||
assertRSQLQuery(TargetFields.CONTROLLERID.name() + "=out=(targetId123,notexist)", 4);
|
||||
}
|
||||
@@ -154,7 +162,7 @@ public class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
|
||||
assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".name==A*", 1);
|
||||
assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".name==noExist*", 0);
|
||||
assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".name=in=(AssignedDs,notexist)", 1);
|
||||
assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".name=out=(AssignedDs,notexist)", 0);
|
||||
assertRSQLQuery(TargetFields.ASSIGNEDDS.name() + ".name=out=(AssignedDs,notexist)", 4);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -166,28 +174,34 @@ public class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
|
||||
assertRSQLQuery(
|
||||
TargetFields.ASSIGNEDDS.name() + ".version=in=(" + TestdataFactory.DEFAULT_VERSION + ",notexist)", 1);
|
||||
assertRSQLQuery(
|
||||
TargetFields.ASSIGNEDDS.name() + ".version=out=(" + TestdataFactory.DEFAULT_VERSION + ",notexist)", 0);
|
||||
TargetFields.ASSIGNEDDS.name() + ".version=out=(" + TestdataFactory.DEFAULT_VERSION + ",notexist)", 4);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Test filter target by tag name")
|
||||
public void testFilterByTag() {
|
||||
assertRSQLQuery(TargetFields.TAG.name() + "==Tag1", 2);
|
||||
assertRSQLQuery(TargetFields.TAG.name() + "!=Tag1", 2);
|
||||
assertRSQLQuery(TargetFields.TAG.name() + "!=Tag1", 3);
|
||||
assertRSQLQuery(TargetFields.TAG.name() + "==T*", 4);
|
||||
assertRSQLQuery(TargetFields.TAG.name() + "!=T*", 1);
|
||||
assertRSQLQuery(TargetFields.TAG.name() + "==noExist*", 0);
|
||||
assertRSQLQuery(TargetFields.TAG.name() + "!=notexist", 4);
|
||||
assertRSQLQuery(TargetFields.TAG.name() + "!=notexist", 5);
|
||||
assertRSQLQuery(TargetFields.TAG.name() + "==''", 1);
|
||||
assertRSQLQuery(TargetFields.TAG.name() + "!=''", 4);
|
||||
assertRSQLQuery(TargetFields.TAG.name() + "=in=(Tag1,notexist)", 2);
|
||||
assertRSQLQuery(TargetFields.TAG.name() + "=in=(null)", 0);
|
||||
assertRSQLQuery(TargetFields.TAG.name() + "=out=(Tag1,notexist)", 2);
|
||||
assertRSQLQuery(TargetFields.TAG.name() + "=out=(null)", 4);
|
||||
assertRSQLQuery(TargetFields.TAG.name() + "=out=(Tag1,notexist)", 3);
|
||||
assertRSQLQuery(TargetFields.TAG.name() + "=out=(null)", 5);
|
||||
assertRSQLQuery(TargetFields.TAG.name() + "==Tag1" + OR + TargetFields.TAG.name() + "==Tag2", 4);
|
||||
assertRSQLQuery(TargetFields.TAG.name() + "!=Tag2" + AND + TargetFields.TAG.name() + "==Tag3", 1);
|
||||
assertRSQLQuery(TargetFields.TAG.name() + "!=Tag2" + OR + TargetFields.TAG.name() + "!=Tag3", 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Test filter target by lastTargetQuery")
|
||||
public void testFilterByLastTargetQuery() throws InterruptedException {
|
||||
assertRSQLQuery(TargetFields.LASTCONTROLLERREQUESTAT.name() + "==" + target.getLastTargetQuery(), 1);
|
||||
assertRSQLQuery(TargetFields.LASTCONTROLLERREQUESTAT.name() + "!=" + target.getLastTargetQuery(), 1);
|
||||
assertRSQLQuery(TargetFields.LASTCONTROLLERREQUESTAT.name() + "!=" + target.getLastTargetQuery(), 4);
|
||||
assertRSQLQuery(TargetFields.LASTCONTROLLERREQUESTAT.name() + "=lt=" + target.getLastTargetQuery(), 0);
|
||||
assertRSQLQuery(TargetFields.LASTCONTROLLERREQUESTAT.name() + "=lt=" + target2.getLastTargetQuery(), 1);
|
||||
assertRSQLQuery(TargetFields.LASTCONTROLLERREQUESTAT.name() + "=gt=" + target.getLastTargetQuery(), 1);
|
||||
@@ -205,7 +219,19 @@ public class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=in=(metaValue,notexist)", 1);
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=out=(metaValue,notexist)", 1);
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".notExist==metaValue", 0);
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey!=metaValue", 1);
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".notExist!=metaValue", 0);
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey!=notExist", 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Test filter based on more complex RSQL queries")
|
||||
public void testFilterByComplexQueries() {
|
||||
assertRSQLQuery(
|
||||
TargetFields.NAME.name() + "!=targetName123" + AND + TargetFields.METADATA.name() + ".metaKey!=value",
|
||||
0);
|
||||
assertRSQLQuery("(" + TargetFields.TAG.name() + "!=TAG1" + OR + TargetFields.TAG.name() + "!=TAG2)" + AND
|
||||
+ TargetFields.CONTROLLERID.name() + "!=targetId1235", 4);
|
||||
}
|
||||
|
||||
private void assertRSQLQuery(final String rsqlParam, final long expcetedTargets) {
|
||||
|
||||
@@ -80,7 +80,7 @@ public class RSQLTargetFilterQueryFieldsTest extends AbstractJpaIntegrationTest
|
||||
assertRSQLQuery(TargetFilterQueryFields.AUTOASSIGNDISTRIBUTIONSET.name() + ".name=in=("
|
||||
+ filter1.getAutoAssignDistributionSet().getName() + ",notexist)", 1);
|
||||
assertRSQLQuery(TargetFilterQueryFields.AUTOASSIGNDISTRIBUTIONSET.name() + ".name=out=("
|
||||
+ filter1.getAutoAssignDistributionSet().getName() + ",notexist)", 1);
|
||||
+ filter1.getAutoAssignDistributionSet().getName() + ",notexist)", 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -93,7 +93,7 @@ public class RSQLTargetFilterQueryFieldsTest extends AbstractJpaIntegrationTest
|
||||
assertRSQLQuery(TargetFilterQueryFields.AUTOASSIGNDISTRIBUTIONSET.name() + ".version=in=("
|
||||
+ TestdataFactory.DEFAULT_VERSION + ",notexist)", 2);
|
||||
assertRSQLQuery(TargetFilterQueryFields.AUTOASSIGNDISTRIBUTIONSET.name() + ".version=out=("
|
||||
+ TestdataFactory.DEFAULT_VERSION + ",notexist)", 0);
|
||||
+ TestdataFactory.DEFAULT_VERSION + ",notexist)", 1);
|
||||
}
|
||||
|
||||
private void assertRSQLQuery(final String rsqlParam, final long expectedFilterQueriesSize) {
|
||||
|
||||
@@ -64,9 +64,9 @@ public class RSQLTargetMetadataFieldsTest extends AbstractJpaIntegrationTest {
|
||||
assertRSQLQuery(TargetMetadataFields.VALUE.name() + "==''", 1);
|
||||
assertRSQLQuery(TargetMetadataFields.VALUE.name() + "!=''", 5);
|
||||
assertRSQLQuery(TargetMetadataFields.VALUE.name() + "==1", 1);
|
||||
assertRSQLQuery(TargetMetadataFields.VALUE.name() + "!=1", 4);
|
||||
assertRSQLQuery(TargetMetadataFields.VALUE.name() + "!=1", 5);
|
||||
assertRSQLQuery(TargetMetadataFields.VALUE.name() + "=in=(1,2)", 2);
|
||||
assertRSQLQuery(TargetMetadataFields.VALUE.name() + "=out=(1,2)", 3);
|
||||
assertRSQLQuery(TargetMetadataFields.VALUE.name() + "=out=(1,2)", 4);
|
||||
}
|
||||
|
||||
private void assertRSQLQuery(final String rsqlParam, final long expectedEntities) {
|
||||
|
||||
@@ -25,6 +25,7 @@ import javax.persistence.criteria.Expression;
|
||||
import javax.persistence.criteria.Path;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
import javax.persistence.criteria.Subquery;
|
||||
import javax.persistence.metamodel.Attribute;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DistributionSetFields;
|
||||
@@ -75,6 +76,11 @@ public class RSQLUtilityTest {
|
||||
@Mock
|
||||
private CriteriaBuilder criteriaBuilderMock;
|
||||
|
||||
@Mock
|
||||
private Subquery<SoftwareModule> subqueryMock;
|
||||
@Mock
|
||||
private Root<SoftwareModule> subqueryRootMock;
|
||||
|
||||
private final Database testDb = Database.H2;
|
||||
|
||||
@Mock
|
||||
@@ -202,27 +208,54 @@ public class RSQLUtilityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void correctRsqlBuildsNotLikePredicate() {
|
||||
public void correctRsqlBuildsSimpleNotLikePredicate() {
|
||||
reset(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
|
||||
final String correctRsql = "name!=abc";
|
||||
when(baseSoftwareModuleRootMock.get("name")).thenReturn(baseSoftwareModuleRootMock);
|
||||
when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class);
|
||||
|
||||
when(criteriaBuilderMock.isNull(any(Expression.class))).thenReturn(mock(Predicate.class));
|
||||
when(criteriaBuilderMock.notLike(any(Expression.class), anyString(), eq('\\')))
|
||||
.thenReturn(mock(Predicate.class));
|
||||
when(criteriaBuilderMock.<String> greaterThanOrEqualTo(any(Expression.class), any(String.class)))
|
||||
.thenReturn(mock(Predicate.class));
|
||||
when(criteriaBuilderMock.upper(eq(pathOfString(baseSoftwareModuleRootMock))))
|
||||
.thenReturn(pathOfString(baseSoftwareModuleRootMock));
|
||||
|
||||
// test
|
||||
RSQLUtility.parse(correctRsql, SoftwareModuleFields.class, null, testDb).toPredicate(baseSoftwareModuleRootMock,
|
||||
criteriaQueryMock, criteriaBuilderMock);
|
||||
|
||||
// verification
|
||||
verify(criteriaBuilderMock, times(1)).and(any(Predicate.class));
|
||||
verify(criteriaBuilderMock, times(1)).or(any(Predicate.class), any(Predicate.class));
|
||||
verify(criteriaBuilderMock, times(1)).isNull(eq(pathOfString(baseSoftwareModuleRootMock)));
|
||||
verify(criteriaBuilderMock, times(1)).notLike(eq(pathOfString(baseSoftwareModuleRootMock)),
|
||||
eq("abc".toUpperCase()), eq('\\'));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void correctRsqlBuildsNotSimpleNotLikePredicate() {
|
||||
reset(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
|
||||
// with this query a subquery has to be made, so it is no simple query
|
||||
final String correctRsql = "type!=abc";
|
||||
when(baseSoftwareModuleRootMock.get(anyString())).thenReturn(baseSoftwareModuleRootMock);
|
||||
when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class);
|
||||
|
||||
when(subqueryRootMock.get(anyString())).thenReturn(mock(Path.class));
|
||||
|
||||
when(criteriaBuilderMock.and(any(), any())).thenReturn(mock(Predicate.class));
|
||||
|
||||
when(criteriaQueryMock.subquery(SoftwareModule.class)).thenReturn(subqueryMock);
|
||||
|
||||
when(subqueryMock.from(SoftwareModule.class)).thenReturn(subqueryRootMock);
|
||||
when(subqueryMock.select(subqueryRootMock)).thenReturn(subqueryMock);
|
||||
|
||||
// test
|
||||
RSQLUtility.parse(correctRsql, SoftwareModuleFields.class, null, testDb).toPredicate(baseSoftwareModuleRootMock,
|
||||
criteriaQueryMock, criteriaBuilderMock);
|
||||
|
||||
// verification
|
||||
verify(criteriaBuilderMock, times(1)).not(criteriaBuilderMock.exists(eq(subqueryMock)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void correctRsqlBuildsLikePredicateWithPercentage() {
|
||||
reset(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock);
|
||||
|
||||
Reference in New Issue
Block a user