Optimize RSQL Visitor G2 (#1828)
Use single join for or of same type as 'tag==tag1 or tag==tag2 or tag==tag3' Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com>
This commit is contained in:
@@ -12,7 +12,9 @@ package org.eclipse.hawkbit.repository.jpa.rsql;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -56,8 +58,8 @@ import org.springframework.util.ObjectUtils;
|
|||||||
* @param <T> the entity type referenced by the root
|
* @param <T> the entity type referenced by the root
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class JpaQueryRsqlVisitorG2<A extends Enum<A> & FieldNameProvider, T> extends AbstractFieldNameRSQLVisitor<A>
|
public class JpaQueryRsqlVisitorG2<A extends Enum<A> & FieldNameProvider, T>
|
||||||
implements RSQLVisitor<List<Predicate>, String> {
|
extends AbstractFieldNameRSQLVisitor<A> implements RSQLVisitor<List<Predicate>, String> {
|
||||||
|
|
||||||
public static final Character LIKE_WILDCARD = '*';
|
public static final Character LIKE_WILDCARD = '*';
|
||||||
private static final char ESCAPE_CHAR = '\\';
|
private static final char ESCAPE_CHAR = '\\';
|
||||||
@@ -73,6 +75,8 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & FieldNameProvider, T> ext
|
|||||||
|
|
||||||
private final SimpleTypeConverter simpleTypeConverter = new SimpleTypeConverter();
|
private final SimpleTypeConverter simpleTypeConverter = new SimpleTypeConverter();
|
||||||
|
|
||||||
|
private boolean inOr;
|
||||||
|
private final Map<Class<?>, Path<Object>> javaTypeToPath = new HashMap<>();
|
||||||
private boolean joinsNeeded;
|
private boolean joinsNeeded;
|
||||||
|
|
||||||
public JpaQueryRsqlVisitorG2(final Class<A> enumType,
|
public JpaQueryRsqlVisitorG2(final Class<A> enumType,
|
||||||
@@ -99,11 +103,17 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & FieldNameProvider, T> ext
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Predicate> visit(final OrNode node, final String param) {
|
public List<Predicate> visit(final OrNode node, final String param) {
|
||||||
final List<Predicate> children = acceptChildren(node);
|
inOr = true;
|
||||||
if (children.isEmpty()) {
|
try {
|
||||||
return toSingleList(cb.conjunction());
|
final List<Predicate> children = acceptChildren(node);
|
||||||
} else {
|
if (children.isEmpty()) {
|
||||||
return toSingleList(cb.or(children.toArray(new Predicate[0])));
|
return toSingleList(cb.conjunction());
|
||||||
|
} else {
|
||||||
|
return toSingleList(cb.or(children.toArray(new Predicate[0])));
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
inOr = false;
|
||||||
|
javaTypeToPath.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,30 +127,29 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & FieldNameProvider, T> ext
|
|||||||
final Path<Object> fieldPath = getFieldPath(root, fieldName.getSubAttributes(finalProperty), fieldName.isMap());
|
final Path<Object> fieldPath = getFieldPath(root, fieldName.getSubAttributes(finalProperty), fieldName.isMap());
|
||||||
|
|
||||||
for (final String value : values) {
|
for (final String value : values) {
|
||||||
transformedValues.add(convertValueIfNecessary(node, fieldName, value, fieldPath));
|
transformedValues.add(convertValueIfNecessary(node, fieldName, fieldPath, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.joinsNeeded = this.joinsNeeded || areJoinsNeeded(node);
|
this.joinsNeeded = this.joinsNeeded || areJoinsNeeded(node);
|
||||||
|
|
||||||
return mapToPredicate(node, fieldPath, node.getArguments(), transformedValues, fieldName, finalProperty);
|
return mapToPredicate(node, fieldName, finalProperty, fieldPath, node.getArguments(), transformedValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Predicate> mapToPredicate(final ComparisonNode node, final Path<Object> fieldPath,
|
private List<Predicate> mapToPredicate(final ComparisonNode node, final A enumField, final String finalProperty,
|
||||||
final List<String> values, final List<Object> transformedValues, final A enumField,
|
final Path<Object> fieldPath,
|
||||||
final String finalProperty) {
|
final List<String> values, final List<Object> transformedValues) {
|
||||||
// if lookup is available, replace macros ...
|
// if lookup is available, replace macros ...
|
||||||
final String value = virtualPropertyReplacer == null ? values.get(0) : virtualPropertyReplacer.replace(values.get(0));
|
final String value = virtualPropertyReplacer == null ? values.get(0) : virtualPropertyReplacer.replace(values.get(0));
|
||||||
|
|
||||||
final Predicate mapPredicate = mapToMapPredicate(node, fieldPath, enumField);
|
final Predicate mapPredicate = mapToMapPredicate(node, enumField, fieldPath);
|
||||||
|
final Predicate valuePredicate = addOperatorPredicate(node, enumField, finalProperty,
|
||||||
final Predicate valuePredicate = addOperatorPredicate(node, getMapValueFieldPath(enumField, fieldPath),
|
getMapValueFieldPath(enumField, fieldPath), transformedValues, value);
|
||||||
transformedValues, value, finalProperty, enumField);
|
|
||||||
|
|
||||||
return toSingleList(mapPredicate != null ? cb.and(mapPredicate, valuePredicate) : valuePredicate);
|
return toSingleList(mapPredicate != null ? cb.and(mapPredicate, valuePredicate) : valuePredicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private Predicate mapToMapPredicate(final ComparisonNode node, final Path<Object> fieldPath, final A enumField) {
|
private Predicate mapToMapPredicate(final ComparisonNode node, final A enumField, final Path<Object> fieldPath) {
|
||||||
if (!enumField.isMap()) {
|
if (!enumField.isMap()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -160,27 +169,27 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & FieldNameProvider, T> ext
|
|||||||
return equal(fieldPath.get(keyFieldName), keyValue);
|
return equal(fieldPath.get(keyFieldName), keyValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Predicate addOperatorPredicate(final ComparisonNode node, final Path<Object> fieldPath,
|
private Predicate addOperatorPredicate(final ComparisonNode node, final A enumField, final String finalProperty,
|
||||||
final List<Object> transformedValues, final String value, final String finalProperty, final A enumField) {
|
final Path<Object> fieldPath, final List<Object> transformedValues, final String value) {
|
||||||
// only 'equal' and 'notEqual' can handle transformed value like enums.
|
// only 'equal' and 'notEqual' can handle transformed value like enums.
|
||||||
// The JPA API cannot handle object types for greaterThan etc. methods.
|
// The JPA API cannot handle object types for greaterThan etc. methods.
|
||||||
final Object transformedValue = transformedValues.get(0);
|
final Object transformedValue = transformedValues.get(0);
|
||||||
final String operator = node.getOperator().getSymbol();
|
final String operator = node.getOperator().getSymbol();
|
||||||
return switch (operator) {
|
return switch (operator) {
|
||||||
case "==" -> getEqualToPredicate(transformedValue, fieldPath);
|
case "==" -> getEqualToPredicate(fieldPath, transformedValue);
|
||||||
case "!=" -> getNotEqualToPredicate(transformedValue, fieldPath, finalProperty, enumField);
|
case "!=" -> getNotEqualToPredicate(enumField, finalProperty, fieldPath, transformedValue);
|
||||||
case "=gt=" -> cb.greaterThan(pathOfString(fieldPath), value);
|
case "=gt=" -> cb.greaterThan(pathOfString(fieldPath), value);
|
||||||
case "=ge=" -> cb.greaterThanOrEqualTo(pathOfString(fieldPath), value);
|
case "=ge=" -> cb.greaterThanOrEqualTo(pathOfString(fieldPath), value);
|
||||||
case "=lt=" -> cb.lessThan(pathOfString(fieldPath), value);
|
case "=lt=" -> cb.lessThan(pathOfString(fieldPath), value);
|
||||||
case "=le=" -> cb.lessThanOrEqualTo(pathOfString(fieldPath), value);
|
case "=le=" -> cb.lessThanOrEqualTo(pathOfString(fieldPath), value);
|
||||||
case "=in=" -> in(pathOfString(fieldPath), transformedValues);
|
case "=in=" -> in(pathOfString(fieldPath), transformedValues);
|
||||||
case "=out=" -> getOutPredicate(transformedValues, finalProperty, enumField, fieldPath);
|
case "=out=" -> getOutPredicate(enumField, finalProperty, fieldPath, transformedValues);
|
||||||
default -> throw new RSQLParameterSyntaxException(
|
default -> throw new RSQLParameterSyntaxException(
|
||||||
"Operator symbol {" + operator + "} is either not supported or not implemented");
|
"Operator symbol {" + operator + "} is either not supported or not implemented");
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private Predicate getEqualToPredicate(final Object transformedValue, final Path<Object> fieldPath) {
|
private Predicate getEqualToPredicate(final Path<Object> fieldPath, final Object transformedValue) {
|
||||||
if (transformedValue == null) {
|
if (transformedValue == null) {
|
||||||
return cb.isNull(pathOfString(fieldPath));
|
return cb.isNull(pathOfString(fieldPath));
|
||||||
}
|
}
|
||||||
@@ -200,9 +209,8 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & FieldNameProvider, T> ext
|
|||||||
return cb.equal(fieldPath, transformedValue);
|
return cb.equal(fieldPath, transformedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Predicate getNotEqualToPredicate(final Object transformedValue, final Path<Object> fieldPath,
|
private Predicate getNotEqualToPredicate(final A enumField, final String finalProperty,
|
||||||
final String finalProperty, final A enumField) {
|
final Path<Object> fieldPath, final Object transformedValue) {
|
||||||
|
|
||||||
if (transformedValue == null) {
|
if (transformedValue == null) {
|
||||||
return cb.isNotNull(pathOfString(fieldPath));
|
return cb.isNotNull(pathOfString(fieldPath));
|
||||||
}
|
}
|
||||||
@@ -222,10 +230,9 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & FieldNameProvider, T> ext
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clearOuterJoinsIfNotNeeded();
|
clearJoinsIfNotNeeded();
|
||||||
|
|
||||||
return toNotExistsSubQueryPredicate(
|
return toNotExistsSubQueryPredicate(enumField, fieldNames, expressionToCompare ->
|
||||||
fieldNames, enumField, expressionToCompare ->
|
|
||||||
isPattern(transformedValueStr) ? // a pattern, use like
|
isPattern(transformedValueStr) ? // a pattern, use like
|
||||||
like(expressionToCompare, toSQL(transformedValueStr)) :
|
like(expressionToCompare, toSQL(transformedValueStr)) :
|
||||||
equal(expressionToCompare, transformedValueStr));
|
equal(expressionToCompare, transformedValueStr));
|
||||||
@@ -234,9 +241,8 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & FieldNameProvider, T> ext
|
|||||||
return toNullOrNotEqualPredicate(fieldPath, transformedValue);
|
return toNullOrNotEqualPredicate(fieldPath, transformedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Predicate getOutPredicate(
|
private Predicate getOutPredicate(final A enumField, final String finalProperty, final Path<Object> fieldPath,
|
||||||
final List<Object> transformedValues, final String finalProperty,
|
final List<Object> transformedValues) {
|
||||||
final A enumField, final Path<Object> fieldPath) {
|
|
||||||
final String[] fieldNames = enumField.getSubAttributes(finalProperty);
|
final String[] fieldNames = enumField.getSubAttributes(finalProperty);
|
||||||
|
|
||||||
if (isSimpleField(fieldNames, enumField.isMap())) {
|
if (isSimpleField(fieldNames, enumField.isMap())) {
|
||||||
@@ -244,42 +250,49 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & FieldNameProvider, T> ext
|
|||||||
return cb.or(cb.isNull(pathOfString), cb.not(in(pathOfString, transformedValues)));
|
return cb.or(cb.isNull(pathOfString), cb.not(in(pathOfString, transformedValues)));
|
||||||
}
|
}
|
||||||
|
|
||||||
clearOuterJoinsIfNotNeeded();
|
clearJoinsIfNotNeeded();
|
||||||
|
|
||||||
return toNotExistsSubQueryPredicate(fieldNames, enumField, expressionToCompare -> in(expressionToCompare, transformedValues));
|
return toNotExistsSubQueryPredicate(enumField, fieldNames,
|
||||||
|
expressionToCompare -> in(expressionToCompare, transformedValues));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Path<Object> getFieldPath(
|
private Path<Object> getFieldPath(
|
||||||
final Root<?> root, final String[] split, final boolean isMapKeyField) {
|
final Root<?> root, final String[] split, final boolean isMapKeyField) {
|
||||||
Path<Object> fieldPath = null;
|
Path<Object> fieldPath = null;
|
||||||
for (int i = 0, end = isMapKeyField ? split.length - 1 : split.length; i < end; i++) {
|
for (int i = 0, end = isMapKeyField ? split.length - 1 : split.length; i < end; i++) {
|
||||||
final String fieldNameSplit = split[i];
|
final String fieldNameSplit = split[i];
|
||||||
fieldPath = fieldPath == null ?
|
fieldPath = fieldPath == null ?
|
||||||
// if root.get creates a join we call join directly in order to specify LEFT JOIN type,
|
getPath(root, fieldNameSplit) : fieldPath.get(fieldNameSplit);
|
||||||
// to include rows for missing in particular table / criteria (root.get creates INNER JOIN)
|
|
||||||
// (see org.eclipse.persistence.internal.jpa.querydef.FromImpl implementation for more details)
|
|
||||||
// otherwise delegate to root.get
|
|
||||||
(isJoin(root, fieldNameSplit) ? root.join(fieldNameSplit, JoinType.LEFT) : root.get(fieldNameSplit)) :
|
|
||||||
fieldPath.get(fieldNameSplit);
|
|
||||||
}
|
}
|
||||||
if (fieldPath == null) {
|
if (fieldPath == null) {
|
||||||
throw new RSQLParameterUnsupportedFieldException("RSQL field path cannot be empty", null);
|
throw new RSQLParameterUnsupportedFieldException("RSQL field path cannot be empty", null);
|
||||||
}
|
}
|
||||||
return fieldPath;
|
return fieldPath;
|
||||||
}
|
}
|
||||||
private static boolean isJoin(final Root<?> root, final String fieldNameSplit) {
|
// if root.get creates a join we call join directly in order to specify LEFT JOIN type,
|
||||||
|
// to include rows for missing in particular table / criteria (root.get creates INNER JOIN)
|
||||||
|
// (see org.eclipse.persistence.internal.jpa.querydef.FromImpl implementation for more details)
|
||||||
|
// otherwise delegate to root.get
|
||||||
|
private Path<Object> getPath(final Root<?> root, final String fieldNameSplit) {
|
||||||
// see org.eclipse.persistence.internal.jpa.querydef.FromImpl implementation for more details
|
// see org.eclipse.persistence.internal.jpa.querydef.FromImpl implementation for more details
|
||||||
// when root.get creates a join
|
// when root.get creates a join
|
||||||
final Attribute<?, ?> attribute = root.getModel().getAttribute(fieldNameSplit);
|
final Attribute<?, ?> attribute = root.getModel().getAttribute(fieldNameSplit);
|
||||||
if (!attribute.isCollection()) {
|
if (!attribute.isCollection()) {
|
||||||
// it is a SingularAttribute and not join if it is of basic persistent type
|
// it is a SingularAttribute and not join if it is of basic persistent type
|
||||||
return !((SingularAttribute<?, ?>) attribute).getType().getPersistenceType().equals(Type.PersistenceType.BASIC);
|
if (((SingularAttribute<?, ?>) attribute).getType().getPersistenceType().equals(Type.PersistenceType.BASIC)) {
|
||||||
|
return root.get(fieldNameSplit);
|
||||||
|
}
|
||||||
} // if a collection - it is a join
|
} // if a collection - it is a join
|
||||||
return true;
|
if (inOr && root == this.root) { // try to reuse join of the same or level and no subquery
|
||||||
|
final Class<?> objectClass = attribute.getJavaType();
|
||||||
|
return javaTypeToPath.computeIfAbsent(objectClass, k -> root.join(fieldNameSplit, JoinType.LEFT));
|
||||||
|
} else {
|
||||||
|
return root.join(fieldNameSplit, JoinType.LEFT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object convertValueIfNecessary(final ComparisonNode node, final A fieldName, final String value,
|
private Object convertValueIfNecessary(
|
||||||
final Path<Object> fieldPath) {
|
final ComparisonNode node, final A fieldName, final Path<Object> fieldPath, final String value) {
|
||||||
// in case the value of an RSQL query e.g. type==application is an
|
// in case the value of an RSQL query e.g. type==application is an
|
||||||
// enum we need to handle it separately because JPA needs the
|
// enum we need to handle it separately because JPA needs the
|
||||||
// correct java-type to build an expression. So String and numeric
|
// correct java-type to build an expression. So String and numeric
|
||||||
@@ -288,20 +301,20 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & FieldNameProvider, T> ext
|
|||||||
// class.
|
// class.
|
||||||
final Class<?> javaType = fieldPath.getJavaType();
|
final Class<?> javaType = fieldPath.getJavaType();
|
||||||
if (javaType != null && javaType.isEnum()) {
|
if (javaType != null && javaType.isEnum()) {
|
||||||
return transformEnumValue(node, value, javaType);
|
return transformEnumValue(node, javaType, value);
|
||||||
}
|
}
|
||||||
if (fieldName instanceof FieldValueConverter) {
|
if (fieldName instanceof FieldValueConverter) {
|
||||||
return convertFieldConverterValue(node, fieldName, value);
|
return convertFieldConverterValue(node, fieldName, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Boolean.TYPE.equals(javaType)) {
|
if (Boolean.TYPE.equals(javaType)) {
|
||||||
return convertBooleanValue(node, value, javaType);
|
return convertBooleanValue(node, javaType, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
private static Object transformEnumValue(final ComparisonNode node, final String value, final Class<?> javaType) {
|
private static Object transformEnumValue(final ComparisonNode node, final Class<?> javaType, final String value) {
|
||||||
final Class<? extends Enum> tmpEnumType = (Class<? extends Enum>) javaType;
|
final Class<? extends Enum> tmpEnumType = (Class<? extends Enum>) javaType;
|
||||||
try {
|
try {
|
||||||
return Enum.valueOf(tmpEnumType, value.toUpperCase());
|
return Enum.valueOf(tmpEnumType, value.toUpperCase());
|
||||||
@@ -318,7 +331,7 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & FieldNameProvider, T> ext
|
|||||||
+ "}", e);
|
+ "}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private Object convertBooleanValue(final ComparisonNode node, final String value, final Class<?> javaType) {
|
private Object convertBooleanValue(final ComparisonNode node, final Class<?> javaType, final String value) {
|
||||||
try {
|
try {
|
||||||
return simpleTypeConverter.convertIfNecessary(value, javaType);
|
return simpleTypeConverter.convertIfNecessary(value, javaType);
|
||||||
} catch (final TypeMismatchException e) {
|
} catch (final TypeMismatchException e) {
|
||||||
@@ -350,7 +363,7 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & FieldNameProvider, T> ext
|
|||||||
return fieldPath.get(valueFieldNameFromSubEntity);
|
return fieldPath.get(valueFieldNameFromSubEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearOuterJoinsIfNotNeeded() {
|
private void clearJoinsIfNotNeeded() {
|
||||||
if (!joinsNeeded) {
|
if (!joinsNeeded) {
|
||||||
root.getJoins().clear();
|
root.getJoins().clear();
|
||||||
}
|
}
|
||||||
@@ -365,21 +378,20 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & FieldNameProvider, T> ext
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
private Predicate toNotExistsSubQueryPredicate(final String[] fieldNames, final A enumField,
|
private Predicate toNotExistsSubQueryPredicate(final A enumField, final String[] fieldNames, final Function<Expression<String>, Predicate> subQueryPredicateProvider) {
|
||||||
final Function<Expression<String>, Predicate> subQueryPredicateProvider) {
|
|
||||||
final Class<?> javaType = root.getJavaType();
|
final Class<?> javaType = root.getJavaType();
|
||||||
final Subquery<?> subquery = query.subquery(javaType);
|
final Subquery<?> subquery = query.subquery(javaType);
|
||||||
final Root subqueryRoot = subquery.from(javaType);
|
final Root subqueryRoot = subquery.from(javaType);
|
||||||
final Predicate equalPredicate = cb.equal(root.get(enumField.identifierFieldName()),
|
final Predicate equalPredicate = cb.equal(root.get(enumField.identifierFieldName()),
|
||||||
subqueryRoot.get(enumField.identifierFieldName()));
|
subqueryRoot.get(enumField.identifierFieldName()));
|
||||||
final Expression<String> expressionToCompare = getExpressionToCompare(
|
final Expression<String> expressionToCompare = getExpressionToCompare(enumField,
|
||||||
getFieldPath(subqueryRoot, fieldNames, enumField.isMap()), enumField);
|
getFieldPath(subqueryRoot, fieldNames, enumField.isMap()));
|
||||||
final Predicate subQueryPredicate = subQueryPredicateProvider.apply(expressionToCompare);
|
final Predicate subQueryPredicate = subQueryPredicateProvider.apply(expressionToCompare);
|
||||||
subquery.select(subqueryRoot).where(cb.and(equalPredicate, subQueryPredicate));
|
subquery.select(subqueryRoot).where(cb.and(equalPredicate, subQueryPredicate));
|
||||||
return cb.not(cb.exists(subquery));
|
return cb.not(cb.exists(subquery));
|
||||||
}
|
}
|
||||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
private Expression<String> getExpressionToCompare(final Path fieldPath, final A enumField) {
|
private Expression<String> getExpressionToCompare(final A enumField, final Path fieldPath) {
|
||||||
if (!enumField.isMap()) {
|
if (!enumField.isMap()) {
|
||||||
return pathOfString(fieldPath);
|
return pathOfString(fieldPath);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.jpa.rsql;
|
|||||||
|
|
||||||
import jakarta.persistence.EntityManager;
|
import jakarta.persistence.EntityManager;
|
||||||
import jakarta.persistence.PersistenceContext;
|
import jakarta.persistence.PersistenceContext;
|
||||||
|
import org.eclipse.hawkbit.repository.FieldNameProvider;
|
||||||
import org.eclipse.hawkbit.repository.TargetFields;
|
import org.eclipse.hawkbit.repository.TargetFields;
|
||||||
import org.eclipse.hawkbit.repository.jpa.RepositoryApplicationConfiguration;
|
import org.eclipse.hawkbit.repository.jpa.RepositoryApplicationConfiguration;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||||
@@ -27,6 +28,7 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
|
|||||||
|
|
||||||
@ActiveProfiles("test")
|
@ActiveProfiles("test")
|
||||||
@SpringBootTest(webEnvironment=NONE, properties = {
|
@SpringBootTest(webEnvironment=NONE, properties = {
|
||||||
|
"hawkbit.rsql.caseInsensitiveDB=true",
|
||||||
"spring.main.allow-bean-definition-overriding=true",
|
"spring.main.allow-bean-definition-overriding=true",
|
||||||
"spring.main.banner-mode=off",
|
"spring.main.banner-mode=off",
|
||||||
"logging.level.root=ERROR" })
|
"logging.level.root=ERROR" })
|
||||||
@@ -44,18 +46,16 @@ public class RSQLToSQLTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void print() {
|
public void print() {
|
||||||
String rsql = "tag==tag1 or tag==tag2 or tag==tag3";
|
print(JpaTarget.class, TargetFields.class, "tag==tag1 or tag==tag2 or tag==tag3");
|
||||||
System.out.println(rsql + "\n" +
|
print(JpaTarget.class, TargetFields.class, "targettype.key==type1 and metadata.key1==target1-value1");
|
||||||
"\tlegacy:\n" +
|
print(JpaTarget.class, TargetFields.class, "(tag!=TAG1 or tag !=TAG2)");
|
||||||
"\t\t" + rsqlToSQL.toSQL(JpaTarget.class, TargetFields.class, rsql, true) + "\n" +
|
}
|
||||||
"\tG2:\n" +
|
|
||||||
"\t\t" + rsqlToSQL.toSQL(JpaTarget.class, TargetFields.class, rsql, false));
|
|
||||||
|
|
||||||
rsql = "targettype.key==type1 and metadata.key1==target1-value1";
|
private <T, A extends Enum<A> & FieldNameProvider> void print(final Class<T> domainClass, final Class<A> fieldsClass, final String rsql) {
|
||||||
System.out.println(rsql + "\n" +
|
System.out.println(rsql);
|
||||||
"\tlegacy:\n" +
|
System.out.println("\tlegacy:\n" +
|
||||||
"\t\t" + rsqlToSQL.toSQL(JpaTarget.class, TargetFields.class, rsql, true) + "\n" +
|
"\t\t" + rsqlToSQL.toSQL(JpaTarget.class, TargetFields.class, rsql, true));
|
||||||
"\tG2:\n" +
|
System.out.println("\tG2:\n" +
|
||||||
"\t\t" + rsqlToSQL.toSQL(JpaTarget.class, TargetFields.class, rsql, false));
|
"\t\t" + rsqlToSQL.toSQL(JpaTarget.class, TargetFields.class, rsql, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user