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:
@@ -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"),
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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()),
|
||||||
|
|||||||
@@ -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"),
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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"),
|
||||||
|
|||||||
@@ -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"),
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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"),
|
||||||
|
|||||||
@@ -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"),
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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"),
|
||||||
|
|||||||
@@ -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()),
|
||||||
|
|||||||
@@ -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"),
|
||||||
|
|||||||
@@ -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());
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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 = '*';
|
||||||
|
|||||||
@@ -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 = '*';
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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"),
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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) {}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user