Return back legacy RSQL visitor until G2 maturity (#1825)
Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com>
This commit is contained in:
@@ -42,8 +42,11 @@ public final class RsqlConfigHolder {
|
||||
@Autowired
|
||||
private RsqlVisitorFactory rsqlVisitorFactory;
|
||||
|
||||
/**
|
||||
* @deprecated in favour of G2 RSQL visitor.
|
||||
*/
|
||||
@Deprecated
|
||||
@Value("${hawkbit.rsql.legacyRsqlVisitor:false}")
|
||||
@Value("${hawkbit.rsql.legacyRsqlVisitor:true}")
|
||||
private boolean legacyRsqlVisitor;
|
||||
|
||||
/**
|
||||
|
||||
@@ -72,6 +72,7 @@ import org.eclipse.hawkbit.repository.model.TargetMetadata;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTypeAssignmentResult;
|
||||
import org.eclipse.hawkbit.repository.rsql.RsqlConfigHolder;
|
||||
import org.eclipse.hawkbit.repository.test.matcher.Expect;
|
||||
import org.eclipse.hawkbit.repository.test.matcher.ExpectEvents;
|
||||
import org.eclipse.hawkbit.repository.test.util.SecurityContextSwitch;
|
||||
@@ -1291,6 +1292,10 @@ class TargetManagementTest extends AbstractJpaIntegrationTest {
|
||||
@Test
|
||||
@Description("Test that RSQL filter finds targets with tag and metadata.")
|
||||
void findTargetsByRsqlWithTypeAndMetadata() {
|
||||
if (RsqlConfigHolder.getInstance().isLegacyRsqlVisitor()) {
|
||||
// legacy visitor fail with that
|
||||
return;
|
||||
}
|
||||
final String controllerId1 = "target1";
|
||||
final String controllerId2 = "target2";
|
||||
createTargetWithMetadata(controllerId1, 2);
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Contributors to the Eclipse Foundation
|
||||
*
|
||||
* 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.jpa.rsql;
|
||||
|
||||
import cz.jirutka.rsql.parser.RSQLParser;
|
||||
import cz.jirutka.rsql.parser.ast.Node;
|
||||
import cz.jirutka.rsql.parser.ast.RSQLOperators;
|
||||
import cz.jirutka.rsql.parser.ast.RSQLVisitor;
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.TypedQuery;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Predicate;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
import org.eclipse.hawkbit.repository.FieldNameProvider;
|
||||
import org.eclipse.hawkbit.repository.rsql.RsqlConfigHolder;
|
||||
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
||||
import org.eclipse.persistence.config.PersistenceUnitProperties;
|
||||
import org.eclipse.persistence.jpa.JpaQuery;
|
||||
import org.eclipse.persistence.queries.DatabaseQuery;
|
||||
import org.springframework.orm.jpa.vendor.Database;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class RSQLToSQL {
|
||||
|
||||
private static final Database DATABASE = Database.H2;
|
||||
private final EntityManager entityManager;
|
||||
|
||||
public RSQLToSQL(final EntityManager entityManager) {
|
||||
this.entityManager = entityManager;
|
||||
}
|
||||
|
||||
public <T, A extends Enum<A> & FieldNameProvider> String toSQL(final Class<T> domainClass, final Class<A> fieldsClass, final String rsql, final boolean legacyRsqlVisitor) {
|
||||
return createDbQuery(domainClass, fieldsClass, rsql, legacyRsqlVisitor).getSQLString();
|
||||
}
|
||||
|
||||
public <T, A extends Enum<A> & FieldNameProvider> DatabaseQuery createDbQuery(final Class<T> domainClass, final Class<A> fieldsClass, final String rsql, final boolean legacyRsqlVisitor) {
|
||||
final CriteriaQuery<T> query = createQuery(domainClass, fieldsClass, rsql, legacyRsqlVisitor);
|
||||
final TypedQuery<?> typedQuery = entityManager.createQuery(query);
|
||||
// executes the query - otherwise the SQL string is not generated
|
||||
typedQuery.setParameter(PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT, "DEFAULT");
|
||||
typedQuery.getResultList();
|
||||
return typedQuery.unwrap(JpaQuery.class).getDatabaseQuery();
|
||||
}
|
||||
|
||||
private <T, A extends Enum<A> & FieldNameProvider> CriteriaQuery<T> createQuery(final Class<T> domainClass, final Class<A> fieldsClass, final String rsql, final boolean legacyRsqlVisitor) {
|
||||
final CriteriaQuery<T> query = entityManager.getCriteriaBuilder().createQuery(domainClass);
|
||||
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
return query.where(
|
||||
RsqlConfigHolder.getInstance().isLegacyRsqlVisitor() == legacyRsqlVisitor ?
|
||||
// use directly
|
||||
RSQLUtility.<A, T>buildRsqlSpecification(rsql, fieldsClass, null, DATABASE)
|
||||
.toPredicate(query.from(domainClass), cb.createQuery(domainClass), cb) :
|
||||
toPredicate(rsql, fieldsClass, null,
|
||||
query.from(domainClass), cb.createQuery(domainClass), cb, legacyRsqlVisitor)
|
||||
);
|
||||
}
|
||||
|
||||
private <T, A extends Enum<A> & FieldNameProvider> Predicate toPredicate(
|
||||
final String rsql,
|
||||
final Class<A> fieldsClass, final VirtualPropertyReplacer virtualPropertyReplacer,
|
||||
final Root<T> root, final CriteriaQuery<?> query, final CriteriaBuilder cb,
|
||||
final boolean legacyRsqlVisitor) {
|
||||
final Node rootNode = new RSQLParser(RSQLOperators.defaultOperators()).parse(rsql);
|
||||
query.distinct(true);
|
||||
|
||||
final RSQLVisitor<List<Predicate>, String> jpqQueryRSQLVisitor =
|
||||
legacyRsqlVisitor ?
|
||||
new JpaQueryRsqlVisitor<>(
|
||||
root, cb, fieldsClass,
|
||||
virtualPropertyReplacer, DATABASE, query,
|
||||
!RsqlConfigHolder.getInstance().isCaseInsensitiveDB() && RsqlConfigHolder.getInstance().isIgnoreCase())
|
||||
:
|
||||
new JpaQueryRsqlVisitorG2<>(
|
||||
fieldsClass, root, query, cb,
|
||||
DATABASE, virtualPropertyReplacer,
|
||||
!RsqlConfigHolder.getInstance().isCaseInsensitiveDB() && RsqlConfigHolder.getInstance().isIgnoreCase());
|
||||
final List<Predicate> accept = rootNode.accept(jpqQueryRSQLVisitor);
|
||||
|
||||
if (CollectionUtils.isEmpty(accept)) {
|
||||
return cb.conjunction();
|
||||
} else {
|
||||
return cb.and(accept.toArray(new Predicate[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Contributors to the Eclipse Foundation
|
||||
*
|
||||
* 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.jpa.rsql;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.PersistenceContext;
|
||||
import org.eclipse.hawkbit.repository.TargetFields;
|
||||
import org.eclipse.hawkbit.repository.jpa.RepositoryApplicationConfiguration;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.test.TestConfiguration;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE;
|
||||
|
||||
@ActiveProfiles("test")
|
||||
@SpringBootTest(webEnvironment=NONE, properties = {
|
||||
"spring.main.allow-bean-definition-overriding=true",
|
||||
"spring.main.banner-mode=off",
|
||||
"logging.level.root=ERROR" })
|
||||
@ContextConfiguration(classes = { RepositoryApplicationConfiguration.class, TestConfiguration.class })
|
||||
@Import(TestChannelBinderConfiguration.class)
|
||||
@Disabled("For manual run only, while playing around with RSQL to SQL")
|
||||
public class RSQLToSQLTest {
|
||||
|
||||
private RSQLToSQL rsqlToSQL;
|
||||
|
||||
@PersistenceContext
|
||||
private void setEntityManager(final EntityManager entityManager) {
|
||||
rsqlToSQL = new RSQLToSQL(entityManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void print() {
|
||||
String rsql = "tag==tag1 or tag==tag2 or tag==tag3";
|
||||
System.out.println(rsql + "\n" +
|
||||
"\tlegacy:\n" +
|
||||
"\t\t" + rsqlToSQL.toSQL(JpaTarget.class, TargetFields.class, rsql, true) + "\n" +
|
||||
"\tG2:\n" +
|
||||
"\t\t" + rsqlToSQL.toSQL(JpaTarget.class, TargetFields.class, rsql, false));
|
||||
|
||||
rsql = "targettype.key==type1 and metadata.key1==target1-value1";
|
||||
System.out.println(rsql + "\n" +
|
||||
"\tlegacy:\n" +
|
||||
"\t\t" + rsqlToSQL.toSQL(JpaTarget.class, TargetFields.class, rsql, true) + "\n" +
|
||||
"\tG2:\n" +
|
||||
"\t\t" + rsqlToSQL.toSQL(JpaTarget.class, TargetFields.class, rsql, false));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user