Extend Query Langage Support (#2696)

* add option for parser replacement - so, one could replace the query language and don't use RSQL
* add easy way to modify query root Node 
* add easy Node modification utilities
* code refactored and naming more 'QL' than 'RSQL' oriented

Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2025-09-26 14:19:25 +03:00
committed by GitHub
parent d0fe120a3b
commit b181b66ee5
45 changed files with 308 additions and 211 deletions

View File

@@ -17,7 +17,7 @@ import lombok.Getter;
* Sort and search fields for actions. * Sort and search fields for actions.
*/ */
@Getter @Getter
public enum ActionFields implements RsqlQueryField, FieldValueConverter<ActionFields> { public enum ActionFields implements QueryField, FieldValueConverter<ActionFields> {
ID("id"), ID("id"),
STATUS("active"), STATUS("active"),

View File

@@ -15,7 +15,7 @@ import lombok.Getter;
* Sort and search fields for action status. * Sort and search fields for action status.
*/ */
@Getter @Getter
public enum ActionStatusFields implements RsqlQueryField { public enum ActionStatusFields implements QueryField {
ID("id"), ID("id"),
@Deprecated @Deprecated

View File

@@ -18,7 +18,7 @@ import lombok.Getter;
* REST API e.g. for sorting etc. * REST API e.g. for sorting etc.
*/ */
@Getter @Getter
public enum DistributionSetFields implements RsqlQueryField { public enum DistributionSetFields implements QueryField {
ID("id"), ID("id"),
TYPE("type", TYPE("type",
@@ -48,7 +48,7 @@ public enum DistributionSetFields implements RsqlQueryField {
@Override @Override
public String getDefaultSubEntityAttribute() { public String getDefaultSubEntityAttribute() {
return this == TYPE ? DistributionSetTypeFields.KEY.getJpaEntityFieldName() : RsqlQueryField.super.getDefaultSubEntityAttribute(); return this == TYPE ? DistributionSetTypeFields.KEY.getJpaEntityFieldName() : QueryField.super.getDefaultSubEntityAttribute();
} }
@Override @Override

View File

@@ -20,7 +20,7 @@ import lombok.Getter;
* filtering over distribution set fields also. * filtering over distribution set fields also.
*/ */
@Getter @Getter
public enum DistributionSetTagFields implements RsqlQueryField { public enum DistributionSetTagFields implements QueryField {
ID(TagFields.ID.getJpaEntityFieldName()), ID(TagFields.ID.getJpaEntityFieldName()),
NAME(TagFields.NAME.getJpaEntityFieldName()), NAME(TagFields.NAME.getJpaEntityFieldName()),

View File

@@ -16,7 +16,7 @@ import lombok.Getter;
* the REST API e.g. for sorting etc. * the REST API e.g. for sorting etc.
*/ */
@Getter @Getter
public enum DistributionSetTypeFields implements RsqlQueryField { public enum DistributionSetTypeFields implements QueryField {
ID("id"), ID("id"),
KEY("key"), KEY("key"),

View File

@@ -16,9 +16,9 @@ import java.util.Map;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
/** /**
* An RSQL query field interface extended by all the fields that could be used in RSQL queries. * A query field interface extended by all the fields that could be used in queries.
*/ */
public interface RsqlQueryField { public interface QueryField {
/** /**
* Separator for the sub attributes * Separator for the sub attributes

View File

@@ -17,7 +17,7 @@ import lombok.Getter;
* Describing the fields of the Rollout model which can be used in the REST API e.g. for sorting etc. * Describing the fields of the Rollout model which can be used in the REST API e.g. for sorting etc.
*/ */
@Getter @Getter
public enum RolloutFields implements RsqlQueryField { public enum RolloutFields implements QueryField {
ID("id"), ID("id"),
NAME("name"), NAME("name"),

View File

@@ -15,7 +15,7 @@ import lombok.Getter;
* Describing the fields of the RolloutGroup model which can be used in the REST API e.g. for sorting etc. * Describing the fields of the RolloutGroup model which can be used in the REST API e.g. for sorting etc.
*/ */
@Getter @Getter
public enum RolloutGroupFields implements RsqlQueryField { public enum RolloutGroupFields implements QueryField {
ID("id"), ID("id"),
NAME("name"), NAME("name"),

View File

@@ -17,7 +17,7 @@ import lombok.Getter;
* Describing the fields of the SoftwareModule model which can be used in the REST API e.g. for sorting etc. * Describing the fields of the SoftwareModule model which can be used in the REST API e.g. for sorting etc.
*/ */
@Getter @Getter
public enum SoftwareModuleFields implements RsqlQueryField { public enum SoftwareModuleFields implements QueryField {
ID("id"), ID("id"),
TYPE("type", TYPE("type",
@@ -44,7 +44,7 @@ public enum SoftwareModuleFields implements RsqlQueryField {
@Override @Override
public String getDefaultSubEntityAttribute() { public String getDefaultSubEntityAttribute() {
return this == TYPE ? SoftwareModuleTypeFields.KEY.getJpaEntityFieldName() : RsqlQueryField.super.getDefaultSubEntityAttribute(); return this == TYPE ? SoftwareModuleTypeFields.KEY.getJpaEntityFieldName() : QueryField.super.getDefaultSubEntityAttribute();
} }
@Override @Override

View File

@@ -15,7 +15,7 @@ import lombok.Getter;
* Describing the fields of the SoftwareModuleType model which can be used in the REST API e.g. for sorting etc. * Describing the fields of the SoftwareModuleType model which can be used in the REST API e.g. for sorting etc.
*/ */
@Getter @Getter
public enum SoftwareModuleTypeFields implements RsqlQueryField { public enum SoftwareModuleTypeFields implements QueryField {
ID("id"), ID("id"),
KEY("key"), KEY("key"),

View File

@@ -15,7 +15,7 @@ import lombok.Getter;
* Describing the fields of the Tag model which can be used in the REST API e.g. for sorting etc. * Describing the fields of the Tag model which can be used in the REST API e.g. for sorting etc.
*/ */
@Getter @Getter
public enum TagFields implements RsqlQueryField { public enum TagFields implements QueryField {
ID("id"), ID("id"),
NAME("name"), NAME("name"),

View File

@@ -18,7 +18,7 @@ import lombok.Getter;
* e.g. for sorting etc. * e.g. for sorting etc.
*/ */
@Getter @Getter
public enum TargetFields implements RsqlQueryField { public enum TargetFields implements QueryField {
ID("controllerId"), ID("controllerId"),
NAME("name"), NAME("name"),
@@ -62,7 +62,7 @@ public enum TargetFields implements RsqlQueryField {
@Override @Override
public String getDefaultSubEntityAttribute() { public String getDefaultSubEntityAttribute() {
return this == TYPE ? TargetTypeFields.KEY.getJpaEntityFieldName() : RsqlQueryField.super.getDefaultSubEntityAttribute(); return this == TYPE ? TargetTypeFields.KEY.getJpaEntityFieldName() : QueryField.super.getDefaultSubEntityAttribute();
} }
@Override @Override

View File

@@ -18,7 +18,7 @@ import lombok.Getter;
* Describing the fields of the Target model which can be used in the REST API e.g. for sorting etc. * Describing the fields of the Target model which can be used in the REST API e.g. for sorting etc.
*/ */
@Getter @Getter
public enum TargetFilterQueryFields implements RsqlQueryField { public enum TargetFilterQueryFields implements QueryField {
ID("id"), ID("id"),
NAME("name"), NAME("name"),

View File

@@ -16,7 +16,7 @@ import lombok.Getter;
* Additionally, here were added fields for Target in order filtering over target fields also. * Additionally, here were added fields for Target in order filtering over target fields also.
*/ */
@Getter @Getter
public enum TargetTagFields implements RsqlQueryField { public enum TargetTagFields implements QueryField {
ID(TagFields.ID.getJpaEntityFieldName()), ID(TagFields.ID.getJpaEntityFieldName()),
NAME(TagFields.NAME.getJpaEntityFieldName()), NAME(TagFields.NAME.getJpaEntityFieldName()),

View File

@@ -15,7 +15,7 @@ import lombok.Getter;
* Describing the fields of the TargetType model which can be used in the REST API * Describing the fields of the TargetType model which can be used in the REST API
*/ */
@Getter @Getter
public enum TargetTypeFields implements RsqlQueryField { public enum TargetTypeFields implements QueryField {
ID("id"), ID("id"),
KEY("key"), KEY("key"),

View File

@@ -18,7 +18,7 @@ import io.github.classgraph.ClassInfo;
import io.github.classgraph.ScanResult; import io.github.classgraph.ScanResult;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
class RsqlQueryFieldsTest { class QueryFieldsTest {
/** /**
* Verifies that fields classes are correctly implemented * Verifies that fields classes are correctly implemented
@@ -28,11 +28,11 @@ class RsqlQueryFieldsTest {
void repositoryManagementMethodsArePreAuthorizedAnnotated() { void repositoryManagementMethodsArePreAuthorizedAnnotated() {
final String packageName = getClass().getPackage().getName(); final String packageName = getClass().getPackage().getName();
try (final ScanResult scanResult = new ClassGraph().acceptPackages(packageName).scan()) { try (final ScanResult scanResult = new ClassGraph().acceptPackages(packageName).scan()) {
final List<? extends Class<? extends RsqlQueryField>> matchingClasses = scanResult.getAllClasses() final List<? extends Class<? extends QueryField>> matchingClasses = scanResult.getAllClasses()
.stream() .stream()
.filter(classInPackage -> classInPackage.implementsInterface(RsqlQueryField.class)) .filter(classInPackage -> classInPackage.implementsInterface(QueryField.class))
.map(ClassInfo::loadClass) .map(ClassInfo::loadClass)
.map(clazz -> (Class<? extends RsqlQueryField>) clazz) .map(clazz -> (Class<? extends QueryField>) clazz)
.toList(); .toList();
assertThat(matchingClasses).isNotEmpty(); assertThat(matchingClasses).isNotEmpty();
matchingClasses.forEach(providerClass -> assertThat(providerClass.getEnumConstants()).isNotEmpty()); matchingClasses.forEach(providerClass -> assertThat(providerClass.getEnumConstants()).isNotEmpty());

View File

@@ -18,7 +18,7 @@ import lombok.NoArgsConstructor;
import org.eclipse.hawkbit.mgmt.rest.resource.exception.SortParameterSyntaxErrorException; import org.eclipse.hawkbit.mgmt.rest.resource.exception.SortParameterSyntaxErrorException;
import org.eclipse.hawkbit.mgmt.rest.resource.exception.SortParameterUnsupportedDirectionException; import org.eclipse.hawkbit.mgmt.rest.resource.exception.SortParameterUnsupportedDirectionException;
import org.eclipse.hawkbit.mgmt.rest.resource.exception.SortParameterUnsupportedFieldException; import org.eclipse.hawkbit.mgmt.rest.resource.exception.SortParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.RsqlQueryField; import org.eclipse.hawkbit.repository.QueryField;
import org.springframework.data.domain.Sort.Direction; import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order; import org.springframework.data.domain.Sort.Order;
@@ -44,15 +44,15 @@ public final class SortUtility {
* sorting will be mapped into the {@link Direction} enum. * sorting will be mapped into the {@link Direction} enum.
* *
* @param enumType the class of the enum which the fields in the sort string should be related to. * @param enumType the class of the enum which the fields in the sort string should be related to.
* @param <T> the type of the enumeration which must be derived from {@link RsqlQueryField} * @param <T> the type of the enumeration which must be derived from {@link QueryField}
* @param sortString the string representation of the query parameters. Might be {@code null} or an empty string. * @param sortString the string representation of the query parameters. Might be {@code null} or an empty string.
* @return a list which holds the {@link RsqlQueryField} and the specific {@link Direction} for them as a tuple. Never {@code null}. * @return a list which holds the {@link QueryField} and the specific {@link Direction} for them as a tuple. Never {@code null}.
* In case of no sorting parameters an empty map will be returned. * In case of no sorting parameters an empty map will be returned.
* @throws SortParameterSyntaxErrorException if the sorting query parameter is not well-formed * @throws SortParameterSyntaxErrorException if the sorting query parameter is not well-formed
* @throws SortParameterUnsupportedFieldException if a field name cannot be mapped to the enum type * @throws SortParameterUnsupportedFieldException if a field name cannot be mapped to the enum type
* @throws SortParameterUnsupportedDirectionException if the given direction is not "ASC" or "DESC" * @throws SortParameterUnsupportedDirectionException if the given direction is not "ASC" or "DESC"
*/ */
public static <T extends Enum<T> & RsqlQueryField> List<Order> parse(final Class<T> enumType, final String sortString) public static <T extends Enum<T> & QueryField> List<Order> parse(final Class<T> enumType, final String sortString)
throws SortParameterSyntaxErrorException { throws SortParameterSyntaxErrorException {
final List<Order> orders = new ArrayList<>(); final List<Order> orders = new ArrayList<>();
// scan the sort tuples e.g. field:direction // scan the sort tuples e.g. field:direction

View File

@@ -0,0 +1,41 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.repository.exception;
import java.io.Serial;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.eclipse.hawkbit.exception.AbstractServerRtException;
import org.eclipse.hawkbit.exception.SpServerError;
/**
* Exception used by the REST API in case of RSQL search filter query.
*/
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public abstract class QueryException extends AbstractServerRtException {
QueryException(final SpServerError error) {
super(error);
}
QueryException(final SpServerError error, final String message) {
super(error, message);
}
QueryException(final SpServerError error, final Throwable cause) {
super(error, cause);
}
QueryException(final SpServerError error, final String message, final Throwable cause) {
super(error, message, cause);
}
}

View File

@@ -21,7 +21,7 @@ import org.eclipse.hawkbit.exception.SpServerError;
*/ */
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true) @ToString(callSuper = true)
public class RSQLParameterSyntaxException extends AbstractServerRtException { public class RSQLParameterSyntaxException extends QueryException {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@@ -21,7 +21,7 @@ import org.eclipse.hawkbit.exception.SpServerError;
*/ */
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true) @ToString(callSuper = true)
public class RSQLParameterUnsupportedFieldException extends AbstractServerRtException { public class RSQLParameterUnsupportedFieldException extends QueryException {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@@ -12,6 +12,7 @@ package org.eclipse.hawkbit.repository.jpa.ql;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.function.UnaryOperator;
import jakarta.annotation.Nonnull; import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable; import jakarta.annotation.Nullable;
@@ -38,6 +39,25 @@ public interface Node {
return op(this, Logical.Operator.OR, other); return op(this, Logical.Operator.OR, other);
} }
// utility method that maps this node with a mapper that could modify comparisons - e.g. change keys, values, operators, or whatever
// if there are no changes the same instance is returned
default Node map(final UnaryOperator<Comparison> mapper) {
if (this instanceof Comparison comparison) {
return mapper.apply(comparison);
} else {
final List<Node> mappedChildren = new ArrayList<>();
boolean modified = false;
for (final Node child : ((Logical) this).getChildren()) {
final Node mapped = child.map(mapper);
mappedChildren.add(mapped);
if (!mapped.equals(child)) {
modified = true;
}
}
return modified ? new Logical(((Logical) this).getOp(), mappedChildren) : this;
}
}
static Logical op(final Node node1, final Logical.Operator op, final Node node2) { static Logical op(final Node node1, final Logical.Operator op, final Node node2) {
if (node1 instanceof Logical logical1 && logical1.getOp() == op) { if (node1 instanceof Logical logical1 && logical1.getOp() == op) {
if (node2 instanceof Logical logical2 && logical2.getOp() == op) { // same op if (node2 instanceof Logical logical2 && logical2.getOp() == op) { // same op
@@ -121,7 +141,7 @@ public interface Node {
private final String symbol; private final String symbol;
Operator(String symbol) { Operator(final String symbol) {
this.symbol = symbol; this.symbol = symbol;
} }

View File

@@ -7,23 +7,26 @@
* *
* SPDX-License-Identifier: EPL-2.0 * SPDX-License-Identifier: EPL-2.0
*/ */
package org.eclipse.hawkbit.repository.jpa.rsql; package org.eclipse.hawkbit.repository.jpa.ql;
import java.util.Objects;
import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManager;
import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.CriteriaQuery;
import cz.jirutka.rsql.parser.RSQLParserException;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.text.StrLookup; import org.apache.commons.lang3.text.StrLookup;
import org.eclipse.hawkbit.repository.RsqlQueryField; import org.eclipse.hawkbit.repository.QueryField;
import org.eclipse.hawkbit.repository.exception.QueryException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.jpa.ql.SpecificationBuilder; import org.eclipse.hawkbit.repository.jpa.ql.Node.Comparison;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlParser;
import org.eclipse.hawkbit.repository.jpa.rsql.legacy.SpecificationBuilderLegacy; import org.eclipse.hawkbit.repository.jpa.rsql.legacy.SpecificationBuilderLegacy;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyResolver; import org.eclipse.hawkbit.repository.rsql.VirtualPropertyResolver;
@@ -69,20 +72,20 @@ import org.springframework.orm.jpa.vendor.Database;
@Slf4j @Slf4j
@Getter @Getter
@NoArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor(access = AccessLevel.PRIVATE)
public class RsqlUtility { public class QLSupport {
private static final RsqlUtility SINGLETON = new RsqlUtility(); private static final QLSupport SINGLETON = new QLSupport();
public enum RsqlToSpecBuilder { public enum SpecBuilder {
LEGACY_G1, // legacy RSQL visitor LEGACY_G1, // legacy RSQL visitor
LEGACY_G2, // G2 RSQL visitor LEGACY_G2, // G2 RSQL visitor
G3 // G3 RSQL visitor - still experimental / yet default G3 // G3 specification builder - still experimental / yet default
} }
/** /**
* If RSQL comparison operators shall ignore the case. If ignore case is <code>true</code> "x == ax" will match "x == aX" * If QL comparison operators shall ignore the case. If ignore case is <code>true</code> "x == ax" will match "x == aX"
*/ */
@Value("${hawkbit.rsql.ignore-case:true}") @Value("${hawkbit.ql.ignore-case:true}")
private boolean ignoreCase; private boolean ignoreCase;
/** /**
* Declares if the database is case-insensitive, by default assumes <code>false</code>. In case it is case-sensitive and, * Declares if the database is case-insensitive, by default assumes <code>false</code>. In case it is case-sensitive and,
@@ -100,8 +103,10 @@ public class RsqlUtility {
@Setter // for tests only @Setter // for tests only
@Deprecated(forRemoval = true, since = "0.6.0") @Deprecated(forRemoval = true, since = "0.6.0")
@Value("${hawkbit.rsql.rsql-to-spec-builder:G3}") // @Value("${hawkbit.rsql.rsql-to-spec-builder:G3}") //
private RsqlToSpecBuilder rsqlToSpecBuilder; private SpecBuilder specBuilder;
@SuppressWarnings({ "rawtypes", "unchecked" })
private QueryParser parser;
private VirtualPropertyReplacer virtualPropertyReplacer; private VirtualPropertyReplacer virtualPropertyReplacer;
private Database database; private Database database;
private EntityManager entityManager; private EntityManager entityManager;
@@ -109,10 +114,15 @@ public class RsqlUtility {
/** /**
* @return The holder singleton instance. * @return The holder singleton instance.
*/ */
public static RsqlUtility getInstance() { public static QLSupport getInstance() {
return SINGLETON; return SINGLETON;
} }
@Autowired
void setQueryParser(final QueryParser parser) {
this.parser = parser;
}
@Autowired(required = false) @Autowired(required = false)
void setVirtualPropertyReplacer(final VirtualPropertyReplacer virtualPropertyReplacer) { void setVirtualPropertyReplacer(final VirtualPropertyReplacer virtualPropertyReplacer) {
this.virtualPropertyReplacer = virtualPropertyReplacer; this.virtualPropertyReplacer = virtualPropertyReplacer;
@@ -132,37 +142,71 @@ public class RsqlUtility {
* Builds a JPA {@link Specification} which corresponds with the given RSQL query. The specification can be used to filter for JPA entities * Builds a JPA {@link Specification} which corresponds with the given RSQL query. The specification can be used to filter for JPA entities
* with the given RSQL query. * with the given RSQL query.
* *
* @param rsql the rsql query to be parsed * @param query the rsql query to be parsed
* @param rsqlQueryFieldType the enum class type which implements the {@link RsqlQueryField} * @param queryFieldType the enum class type which implements the {@link QueryField}
* @return a specification which can be used with JPA * @return a specification which can be used with JPA
* @throws RSQLParameterUnsupportedFieldException if a field in the RSQL string is used but not provided by the * @throws RSQLParameterUnsupportedFieldException if a field in the RSQL string is used but not provided by the
* given {@code fieldNameProvider} * given {@code fieldNameProvider}
* @throws RSQLParameterSyntaxException if the RSQL syntax is wrong * @throws RSQLParameterSyntaxException if the RSQL syntax is wrong
*/ */
public <A extends Enum<A> & RsqlQueryField, T> Specification<T> buildRsqlSpecification( public <A extends Enum<A> & QueryField, T> Specification<T> buildSpec(
final String rsql, final Class<A> rsqlQueryFieldType) { final String query, final Class<A> queryFieldType) {
if (rsqlToSpecBuilder == RsqlToSpecBuilder.G3) { if (specBuilder == SpecBuilder.G3) {
return new SpecificationBuilder<T>(virtualPropertyReplacer, !caseInsensitiveDB && ignoreCase, database) return new SpecificationBuilder<T>(!caseInsensitiveDB && ignoreCase, database)
.specification(RsqlParser.parse(caseInsensitiveDB || ignoreCase ? rsql.toLowerCase() : rsql, rsqlQueryFieldType)); .specification(parser.parse(caseInsensitiveDB || ignoreCase ? query.toLowerCase() : query, queryFieldType));
} else { } else {
return new SpecificationBuilderLegacy<A, T>(rsqlQueryFieldType, virtualPropertyReplacer, database).specification(rsql); return new SpecificationBuilderLegacy<A, T>(queryFieldType, virtualPropertyReplacer, database).specification(query);
} }
} }
/** /**
* Validates the RSQL string * Validates the query string
* *
* @param rsql RSQL string to validate * @param query query string to validate
* @param rsqlQueryFieldType the enum class type which implements the {@link RsqlQueryField} * @param queryFieldType the enum class type which implements the {@link QueryField}
* @param jpaType the JPA entity type to validate against * @param jpaType the JPA entity type to validate against
* @throws RSQLParserException if RSQL syntax is invalid * @throws QueryException if query is invalid
* @throws RSQLParameterUnsupportedFieldException if RSQL key is not allowed
*/ */
@SuppressWarnings({ "unchecked", "rawtypes" }) @SuppressWarnings({ "unchecked", "rawtypes" })
public <A extends Enum<A> & RsqlQueryField> void validateRsqlFor( public <A extends Enum<A> & QueryField> void validateQuery(final String query, final Class<A> queryFieldType, final Class<?> jpaType) {
final String rsql, final Class<A> rsqlQueryFieldType, final Class<?> jpaType) {
final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
final CriteriaQuery<?> criteriaQuery = criteriaBuilder.createQuery(jpaType); final CriteriaQuery<?> criteriaQuery = criteriaBuilder.createQuery(jpaType);
buildRsqlSpecification(rsql, rsqlQueryFieldType).toPredicate(criteriaQuery.from((Class) jpaType), criteriaQuery, criteriaBuilder); buildSpec(query, queryFieldType).toPredicate(criteriaQuery.from((Class) jpaType), criteriaQuery, criteriaBuilder);
}
public interface QueryParser {
<T extends Enum<T> & QueryField> Node parse(final String query, final Class<T> queryFieldType) throws QueryException;
}
public static class DefaultQueryParser implements QueryParser {
private VirtualPropertyReplacer virtualPropertyReplacer;
@Autowired(required = false)
void setVirtualPropertyReplacer(final VirtualPropertyReplacer virtualPropertyReplacer) {
this.virtualPropertyReplacer = virtualPropertyReplacer;
}
@Override
public <T extends Enum<T> & QueryField> Node parse(final String query, final Class<T> queryFieldType) throws QueryException {
return RsqlParser.parse(query, queryFieldType).map(this::map);
}
protected Comparison map(final Comparison comparison) {
final String key = mapKey(comparison.getKey(), comparison).toString();
final Object value = mapValue(comparison.getValue(), comparison);
return key.equals(comparison.getKey()) && Objects.equals(value, comparison.getValue())
? comparison : Comparison.builder().key(key).op(comparison.getOp()).value(value).build();
}
// just extension points for subclasses
protected Object mapKey(final String key, final Comparison comparison) {
return key;
}
protected Object mapValue(final Object value, final Comparison comparison) {
return value instanceof String strValue ? virtualPropertyReplacer.replace(strValue) : value;
}
} }
} }

View File

@@ -63,14 +63,10 @@ public class SpecificationBuilder<T> {
private static final char ESCAPE_CHAR = '\\'; private static final char ESCAPE_CHAR = '\\';
private final VirtualPropertyReplacer virtualPropertyReplacer;
private final boolean ensureIgnoreCase; private final boolean ensureIgnoreCase;
private final Database database; private final Database database;
public SpecificationBuilder( public SpecificationBuilder(final boolean ensureIgnoreCase, final Database database) {
final VirtualPropertyReplacer virtualPropertyReplacer,
final boolean ensureIgnoreCase, final Database database) {
this.virtualPropertyReplacer = virtualPropertyReplacer;
this.ensureIgnoreCase = ensureIgnoreCase; this.ensureIgnoreCase = ensureIgnoreCase;
this.database = database; this.database = database;
} }
@@ -244,10 +240,6 @@ public class SpecificationBuilder<T> {
private List<Object> getValues(final Comparison comparison, final Class<?> javaType) { private List<Object> getValues(final Comparison comparison, final Class<?> javaType) {
final Object value = comparison.getValue(); final Object value = comparison.getValue();
final List<Object> values = (value == null ? NULL_VALUE : (value instanceof List<?> list ? list : List.of(value))).stream() final List<Object> values = (value == null ? NULL_VALUE : (value instanceof List<?> list ? list : List.of(value))).stream()
// if lookup is available, replace macros ...
.map(element -> virtualPropertyReplacer != null && element instanceof String strElement
? virtualPropertyReplacer.replace(strElement)
: element)
// converts value to the correct type // converts value to the correct type
.map(element -> element instanceof String strElement .map(element -> element instanceof String strElement
? convertValueIfNecessary(strElement, javaType, comparison) ? convertValueIfNecessary(strElement, javaType, comparison)

View File

@@ -17,9 +17,9 @@ import jakarta.persistence.TypedQuery;
import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.CriteriaQuery;
import org.eclipse.hawkbit.repository.RsqlQueryField; import org.eclipse.hawkbit.repository.QueryField;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility; import org.eclipse.hawkbit.repository.jpa.ql.QLSupport;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder; import org.eclipse.hawkbit.repository.jpa.ql.QLSupport.SpecBuilder;
public class HawkbitQlToSql { public class HawkbitQlToSql {
@@ -31,8 +31,8 @@ public class HawkbitQlToSql {
isEclipselink = entityManager.getProperties().keySet().stream().anyMatch(key -> key.startsWith("eclipselink.")); isEclipselink = entityManager.getProperties().keySet().stream().anyMatch(key -> key.startsWith("eclipselink."));
} }
public <T, A extends Enum<A> & RsqlQueryField> String toSQL( public <T, A extends Enum<A> & QueryField> String toSQL(
final Class<T> domainClass, final Class<A> fieldsClass, final String rsql, final RsqlToSpecBuilder rsqlToSpecBuilder) { final Class<T> domainClass, final Class<A> fieldsClass, final String rsql, final SpecBuilder rsqlToSpecBuilder) {
final CriteriaQuery<T> query = createQuery(domainClass, fieldsClass, rsql, rsqlToSpecBuilder); final CriteriaQuery<T> query = createQuery(domainClass, fieldsClass, rsql, rsqlToSpecBuilder);
final TypedQuery<?> typedQuery = entityManager.createQuery(query); final TypedQuery<?> typedQuery = entityManager.createQuery(query);
if (isEclipselink) { if (isEclipselink) {
@@ -54,20 +54,20 @@ public class HawkbitQlToSql {
} }
} }
private <T, A extends Enum<A> & RsqlQueryField> CriteriaQuery<T> createQuery( private <T, A extends Enum<A> & QueryField> CriteriaQuery<T> createQuery(
final Class<T> domainClass, final Class<A> fieldsClass, final String rsql, final RsqlToSpecBuilder rsqlToSpecBuilder) { final Class<T> domainClass, final Class<A> fieldsClass, final String rsql, final SpecBuilder rsqlToSpecBuilder) {
final CriteriaQuery<T> query = entityManager.getCriteriaBuilder().createQuery(domainClass); final CriteriaQuery<T> query = entityManager.getCriteriaBuilder().createQuery(domainClass);
final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
final RsqlToSpecBuilder defaultRsqlToSpecBuilder = RsqlUtility.getInstance().getRsqlToSpecBuilder(); final SpecBuilder defaultRsqlToSpecBuilder = QLSupport.getInstance().getSpecBuilder();
if (defaultRsqlToSpecBuilder != rsqlToSpecBuilder) { if (defaultRsqlToSpecBuilder != rsqlToSpecBuilder) {
RsqlUtility.getInstance().setRsqlToSpecBuilder(rsqlToSpecBuilder); QLSupport.getInstance().setSpecBuilder(rsqlToSpecBuilder);
} }
try { try {
return query.where(RsqlUtility.getInstance().<A, T> buildRsqlSpecification(rsql, fieldsClass) return query.where(QLSupport.getInstance().<A, T> buildSpec(rsql, fieldsClass)
.toPredicate(query.from(domainClass), cb.createQuery(domainClass), cb)); .toPredicate(query.from(domainClass), cb.createQuery(domainClass), cb));
} finally { } finally {
if (defaultRsqlToSpecBuilder != rsqlToSpecBuilder) { if (defaultRsqlToSpecBuilder != rsqlToSpecBuilder) {
RsqlUtility.getInstance().setRsqlToSpecBuilder(defaultRsqlToSpecBuilder); QLSupport.getInstance().setSpecBuilder(defaultRsqlToSpecBuilder);
} }
} }
} }

View File

@@ -9,8 +9,8 @@
*/ */
package org.eclipse.hawkbit.repository.jpa.rsql; package org.eclipse.hawkbit.repository.jpa.rsql;
import static org.eclipse.hawkbit.repository.RsqlQueryField.SUB_ATTRIBUTE_SEPARATOR; import static org.eclipse.hawkbit.repository.QueryField.SUB_ATTRIBUTE_SEPARATOR;
import static org.eclipse.hawkbit.repository.RsqlQueryField.SUB_ATTRIBUTE_SPLIT_REGEX; import static org.eclipse.hawkbit.repository.QueryField.SUB_ATTRIBUTE_SPLIT_REGEX;
import static org.eclipse.hawkbit.repository.jpa.ql.Node.Comparison.Operator.EQ; import static org.eclipse.hawkbit.repository.jpa.ql.Node.Comparison.Operator.EQ;
import static org.eclipse.hawkbit.repository.jpa.ql.Node.Comparison.Operator.GT; import static org.eclipse.hawkbit.repository.jpa.ql.Node.Comparison.Operator.GT;
import static org.eclipse.hawkbit.repository.jpa.ql.Node.Comparison.Operator.GTE; import static org.eclipse.hawkbit.repository.jpa.ql.Node.Comparison.Operator.GTE;
@@ -42,7 +42,7 @@ import lombok.AccessLevel;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.hawkbit.repository.FieldValueConverter; import org.eclipse.hawkbit.repository.FieldValueConverter;
import org.eclipse.hawkbit.repository.RsqlQueryField; import org.eclipse.hawkbit.repository.QueryField;
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.jpa.ql.Node; import org.eclipse.hawkbit.repository.jpa.ql.Node;
@@ -82,8 +82,8 @@ public class RsqlParser {
return parse(rsql, (Function<String, Key>) null); return parse(rsql, (Function<String, Key>) null);
} }
public static <T extends Enum<T> & RsqlQueryField> Node parse(final String rsql, final Class<T> rsqlQueryFieldType) { public static <T extends Enum<T> & QueryField> Node parse(final String rsql, final Class<T> queryFieldType) {
return parse(rsql, rsqlQueryFieldType == null ? null : key -> resolveKey(key, rsqlQueryFieldType)); return parse(rsql, queryFieldType == null ? null : key -> resolveKey(key, queryFieldType));
} }
private static Node parse(final String rsql, final Function<String, Key> keyResolver) { private static Node parse(final String rsql, final Function<String, Key> keyResolver) {
@@ -97,7 +97,7 @@ public class RsqlParser {
} }
@SuppressWarnings("java:S3776") // java:S3776 - group in single method for easier read of whole logic @SuppressWarnings("java:S3776") // java:S3776 - group in single method for easier read of whole logic
private static <T extends Enum<T> & RsqlQueryField> Key resolveKey(final String key, final Class<T> rsqlQueryFieldType) { private static <T extends Enum<T> & QueryField> Key resolveKey(final String key, final Class<T> rsqlQueryFieldType) {
final int firstSeparatorIndex = key.indexOf(SUB_ATTRIBUTE_SEPARATOR); final int firstSeparatorIndex = key.indexOf(SUB_ATTRIBUTE_SEPARATOR);
final String enumName = (firstSeparatorIndex == -1 ? key : key.substring(0, firstSeparatorIndex)).toUpperCase(); final String enumName = (firstSeparatorIndex == -1 ? key : key.substring(0, firstSeparatorIndex)).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);
@@ -151,9 +151,7 @@ public class RsqlParser {
} }
} }
return new return new Key(attribute, RsqlVisitor.valueConverter(enumValue));
Key(attribute, RsqlVisitor.valueConverter(enumValue));
} }
private record Key(String path, UnaryOperator<Object> converter) {} private record Key(String path, UnaryOperator<Object> converter) {}

View File

@@ -23,7 +23,7 @@ import cz.jirutka.rsql.parser.ast.ComparisonOperator;
import cz.jirutka.rsql.parser.ast.RSQLOperators; import cz.jirutka.rsql.parser.ast.RSQLOperators;
import lombok.Value; import lombok.Value;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.hawkbit.repository.RsqlQueryField; import org.eclipse.hawkbit.repository.QueryField;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.jpa.ql.SpecificationBuilder; import org.eclipse.hawkbit.repository.jpa.ql.SpecificationBuilder;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
@@ -33,7 +33,7 @@ import org.springframework.util.ObjectUtils;
*/ */
@Deprecated(forRemoval = true, since = "0.9.0") @Deprecated(forRemoval = true, since = "0.9.0")
@Slf4j @Slf4j
public abstract class AbstractRSQLVisitor<A extends Enum<A> & RsqlQueryField> { public abstract class AbstractRSQLVisitor<A extends Enum<A> & QueryField> {
static final ComparisonOperator IS = new ComparisonOperator("=is=", "=eq="); static final ComparisonOperator IS = new ComparisonOperator("=is=", "=eq=");
static final ComparisonOperator NOT = new ComparisonOperator("=not=", "=ne="); static final ComparisonOperator NOT = new ComparisonOperator("=not=", "=ne=");
@@ -56,7 +56,7 @@ public abstract class AbstractRSQLVisitor<A extends Enum<A> & RsqlQueryField> {
@SuppressWarnings("java:S1066") // java:S1066 - more readable with separate "if" statements @SuppressWarnings("java:S1066") // java:S1066 - more readable with separate "if" statements
protected QueryPath getQueryPath(final ComparisonNode node) { protected QueryPath getQueryPath(final ComparisonNode node) {
final int firstSeparatorIndex = node.getSelector().indexOf(RsqlQueryField.SUB_ATTRIBUTE_SEPARATOR); final int firstSeparatorIndex = node.getSelector().indexOf(QueryField.SUB_ATTRIBUTE_SEPARATOR);
final String enumName = (firstSeparatorIndex == -1 final String enumName = (firstSeparatorIndex == -1
? node.getSelector() ? node.getSelector()
: node.getSelector().substring(0, firstSeparatorIndex)).toUpperCase(); : node.getSelector().substring(0, firstSeparatorIndex)).toUpperCase();
@@ -99,14 +99,14 @@ public abstract class AbstractRSQLVisitor<A extends Enum<A> & RsqlQueryField> {
private String[] getSplit(final A enumValue, final String rsqlFieldName) { private String[] getSplit(final A enumValue, final String rsqlFieldName) {
if (enumValue.isMap()) { if (enumValue.isMap()) {
final String[] split = rsqlFieldName.split(RsqlQueryField.SUB_ATTRIBUTE_SPLIT_REGEX, 2); final String[] split = rsqlFieldName.split(QueryField.SUB_ATTRIBUTE_SPLIT_REGEX, 2);
if (split.length != 2 || ObjectUtils.isEmpty(split[1])) { if (split.length != 2 || ObjectUtils.isEmpty(split[1])) {
throw new RSQLParameterUnsupportedFieldException( throw new RSQLParameterUnsupportedFieldException(
"The syntax of the given map search parameter field {" + rsqlFieldName + "} is wrong. Syntax is: <enum name>.<key name>"); "The syntax of the given map search parameter field {" + rsqlFieldName + "} is wrong. Syntax is: <enum name>.<key name>");
} }
return split; return split;
} else { } else {
return rsqlFieldName.split(RsqlQueryField.SUB_ATTRIBUTE_SPLIT_REGEX); return rsqlFieldName.split(QueryField.SUB_ATTRIBUTE_SPLIT_REGEX);
} }
} }
@@ -123,7 +123,7 @@ public abstract class AbstractRSQLVisitor<A extends Enum<A> & RsqlQueryField> {
} }
for (final String attribute : subEntityAttributes) { for (final String attribute : subEntityAttributes) {
final String[] graph = attribute.split(RsqlQueryField.SUB_ATTRIBUTE_SPLIT_REGEX); final String[] graph = attribute.split(QueryField.SUB_ATTRIBUTE_SPLIT_REGEX);
for (final String subAttribute : graph) { for (final String subAttribute : graph) {
if (subAttribute.equalsIgnoreCase(propertyField)) { if (subAttribute.equalsIgnoreCase(propertyField)) {
return true; return true;
@@ -158,7 +158,7 @@ public abstract class AbstractRSQLVisitor<A extends Enum<A> & RsqlQueryField> {
.filter(enumField -> enumField.getSubEntityAttributes().isEmpty()).map(enumField -> { .filter(enumField -> enumField.getSubEntityAttributes().isEmpty()).map(enumField -> {
final String enumFieldName = enumField.name().toLowerCase(); final String enumFieldName = enumField.name().toLowerCase();
if (enumField.isMap()) { if (enumField.isMap()) {
return enumFieldName + RsqlQueryField.SUB_ATTRIBUTE_SEPARATOR + "keyName"; return enumFieldName + QueryField.SUB_ATTRIBUTE_SEPARATOR + "keyName";
} else { } else {
return enumFieldName; return enumFieldName;
} }
@@ -167,7 +167,7 @@ public abstract class AbstractRSQLVisitor<A extends Enum<A> & RsqlQueryField> {
.filter(enumField -> !enumField.getSubEntityAttributes().isEmpty()).flatMap(enumField -> { .filter(enumField -> !enumField.getSubEntityAttributes().isEmpty()).flatMap(enumField -> {
final List<String> subEntity = enumField final List<String> subEntity = enumField
.getSubEntityAttributes().stream().map(fieldName -> enumField.name().toLowerCase() .getSubEntityAttributes().stream().map(fieldName -> enumField.name().toLowerCase()
+ RsqlQueryField.SUB_ATTRIBUTE_SEPARATOR + fieldName) + QueryField.SUB_ATTRIBUTE_SEPARATOR + fieldName)
.toList(); .toList();
return subEntity.stream(); return subEntity.stream();

View File

@@ -43,7 +43,7 @@ import cz.jirutka.rsql.parser.ast.RSQLVisitor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.math.NumberUtils; import org.apache.commons.lang3.math.NumberUtils;
import org.eclipse.hawkbit.repository.FieldValueConverter; import org.eclipse.hawkbit.repository.FieldValueConverter;
import org.eclipse.hawkbit.repository.RsqlQueryField; import org.eclipse.hawkbit.repository.QueryField;
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
@@ -65,7 +65,7 @@ import org.springframework.util.ObjectUtils;
*/ */
@Deprecated(forRemoval = true, since = "0.6.0") @Deprecated(forRemoval = true, since = "0.6.0")
@Slf4j @Slf4j
public class JpaQueryRsqlVisitor<A extends Enum<A> & RsqlQueryField, T> extends AbstractRSQLVisitor<A> public class JpaQueryRsqlVisitor<A extends Enum<A> & QueryField, T> extends AbstractRSQLVisitor<A>
implements RSQLVisitor<List<Predicate>, String> { implements RSQLVisitor<List<Predicate>, String> {
public static final Character LIKE_WILDCARD = '*'; public static final Character LIKE_WILDCARD = '*';

View File

@@ -41,7 +41,7 @@ import cz.jirutka.rsql.parser.ast.RSQLVisitor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.math.NumberUtils; import org.apache.commons.lang3.math.NumberUtils;
import org.eclipse.hawkbit.repository.FieldValueConverter; import org.eclipse.hawkbit.repository.FieldValueConverter;
import org.eclipse.hawkbit.repository.RsqlQueryField; import org.eclipse.hawkbit.repository.QueryField;
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.jpa.ql.SpecificationBuilder; import org.eclipse.hawkbit.repository.jpa.ql.SpecificationBuilder;
@@ -62,7 +62,7 @@ import org.springframework.util.ObjectUtils;
*/ */
@Deprecated(forRemoval = true, since = "0.9.0") @Deprecated(forRemoval = true, since = "0.9.0")
@Slf4j @Slf4j
public class JpaQueryRsqlVisitorG2<A extends Enum<A> & RsqlQueryField, T> public class JpaQueryRsqlVisitorG2<A extends Enum<A> & QueryField, T>
extends AbstractRSQLVisitor<A> implements RSQLVisitor<List<Predicate>, String> { extends AbstractRSQLVisitor<A> implements RSQLVisitor<List<Predicate>, String> {
public static final Character LIKE_WILDCARD = '*'; public static final Character LIKE_WILDCARD = '*';

View File

@@ -10,7 +10,7 @@
package org.eclipse.hawkbit.repository.jpa.rsql.legacy; package org.eclipse.hawkbit.repository.jpa.rsql.legacy;
import static org.eclipse.hawkbit.repository.jpa.rsql.legacy.AbstractRSQLVisitor.OPERATORS; import static org.eclipse.hawkbit.repository.jpa.rsql.legacy.AbstractRSQLVisitor.OPERATORS;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.LEGACY_G1; import static org.eclipse.hawkbit.repository.jpa.ql.QLSupport.SpecBuilder.LEGACY_G1;
import java.util.List; import java.util.List;
@@ -21,10 +21,10 @@ import cz.jirutka.rsql.parser.RSQLParserException;
import cz.jirutka.rsql.parser.ast.Node; import cz.jirutka.rsql.parser.ast.Node;
import cz.jirutka.rsql.parser.ast.RSQLVisitor; import cz.jirutka.rsql.parser.ast.RSQLVisitor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.hawkbit.repository.RsqlQueryField; import org.eclipse.hawkbit.repository.QueryField;
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
import org.eclipse.hawkbit.repository.jpa.ql.SpecificationBuilder; import org.eclipse.hawkbit.repository.jpa.ql.SpecificationBuilder;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility; import org.eclipse.hawkbit.repository.jpa.ql.QLSupport;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.domain.Specification;
import org.springframework.orm.jpa.vendor.Database; import org.springframework.orm.jpa.vendor.Database;
@@ -35,7 +35,7 @@ import org.springframework.util.CollectionUtils;
*/ */
@Deprecated(forRemoval = true, since = "0.9.0") @Deprecated(forRemoval = true, since = "0.9.0")
@Slf4j @Slf4j
public class SpecificationBuilderLegacy<A extends Enum<A> & RsqlQueryField, T> { public class SpecificationBuilderLegacy<A extends Enum<A> & QueryField, T> {
private final Class<A> rsqlQueryFieldType; private final Class<A> rsqlQueryFieldType;
private final VirtualPropertyReplacer virtualPropertyReplacer; private final VirtualPropertyReplacer virtualPropertyReplacer;
@@ -50,14 +50,14 @@ public class SpecificationBuilderLegacy<A extends Enum<A> & RsqlQueryField, T> {
public Specification<T> specification(final String rsql) { public Specification<T> specification(final String rsql) {
return (root, query, cb) -> { return (root, query, cb) -> {
final RsqlUtility rsqlUtility = RsqlUtility.getInstance(); final QLSupport rsqlUtility = QLSupport.getInstance();
final Node rootNode = parseRsql(rsql, rsqlUtility); final Node rootNode = parseRsql(rsql, rsqlUtility);
query.distinct(true); query.distinct(true);
final boolean ensureIgnoreCase = !rsqlUtility.isCaseInsensitiveDB() && rsqlUtility.isIgnoreCase(); final boolean ensureIgnoreCase = !rsqlUtility.isCaseInsensitiveDB() && rsqlUtility.isIgnoreCase();
final RSQLVisitor<List<Predicate>, String> jpqQueryRSQLVisitor = final RSQLVisitor<List<Predicate>, String> jpqQueryRSQLVisitor =
rsqlUtility.getRsqlToSpecBuilder() == LEGACY_G1 rsqlUtility.getSpecBuilder() == LEGACY_G1
? new JpaQueryRsqlVisitor<>(root, cb, rsqlQueryFieldType, virtualPropertyReplacer, database, query, ensureIgnoreCase) ? new JpaQueryRsqlVisitor<>(root, cb, rsqlQueryFieldType, virtualPropertyReplacer, database, query, ensureIgnoreCase)
: new JpaQueryRsqlVisitorG2<>(rsqlQueryFieldType, root, query, cb, database, virtualPropertyReplacer, ensureIgnoreCase); : new JpaQueryRsqlVisitorG2<>(rsqlQueryFieldType, root, query, cb, database, virtualPropertyReplacer, ensureIgnoreCase);
final List<Predicate> accept = rootNode.accept(jpqQueryRSQLVisitor); final List<Predicate> accept = rootNode.accept(jpqQueryRSQLVisitor);
@@ -70,7 +70,7 @@ public class SpecificationBuilderLegacy<A extends Enum<A> & RsqlQueryField, T> {
}; };
} }
private static Node parseRsql(final String rsql, final RsqlUtility rsqlUtility) { private static Node parseRsql(final String rsql, final QLSupport rsqlUtility) {
log.debug("Parsing rsql string {}", rsql); log.debug("Parsing rsql string {}", rsql);
try { try {
return new RSQLParser(OPERATORS).parse(rsqlUtility.isCaseInsensitiveDB() || rsqlUtility.isIgnoreCase() ? rsql.toLowerCase() : rsql); return new RSQLParser(OPERATORS).parse(rsqlUtility.isCaseInsensitiveDB() || rsqlUtility.isIgnoreCase() ? rsql.toLowerCase() : rsql);

View File

@@ -9,17 +9,16 @@
*/ */
package org.eclipse.hawkbit.repository.jpa.ql; package org.eclipse.hawkbit.repository.jpa.ql;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.LEGACY_G1; import static org.eclipse.hawkbit.repository.jpa.ql.QLSupport.SpecBuilder.LEGACY_G1;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.LEGACY_G2; import static org.eclipse.hawkbit.repository.jpa.ql.QLSupport.SpecBuilder.LEGACY_G2;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.hawkbit.repository.RsqlQueryField; import org.eclipse.hawkbit.repository.QueryField;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility; import org.eclipse.hawkbit.repository.jpa.ql.QLSupport.SpecBuilder;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder;
import org.eclipse.hawkbit.repository.jpa.rsql.legacy.SpecificationBuilderLegacy; import org.eclipse.hawkbit.repository.jpa.rsql.legacy.SpecificationBuilderLegacy;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.domain.Specification;
@@ -31,13 +30,13 @@ class SpecificationBuilderLegacyTest extends SpecificationBuilderTest {
private final SpecificationBuilderLegacy<RootField, Root> builder = new SpecificationBuilderLegacy<>(RootField.class, null, Database.H2); private final SpecificationBuilderLegacy<RootField, Root> builder = new SpecificationBuilderLegacy<>(RootField.class, null, Database.H2);
private static void runWithRsqlToSpecBuilder(final Runnable runnable, final RsqlToSpecBuilder rsqlToSpecBuilder) { private static void runWithRsqlToSpecBuilder(final Runnable runnable, final SpecBuilder rsqlToSpecBuilder) {
final RsqlToSpecBuilder defaultBuilder = RsqlUtility.getInstance().getRsqlToSpecBuilder(); final SpecBuilder defaultBuilder = QLSupport.getInstance().getSpecBuilder();
RsqlUtility.getInstance().setRsqlToSpecBuilder(rsqlToSpecBuilder); QLSupport.getInstance().setSpecBuilder(rsqlToSpecBuilder);
try { try {
runnable.run(); runnable.run();
} finally { } finally {
RsqlUtility.getInstance().setRsqlToSpecBuilder(defaultBuilder); QLSupport.getInstance().setSpecBuilder(defaultBuilder);
} }
} }
@@ -110,7 +109,7 @@ class SpecificationBuilderLegacyTest extends SpecificationBuilderTest {
} }
@Getter @Getter
private enum RootField implements RsqlQueryField { private enum RootField implements QueryField {
INTVALUE("intValue"), INTVALUE("intValue"),
STRVALUE("strValue"), STRVALUE("strValue"),

View File

@@ -10,9 +10,9 @@
package org.eclipse.hawkbit.repository.jpa.ql; package org.eclipse.hawkbit.repository.jpa.ql;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.G3; import static org.eclipse.hawkbit.repository.jpa.ql.QLSupport.SpecBuilder.G3;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.LEGACY_G1; import static org.eclipse.hawkbit.repository.jpa.ql.QLSupport.SpecBuilder.LEGACY_G1;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.LEGACY_G2; import static org.eclipse.hawkbit.repository.jpa.ql.QLSupport.SpecBuilder.LEGACY_G2;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -22,9 +22,9 @@ import java.util.stream.StreamSupport;
import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManager;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.hawkbit.repository.jpa.ql.QLSupport.SpecBuilder;
import org.eclipse.hawkbit.repository.jpa.ql.utils.HawkbitQlToSql; import org.eclipse.hawkbit.repository.jpa.ql.utils.HawkbitQlToSql;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlParser; import org.eclipse.hawkbit.repository.jpa.rsql.RsqlParser;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.SpringBootConfiguration;
@@ -51,7 +51,7 @@ class SpecificationBuilderTest {
@Autowired @Autowired
private EntityManager entityManager; private EntityManager entityManager;
private final SpecificationBuilder<Root> builder = new SpecificationBuilder<>(null, false, Database.H2); private final SpecificationBuilder<Root> builder = new SpecificationBuilder<>(false, Database.H2);
@Test @Test
void singularStringAttribute() { void singularStringAttribute() {
@@ -573,8 +573,8 @@ class SpecificationBuilderTest {
return builder.specification(RsqlParser.parse(rsql)); return builder.specification(RsqlParser.parse(rsql));
} }
private static RsqlUtility.RsqlToSpecBuilder getRsqlToSpecBuilder() { private static SpecBuilder getRsqlToSpecBuilder() {
return RsqlUtility.getInstance().getRsqlToSpecBuilder(); return QLSupport.getInstance().getSpecBuilder();
} }
@SpringBootConfiguration @SpringBootConfiguration

View File

@@ -91,11 +91,9 @@ public class DefaultRolloutApprovalStrategy implements RolloutApprovalStrategy {
// scheduler under SYSTEM user context, thus we get the // scheduler under SYSTEM user context, thus we get the
// user based on the properties of initially created rollout entity // user based on the properties of initially created rollout entity
if (RolloutStatus.CREATING == rollout.getStatus()) { if (RolloutStatus.CREATING == rollout.getStatus()) {
final String actor = rollout.getLastModifiedBy() != null ? rollout.getLastModifiedBy() final String actor = rollout.getLastModifiedBy() != null ? rollout.getLastModifiedBy() : rollout.getCreatedBy();
: rollout.getCreatedBy();
if (!ObjectUtils.isEmpty(actor)) { if (!ObjectUtils.isEmpty(actor)) {
return systemSecurityContext.runAsSystem( return systemSecurityContext.runAsSystem(() -> userAuthoritiesResolver.getUserAuthorities(rollout.getTenant(), actor));
() -> userAuthoritiesResolver.getUserAuthorities(rollout.getTenant(), actor));
} }
} }

View File

@@ -67,6 +67,8 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType;
import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder; import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.EntityInterceptorHolder; import org.eclipse.hawkbit.repository.jpa.model.helper.EntityInterceptorHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.TenantAwareHolder; import org.eclipse.hawkbit.repository.jpa.model.helper.TenantAwareHolder;
import org.eclipse.hawkbit.repository.jpa.ql.QLSupport.DefaultQueryParser;
import org.eclipse.hawkbit.repository.jpa.ql.QLSupport.QueryParser;
import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository; import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetRepository; import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetRepository;
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTypeRepository; import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTypeRepository;
@@ -86,7 +88,7 @@ import org.eclipse.hawkbit.repository.jpa.rollout.condition.RolloutGroupEvaluati
import org.eclipse.hawkbit.repository.jpa.rollout.condition.StartNextGroupRolloutGroupSuccessAction; import org.eclipse.hawkbit.repository.jpa.rollout.condition.StartNextGroupRolloutGroupSuccessAction;
import org.eclipse.hawkbit.repository.jpa.rollout.condition.ThresholdRolloutGroupErrorCondition; import org.eclipse.hawkbit.repository.jpa.rollout.condition.ThresholdRolloutGroupErrorCondition;
import org.eclipse.hawkbit.repository.jpa.rollout.condition.ThresholdRolloutGroupSuccessCondition; import org.eclipse.hawkbit.repository.jpa.rollout.condition.ThresholdRolloutGroupSuccessCondition;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility; import org.eclipse.hawkbit.repository.jpa.ql.QLSupport;
import org.eclipse.hawkbit.repository.jpa.utils.ExceptionMapper; import org.eclipse.hawkbit.repository.jpa.utils.ExceptionMapper;
import org.eclipse.hawkbit.repository.model.RolloutGroup; import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModule;
@@ -513,14 +515,20 @@ public class JpaRepositoryConfiguration {
return new RolloutScheduler(rolloutHandler, systemManagement, systemSecurityContext, threadPoolSize, meterRegistry); return new RolloutScheduler(rolloutHandler, systemManagement, systemSecurityContext, threadPoolSize, meterRegistry);
} }
@Bean
@ConditionalOnMissingBean
QueryParser queryParser() {
return new DefaultQueryParser();
}
/** /**
* Register the {@link RsqlUtility} bean to force Spring to inject values and auto-wired fields. * Register the {@link QLSupport} bean to force Spring to inject values and auto-wired fields.
* *
* @return The {@link RsqlUtility} singleton. * @return The {@link QLSupport} singleton.
*/ */
@Bean @Bean
RsqlUtility rsqlUtility() { QLSupport rsqlUtility() {
return RsqlUtility.getInstance(); return QLSupport.getInstance();
} }
/** /**

View File

@@ -21,10 +21,10 @@ import java.util.regex.Pattern;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.hawkbit.ContextAware; import org.eclipse.hawkbit.ContextAware;
import org.eclipse.hawkbit.repository.RsqlQueryField; import org.eclipse.hawkbit.repository.QueryField;
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException; import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
import org.eclipse.hawkbit.repository.jpa.ql.EntityMatcher; import org.eclipse.hawkbit.repository.jpa.ql.EntityMatcher;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility; import org.eclipse.hawkbit.repository.jpa.ql.QLSupport;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.domain.Specification;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
@@ -32,7 +32,7 @@ import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
@Slf4j @Slf4j
public class DefaultAccessController<A extends Enum<A> & RsqlQueryField, T> implements AccessController<T> { public class DefaultAccessController<A extends Enum<A> & QueryField, T> implements AccessController<T> {
private final Class<A> rsqlQueryFieldType; private final Class<A> rsqlQueryFieldType;
private final Map<Operation, List<String>> permissions = new EnumMap<>(Operation.class); private final Map<Operation, List<String>> permissions = new EnumMap<>(Operation.class);
@@ -69,7 +69,7 @@ public class DefaultAccessController<A extends Enum<A> & RsqlQueryField, T> impl
scopes.size() == 1 scopes.size() == 1
? scopes.get(0) // single scope ? scopes.get(0) // single scope
: "(" + String.join(") or (", scopes) + ")") // join multiple scopes with 'or' - union : "(" + String.join(") or (", scopes) + ")") // join multiple scopes with 'or' - union
.map(rsql -> RsqlUtility.getInstance().buildRsqlSpecification(rsql, rsqlQueryFieldType)); .map(rsql -> QLSupport.getInstance().buildSpec(rsql, rsqlQueryFieldType));
} }
@Override @Override

View File

@@ -39,7 +39,7 @@ import lombok.extern.slf4j.Slf4j;
import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.Identifiable; import org.eclipse.hawkbit.repository.Identifiable;
import org.eclipse.hawkbit.repository.RepositoryManagement; import org.eclipse.hawkbit.repository.RepositoryManagement;
import org.eclipse.hawkbit.repository.RsqlQueryField; import org.eclipse.hawkbit.repository.QueryField;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.InvalidDistributionSetException; import org.eclipse.hawkbit.repository.exception.InvalidDistributionSetException;
import org.eclipse.hawkbit.repository.jpa.Jpa; import org.eclipse.hawkbit.repository.jpa.Jpa;
@@ -49,7 +49,7 @@ import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity; import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity;
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity_; import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity_;
import org.eclipse.hawkbit.repository.jpa.repository.BaseEntityRepository; import org.eclipse.hawkbit.repository.jpa.repository.BaseEntityRepository;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility; import org.eclipse.hawkbit.repository.jpa.ql.QLSupport;
import org.eclipse.hawkbit.utils.ObjectCopyUtil; import org.eclipse.hawkbit.utils.ObjectCopyUtil;
import org.springframework.dao.ConcurrencyFailureException; import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
@@ -79,7 +79,7 @@ import org.springframework.validation.annotation.Validated;
@Transactional(readOnly = true) @Transactional(readOnly = true)
@Validated @Validated
@Slf4j @Slf4j
abstract class AbstractJpaRepositoryManagement<T extends AbstractJpaBaseEntity, C, U extends Identifiable<Long>, R extends BaseEntityRepository<T>, A extends Enum<A> & RsqlQueryField> abstract class AbstractJpaRepositoryManagement<T extends AbstractJpaBaseEntity, C, U extends Identifiable<Long>, R extends BaseEntityRepository<T>, A extends Enum<A> & QueryField>
implements RepositoryManagement<T, C, U> { implements RepositoryManagement<T, C, U> {
public static final String DELETED = "deleted"; public static final String DELETED = "deleted";
@@ -258,8 +258,8 @@ abstract class AbstractJpaRepositoryManagement<T extends AbstractJpaBaseEntity,
@NotNull @NotNull
private List<Specification<T>> rsqlSpec(final String rsql) { private List<Specification<T>> rsqlSpec(final String rsql) {
return isNotDeleted() return isNotDeleted()
.map(isNotDeleted -> List.of(RsqlUtility.getInstance().<A, T> buildRsqlSpecification(rsql, fieldsClass()), isNotDeleted)) .map(isNotDeleted -> List.of(QLSupport.getInstance().<A, T> buildSpec(rsql, fieldsClass()), isNotDeleted))
.orElseGet(() -> List.of(RsqlUtility.getInstance().buildRsqlSpecification(rsql, fieldsClass()))); .orElseGet(() -> List.of(QLSupport.getInstance().buildSpec(rsql, fieldsClass())));
} }
protected void checkUpdate(final U update, final T distributionSet) {} protected void checkUpdate(final U update, final T distributionSet) {}

View File

@@ -26,9 +26,8 @@ import jakarta.persistence.EntityManager;
import org.eclipse.hawkbit.repository.Identifiable; import org.eclipse.hawkbit.repository.Identifiable;
import org.eclipse.hawkbit.repository.MetadataSupport; import org.eclipse.hawkbit.repository.MetadataSupport;
import org.eclipse.hawkbit.repository.RsqlQueryField; import org.eclipse.hawkbit.repository.QueryField;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.InvalidDistributionSetException;
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity; import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity;
import org.eclipse.hawkbit.repository.jpa.model.WithMetadata; import org.eclipse.hawkbit.repository.jpa.model.WithMetadata;
import org.eclipse.hawkbit.repository.jpa.repository.BaseEntityRepository; import org.eclipse.hawkbit.repository.jpa.repository.BaseEntityRepository;
@@ -39,7 +38,7 @@ import org.springframework.retry.annotation.Retryable;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@SuppressWarnings("java:S119") // java:S119 - better self explainable @SuppressWarnings("java:S119") // java:S119 - better self explainable
abstract class AbstractJpaRepositoryWithMetadataManagement<T extends AbstractJpaBaseEntity & WithMetadata<MV, MVI>, C, U extends Identifiable<Long>, R extends BaseEntityRepository<T>, A extends Enum<A> & RsqlQueryField, MV, MVI extends MV> abstract class AbstractJpaRepositoryWithMetadataManagement<T extends AbstractJpaBaseEntity & WithMetadata<MV, MVI>, C, U extends Identifiable<Long>, R extends BaseEntityRepository<T>, A extends Enum<A> & QueryField, MV, MVI extends MV>
extends AbstractJpaRepositoryManagement<T, C, U, R, A> implements MetadataSupport<MV> { extends AbstractJpaRepositoryManagement<T, C, U, R, A> implements MetadataSupport<MV> {
private final Supplier<MVI> metadataValueCreator; private final Supplier<MVI> metadataValueCreator;

View File

@@ -65,7 +65,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository; import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
import org.eclipse.hawkbit.repository.jpa.repository.ActionStatusRepository; import org.eclipse.hawkbit.repository.jpa.repository.ActionStatusRepository;
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository; import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility; import org.eclipse.hawkbit.repository.jpa.ql.QLSupport;
import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications; import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications;
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications; import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper; import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
@@ -252,7 +252,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
assertTargetReadAllowed(controllerId); assertTargetReadAllowed(controllerId);
final List<Specification<JpaAction>> specList = Arrays.asList( final List<Specification<JpaAction>> specList = Arrays.asList(
RsqlUtility.getInstance().buildRsqlSpecification(rsql, ActionFields.class), QLSupport.getInstance().buildSpec(rsql, ActionFields.class),
ActionSpecifications.byTargetControllerId(controllerId)); ActionSpecifications.byTargetControllerId(controllerId));
return JpaManagementHelper.countBySpec(actionRepository, specList); return JpaManagementHelper.countBySpec(actionRepository, specList);
@@ -265,7 +265,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
@Override @Override
public long countActions(final String rsql) { public long countActions(final String rsql) {
final List<Specification<JpaAction>> specList = List.of(RsqlUtility.getInstance().buildRsqlSpecification(rsql, ActionFields.class)); final List<Specification<JpaAction>> specList = List.of(QLSupport.getInstance().buildSpec(rsql, ActionFields.class));
return JpaManagementHelper.countBySpec(actionRepository, specList); return JpaManagementHelper.countBySpec(actionRepository, specList);
} }
@@ -288,7 +288,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
@Override @Override
public Slice<Action> findActions(final String rsql, final Pageable pageable) { public Slice<Action> findActions(final String rsql, final Pageable pageable) {
final List<Specification<JpaAction>> specList = List.of(RsqlUtility.getInstance().buildRsqlSpecification(rsql, ActionFields.class)); final List<Specification<JpaAction>> specList = List.of(QLSupport.getInstance().buildSpec(rsql, ActionFields.class));
return JpaManagementHelper.findAllWithoutCountBySpec(actionRepository, specList, pageable); return JpaManagementHelper.findAllWithoutCountBySpec(actionRepository, specList, pageable);
} }
@@ -297,7 +297,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
assertTargetReadAllowed(controllerId); assertTargetReadAllowed(controllerId);
final List<Specification<JpaAction>> specList = Arrays.asList( final List<Specification<JpaAction>> specList = Arrays.asList(
RsqlUtility.getInstance().buildRsqlSpecification(rsql, ActionFields.class), QLSupport.getInstance().buildSpec(rsql, ActionFields.class),
ActionSpecifications.byTargetControllerId(controllerId)); ActionSpecifications.byTargetControllerId(controllerId));
return JpaManagementHelper.findAllWithCountBySpec(actionRepository, specList, pageable); return JpaManagementHelper.findAllWithCountBySpec(actionRepository, specList, pageable);

View File

@@ -18,7 +18,6 @@ import java.util.Collections;
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.Optional;
import java.util.Set; import java.util.Set;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.Function; import java.util.function.Function;
@@ -47,7 +46,7 @@ import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetRepository;
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTagRepository; import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTagRepository;
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleRepository; import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleRepository;
import org.eclipse.hawkbit.repository.jpa.repository.TargetFilterQueryRepository; import org.eclipse.hawkbit.repository.jpa.repository.TargetFilterQueryRepository;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility; import org.eclipse.hawkbit.repository.jpa.ql.QLSupport;
import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetSpecification; import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetSpecification;
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper; import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
@@ -324,7 +323,7 @@ public class JpaDistributionSetManagement
return JpaManagementHelper.findAllWithCountBySpec( return JpaManagementHelper.findAllWithCountBySpec(
jpaRepository, jpaRepository,
List.of( List.of(
RsqlUtility.getInstance().buildRsqlSpecification(rsql, DistributionSetFields.class), QLSupport.getInstance().buildSpec(rsql, DistributionSetFields.class),
DistributionSetSpecification.hasTag(tagId), DistributionSetSpecification.isNotDeleted()), DistributionSetSpecification.hasTag(tagId), DistributionSetSpecification.isNotDeleted()),
pageable); pageable);
} }

View File

@@ -13,7 +13,6 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManager;
@@ -40,7 +39,7 @@ import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
import org.eclipse.hawkbit.repository.jpa.repository.RolloutGroupRepository; import org.eclipse.hawkbit.repository.jpa.repository.RolloutGroupRepository;
import org.eclipse.hawkbit.repository.jpa.repository.RolloutRepository; import org.eclipse.hawkbit.repository.jpa.repository.RolloutRepository;
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository; import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility; import org.eclipse.hawkbit.repository.jpa.ql.QLSupport;
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications; import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus; import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus;
@@ -136,7 +135,7 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
throwEntityNotFoundExceptionIfRolloutDoesNotExist(rolloutId); throwEntityNotFoundExceptionIfRolloutDoesNotExist(rolloutId);
final List<Specification<JpaRolloutGroup>> specList = Arrays.asList( final List<Specification<JpaRolloutGroup>> specList = Arrays.asList(
RsqlUtility.getInstance().buildRsqlSpecification(rsql, RolloutGroupFields.class), QLSupport.getInstance().buildSpec(rsql, RolloutGroupFields.class),
(root, query, cb) -> cb.equal(root.get(JpaRolloutGroup_.rollout).get(AbstractJpaBaseEntity_.id), rolloutId)); (root, query, cb) -> cb.equal(root.get(JpaRolloutGroup_.rollout).get(AbstractJpaBaseEntity_.id), rolloutId));
return JpaManagementHelper.findAllWithCountBySpec(rolloutGroupRepository, specList, pageable); return JpaManagementHelper.findAllWithCountBySpec(rolloutGroupRepository, specList, pageable);
@@ -194,7 +193,7 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
throwExceptionIfRolloutGroupDoesNotExist(rolloutGroupId); throwExceptionIfRolloutGroupDoesNotExist(rolloutGroupId);
final List<Specification<JpaTarget>> specList = Arrays.asList( final List<Specification<JpaTarget>> specList = Arrays.asList(
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class), QLSupport.getInstance().buildSpec(rsql, TargetFields.class),
(root, query, cb) -> { (root, query, cb) -> {
final ListJoin<JpaTarget, RolloutTargetGroup> rolloutTargetJoin = root.join(JpaTarget_.rolloutTargetGroup); final ListJoin<JpaTarget, RolloutTargetGroup> rolloutTargetJoin = root.join(JpaTarget_.rolloutTargetGroup);
return cb.equal(rolloutTargetJoin.get(RolloutTargetGroup_.rolloutGroup).get(AbstractJpaBaseEntity_.id), rolloutGroupId); return cb.equal(rolloutTargetJoin.get(RolloutTargetGroup_.rolloutGroup).get(AbstractJpaBaseEntity_.id), rolloutGroupId);

View File

@@ -66,7 +66,7 @@ import org.eclipse.hawkbit.repository.jpa.repository.RolloutGroupRepository;
import org.eclipse.hawkbit.repository.jpa.repository.RolloutRepository; import org.eclipse.hawkbit.repository.jpa.repository.RolloutRepository;
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository; import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
import org.eclipse.hawkbit.repository.jpa.rollout.condition.StartNextGroupRolloutGroupSuccessAction; import org.eclipse.hawkbit.repository.jpa.rollout.condition.StartNextGroupRolloutGroupSuccessAction;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility; import org.eclipse.hawkbit.repository.jpa.ql.QLSupport;
import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications; import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications;
import org.eclipse.hawkbit.repository.jpa.specifications.RolloutSpecification; import org.eclipse.hawkbit.repository.jpa.specifications.RolloutSpecification;
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper; import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
@@ -285,7 +285,7 @@ public class JpaRolloutManagement implements RolloutManagement {
@Override @Override
public Page<Rollout> findByRsql(final String rsql, final boolean deleted, final Pageable pageable) { public Page<Rollout> findByRsql(final String rsql, final boolean deleted, final Pageable pageable) {
final List<Specification<JpaRollout>> specList = List.of( final List<Specification<JpaRollout>> specList = List.of(
RsqlUtility.getInstance().buildRsqlSpecification(rsql, RolloutFields.class), QLSupport.getInstance().buildSpec(rsql, RolloutFields.class),
RolloutSpecification.isDeleted(deleted, pageable.getSort())); RolloutSpecification.isDeleted(deleted, pageable.getSort()));
return JpaManagementHelper.convertPage(rolloutRepository.findAll(JpaManagementHelper.combineWithAnd(specList), pageable), pageable); return JpaManagementHelper.convertPage(rolloutRepository.findAll(JpaManagementHelper.combineWithAnd(specList), pageable), pageable);
} }
@@ -293,7 +293,7 @@ public class JpaRolloutManagement implements RolloutManagement {
@Override @Override
public Page<Rollout> findByRsqlWithDetailedStatus(final String rsql, final boolean deleted, final Pageable pageable) { public Page<Rollout> findByRsqlWithDetailedStatus(final String rsql, final boolean deleted, final Pageable pageable) {
final List<Specification<JpaRollout>> specList = List.of( final List<Specification<JpaRollout>> specList = List.of(
RsqlUtility.getInstance().buildRsqlSpecification(rsql, RolloutFields.class), QLSupport.getInstance().buildSpec(rsql, RolloutFields.class),
RolloutSpecification.isDeleted(deleted, pageable.getSort())); RolloutSpecification.isDeleted(deleted, pageable.getSort()));
return appendStatusDetails(JpaManagementHelper.convertPage( return appendStatusDetails(JpaManagementHelper.convertPage(
rolloutRepository.findAll(JpaManagementHelper.combineWithAnd(specList), JpaRollout_.GRAPH_ROLLOUT_DS, pageable), pageable)); rolloutRepository.findAll(JpaManagementHelper.combineWithAnd(specList), JpaRollout_.GRAPH_ROLLOUT_DS, pageable), pageable));

View File

@@ -36,7 +36,7 @@ import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetFilterQuery; import org.eclipse.hawkbit.repository.jpa.model.JpaTargetFilterQuery;
import org.eclipse.hawkbit.repository.jpa.repository.TargetFilterQueryRepository; import org.eclipse.hawkbit.repository.jpa.repository.TargetFilterQueryRepository;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility; import org.eclipse.hawkbit.repository.jpa.ql.QLSupport;
import org.eclipse.hawkbit.repository.jpa.specifications.TargetFilterQuerySpecification; import org.eclipse.hawkbit.repository.jpa.specifications.TargetFilterQuerySpecification;
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper; import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
import org.eclipse.hawkbit.repository.jpa.utils.WeightValidationHelper; import org.eclipse.hawkbit.repository.jpa.utils.WeightValidationHelper;
@@ -117,7 +117,7 @@ class JpaTargetFilterQueryManagement
@Override @Override
public void verifyTargetFilterQuerySyntax(final String query) { public void verifyTargetFilterQuerySyntax(final String query) {
try { try {
RsqlUtility.getInstance().validateRsqlFor(query, TargetFields.class, JpaTarget.class); QLSupport.getInstance().validateQuery(query, TargetFields.class, JpaTarget.class);
} catch (final RSQLParserException | RSQLParameterUnsupportedFieldException e) { } catch (final RSQLParserException | RSQLParameterUnsupportedFieldException e) {
log.debug("The RSQL query '{}}' is invalid.", query, e); log.debug("The RSQL query '{}}' is invalid.", query, e);
throw new RSQLParameterSyntaxException("Cannot create a Rollout with an empty target query filter!"); throw new RSQLParameterSyntaxException("Cannot create a Rollout with an empty target query filter!");
@@ -136,7 +136,7 @@ class JpaTargetFilterQueryManagement
final List<Specification<JpaTargetFilterQuery>> specList = new ArrayList<>(2); final List<Specification<JpaTargetFilterQuery>> specList = new ArrayList<>(2);
specList.add(TargetFilterQuerySpecification.byAutoAssignDS(distributionSet)); specList.add(TargetFilterQuerySpecification.byAutoAssignDS(distributionSet));
if (!ObjectUtils.isEmpty(rsql)) { if (!ObjectUtils.isEmpty(rsql)) {
specList.add(RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFilterQueryFields.class)); specList.add(QLSupport.getInstance().buildSpec(rsql, TargetFilterQueryFields.class));
} }
return JpaManagementHelper.findAllWithCountBySpec(jpaRepository, specList, pageable); return JpaManagementHelper.findAllWithCountBySpec(jpaRepository, specList, pageable);
@@ -225,7 +225,7 @@ class JpaTargetFilterQueryManagement
}); });
Optional.ofNullable(create.getQuery()).ifPresent(query -> { Optional.ofNullable(create.getQuery()).ifPresent(query -> {
// validate the RSQL query syntax // validate the RSQL query syntax
RsqlUtility.getInstance().validateRsqlFor(query, TargetFields.class, JpaTarget.class); QLSupport.getInstance().validateQuery(query, TargetFields.class, JpaTarget.class);
// enforce the 'max targets per auto assign' quota right here even if the result of the filter query can vary over time // enforce the 'max targets per auto assign' quota right here even if the result of the filter query can vary over time
Optional.ofNullable(create.getAutoAssignDistributionSet()).ifPresent(dsId -> { Optional.ofNullable(create.getAutoAssignDistributionSet()).ifPresent(dsId -> {
@@ -242,7 +242,7 @@ class JpaTargetFilterQueryManagement
final JpaTargetFilterQuery targetFilterQuery = jpaRepository.getById(update.getId()); final JpaTargetFilterQuery targetFilterQuery = jpaRepository.getById(update.getId());
Optional.ofNullable(update.getQuery()).ifPresent(query -> { Optional.ofNullable(update.getQuery()).ifPresent(query -> {
// validate the RSQL query syntax // validate the RSQL query syntax
RsqlUtility.getInstance().validateRsqlFor(query, TargetFields.class, JpaTarget.class); QLSupport.getInstance().validateQuery(query, TargetFields.class, JpaTarget.class);
Optional.ofNullable(targetFilterQuery.getAutoAssignDistributionSet()).ifPresent(autoAssignDs -> { Optional.ofNullable(targetFilterQuery.getAutoAssignDistributionSet()).ifPresent(autoAssignDs -> {
// enforce the 'max targets per auto assignment'-quota only if the query is going to change // enforce the 'max targets per auto assignment'-quota only if the query is going to change

View File

@@ -50,7 +50,7 @@ import org.eclipse.hawkbit.repository.jpa.repository.RolloutGroupRepository;
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository; import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
import org.eclipse.hawkbit.repository.jpa.repository.TargetTagRepository; import org.eclipse.hawkbit.repository.jpa.repository.TargetTagRepository;
import org.eclipse.hawkbit.repository.jpa.repository.TargetTypeRepository; import org.eclipse.hawkbit.repository.jpa.repository.TargetTypeRepository;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility; import org.eclipse.hawkbit.repository.jpa.ql.QLSupport;
import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder; import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder;
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications; import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper; import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
@@ -59,7 +59,6 @@ import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.RolloutGroup; import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetTag; import org.eclipse.hawkbit.repository.model.TargetTag;
import org.eclipse.hawkbit.repository.model.TargetType;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
import org.springframework.dao.ConcurrencyFailureException; import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
@@ -112,11 +111,11 @@ public class JpaTargetManagement
@Override @Override
public boolean isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable( public boolean isTargetMatchingQueryAndDSNotAssignedAndCompatibleAndUpdatable(
final String controllerId, final long distributionSetId, final String targetFilterQuery) { final String controllerId, final long distributionSetId, final String targetFilterQuery) {
RsqlUtility.getInstance().validateRsqlFor(targetFilterQuery, TargetFields.class, JpaTarget.class); QLSupport.getInstance().validateQuery(targetFilterQuery, TargetFields.class, JpaTarget.class);
final DistributionSet ds = distributionSetManagement.get(distributionSetId); final DistributionSet ds = distributionSetManagement.get(distributionSetId);
final Long distSetTypeId = ds.getType().getId(); final Long distSetTypeId = ds.getType().getId();
final List<Specification<JpaTarget>> specList = List.of( final List<Specification<JpaTarget>> specList = List.of(
RsqlUtility.getInstance().buildRsqlSpecification(targetFilterQuery, TargetFields.class), QLSupport.getInstance().buildSpec(targetFilterQuery, TargetFields.class),
TargetSpecifications.hasNotDistributionSetInActions(distributionSetId), TargetSpecifications.hasNotDistributionSetInActions(distributionSetId),
TargetSpecifications.isCompatibleWithDistributionSetType(distSetTypeId), TargetSpecifications.isCompatibleWithDistributionSetType(distSetTypeId),
TargetSpecifications.hasControllerId(controllerId)); TargetSpecifications.hasControllerId(controllerId));
@@ -157,7 +156,7 @@ public class JpaTargetManagement
.findAllWithoutCount( .findAllWithoutCount(
AccessController.Operation.UPDATE, AccessController.Operation.UPDATE,
combineWithAnd(List.of( combineWithAnd(List.of(
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class), QLSupport.getInstance().buildSpec(rsql, TargetFields.class),
TargetSpecifications.hasNotDistributionSetInActions(distributionSetId), TargetSpecifications.hasNotDistributionSetInActions(distributionSetId),
TargetSpecifications.isCompatibleWithDistributionSetType(distSetTypeId))), TargetSpecifications.isCompatibleWithDistributionSetType(distSetTypeId))),
pageable) pageable)
@@ -170,7 +169,7 @@ public class JpaTargetManagement
return jpaRepository return jpaRepository
.findAllWithoutCount(AccessController.Operation.UPDATE, .findAllWithoutCount(AccessController.Operation.UPDATE,
combineWithAnd(List.of( combineWithAnd(List.of(
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class), QLSupport.getInstance().buildSpec(rsql, TargetFields.class),
TargetSpecifications.isNotInRolloutGroups(groups), TargetSpecifications.isNotInRolloutGroups(groups),
TargetSpecifications.isCompatibleWithDistributionSetType(dsType.getId()))), TargetSpecifications.isCompatibleWithDistributionSetType(dsType.getId()))),
pageable) pageable)
@@ -191,7 +190,7 @@ public class JpaTargetManagement
return jpaRepository return jpaRepository
.findAllWithoutCount(AccessController.Operation.UPDATE, .findAllWithoutCount(AccessController.Operation.UPDATE,
combineWithAnd(List.of( combineWithAnd(List.of(
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class), QLSupport.getInstance().buildSpec(rsql, TargetFields.class),
TargetSpecifications.hasNoOverridingActionsAndNotInRollout(rolloutId), TargetSpecifications.hasNoOverridingActionsAndNotInRollout(rolloutId),
TargetSpecifications.isCompatibleWithDistributionSetType(distributionSetType.getId()))), TargetSpecifications.isCompatibleWithDistributionSetType(distributionSetType.getId()))),
pageable) pageable)
@@ -222,7 +221,7 @@ public class JpaTargetManagement
final DistributionSet validDistSet = distributionSetManagement.get(distributionSetId); final DistributionSet validDistSet = distributionSetManagement.get(distributionSetId);
final List<Specification<JpaTarget>> specList = List.of( final List<Specification<JpaTarget>> specList = List.of(
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class), QLSupport.getInstance().buildSpec(rsql, TargetFields.class),
TargetSpecifications.hasAssignedDistributionSet(validDistSet.getId())); TargetSpecifications.hasAssignedDistributionSet(validDistSet.getId()));
return JpaManagementHelper.findAllWithCountBySpec(jpaRepository, specList, pageable); return JpaManagementHelper.findAllWithCountBySpec(jpaRepository, specList, pageable);
@@ -241,7 +240,7 @@ public class JpaTargetManagement
final DistributionSet validDistSet = distributionSetManagement.get(distributionSetId); final DistributionSet validDistSet = distributionSetManagement.get(distributionSetId);
final List<Specification<JpaTarget>> specList = List.of( final List<Specification<JpaTarget>> specList = List.of(
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class), QLSupport.getInstance().buildSpec(rsql, TargetFields.class),
TargetSpecifications.hasInstalledDistributionSet(validDistSet.getId())); TargetSpecifications.hasInstalledDistributionSet(validDistSet.getId()));
return JpaManagementHelper.findAllWithCountBySpec(jpaRepository, specList, pageable); return JpaManagementHelper.findAllWithCountBySpec(jpaRepository, specList, pageable);
@@ -258,7 +257,7 @@ public class JpaTargetManagement
throwEntityNotFoundExceptionIfTagDoesNotExist(tagId); throwEntityNotFoundExceptionIfTagDoesNotExist(tagId);
final List<Specification<JpaTarget>> specList = List.of( final List<Specification<JpaTarget>> specList = List.of(
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class), QLSupport.getInstance().buildSpec(rsql, TargetFields.class),
TargetSpecifications.hasTag(tagId)); TargetSpecifications.hasTag(tagId));
return JpaManagementHelper.findAllWithCountBySpec(jpaRepository, specList, pageable); return JpaManagementHelper.findAllWithCountBySpec(jpaRepository, specList, pageable);
@@ -267,7 +266,7 @@ public class JpaTargetManagement
@Override @Override
public long countByRsqlAndCompatible(final String rsql, final Long distributionSetIdTypeId) { public long countByRsqlAndCompatible(final String rsql, final Long distributionSetIdTypeId) {
final List<Specification<JpaTarget>> specList = List.of( final List<Specification<JpaTarget>> specList = List.of(
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class), QLSupport.getInstance().buildSpec(rsql, TargetFields.class),
TargetSpecifications.isCompatibleWithDistributionSetType(distributionSetIdTypeId)); TargetSpecifications.isCompatibleWithDistributionSetType(distributionSetIdTypeId));
return JpaManagementHelper.countBySpec(jpaRepository, specList); return JpaManagementHelper.countBySpec(jpaRepository, specList);
} }
@@ -286,7 +285,7 @@ public class JpaTargetManagement
return jpaRepository.count( return jpaRepository.count(
AccessController.Operation.UPDATE, AccessController.Operation.UPDATE,
combineWithAnd(List.of( combineWithAnd(List.of(
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class), QLSupport.getInstance().buildSpec(rsql, TargetFields.class),
TargetSpecifications.hasNotDistributionSetInActions(distributionSetId), TargetSpecifications.hasNotDistributionSetInActions(distributionSetId),
TargetSpecifications.isCompatibleWithDistributionSetType(distSetTypeId)))); TargetSpecifications.isCompatibleWithDistributionSetType(distSetTypeId))));
} }
@@ -296,7 +295,7 @@ public class JpaTargetManagement
final String rsql, final Collection<Long> groups, final DistributionSetType dsType) { final String rsql, final Collection<Long> groups, final DistributionSetType dsType) {
return jpaRepository.count(AccessController.Operation.UPDATE, return jpaRepository.count(AccessController.Operation.UPDATE,
combineWithAnd(List.of( combineWithAnd(List.of(
RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class), QLSupport.getInstance().buildSpec(rsql, TargetFields.class),
TargetSpecifications.isNotInRolloutGroups(groups), TargetSpecifications.isNotInRolloutGroups(groups),
TargetSpecifications.isCompatibleWithDistributionSetType(dsType.getId())))); TargetSpecifications.isCompatibleWithDistributionSetType(dsType.getId()))));
} }
@@ -416,7 +415,7 @@ public class JpaTargetManagement
@Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, @Retryable(retryFor = { ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX,
backoff = @Backoff(delay = Constants.TX_RT_DELAY)) backoff = @Backoff(delay = Constants.TX_RT_DELAY))
public void assignTargetGroupWithRsql(String group, String rsql) { public void assignTargetGroupWithRsql(String group, String rsql) {
final Specification<JpaTarget> rsqlSpecification = RsqlUtility.getInstance().buildRsqlSpecification(rsql, TargetFields.class); final Specification<JpaTarget> rsqlSpecification = QLSupport.getInstance().buildSpec(rsql, TargetFields.class);
final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
final CriteriaUpdate<JpaTarget> criteriaUpdateQuery = cb.createCriteriaUpdate(JpaTarget.class); final CriteriaUpdate<JpaTarget> criteriaUpdateQuery = cb.createCriteriaUpdate(JpaTarget.class);

View File

@@ -12,7 +12,7 @@ package org.eclipse.hawkbit.repository.jpa.management;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.fail; import static org.assertj.core.api.Assertions.fail;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.LEGACY_G1; import static org.eclipse.hawkbit.repository.jpa.ql.QLSupport.SpecBuilder.LEGACY_G1;
import java.net.URI; import java.net.URI;
import java.util.ArrayList; import java.util.ArrayList;
@@ -62,7 +62,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag; import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility; import org.eclipse.hawkbit.repository.jpa.ql.QLSupport;
import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate; import org.eclipse.hawkbit.repository.model.Action.ActionStatusCreate;
import org.eclipse.hawkbit.repository.model.Action.Status; import org.eclipse.hawkbit.repository.model.Action.Status;
@@ -636,7 +636,7 @@ class TargetManagementTest extends AbstractRepositoryManagementWithMetadataTest<
*/ */
@Test @Test
void findTargetsByRsqlWithTypeAndMetadata() { void findTargetsByRsqlWithTypeAndMetadata() {
if (RsqlUtility.getInstance().getRsqlToSpecBuilder() == LEGACY_G1) { if (QLSupport.getInstance().getSpecBuilder() == LEGACY_G1) {
// legacy visitor fail with that // legacy visitor fail with that
return; return;
} }

View File

@@ -11,8 +11,8 @@ package org.eclipse.hawkbit.repository.jpa.rsql;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.LEGACY_G2; import static org.eclipse.hawkbit.repository.jpa.ql.QLSupport.SpecBuilder.LEGACY_G2;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.LEGACY_G1; import static org.eclipse.hawkbit.repository.jpa.ql.QLSupport.SpecBuilder.LEGACY_G1;
import java.util.Arrays; import java.util.Arrays;
import java.util.Map; import java.util.Map;
@@ -25,6 +25,7 @@ import org.eclipse.hawkbit.repository.TargetTypeManagement;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
import org.eclipse.hawkbit.repository.jpa.ql.QLSupport;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetTag; import org.eclipse.hawkbit.repository.model.TargetTag;
@@ -177,7 +178,7 @@ class RsqlTargetFieldTest extends AbstractJpaIntegrationTest {
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null==null", 1); // "null" check assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null==null", 1); // "null" check
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a==null", 0); // "null" check assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a==null", 0); // "null" check
if (RsqlUtility.getInstance().getRsqlToSpecBuilder() != LEGACY_G1) { if (QLSupport.getInstance().getSpecBuilder() != LEGACY_G1) {
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.dot=is=value.dot", 1); assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.dot=is=value.dot", 1);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null=is=null", 5); // null check assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null=is=null", 5); // null check
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a=is=null", 1 + 5); // null check assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a=is=null", 1 + 5); // null check
@@ -191,22 +192,22 @@ class RsqlTargetFieldTest extends AbstractJpaIntegrationTest {
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null!=null2", 1); // value check assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null!=null2", 1); // value check
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a!=null", 0); // "null" check assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a!=null", 0); // "null" check
if (RsqlUtility.getInstance().getRsqlToSpecBuilder() != LEGACY_G1) { if (QLSupport.getInstance().getSpecBuilder() != LEGACY_G1) {
assertRSQLQuery( assertRSQLQuery(
TargetFields.ATTRIBUTE.name() + ".test.dot=not=value.dot", TargetFields.ATTRIBUTE.name() + ".test.dot=not=value.dot",
RsqlUtility.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 5 : 0); QLSupport.getInstance().getSpecBuilder() == LEGACY_G2 ? 5 : 0);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null=not=null", 1); // null check assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null=not=null", 1); // null check
assertRSQLQuery( assertRSQLQuery(
TargetFields.ATTRIBUTE.name() + ".test.null=not=null2", TargetFields.ATTRIBUTE.name() + ".test.null=not=null2",
1 + (RsqlUtility.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 5 : 0)); // value check 1 + (QLSupport.getInstance().getSpecBuilder() == LEGACY_G2 ? 5 : 0)); // value check
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a=not=null", 0); // null check assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a=not=null", 0); // null check
assertRSQLQuery( assertRSQLQuery(
TargetFields.ATTRIBUTE.name() + ".test.dot=ne=value.dot", TargetFields.ATTRIBUTE.name() + ".test.dot=ne=value.dot",
RsqlUtility.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 5 : 0); QLSupport.getInstance().getSpecBuilder() == LEGACY_G2 ? 5 : 0);
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null=ne=null", 1); // null check assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null=ne=null", 1); // null check
assertRSQLQuery( assertRSQLQuery(
TargetFields.ATTRIBUTE.name() + ".test.null=ne=null2", TargetFields.ATTRIBUTE.name() + ".test.null=ne=null2",
1 + (RsqlUtility.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 5 : 0)); // value check 1 + (QLSupport.getInstance().getSpecBuilder() == LEGACY_G2 ? 5 : 0)); // value check
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a=ne=null", 0); // null check assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a=ne=null", 0); // null check
} }
@@ -303,7 +304,7 @@ class RsqlTargetFieldTest extends AbstractJpaIntegrationTest {
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey==noExist*", 0); assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey==noExist*", 0);
assertRSQLQuery(TargetFields.METADATA.name() + ".notExist==metaValue", 0); assertRSQLQuery(TargetFields.METADATA.name() + ".notExist==metaValue", 0);
if (RsqlUtility.getInstance().getRsqlToSpecBuilder() != LEGACY_G1) { if (QLSupport.getInstance().getSpecBuilder() != LEGACY_G1) {
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=is=metaValue", 1); assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=is=metaValue", 1);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=is=null", 4); // null check (1 of the initial five has) assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=is=null", 4); // null check (1 of the initial five has)
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=is=*v*", 2); assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=is=*v*", 2);
@@ -321,27 +322,27 @@ class RsqlTargetFieldTest extends AbstractJpaIntegrationTest {
assertRSQLQuery(TargetFields.METADATA.name() + ".notExist!=metaValue", 0); assertRSQLQuery(TargetFields.METADATA.name() + ".notExist!=metaValue", 0);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey!=notExist", 2); assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey!=notExist", 2);
if (RsqlUtility.getInstance().getRsqlToSpecBuilder() != LEGACY_G1) { if (QLSupport.getInstance().getSpecBuilder() != LEGACY_G1) {
assertRSQLQuery( assertRSQLQuery(
TargetFields.METADATA.name() + ".metaKey=not=metaValue", TargetFields.METADATA.name() + ".metaKey=not=metaValue",
RsqlUtility.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 1 + 4 : 1); QLSupport.getInstance().getSpecBuilder() == LEGACY_G2 ? 1 + 4 : 1);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=not=null", 2); // null check (2 of the initial five) assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=not=null", 2); // null check (2 of the initial five)
assertRSQLQuery( assertRSQLQuery(
TargetFields.METADATA.name() + ".notExist=not=metaValue", TargetFields.METADATA.name() + ".notExist=not=metaValue",
RsqlUtility.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 1 + 5 : 0); QLSupport.getInstance().getSpecBuilder() == LEGACY_G2 ? 1 + 5 : 0);
assertRSQLQuery( assertRSQLQuery(
TargetFields.METADATA.name() + ".metaKey=not=notExist", TargetFields.METADATA.name() + ".metaKey=not=notExist",
RsqlUtility.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 2 + 4 : 2); QLSupport.getInstance().getSpecBuilder() == LEGACY_G2 ? 2 + 4 : 2);
assertRSQLQuery( assertRSQLQuery(
TargetFields.METADATA.name() + ".metaKey=ne=metaValue", TargetFields.METADATA.name() + ".metaKey=ne=metaValue",
RsqlUtility.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 1 + 4 : 1); QLSupport.getInstance().getSpecBuilder() == LEGACY_G2 ? 1 + 4 : 1);
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=ne=null", 2); // null check (2 of the initial five) assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=ne=null", 2); // null check (2 of the initial five)
assertRSQLQuery( assertRSQLQuery(
TargetFields.METADATA.name() + ".notExist=ne=metaValue", TargetFields.METADATA.name() + ".notExist=ne=metaValue",
RsqlUtility.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 1 + 5 : 0); QLSupport.getInstance().getSpecBuilder() == LEGACY_G2 ? 1 + 5 : 0);
assertRSQLQuery( assertRSQLQuery(
TargetFields.METADATA.name() + ".metaKey=ne=notExist", TargetFields.METADATA.name() + ".metaKey=ne=notExist",
RsqlUtility.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 2 + 4 : 2); QLSupport.getInstance().getSpecBuilder() == LEGACY_G2 ? 2 + 4 : 2);
} }
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=in=(metaValue,notexist)", 1); assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=in=(metaValue,notexist)", 1);
@@ -374,26 +375,26 @@ class RsqlTargetFieldTest extends AbstractJpaIntegrationTest {
*/ */
@Test @Test
void rsqlValidTargetFields() { void rsqlValidTargetFields() {
RsqlUtility.getInstance().validateRsqlFor( QLSupport.getInstance().validateQuery(
"ID == '0123' and NAME == abcd and DESCRIPTION == absd and CREATEDAT =lt= 0123 and LASTMODIFIEDAT =gt= 0123" + "ID == '0123' and NAME == abcd and DESCRIPTION == absd and CREATEDAT =lt= 0123 and LASTMODIFIEDAT =gt= 0123" +
" and CONTROLLERID == 0123 and UPDATESTATUS == PENDING and IPADDRESS == 0123 and LASTCONTROLLERREQUESTAT == 0123" + " and CONTROLLERID == 0123 and UPDATESTATUS == PENDING and IPADDRESS == 0123 and LASTCONTROLLERREQUESTAT == 0123" +
" and tag == beta", " and tag == beta",
TargetFields.class, JpaTarget.class); TargetFields.class, JpaTarget.class);
RsqlUtility.getInstance().validateRsqlFor( QLSupport.getInstance().validateQuery(
"ASSIGNEDDS.name == abcd and ASSIGNEDDS.version == 0123 and INSTALLEDDS.name == abcd and INSTALLEDDS.version == 0123", "ASSIGNEDDS.name == abcd and ASSIGNEDDS.version == 0123 and INSTALLEDDS.name == abcd and INSTALLEDDS.version == 0123",
TargetFields.class, JpaTarget.class); TargetFields.class, JpaTarget.class);
RsqlUtility.getInstance().validateRsqlFor( QLSupport.getInstance().validateQuery(
"ATTRIBUTE.subkey1 == test and ATTRIBUTE.subkey2 == test and METADATA.metakey1 == abcd and METADATA.metavalue2 == asdfg", "ATTRIBUTE.subkey1 == test and ATTRIBUTE.subkey2 == test and METADATA.metakey1 == abcd and METADATA.metavalue2 == asdfg",
TargetFields.class, JpaTarget.class); TargetFields.class, JpaTarget.class);
RsqlUtility.getInstance().validateRsqlFor( QLSupport.getInstance().validateQuery(
"CREATEDAT =lt= ${NOW_TS} and LASTMODIFIEDAT =ge= ${OVERDUE_TS}", "CREATEDAT =lt= ${NOW_TS} and LASTMODIFIEDAT =ge= ${OVERDUE_TS}",
TargetFields.class, JpaTarget.class); TargetFields.class, JpaTarget.class);
RsqlUtility.getInstance().validateRsqlFor( QLSupport.getInstance().validateQuery(
"ATTRIBUTE.test.dot == test and ATTRIBUTE.subkey2 == test and METADATA.test.dot == abcd and METADATA.metavalue2 == asdfg", "ATTRIBUTE.test.dot == test and ATTRIBUTE.subkey2 == test and METADATA.test.dot == abcd and METADATA.metavalue2 == asdfg",
TargetFields.class, JpaTarget.class); TargetFields.class, JpaTarget.class);
assertThatExceptionOfType(RSQLParameterUnsupportedFieldException.class) assertThatExceptionOfType(RSQLParameterUnsupportedFieldException.class)
.isThrownBy(() -> RsqlUtility.getInstance().validateRsqlFor("wrongfield == abcd", TargetFields.class, JpaTarget.class)); .isThrownBy(() -> QLSupport.getInstance().validateQuery("wrongfield == abcd", TargetFields.class, JpaTarget.class));
} }
/** /**
@@ -448,6 +449,6 @@ class RsqlTargetFieldTest extends AbstractJpaIntegrationTest {
private void assertRSQLQueryThrowsException(final String rsql) { private void assertRSQLQueryThrowsException(final String rsql) {
assertThatExceptionOfType(RSQLParameterUnsupportedFieldException.class) assertThatExceptionOfType(RSQLParameterUnsupportedFieldException.class)
.isThrownBy(() -> RsqlUtility.getInstance().validateRsqlFor(rsql, TargetFields.class, JpaTarget.class)); .isThrownBy(() -> QLSupport.getInstance().validateQuery(rsql, TargetFields.class, JpaTarget.class));
} }
} }

View File

@@ -9,15 +9,15 @@
*/ */
package org.eclipse.hawkbit.repository.jpa.rsql; package org.eclipse.hawkbit.repository.jpa.rsql;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.LEGACY_G2; import static org.eclipse.hawkbit.repository.jpa.ql.QLSupport.SpecBuilder.LEGACY_G2;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.G3; import static org.eclipse.hawkbit.repository.jpa.ql.QLSupport.SpecBuilder.G3;
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlUtility.RsqlToSpecBuilder.LEGACY_G1; import static org.eclipse.hawkbit.repository.jpa.ql.QLSupport.SpecBuilder.LEGACY_G1;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE;
import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext; import jakarta.persistence.PersistenceContext;
import org.eclipse.hawkbit.repository.RsqlQueryField; import org.eclipse.hawkbit.repository.QueryField;
import org.eclipse.hawkbit.repository.SoftwareModuleFields; import org.eclipse.hawkbit.repository.SoftwareModuleFields;
import org.eclipse.hawkbit.repository.TargetFields; import org.eclipse.hawkbit.repository.TargetFields;
import org.eclipse.hawkbit.repository.jpa.JpaRepositoryConfiguration; import org.eclipse.hawkbit.repository.jpa.JpaRepositoryConfiguration;
@@ -130,7 +130,7 @@ class RsqlToSqlTest {
rsqlToSQL = new HawkbitQlToSql(entityManager); rsqlToSQL = new HawkbitQlToSql(entityManager);
} }
private <T, A extends Enum<A> & RsqlQueryField> void print(final Class<T> domainClass, final Class<A> fieldsClass, final String rsql) { private <T, A extends Enum<A> & QueryField> void print(final Class<T> domainClass, final Class<A> fieldsClass, final String rsql) {
System.out.println(rsql); System.out.println(rsql);
final String legacy = rsqlToSQL.toSQL(domainClass, fieldsClass, rsql, LEGACY_G1); final String legacy = rsqlToSQL.toSQL(domainClass, fieldsClass, rsql, LEGACY_G1);
final String g2 = rsqlToSQL.toSQL(domainClass, fieldsClass, rsql, LEGACY_G2); final String g2 = rsqlToSQL.toSQL(domainClass, fieldsClass, rsql, LEGACY_G2);
@@ -143,7 +143,7 @@ class RsqlToSqlTest {
} }
} }
private <T, A extends Enum<A> & RsqlQueryField> void printFrom(final Class<T> domainClass, final Class<A> fieldsClass, final String rsql) { private <T, A extends Enum<A> & QueryField> void printFrom(final Class<T> domainClass, final Class<A> fieldsClass, final String rsql) {
System.out.println(rsql); System.out.println(rsql);
final String legacy = rsqlToSQL.toSQL(domainClass, fieldsClass, rsql, LEGACY_G1); final String legacy = rsqlToSQL.toSQL(domainClass, fieldsClass, rsql, LEGACY_G1);
final String g2 = rsqlToSQL.toSQL(domainClass, fieldsClass, rsql, LEGACY_G2); final String g2 = rsqlToSQL.toSQL(domainClass, fieldsClass, rsql, LEGACY_G2);