Refactor RSQL searach fields related classes (3) (#1836)
Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com>
This commit is contained in:
@@ -25,7 +25,7 @@ import java.util.Optional;
|
|||||||
public enum DistributionSetFields implements RsqlQueryField {
|
public enum DistributionSetFields implements RsqlQueryField {
|
||||||
|
|
||||||
ID("id"),
|
ID("id"),
|
||||||
TYPE("type.key"),
|
TYPE("type", "key"),
|
||||||
NAME("name"),
|
NAME("name"),
|
||||||
DESCRIPTION("description"),
|
DESCRIPTION("description"),
|
||||||
CREATEDAT("createdAt"),
|
CREATEDAT("createdAt"),
|
||||||
@@ -33,27 +33,27 @@ public enum DistributionSetFields implements RsqlQueryField {
|
|||||||
VERSION("version"),
|
VERSION("version"),
|
||||||
COMPLETE("complete"),
|
COMPLETE("complete"),
|
||||||
MODULE("modules", SoftwareModuleFields.ID.getJpaEntityFieldName(), SoftwareModuleFields.NAME.getJpaEntityFieldName()),
|
MODULE("modules", SoftwareModuleFields.ID.getJpaEntityFieldName(), SoftwareModuleFields.NAME.getJpaEntityFieldName()),
|
||||||
TAG("tags.name"),
|
TAG("tags", "name"),
|
||||||
METADATA("metadata", new SimpleImmutableEntry<>("key", "value")),
|
METADATA("metadata", new SimpleImmutableEntry<>("key", "value")),
|
||||||
VALID("valid");
|
VALID("valid");
|
||||||
|
|
||||||
private final String jpaEntityFieldName;
|
private final String jpaEntityFieldName;
|
||||||
private final Entry<String, String> subEntityMapTuple;
|
|
||||||
private final List<String> subEntityAttributes;
|
private final List<String> subEntityAttributes;
|
||||||
|
private final Entry<String, String> subEntityMapTuple;
|
||||||
|
|
||||||
DistributionSetFields(final String jpaEntityFieldName) {
|
DistributionSetFields(final String jpaEntityFieldName) {
|
||||||
this(jpaEntityFieldName, null, Collections.emptyList());
|
this(jpaEntityFieldName, Collections.emptyList(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
DistributionSetFields(final String jpaEntityFieldName, final String... subEntityAttributes) {
|
DistributionSetFields(final String jpaEntityFieldName, final String... subEntityAttributes) {
|
||||||
this(jpaEntityFieldName, null, List.of(subEntityAttributes));
|
this(jpaEntityFieldName, List.of(subEntityAttributes), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
DistributionSetFields(final String jpaEntityFieldName, final Entry<String, String> subEntityMapTuple) {
|
DistributionSetFields(final String jpaEntityFieldName, final Entry<String, String> subEntityMapTuple) {
|
||||||
this(jpaEntityFieldName, subEntityMapTuple, Collections.emptyList());
|
this(jpaEntityFieldName, Collections.emptyList(), subEntityMapTuple);
|
||||||
}
|
}
|
||||||
|
|
||||||
DistributionSetFields(final String jpaEntityFieldName, final Entry<String, String> subEntityMapTuple, List<String> subEntityAttributes) {
|
DistributionSetFields(final String jpaEntityFieldName, List<String> subEntityAttributes, final Entry<String, String> subEntityMapTuple) {
|
||||||
this.jpaEntityFieldName = jpaEntityFieldName;
|
this.jpaEntityFieldName = jpaEntityFieldName;
|
||||||
this.subEntityMapTuple = subEntityMapTuple;
|
this.subEntityMapTuple = subEntityMapTuple;
|
||||||
this.subEntityAttributes = subEntityAttributes;
|
this.subEntityAttributes = subEntityAttributes;
|
||||||
|
|||||||
@@ -35,23 +35,6 @@ public interface RsqlQueryField {
|
|||||||
@NotNull
|
@NotNull
|
||||||
String getJpaEntityFieldName();
|
String getJpaEntityFieldName();
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the sub attributes
|
|
||||||
*
|
|
||||||
* @param propertyFieldName the given field
|
|
||||||
* @return array consisting of sub attributes
|
|
||||||
*/
|
|
||||||
default String[] getSubAttributes(final String propertyFieldName) {
|
|
||||||
if (isMap()) {
|
|
||||||
final String[] subAttributes = propertyFieldName.split(SUB_ATTRIBUTE_SPLIT_REGEX, 2);
|
|
||||||
// [0] field name | [1] key name (could miss, e.g. for target attributes)
|
|
||||||
final String mapKeyName = subAttributes.length == 2 ? subAttributes[1] : null;
|
|
||||||
return ObjectUtils.isEmpty(mapKeyName) ? new String[] { getJpaEntityFieldName() } : new String[] { getJpaEntityFieldName(), mapKeyName };
|
|
||||||
} else {
|
|
||||||
return propertyFieldName.split(SUB_ATTRIBUTE_SPLIT_REGEX);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains the sub entity the given field.
|
* Contains the sub entity the given field.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ package org.eclipse.hawkbit.repository;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
import java.util.AbstractMap.SimpleImmutableEntry;
|
import java.util.AbstractMap.SimpleImmutableEntry;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@@ -22,22 +24,31 @@ import java.util.Optional;
|
|||||||
public enum SoftwareModuleFields implements RsqlQueryField {
|
public enum SoftwareModuleFields implements RsqlQueryField {
|
||||||
|
|
||||||
ID("id"),
|
ID("id"),
|
||||||
TYPE("type.key"),
|
TYPE("type", "key"),
|
||||||
NAME("name"),
|
NAME("name"),
|
||||||
DESCRIPTION("description"),
|
DESCRIPTION("description"),
|
||||||
VERSION("version"),
|
VERSION("version"),
|
||||||
METADATA("metadata", new SimpleImmutableEntry<>("key", "value"));
|
METADATA("metadata", new SimpleImmutableEntry<>("key", "value"));
|
||||||
|
|
||||||
private final String jpaEntityFieldName;
|
private final String jpaEntityFieldName;
|
||||||
private Entry<String, String> subEntityMapTuple;
|
private final List<String> subEntityAttributes;
|
||||||
|
private final Entry<String, String> subEntityMapTuple;
|
||||||
|
|
||||||
SoftwareModuleFields(final String jpaEntityFieldName) {
|
SoftwareModuleFields(final String jpaEntityFieldName) {
|
||||||
this(jpaEntityFieldName, null);
|
this(jpaEntityFieldName, Collections.emptyList(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SoftwareModuleFields(final String jpaEntityFieldName, final String... subEntityAttributes) {
|
||||||
|
this(jpaEntityFieldName, List.of(subEntityAttributes), null);
|
||||||
|
}
|
||||||
SoftwareModuleFields(final String jpaEntityFieldName, final Entry<String, String> subEntityMapTuple) {
|
SoftwareModuleFields(final String jpaEntityFieldName, final Entry<String, String> subEntityMapTuple) {
|
||||||
|
this(jpaEntityFieldName, Collections.emptyList(), subEntityMapTuple);
|
||||||
|
}
|
||||||
|
|
||||||
|
SoftwareModuleFields(final String jpaEntityFieldName, List<String> subEntityAttributes, final Entry<String, String> subEntityMapTuple) {
|
||||||
this.jpaEntityFieldName = jpaEntityFieldName;
|
this.jpaEntityFieldName = jpaEntityFieldName;
|
||||||
this.subEntityMapTuple = subEntityMapTuple;
|
this.subEntityMapTuple = subEntityMapTuple;
|
||||||
|
this.subEntityAttributes = subEntityAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ public enum TargetFields implements RsqlQueryField {
|
|||||||
ATTRIBUTE("controllerAttributes"),
|
ATTRIBUTE("controllerAttributes"),
|
||||||
ASSIGNEDDS("assignedDistributionSet", "name", "version"),
|
ASSIGNEDDS("assignedDistributionSet", "name", "version"),
|
||||||
INSTALLEDDS("installedDistributionSet", "name", "version"),
|
INSTALLEDDS("installedDistributionSet", "name", "version"),
|
||||||
TAG("tags.name"),
|
TAG("tags", "name"),
|
||||||
LASTCONTROLLERREQUESTAT("lastTargetQuery"),
|
LASTCONTROLLERREQUESTAT("lastTargetQuery"),
|
||||||
METADATA("metadata", new SimpleImmutableEntry<>("key", "value")),
|
METADATA("metadata", new SimpleImmutableEntry<>("key", "value")),
|
||||||
TARGETTYPE("targetType", TargetTypeFields.KEY.getJpaEntityFieldName(), TargetTypeFields.NAME.getJpaEntityFieldName());
|
TARGETTYPE("targetType", TargetTypeFields.KEY.getJpaEntityFieldName(), TargetTypeFields.NAME.getJpaEntityFieldName());
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import org.eclipse.hawkbit.repository.RsqlQueryField;
|
|||||||
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
|
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
|
||||||
|
|
||||||
import cz.jirutka.rsql.parser.ast.ComparisonNode;
|
import cz.jirutka.rsql.parser.ast.ComparisonNode;
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public abstract class AbstractRSQLVisitor<A extends Enum<A> & RsqlQueryField> {
|
public abstract class AbstractRSQLVisitor<A extends Enum<A> & RsqlQueryField> {
|
||||||
@@ -28,14 +29,14 @@ public abstract class AbstractRSQLVisitor<A extends Enum<A> & RsqlQueryField> {
|
|||||||
private final Class<A> rsqlQueryFieldType;
|
private final Class<A> rsqlQueryFieldType;
|
||||||
|
|
||||||
@Value
|
@Value
|
||||||
protected class RsqlField {
|
protected class QuertPath {
|
||||||
|
|
||||||
A enumValue;
|
A enumValue;
|
||||||
String[] subAttributes;
|
String[] jpaPath;
|
||||||
|
|
||||||
private RsqlField(final A enumValue, final String[] subAttributes) {
|
private QuertPath(final A enumValue, final String[] jpaPath) {
|
||||||
this.enumValue = enumValue;
|
this.enumValue = enumValue;
|
||||||
this.subAttributes = subAttributes;
|
this.jpaPath = jpaPath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,49 +44,74 @@ public abstract class AbstractRSQLVisitor<A extends Enum<A> & RsqlQueryField> {
|
|||||||
this.rsqlQueryFieldType = rsqlQueryFieldType;
|
this.rsqlQueryFieldType = rsqlQueryFieldType;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected RsqlField getRsqlField(final ComparisonNode node) {
|
protected QuertPath getQuertPath(final ComparisonNode node) {
|
||||||
final String[] graph = node.getSelector().split(RsqlQueryField.SUB_ATTRIBUTE_SPLIT_REGEX);
|
final String[] path = node.getSelector().split(RsqlQueryField.SUB_ATTRIBUTE_SPLIT_REGEX);
|
||||||
final String enumName = graph.length == 0 ? node.getSelector() : graph[0];
|
if (path.length == 0) {
|
||||||
|
throw createRSQLParameterUnsupportedException(node, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String enumName = path[0].toUpperCase();
|
||||||
log.debug("get field identifier by name {} of enum type {}", enumName, rsqlQueryFieldType);
|
log.debug("get field identifier by name {} of enum type {}", enumName, rsqlQueryFieldType);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final A enumValue = Enum.valueOf(rsqlQueryFieldType, enumName.toUpperCase());
|
final A enumValue = Enum.valueOf(rsqlQueryFieldType, enumName);
|
||||||
final String[] subAttributes = enumValue.getSubAttributes(node.getSelector());
|
String[] split = getSplit(enumValue, node.getSelector());
|
||||||
|
|
||||||
// validate
|
// validate
|
||||||
if (enumValue.isMap()) {
|
if (enumValue.isMap()) {
|
||||||
// <enum>.<key>
|
// <enum>.<key>
|
||||||
if (subAttributes.length != 2) {
|
if (split.length != 2) {
|
||||||
throw new RSQLParameterUnsupportedFieldException(
|
throw new RSQLParameterUnsupportedFieldException(
|
||||||
"The syntax of the given map search parameter field {" + node.getSelector() + "} is wrong. Syntax is: <enum name>.<key name>");
|
"The syntax of the given map search parameter field {" + node.getSelector() + "} is wrong. Syntax is: <enum name>.<key name>");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// sub entity need minimum 1 dot
|
// sub entity need minimum 1 dot
|
||||||
if (!enumValue.getSubEntityAttributes().isEmpty() && subAttributes.length < 2) {
|
if (!enumValue.getSubEntityAttributes().isEmpty() && split.length < 2) {
|
||||||
throw createRSQLParameterUnsupportedException(node, null);
|
if (enumValue.getSubEntityAttributes().size() == 1) { // single sub attribute - so default
|
||||||
|
split = new String[] { split[0], enumValue.getSubEntityAttributes().get(0) };
|
||||||
|
} else {
|
||||||
|
throw createRSQLParameterUnsupportedException(node, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// build property and validate sub attributes
|
// validate and normalize (replace enum name with JPA entity field name and format the rest) prepare jpa path
|
||||||
final StringBuilder fieldNameBuilder = new StringBuilder(enumValue.getJpaEntityFieldName());
|
split[0] = enumValue.getJpaEntityFieldName();
|
||||||
for (int i = 1; i < subAttributes.length; i++) {
|
for (int i = 1; i < split.length; i++) {
|
||||||
final String propertyField = getFormattedSubEntityAttribute(enumValue, subAttributes[i]);
|
split[i] = getFormattedSubEntityAttribute(enumValue, split[i]);
|
||||||
|
|
||||||
if (!enumValue.containsSubEntityAttribute(propertyField)) {
|
if (!enumValue.containsSubEntityAttribute(split[i])) {
|
||||||
if (i != subAttributes.length - 1 || !enumValue.isMap()) {
|
if (i != split.length - 1 || !enumValue.isMap()) {
|
||||||
throw createRSQLParameterUnsupportedException(node, null);
|
throw createRSQLParameterUnsupportedException(node, null);
|
||||||
} // otherwise - the key of map is not in the sub entity attributes
|
} // otherwise - the key of map is not in the sub entity attributes
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldNameBuilder.append(RsqlQueryField.SUB_ATTRIBUTE_SEPARATOR).append(propertyField);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new RsqlField(enumValue, enumValue.getSubAttributes(fieldNameBuilder.toString()));
|
return new QuertPath(enumValue, split);
|
||||||
} catch (final IllegalArgumentException e) {
|
} catch (final IllegalArgumentException e) {
|
||||||
throw createRSQLParameterUnsupportedException(node, e);
|
throw createRSQLParameterUnsupportedException(node, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the sub attributes
|
||||||
|
*
|
||||||
|
* @param rsqlFieldName the given field
|
||||||
|
* @return array consisting of sub attributes
|
||||||
|
*/
|
||||||
|
private String[] getSplit(final A enumValue, final String rsqlFieldName) {
|
||||||
|
if (enumValue.isMap()) {
|
||||||
|
final String[] subAttributes = rsqlFieldName.split(RsqlQueryField.SUB_ATTRIBUTE_SPLIT_REGEX, 2);
|
||||||
|
// [0] field name | [1] key name (could miss, e.g. for target attributes)
|
||||||
|
final String mapKeyName = subAttributes.length == 2 ? subAttributes[1] : null;
|
||||||
|
return ObjectUtils.isEmpty(mapKeyName) ?
|
||||||
|
new String[] { enumValue.getJpaEntityFieldName() } :
|
||||||
|
new String[] { enumValue.getJpaEntityFieldName(), mapKeyName };
|
||||||
|
} else {
|
||||||
|
return rsqlFieldName.split(RsqlQueryField.SUB_ATTRIBUTE_SPLIT_REGEX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param node current processing node
|
* @param node current processing node
|
||||||
* @param rootException in case there is a cause otherwise {@code null}
|
* @param rootException in case there is a cause otherwise {@code null}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public class FieldValidationRsqlVisitor<A extends Enum<A> & RsqlQueryField> exte
|
|||||||
@Override
|
@Override
|
||||||
public Void visit(final ComparisonNode node, final String param) {
|
public Void visit(final ComparisonNode node, final String param) {
|
||||||
// get AND validates
|
// get AND validates
|
||||||
getRsqlField(node);
|
getQuertPath(node);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -171,12 +171,12 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & RsqlQueryField, T> extends
|
|||||||
* @param enumField
|
* @param enumField
|
||||||
* field from a FieldNameProvider to resolve on the persistence
|
* field from a FieldNameProvider to resolve on the persistence
|
||||||
* layer
|
* layer
|
||||||
* @param rsqlField RSQL field
|
* @param queryPath RSQL field
|
||||||
* @return the Path for a field
|
* @return the Path for a field
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private Path<Object> getFieldPath(final A enumField, final RsqlField rsqlField) {
|
private Path<Object> getFieldPath(final A enumField, final QuertPath queryPath) {
|
||||||
return (Path<Object>) getFieldPath(root, rsqlField.getSubAttributes(), enumField.isMap(),
|
return (Path<Object>) getFieldPath(root, queryPath.getJpaPath(), enumField.isMap(),
|
||||||
this::getJoinFieldPath).orElseThrow(
|
this::getJoinFieldPath).orElseThrow(
|
||||||
() -> new RSQLParameterUnsupportedFieldException("RSQL field path cannot be empty", null));
|
() -> new RSQLParameterUnsupportedFieldException("RSQL field path cannot be empty", null));
|
||||||
}
|
}
|
||||||
@@ -217,19 +217,19 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & RsqlQueryField, T> extends
|
|||||||
// https://jira.sonarsource.com/browse/SONARJAVA-1478
|
// https://jira.sonarsource.com/browse/SONARJAVA-1478
|
||||||
@SuppressWarnings({ "squid:S2095" })
|
@SuppressWarnings({ "squid:S2095" })
|
||||||
public List<Predicate> visit(final ComparisonNode node, final String param) {
|
public List<Predicate> visit(final ComparisonNode node, final String param) {
|
||||||
final RsqlField rsqlField = getRsqlField(node);
|
final QuertPath queryPath = getQuertPath(node);
|
||||||
|
|
||||||
final List<String> values = node.getArguments();
|
final List<String> values = node.getArguments();
|
||||||
final List<Object> transformedValues = new ArrayList<>();
|
final List<Object> transformedValues = new ArrayList<>();
|
||||||
final Path<Object> fieldPath = getFieldPath(rsqlField.getEnumValue(), rsqlField);
|
final Path<Object> fieldPath = getFieldPath(queryPath.getEnumValue(), queryPath);
|
||||||
|
|
||||||
for (final String value : values) {
|
for (final String value : values) {
|
||||||
transformedValues.add(convertValueIfNecessary(node, rsqlField.getEnumValue(), value, fieldPath));
|
transformedValues.add(convertValueIfNecessary(node, queryPath.getEnumValue(), value, fieldPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.joinsNeeded = this.joinsNeeded || areJoinsNeeded(node);
|
this.joinsNeeded = this.joinsNeeded || areJoinsNeeded(node);
|
||||||
|
|
||||||
return mapToPredicate(node, fieldPath, node.getArguments(), transformedValues, rsqlField);
|
return mapToPredicate(node, fieldPath, node.getArguments(), transformedValues, queryPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean areJoinsNeeded(final ComparisonNode node) {
|
private static boolean areJoinsNeeded(final ComparisonNode node) {
|
||||||
@@ -305,7 +305,7 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & RsqlQueryField, T> extends
|
|||||||
}
|
}
|
||||||
|
|
||||||
private List<Predicate> mapToPredicate(final ComparisonNode node, final Path<Object> fieldPath,
|
private List<Predicate> mapToPredicate(final ComparisonNode node, final Path<Object> fieldPath,
|
||||||
final List<String> values, final List<Object> transformedValues, final RsqlField rsqlField) {
|
final List<String> values, final List<Object> transformedValues, final QuertPath queryPath) {
|
||||||
|
|
||||||
String value = values.get(0);
|
String value = values.get(0);
|
||||||
// if lookup is available, replace macros ...
|
// if lookup is available, replace macros ...
|
||||||
@@ -313,16 +313,16 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & RsqlQueryField, T> extends
|
|||||||
value = virtualPropertyReplacer.replace(value);
|
value = virtualPropertyReplacer.replace(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Predicate mapPredicate = mapToMapPredicate(node, fieldPath, rsqlField.getEnumValue());
|
final Predicate mapPredicate = mapToMapPredicate(fieldPath, queryPath);
|
||||||
|
|
||||||
final Predicate valuePredicate = addOperatorPredicate(node, getMapValueFieldPath(rsqlField.getEnumValue(), fieldPath),
|
final Predicate valuePredicate = addOperatorPredicate(node, getMapValueFieldPath(queryPath.getEnumValue(), fieldPath),
|
||||||
transformedValues, value, rsqlField);
|
transformedValues, value, queryPath);
|
||||||
|
|
||||||
return toSingleList(mapPredicate != null ? cb.and(mapPredicate, valuePredicate) : valuePredicate);
|
return toSingleList(mapPredicate != null ? cb.and(mapPredicate, valuePredicate) : valuePredicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Predicate addOperatorPredicate(final ComparisonNode node, final Path<Object> fieldPath,
|
private Predicate addOperatorPredicate(final ComparisonNode node, final Path<Object> fieldPath,
|
||||||
final List<Object> transformedValues, final String value, final RsqlField rsqlField) {
|
final List<Object> transformedValues, final String value, final QuertPath queryPath) {
|
||||||
|
|
||||||
// only 'equal' and 'notEqual' can handle transformed value like
|
// only 'equal' and 'notEqual' can handle transformed value like
|
||||||
// enums. The JPA API cannot handle object types for greaterThan etc
|
// enums. The JPA API cannot handle object types for greaterThan etc
|
||||||
@@ -334,7 +334,7 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & RsqlQueryField, T> extends
|
|||||||
case "==":
|
case "==":
|
||||||
return getEqualToPredicate(transformedValue, fieldPath);
|
return getEqualToPredicate(transformedValue, fieldPath);
|
||||||
case "!=":
|
case "!=":
|
||||||
return getNotEqualToPredicate(transformedValue, fieldPath, rsqlField);
|
return getNotEqualToPredicate(transformedValue, fieldPath, queryPath);
|
||||||
case "=gt=":
|
case "=gt=":
|
||||||
return cb.greaterThan(pathOfString(fieldPath), value);
|
return cb.greaterThan(pathOfString(fieldPath), value);
|
||||||
case "=ge=":
|
case "=ge=":
|
||||||
@@ -346,7 +346,7 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & RsqlQueryField, T> extends
|
|||||||
case "=in=":
|
case "=in=":
|
||||||
return in(pathOfString(fieldPath), transformedValues);
|
return in(pathOfString(fieldPath), transformedValues);
|
||||||
case "=out=":
|
case "=out=":
|
||||||
return getOutPredicate(transformedValues, rsqlField, fieldPath);
|
return getOutPredicate(transformedValues, queryPath, fieldPath);
|
||||||
default:
|
default:
|
||||||
throw new RSQLParameterSyntaxException(
|
throw new RSQLParameterSyntaxException(
|
||||||
"operator symbol {" + operator + "} is either not supported or not implemented");
|
"operator symbol {" + operator + "} is either not supported or not implemented");
|
||||||
@@ -355,17 +355,17 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & RsqlQueryField, T> extends
|
|||||||
|
|
||||||
private Predicate getOutPredicate(
|
private Predicate getOutPredicate(
|
||||||
final List<Object> transformedValues,
|
final List<Object> transformedValues,
|
||||||
final RsqlField rsqlField, final Path<Object> fieldPath) {
|
final QuertPath queryPath, final Path<Object> fieldPath) {
|
||||||
final String[] fieldNames = rsqlField.getSubAttributes();
|
final String[] fieldNames = queryPath.getJpaPath();
|
||||||
|
|
||||||
if (isSimpleField(fieldNames, rsqlField.getEnumValue().isMap())) {
|
if (isSimpleField(fieldNames, queryPath.getEnumValue().isMap())) {
|
||||||
final Path<String> pathOfString = pathOfString(fieldPath);
|
final Path<String> pathOfString = pathOfString(fieldPath);
|
||||||
return cb.or(cb.isNull(pathOfString), cb.not(in(pathOfString, transformedValues)));
|
return cb.or(cb.isNull(pathOfString), cb.not(in(pathOfString, transformedValues)));
|
||||||
}
|
}
|
||||||
|
|
||||||
clearOuterJoinsIfNotNeeded();
|
clearOuterJoinsIfNotNeeded();
|
||||||
|
|
||||||
return toNotExistsSubQueryPredicate(fieldNames, rsqlField.getEnumValue(), expressionToCompare -> in(expressionToCompare, transformedValues));
|
return toNotExistsSubQueryPredicate(fieldNames, queryPath.getEnumValue(), expressionToCompare -> in(expressionToCompare, transformedValues));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Path<Object> getMapValueFieldPath(final A enumField, final Path<Object> fieldPath) {
|
private Path<Object> getMapValueFieldPath(final A enumField, final Path<Object> fieldPath) {
|
||||||
@@ -378,20 +378,19 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & RsqlQueryField, T> extends
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private Predicate mapToMapPredicate(final ComparisonNode node, final Path<Object> fieldPath, final A enumField) {
|
private Predicate mapToMapPredicate(final Path<Object> fieldPath, final QuertPath queryPath) {
|
||||||
if (!enumField.isMap()) {
|
if (!queryPath.getEnumValue().isMap()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final String[] graph = enumField.getSubAttributes(node.getSelector());
|
final String[] graph = queryPath.getJpaPath();
|
||||||
|
|
||||||
final String keyValue = graph[graph.length - 1];
|
final String keyValue = graph[graph.length - 1];
|
||||||
if (fieldPath instanceof MapJoin) {
|
if (fieldPath instanceof MapJoin) {
|
||||||
// Currently we support only string key. So below cast is safe.
|
// Currently we support only string key. So below cast is safe.
|
||||||
return equal((Expression<String>) (((MapJoin<?, ?, ?>) fieldPath).key()), keyValue);
|
return equal((Expression<String>) (((MapJoin<?, ?, ?>) fieldPath).key()), keyValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
final String keyFieldName = enumField.getSubEntityMapTuple().map(Entry::getKey)
|
final String keyFieldName = queryPath.getEnumValue().getSubEntityMapTuple().map(Entry::getKey)
|
||||||
.orElseThrow(() -> new UnsupportedOperationException(
|
.orElseThrow(() -> new UnsupportedOperationException(
|
||||||
"For the fields, defined as Map, only Map java type or tuple in the form of " +
|
"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!"));
|
"SimpleImmutableEntry are allowed. Neither of those could be found!"));
|
||||||
@@ -419,7 +418,7 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & RsqlQueryField, T> extends
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Predicate getNotEqualToPredicate(final Object transformedValue, final Path<Object> fieldPath,
|
private Predicate getNotEqualToPredicate(final Object transformedValue, final Path<Object> fieldPath,
|
||||||
final RsqlField rsqlField) {
|
final QuertPath queryPath) {
|
||||||
|
|
||||||
if (transformedValue == null) {
|
if (transformedValue == null) {
|
||||||
return cb.isNotNull(pathOfString(fieldPath));
|
return cb.isNotNull(pathOfString(fieldPath));
|
||||||
@@ -430,9 +429,9 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & RsqlQueryField, T> extends
|
|||||||
return cb.and(cb.isNotNull(pathOfString(fieldPath)), cb.notEqual(pathOfString(fieldPath), ""));
|
return cb.and(cb.isNotNull(pathOfString(fieldPath)), cb.notEqual(pathOfString(fieldPath), ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
final String[] fieldNames = rsqlField.getSubAttributes();
|
final String[] fieldNames = queryPath.getJpaPath();
|
||||||
|
|
||||||
if (isSimpleField(fieldNames, rsqlField.getEnumValue().isMap())) {
|
if (isSimpleField(fieldNames, queryPath.getEnumValue().isMap())) {
|
||||||
if (isPattern(transformedValueStr)) { // a pattern, use like
|
if (isPattern(transformedValueStr)) { // a pattern, use like
|
||||||
return cb.or(cb.isNull(pathOfString(fieldPath)), notLike(pathOfString(fieldPath), toSQL(transformedValueStr)));
|
return cb.or(cb.isNull(pathOfString(fieldPath)), notLike(pathOfString(fieldPath), toSQL(transformedValueStr)));
|
||||||
} else {
|
} else {
|
||||||
@@ -443,9 +442,9 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & RsqlQueryField, T> extends
|
|||||||
clearOuterJoinsIfNotNeeded();
|
clearOuterJoinsIfNotNeeded();
|
||||||
|
|
||||||
if (isPattern(transformedValueStr)) { // a pattern, use like
|
if (isPattern(transformedValueStr)) { // a pattern, use like
|
||||||
return toNotExistsSubQueryPredicate(fieldNames, rsqlField.getEnumValue(), expressionToCompare -> like(expressionToCompare, toSQL(transformedValueStr)));
|
return toNotExistsSubQueryPredicate(fieldNames, queryPath.getEnumValue(), expressionToCompare -> like(expressionToCompare, toSQL(transformedValueStr)));
|
||||||
} else {
|
} else {
|
||||||
return toNotExistsSubQueryPredicate(fieldNames, rsqlField.getEnumValue(), expressionToCompare -> equal(expressionToCompare, transformedValueStr));
|
return toNotExistsSubQueryPredicate(fieldNames, queryPath.getEnumValue(), expressionToCompare -> equal(expressionToCompare, transformedValueStr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -110,30 +110,30 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & RsqlQueryField, T>
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Predicate> visit(final ComparisonNode node, final String param) {
|
public List<Predicate> visit(final ComparisonNode node, final String param) {
|
||||||
final RsqlField rsqlField = getRsqlField(node);
|
final QuertPath queryField = getQuertPath(node);
|
||||||
|
|
||||||
final List<String> values = node.getArguments();
|
final List<String> values = node.getArguments();
|
||||||
final List<Object> transformedValues = new ArrayList<>();
|
final List<Object> transformedValues = new ArrayList<>();
|
||||||
final Path<Object> fieldPath = getFieldPath(root, rsqlField);
|
final Path<Object> fieldPath = getFieldPath(root, queryField);
|
||||||
|
|
||||||
for (final String value : values) {
|
for (final String value : values) {
|
||||||
transformedValues.add(convertValueIfNecessary(node, rsqlField.getEnumValue(), fieldPath, value));
|
transformedValues.add(convertValueIfNecessary(node, queryField.getEnumValue(), fieldPath, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.joinsNeeded = this.joinsNeeded || areJoinsNeeded(node);
|
this.joinsNeeded = this.joinsNeeded || areJoinsNeeded(node);
|
||||||
|
|
||||||
return mapToPredicate(node, rsqlField, fieldPath, node.getArguments(), transformedValues);
|
return mapToPredicate(node, queryField, fieldPath, node.getArguments(), transformedValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Predicate> mapToPredicate(final ComparisonNode node, final RsqlField rsqlField,
|
private List<Predicate> mapToPredicate(final ComparisonNode node, final QuertPath queryField,
|
||||||
final Path<Object> fieldPath,
|
final Path<Object> fieldPath,
|
||||||
final List<String> values, final List<Object> transformedValues) {
|
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, rsqlField.getEnumValue(), fieldPath);
|
final Predicate mapPredicate = queryField.getEnumValue().isMap() ? mapToMapPredicate(queryField, fieldPath) : null;
|
||||||
final Predicate valuePredicate = addOperatorPredicate(node, rsqlField,
|
final Predicate valuePredicate = addOperatorPredicate(node, queryField,
|
||||||
getValueFieldPath(rsqlField.getEnumValue(), fieldPath), transformedValues, value);
|
getValueFieldPath(queryField.getEnumValue(), fieldPath), transformedValues, value);
|
||||||
|
|
||||||
return Collections.singletonList(mapPredicate != null ? cb.and(mapPredicate, valuePredicate) : valuePredicate);
|
return Collections.singletonList(mapPredicate != null ? cb.and(mapPredicate, valuePredicate) : valuePredicate);
|
||||||
}
|
}
|
||||||
@@ -145,26 +145,21 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & RsqlQueryField, T>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private Predicate mapToMapPredicate(final ComparisonNode node, final A enumField, final Path<Object> fieldPath) {
|
private Predicate mapToMapPredicate(final QuertPath queryField, final Path<Object> fieldPath) {
|
||||||
if (!enumField.isMap()) {
|
final String[] graph = queryField.getJpaPath();
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String[] graph = enumField.getSubAttributes(node.getSelector());
|
|
||||||
|
|
||||||
final String keyValue = graph[graph.length - 1];
|
final String keyValue = graph[graph.length - 1];
|
||||||
if (fieldPath instanceof MapJoin) {
|
if (fieldPath instanceof MapJoin) {
|
||||||
// Currently we support only string key. So below cast is safe.
|
// Currently we support only string key. So below cast is safe.
|
||||||
return equal((Expression<String>) (((MapJoin<?, ?, ?>) fieldPath).key()), keyValue);
|
return equal((Expression<String>) (((MapJoin<?, ?, ?>) fieldPath).key()), keyValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
final String keyFieldName = enumField.getSubEntityMapTuple().map(Entry::getKey)
|
final String keyFieldName = queryField.getEnumValue().getSubEntityMapTuple().map(Entry::getKey)
|
||||||
.orElseThrow(() -> new UnsupportedOperationException(
|
.orElseThrow(() -> new UnsupportedOperationException(
|
||||||
"For the fields, defined as Map, only Map java type or tuple in the form of " +
|
"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!"));
|
"SimpleImmutableEntry are allowed. Neither of those could be found!"));
|
||||||
return equal(fieldPath.get(keyFieldName), keyValue);
|
return equal(fieldPath.get(keyFieldName), keyValue);
|
||||||
}
|
}
|
||||||
private Predicate addOperatorPredicate(final ComparisonNode node, final RsqlField rsqlField,
|
private Predicate addOperatorPredicate(final ComparisonNode node, final QuertPath queryField,
|
||||||
final Path<Object> fieldPath, final List<Object> transformedValues, final String value) {
|
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.
|
||||||
@@ -172,13 +167,13 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & RsqlQueryField, T>
|
|||||||
final String operator = node.getOperator().getSymbol();
|
final String operator = node.getOperator().getSymbol();
|
||||||
return switch (operator) {
|
return switch (operator) {
|
||||||
case "==" -> getEqualToPredicate(fieldPath, transformedValue);
|
case "==" -> getEqualToPredicate(fieldPath, transformedValue);
|
||||||
case "!=" -> getNotEqualToPredicate(rsqlField, fieldPath, transformedValue);
|
case "!=" -> getNotEqualToPredicate(queryField, 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(rsqlField, fieldPath, transformedValues);
|
case "=out=" -> getOutPredicate(queryField, 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");
|
||||||
};
|
};
|
||||||
@@ -203,7 +198,7 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & RsqlQueryField, T>
|
|||||||
return cb.equal(fieldPath, transformedValue);
|
return cb.equal(fieldPath, transformedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Predicate getNotEqualToPredicate(final RsqlField rsqlField,
|
private Predicate getNotEqualToPredicate(final QuertPath queryField,
|
||||||
final Path<Object> fieldPath, final Object transformedValue) {
|
final Path<Object> fieldPath, final Object transformedValue) {
|
||||||
if (transformedValue == null) {
|
if (transformedValue == null) {
|
||||||
return cb.isNotNull(fieldPath);
|
return cb.isNotNull(fieldPath);
|
||||||
@@ -214,9 +209,9 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & RsqlQueryField, T>
|
|||||||
return cb.and(cb.isNotNull(fieldPath), cb.notEqual(pathOfString(fieldPath), ""));
|
return cb.and(cb.isNotNull(fieldPath), cb.notEqual(pathOfString(fieldPath), ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
final String[] fieldNames = rsqlField.getSubAttributes();
|
final String[] fieldNames = queryField.getJpaPath();
|
||||||
|
|
||||||
if (isSimpleField(fieldNames, rsqlField.getEnumValue().isMap())) {
|
if (isSimpleField(fieldNames, queryField.getEnumValue().isMap())) {
|
||||||
if (isPattern(transformedValueStr)) { // a pattern, use like
|
if (isPattern(transformedValueStr)) { // a pattern, use like
|
||||||
return cb.or(cb.isNull(fieldPath), notLike(pathOfString(fieldPath), toSQL(transformedValueStr)));
|
return cb.or(cb.isNull(fieldPath), notLike(pathOfString(fieldPath), toSQL(transformedValueStr)));
|
||||||
} else {
|
} else {
|
||||||
@@ -225,7 +220,7 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & RsqlQueryField, T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
clearJoinsIfNotNeeded();
|
clearJoinsIfNotNeeded();
|
||||||
return toNotExistsSubQueryPredicate(rsqlField, expressionToCompare ->
|
return toNotExistsSubQueryPredicate(queryField, 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,22 +229,22 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & RsqlQueryField, T>
|
|||||||
return toNullOrNotEqualPredicate(fieldPath, transformedValue);
|
return toNullOrNotEqualPredicate(fieldPath, transformedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Predicate getOutPredicate(final RsqlField rsqlField, final Path<Object> fieldPath,
|
private Predicate getOutPredicate(final QuertPath queryField, final Path<Object> fieldPath,
|
||||||
final List<Object> transformedValues) {
|
final List<Object> transformedValues) {
|
||||||
final String[] subAttributes = rsqlField.getSubAttributes();
|
final String[] subAttributes = queryField.getJpaPath();
|
||||||
|
|
||||||
if (isSimpleField(subAttributes, rsqlField.getEnumValue().isMap())) {
|
if (isSimpleField(subAttributes, queryField.getEnumValue().isMap())) {
|
||||||
return cb.or(cb.isNull(fieldPath), cb.not(in(pathOfString(fieldPath), transformedValues)));
|
return cb.or(cb.isNull(fieldPath), cb.not(in(pathOfString(fieldPath), transformedValues)));
|
||||||
}
|
}
|
||||||
|
|
||||||
clearJoinsIfNotNeeded();
|
clearJoinsIfNotNeeded();
|
||||||
return toNotExistsSubQueryPredicate(rsqlField, expressionToCompare -> in(expressionToCompare, transformedValues));
|
return toNotExistsSubQueryPredicate(queryField, expressionToCompare -> in(expressionToCompare, transformedValues));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Path<Object> getFieldPath(final Root<?> root, final RsqlField rsqlField) {
|
private Path<Object> getFieldPath(final Root<?> root, final QuertPath queryField) {
|
||||||
final String[] split = rsqlField.getSubAttributes();
|
final String[] split = queryField.getJpaPath();
|
||||||
Path<Object> fieldPath = null;
|
Path<Object> fieldPath = null;
|
||||||
for (int i = 0, end = rsqlField.getEnumValue().isMap() ? split.length - 1 : split.length; i < end; i++) {
|
for (int i = 0, end = queryField.getEnumValue().isMap() ? split.length - 1 : split.length; i < end; i++) {
|
||||||
final String fieldNameSplit = split[i];
|
final String fieldNameSplit = split[i];
|
||||||
fieldPath = fieldPath == null ? getPath(root, fieldNameSplit) : fieldPath.get(fieldNameSplit);
|
fieldPath = fieldPath == null ? getPath(root, fieldNameSplit) : fieldPath.get(fieldNameSplit);
|
||||||
}
|
}
|
||||||
@@ -358,14 +353,14 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & RsqlQueryField, T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
private Predicate toNotExistsSubQueryPredicate(final RsqlField rsqlField, final Function<Expression<String>, Predicate> subQueryPredicateProvider) {
|
private Predicate toNotExistsSubQueryPredicate(final QuertPath queryField, 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(rsqlField.getEnumValue().identifierFieldName()),
|
final Predicate equalPredicate = cb.equal(root.get(queryField.getEnumValue().identifierFieldName()),
|
||||||
subqueryRoot.get(rsqlField.getEnumValue().identifierFieldName()));
|
subqueryRoot.get(queryField.getEnumValue().identifierFieldName()));
|
||||||
final Expression<String> expressionToCompare = getExpressionToCompare(rsqlField.getEnumValue(),
|
final Expression<String> expressionToCompare = getExpressionToCompare(queryField.getEnumValue(),
|
||||||
getFieldPath(subqueryRoot, rsqlField));
|
getFieldPath(subqueryRoot, queryField));
|
||||||
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));
|
||||||
|
|||||||
Reference in New Issue
Block a user