Simplify RSQL fields (#2416)
Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
@@ -42,11 +42,6 @@ public enum ActionFields implements RsqlQueryField, FieldValueConverter<ActionFi
|
|||||||
private final String jpaEntityFieldName;
|
private final String jpaEntityFieldName;
|
||||||
private final List<String> subEntityAttributes;
|
private final List<String> subEntityAttributes;
|
||||||
|
|
||||||
ActionFields(final String jpaEntityFieldName) {
|
|
||||||
this.jpaEntityFieldName = jpaEntityFieldName;
|
|
||||||
this.subEntityAttributes = Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
ActionFields(final String jpaEntityFieldName, final String... subEntityAttributes) {
|
ActionFields(final String jpaEntityFieldName, final String... subEntityAttributes) {
|
||||||
this.jpaEntityFieldName = jpaEntityFieldName;
|
this.jpaEntityFieldName = jpaEntityFieldName;
|
||||||
this.subEntityAttributes = List.of(subEntityAttributes);
|
this.subEntityAttributes = List.of(subEntityAttributes);
|
||||||
|
|||||||
@@ -34,33 +34,19 @@ public enum DistributionSetFields implements RsqlQueryField {
|
|||||||
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"),
|
||||||
VALID("valid");
|
VALID("valid");
|
||||||
|
|
||||||
private final String jpaEntityFieldName;
|
private final String jpaEntityFieldName;
|
||||||
private final List<String> subEntityAttributes;
|
private final List<String> subEntityAttributes;
|
||||||
private final Entry<String, String> subEntityMapTuple;
|
|
||||||
|
|
||||||
DistributionSetFields(final String jpaEntityFieldName) {
|
|
||||||
this(jpaEntityFieldName, Collections.emptyList(), null);
|
|
||||||
}
|
|
||||||
|
|
||||||
DistributionSetFields(final String jpaEntityFieldName, final String... subEntityAttributes) {
|
DistributionSetFields(final String jpaEntityFieldName, final String... subEntityAttributes) {
|
||||||
this(jpaEntityFieldName, List.of(subEntityAttributes), null);
|
|
||||||
}
|
|
||||||
|
|
||||||
DistributionSetFields(final String jpaEntityFieldName, final Entry<String, String> subEntityMapTuple) {
|
|
||||||
this(jpaEntityFieldName, Collections.emptyList(), subEntityMapTuple);
|
|
||||||
}
|
|
||||||
|
|
||||||
DistributionSetFields(final String jpaEntityFieldName, List<String> subEntityAttributes, final Entry<String, String> subEntityMapTuple) {
|
|
||||||
this.jpaEntityFieldName = jpaEntityFieldName;
|
this.jpaEntityFieldName = jpaEntityFieldName;
|
||||||
this.subEntityMapTuple = subEntityMapTuple;
|
this.subEntityAttributes = List.of(subEntityAttributes);
|
||||||
this.subEntityAttributes = subEntityAttributes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<Entry<String, String>> getSubEntityMapTuple() {
|
public boolean isMap() {
|
||||||
return Optional.ofNullable(subEntityMapTuple);
|
return this == METADATA;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -27,17 +27,13 @@ public enum DistributionSetTagFields implements RsqlQueryField {
|
|||||||
NAME(TagFields.NAME.getJpaEntityFieldName()),
|
NAME(TagFields.NAME.getJpaEntityFieldName()),
|
||||||
DESCRIPTION(TagFields.DESCRIPTION.getJpaEntityFieldName()),
|
DESCRIPTION(TagFields.DESCRIPTION.getJpaEntityFieldName()),
|
||||||
COLOUR(TagFields.COLOUR.getJpaEntityFieldName()),
|
COLOUR(TagFields.COLOUR.getJpaEntityFieldName()),
|
||||||
DISTRIBUTIONSET("assignedToDistributionSet",
|
DISTRIBUTIONSET(
|
||||||
|
"assignedToDistributionSet",
|
||||||
DistributionSetFields.ID.getJpaEntityFieldName(), DistributionSetFields.NAME.getJpaEntityFieldName());
|
DistributionSetFields.ID.getJpaEntityFieldName(), DistributionSetFields.NAME.getJpaEntityFieldName());
|
||||||
|
|
||||||
private final String jpaEntityFieldName;
|
private final String jpaEntityFieldName;
|
||||||
private final List<String> subEntityAttributes;
|
private final List<String> subEntityAttributes;
|
||||||
|
|
||||||
DistributionSetTagFields(final String jpaEntityFieldName) {
|
|
||||||
this.jpaEntityFieldName = jpaEntityFieldName;
|
|
||||||
this.subEntityAttributes = Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
DistributionSetTagFields(final String jpaEntityFieldName, final String... subEntityAttributes) {
|
DistributionSetTagFields(final String jpaEntityFieldName, final String... subEntityAttributes) {
|
||||||
this.jpaEntityFieldName = jpaEntityFieldName;
|
this.jpaEntityFieldName = jpaEntityFieldName;
|
||||||
this.subEntityAttributes = List.of(subEntityAttributes);
|
this.subEntityAttributes = List.of(subEntityAttributes);
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ package org.eclipse.hawkbit.repository;
|
|||||||
* A value convert which converts given string based values into an object which
|
* A value convert which converts given string based values into an object which
|
||||||
* can be used for building generic queries. Mapping external API values e.g.
|
* can be used for building generic queries. Mapping external API values e.g.
|
||||||
* REST API to inside representation on database. E.g. mapping 'pending' or
|
* REST API to inside representation on database. E.g. mapping 'pending' or
|
||||||
* 'finished' values in rest queries to Action#isActive boolean
|
* 'finished' values in rest queries to Action#isActive boolean value.
|
||||||
* value.
|
|
||||||
*
|
*
|
||||||
* @param <T> the enum parameter
|
* @param <T> the enum parameter
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -24,18 +24,15 @@ public enum RolloutFields implements RsqlQueryField {
|
|||||||
NAME("name"),
|
NAME("name"),
|
||||||
DESCRIPTION("description"),
|
DESCRIPTION("description"),
|
||||||
STATUS("status"),
|
STATUS("status"),
|
||||||
DISTRIBUTIONSET("distributionSet", DistributionSetFields.ID.getJpaEntityFieldName(),
|
DISTRIBUTIONSET(
|
||||||
|
"distributionSet",
|
||||||
|
DistributionSetFields.ID.getJpaEntityFieldName(),
|
||||||
DistributionSetFields.NAME.getJpaEntityFieldName(), DistributionSetFields.VERSION.getJpaEntityFieldName(),
|
DistributionSetFields.NAME.getJpaEntityFieldName(), DistributionSetFields.VERSION.getJpaEntityFieldName(),
|
||||||
DistributionSetFields.TYPE.getJpaEntityFieldName());
|
DistributionSetFields.TYPE.getJpaEntityFieldName());
|
||||||
|
|
||||||
private final String jpaEntityFieldName;
|
private final String jpaEntityFieldName;
|
||||||
private final List<String> subEntityAttributes;
|
private final List<String> subEntityAttributes;
|
||||||
|
|
||||||
RolloutFields(final String jpaEntityFieldName) {
|
|
||||||
this.jpaEntityFieldName = jpaEntityFieldName;
|
|
||||||
this.subEntityAttributes = Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
RolloutFields(final String jpaEntityFieldName, final String... subEntityAttributes) {
|
RolloutFields(final String jpaEntityFieldName, final String... subEntityAttributes) {
|
||||||
this.jpaEntityFieldName = jpaEntityFieldName;
|
this.jpaEntityFieldName = jpaEntityFieldName;
|
||||||
this.subEntityAttributes = List.of(subEntityAttributes);
|
this.subEntityAttributes = List.of(subEntityAttributes);
|
||||||
|
|||||||
@@ -34,30 +34,6 @@ public interface RsqlQueryField {
|
|||||||
@NotNull
|
@NotNull
|
||||||
String getJpaEntityFieldName();
|
String getJpaEntityFieldName();
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains the sub entity the given field.
|
|
||||||
*
|
|
||||||
* @param propertyField the given field
|
|
||||||
* @return <code>true</code> contains <code>false</code> contains not
|
|
||||||
*/
|
|
||||||
default boolean containsSubEntityAttribute(final String propertyField) {
|
|
||||||
final List<String> subEntityAttributes = getSubEntityAttributes();
|
|
||||||
if (subEntityAttributes.contains(propertyField)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (final String attribute : subEntityAttributes) {
|
|
||||||
final String[] graph = attribute.split(SUB_ATTRIBUTE_SPLIT_REGEX);
|
|
||||||
for (final String subAttribute : graph) {
|
|
||||||
if (subAttribute.equalsIgnoreCase(propertyField)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return all sub entities attributes.
|
* @return all sub entities attributes.
|
||||||
*/
|
*/
|
||||||
@@ -65,22 +41,6 @@ public interface RsqlQueryField {
|
|||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return a key/value tuple of a sub entity.
|
|
||||||
*/
|
|
||||||
default Optional<Entry<String, String>> getSubEntityMapTuple() {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is the entity field a {@link Map} consisting of key-value pairs.
|
|
||||||
*
|
|
||||||
* @return <code>true</code> is a map <code>false</code> is not a map
|
|
||||||
*/
|
|
||||||
default boolean isMap() {
|
|
||||||
return getSubEntityMapTuple().isPresent();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of the field, that identifies the entity.
|
* Returns the name of the field, that identifies the entity.
|
||||||
*
|
*
|
||||||
@@ -89,4 +49,13 @@ public interface RsqlQueryField {
|
|||||||
default String identifierFieldName() {
|
default String identifierFieldName() {
|
||||||
return "id";
|
return "id";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the entity field a {@link Map} consisting of key-value pairs.
|
||||||
|
*
|
||||||
|
* @return <code>true</code> is a map <code>false</code> is not a map
|
||||||
|
*/
|
||||||
|
default boolean isMap() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -45,25 +45,10 @@ public enum TargetFields implements RsqlQueryField {
|
|||||||
|
|
||||||
private final String jpaEntityFieldName;
|
private final String jpaEntityFieldName;
|
||||||
private final List<String> subEntityAttributes;
|
private final List<String> subEntityAttributes;
|
||||||
private final Entry<String, String> subEntityMapTuple;
|
|
||||||
|
|
||||||
TargetFields(final String jpaEntityFieldName) {
|
|
||||||
this(jpaEntityFieldName, Collections.emptyList(), null);
|
|
||||||
}
|
|
||||||
|
|
||||||
TargetFields(final String jpaEntityFieldName, final String... subEntityAttributes) {
|
TargetFields(final String jpaEntityFieldName, final String... subEntityAttributes) {
|
||||||
this(jpaEntityFieldName, List.of(subEntityAttributes), null);
|
|
||||||
}
|
|
||||||
|
|
||||||
TargetFields(final String jpaEntityFieldName, final List<String> subEntityAttributes, final Entry<String, String> subEntityMapTuple) {
|
|
||||||
this.jpaEntityFieldName = jpaEntityFieldName;
|
this.jpaEntityFieldName = jpaEntityFieldName;
|
||||||
this.subEntityAttributes = subEntityAttributes;
|
this.subEntityAttributes = List.of(subEntityAttributes);
|
||||||
this.subEntityMapTuple = subEntityMapTuple;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<Entry<String, String>> getSubEntityMapTuple() {
|
|
||||||
return Optional.ofNullable(subEntityMapTuple);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ public enum TargetFilterQueryFields implements RsqlQueryField {
|
|||||||
AUTOASSIGNDISTRIBUTIONSET("autoAssignDistributionSet", "name", "version");
|
AUTOASSIGNDISTRIBUTIONSET("autoAssignDistributionSet", "name", "version");
|
||||||
|
|
||||||
private final String jpaEntityFieldName;
|
private final String jpaEntityFieldName;
|
||||||
private List<String> subEntityAttributes;
|
private final List<String> subEntityAttributes;
|
||||||
|
|
||||||
TargetFilterQueryFields(final String jpaEntityFieldName) {
|
TargetFilterQueryFields(final String jpaEntityFieldName) {
|
||||||
this(jpaEntityFieldName, Collections.emptyList());
|
this(jpaEntityFieldName, Collections.emptyList());
|
||||||
|
|||||||
@@ -36,12 +36,6 @@ class FileNameFieldsTest {
|
|||||||
assertThat(matchingClasses).isNotEmpty();
|
assertThat(matchingClasses).isNotEmpty();
|
||||||
matchingClasses.forEach(providerClass -> {
|
matchingClasses.forEach(providerClass -> {
|
||||||
assertThat(providerClass.getEnumConstants()).isNotEmpty();
|
assertThat(providerClass.getEnumConstants()).isNotEmpty();
|
||||||
for (final RsqlQueryField provider : providerClass.getEnumConstants()) {
|
|
||||||
if (provider.isMap() && !provider.getSubEntityAttributes().isEmpty()) {
|
|
||||||
throw new UnsupportedOperationException(
|
|
||||||
"Currently sub-entity attributes for maps are not supported, alternatively you could use the key/value tuple, defined by SimpleImmutableEntry class");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ public abstract class AbstractRSQLVisitor<A extends Enum<A> & RsqlQueryField> {
|
|||||||
for (int i = 1; i < split.length; i++) {
|
for (int i = 1; i < split.length; i++) {
|
||||||
split[i] = getFormattedSubEntityAttribute(enumValue, split[i]);
|
split[i] = getFormattedSubEntityAttribute(enumValue, split[i]);
|
||||||
|
|
||||||
if (!enumValue.containsSubEntityAttribute(split[i])) {
|
if (!containsSubEntityAttribute(enumValue, split[i])) {
|
||||||
if (i != split.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
|
||||||
@@ -86,6 +86,32 @@ public abstract class AbstractRSQLVisitor<A extends Enum<A> & RsqlQueryField> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains the sub entity the given field.
|
||||||
|
*
|
||||||
|
* @param propertyField the given field
|
||||||
|
* @return <code>true</code> contains <code>false</code> contains not
|
||||||
|
*/
|
||||||
|
private boolean containsSubEntityAttribute(final A enumField, final String propertyField) {
|
||||||
|
final List<String> subEntityAttributes = enumField.getSubEntityAttributes();
|
||||||
|
if (subEntityAttributes.contains(propertyField)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final String attribute : subEntityAttributes) {
|
||||||
|
final String[] graph = attribute.split(RsqlQueryField.SUB_ATTRIBUTE_SPLIT_REGEX);
|
||||||
|
for (final String subAttribute : graph) {
|
||||||
|
if (subAttribute.equalsIgnoreCase(propertyField)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @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}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) 2021 Bosch.IO GmbH and others
|
* Copyright (c) 2025 Contributors to the Eclipse Foundation
|
||||||
*
|
*
|
||||||
* This program and the accompanying materials are made
|
* This program and the accompanying materials are made
|
||||||
* available under the terms of the Eclipse Public License 2.0
|
* available under the terms of the Eclipse Public License 2.0
|
||||||
@@ -16,7 +16,6 @@ import java.util.HashMap;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
@@ -344,9 +343,8 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & RsqlQueryField, T> extends
|
|||||||
|
|
||||||
final Predicate mapPredicate = mapToMapPredicate(fieldPath, queryPath);
|
final Predicate mapPredicate = mapToMapPredicate(fieldPath, queryPath);
|
||||||
|
|
||||||
final Predicate valuePredicate = addOperatorPredicate(node, getMapValueFieldPath(queryPath.getEnumValue(), fieldPath),
|
|
||||||
transformedValues, value, queryPath);
|
|
||||||
|
|
||||||
|
final Predicate valuePredicate = addOperatorPredicate(node, fieldPath, transformedValues, value, queryPath);
|
||||||
return toSingleList(mapPredicate != null ? cb.and(mapPredicate, valuePredicate) : valuePredicate);
|
return toSingleList(mapPredicate != null ? cb.and(mapPredicate, valuePredicate) : valuePredicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,15 +396,6 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & RsqlQueryField, T> extends
|
|||||||
expressionToCompare -> in(expressionToCompare, transformedValues));
|
expressionToCompare -> in(expressionToCompare, transformedValues));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Path<Object> getMapValueFieldPath(final A enumField, final Path<Object> fieldPath) {
|
|
||||||
final String valueFieldNameFromSubEntity = enumField.getSubEntityMapTuple().map(Entry::getValue).orElse(null);
|
|
||||||
|
|
||||||
if (!enumField.isMap() || valueFieldNameFromSubEntity == null) {
|
|
||||||
return fieldPath;
|
|
||||||
}
|
|
||||||
return fieldPath.get(valueFieldNameFromSubEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private Predicate mapToMapPredicate(final Path<Object> fieldPath, final QueryPath queryPath) {
|
private Predicate mapToMapPredicate(final Path<Object> fieldPath, final QueryPath queryPath) {
|
||||||
if (!queryPath.getEnumValue().isMap()) {
|
if (!queryPath.getEnumValue().isMap()) {
|
||||||
@@ -415,16 +404,8 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & RsqlQueryField, T> extends
|
|||||||
|
|
||||||
final String[] graph = queryPath.getJpaPath();
|
final String[] graph = queryPath.getJpaPath();
|
||||||
final String keyValue = graph[graph.length - 1];
|
final String keyValue = graph[graph.length - 1];
|
||||||
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 = queryPath.getEnumValue().getSubEntityMapTuple().map(Entry::getKey)
|
|
||||||
.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 equal(fieldPath.get(keyFieldName), keyValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Predicate getEqualToPredicate(final Object transformedValue, final Path<Object> fieldPath) {
|
private Predicate getEqualToPredicate(final Object transformedValue, final Path<Object> fieldPath) {
|
||||||
@@ -514,17 +495,12 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & RsqlQueryField, T> extends
|
|||||||
|
|
||||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
private Expression<String> getExpressionToCompare(final Path innerFieldPath, final A enumField) {
|
private Expression<String> getExpressionToCompare(final Path innerFieldPath, final A enumField) {
|
||||||
if (!enumField.isMap()) {
|
if (enumField.isMap()){
|
||||||
return pathOfString(innerFieldPath);
|
|
||||||
}
|
|
||||||
if (innerFieldPath 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 (Expression<String>) (((MapJoin<?, ?, ?>) pathOfString(innerFieldPath)).value());
|
return (Expression<String>) (((MapJoin<?, ?, ?>) pathOfString(innerFieldPath)).value());
|
||||||
|
} else {
|
||||||
|
return pathOfString(innerFieldPath);
|
||||||
}
|
}
|
||||||
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 String toSQL(final String transformedValue) {
|
private String toSQL(final String transformedValue) {
|
||||||
|
|||||||
@@ -9,14 +9,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.repository.jpa.rsql;
|
package org.eclipse.hawkbit.repository.jpa.rsql;
|
||||||
|
|
||||||
import java.util.AbstractMap;
|
|
||||||
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.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||||
@@ -125,7 +123,7 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & RsqlQueryField, T>
|
|||||||
if (values.get(0) == null) {
|
if (values.get(0) == null) {
|
||||||
// IS operator for maps and null value is treated as doesn't exist correspondingly
|
// IS operator for maps and null value is treated as doesn't exist correspondingly
|
||||||
((PluralJoin<?, ?, ?>) fieldPath).on(toMapEntryKeyPredicate(queryPath, fieldPath));
|
((PluralJoin<?, ?, ?>) fieldPath).on(toMapEntryKeyPredicate(queryPath, fieldPath));
|
||||||
return cb.isNull(getValueFieldPath(queryPath, fieldPath));
|
return cb.isNull(fieldPath);
|
||||||
}
|
}
|
||||||
} else if (node.getOperator() == RSQLUtility.NOT) {
|
} else if (node.getOperator() == RSQLUtility.NOT) {
|
||||||
if (values.size() != 1) {
|
if (values.size() != 1) {
|
||||||
@@ -133,13 +131,12 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & RsqlQueryField, T>
|
|||||||
}
|
}
|
||||||
// NOT operator for maps and null value is treated as does exist correspondingly
|
// NOT operator for maps and null value is treated as does exist correspondingly
|
||||||
((PluralJoin<?, ?, ?>) fieldPath).on(toMapEntryKeyPredicate(queryPath, fieldPath));
|
((PluralJoin<?, ?, ?>) fieldPath).on(toMapEntryKeyPredicate(queryPath, fieldPath));
|
||||||
final Path<?> valueFieldPath = getValueFieldPath(queryPath, fieldPath);
|
|
||||||
if (values.get(0) == null) {
|
if (values.get(0) == null) {
|
||||||
// special handling of "exists"
|
// special handling of "exists"
|
||||||
return cb.isNotNull(valueFieldPath);
|
return cb.isNotNull(fieldPath);
|
||||||
} else {
|
} else {
|
||||||
// special handling or "not equal" or null (same as != but with possible optimized join - no subquery)
|
// special handling or "not equal" or null (same as != but with possible optimized join - no subquery)
|
||||||
return toNotEqualToPredicate(queryPath, valueFieldPath, values.get(0));
|
return toNotEqualToPredicate(queryPath, fieldPath, values.get(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mapEntryKeyPredicate = toMapEntryKeyPredicate(queryPath, fieldPath);
|
mapEntryKeyPredicate = toMapEntryKeyPredicate(queryPath, fieldPath);
|
||||||
@@ -147,38 +144,15 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & RsqlQueryField, T>
|
|||||||
mapEntryKeyPredicate = null;
|
mapEntryKeyPredicate = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Predicate valuePredicate = toOperatorAndValuePredicate(node, queryPath, getValueFieldPath(queryPath, fieldPath), values);
|
final Predicate valuePredicate = toOperatorAndValuePredicate(node, queryPath, fieldPath, values);
|
||||||
|
|
||||||
return mapEntryKeyPredicate == null ? valuePredicate : cb.and(mapEntryKeyPredicate, valuePredicate);
|
return mapEntryKeyPredicate == null ? valuePredicate : cb.and(mapEntryKeyPredicate, valuePredicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
private Predicate toMapEntryKeyPredicate(final QueryPath queryPath, final Path<?> fieldPath) {
|
private Predicate toMapEntryKeyPredicate(final QueryPath queryPath, final Path<?> fieldPath) {
|
||||||
final String[] graph = queryPath.getJpaPath();
|
final String[] graph = queryPath.getJpaPath();
|
||||||
return equal(mapEntryKeyPath(queryPath, fieldPath), graph[graph.length - 1]);
|
return equal((Path<String>) ((MapJoin<?, ?, ?>) fieldPath).key(), graph[graph.length - 1]);
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private Path<String> mapEntryKeyPath(final QueryPath queryPath, final Path<?> fieldPath) {
|
|
||||||
if (fieldPath instanceof MapJoin) {
|
|
||||||
// Currently we support only string key. So below cast is safe.
|
|
||||||
return (Path<String>) ((MapJoin<?, ?, ?>) fieldPath).key();
|
|
||||||
}
|
|
||||||
|
|
||||||
return fieldPath.get(queryPath.getEnumValue().getSubEntityMapTuple()
|
|
||||||
.map(Entry::getKey)
|
|
||||||
.orElseThrow(() -> new UnsupportedOperationException(String.format(
|
|
||||||
"For the fields, defined as Map, only %s java type or tuple in the form of %s are allowed!",
|
|
||||||
Map.class.getName(), AbstractMap.SimpleImmutableEntry.class.getName()))));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Path<?> getValueFieldPath(final QueryPath queryPath, final Path<?> fieldPath) {
|
|
||||||
final A enumField = queryPath.getEnumValue();
|
|
||||||
if (enumField.isMap()) {
|
|
||||||
final Path<?> mapValuePath = enumField.getSubEntityMapTuple().map(Entry::getValue).map(fieldPath::get).orElse(null);
|
|
||||||
return mapValuePath == null ? fieldPath : mapValuePath;
|
|
||||||
} else {
|
|
||||||
return fieldPath;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Predicate toOperatorAndValuePredicate(
|
private Predicate toOperatorAndValuePredicate(
|
||||||
@@ -359,20 +333,12 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & RsqlQueryField, T>
|
|||||||
|
|
||||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
private Path<String> getExpressionToCompare(final A enumField, final Path fieldPath) {
|
private Path<String> getExpressionToCompare(final A enumField, final Path fieldPath) {
|
||||||
if (!enumField.isMap()) {
|
if (enumField.isMap()) {
|
||||||
return pathOfString(fieldPath);
|
|
||||||
}
|
|
||||||
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 (Path<String>) (((MapJoin<?, ?, ?>) fieldPath).value());
|
return (Path<String>) (((MapJoin<?, ?, ?>) fieldPath).value());
|
||||||
|
} else {
|
||||||
|
return pathOfString(fieldPath);
|
||||||
}
|
}
|
||||||
return enumField.getSubEntityMapTuple()
|
|
||||||
.map(Entry::getValue)
|
|
||||||
.map(fieldPath::<String>get)
|
|
||||||
.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!"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// result is String, enum value, boolean or null
|
// result is String, enum value, boolean or null
|
||||||
|
|||||||
Reference in New Issue
Block a user