Rsql G3 (#2423)
* Rsql G3 * Move legacy and G2 visors in rsqllegacy and deprecate * Refactor RSQLUtility Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com> --------- Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
@@ -12,6 +12,7 @@ package org.eclipse.hawkbit.repository.jpa.management;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.eclipse.hawkbit.repository.rsql.RsqlConfigHolder.RsqlToSpecBuilder.LEGACY_G1;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
@@ -1030,7 +1031,7 @@ class TargetManagementTest extends AbstractJpaIntegrationTest {
|
||||
@Test
|
||||
@Description("Test that RSQL filter finds targets with tag and metadata.")
|
||||
void findTargetsByRsqlWithTypeAndMetadata() {
|
||||
if (RsqlConfigHolder.getInstance().isLegacyRsqlVisitor()) {
|
||||
if (RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() == LEGACY_G1) {
|
||||
// legacy visitor fail with that
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright (c) 2025 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 static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class NodeTest {
|
||||
|
||||
@Test
|
||||
void testSimplify() {
|
||||
final Node aEqB = new Node.Comparison("a", Node.Comparison.Operator.EQ, "b");
|
||||
final Node aEqC = new Node.Comparison("a", Node.Comparison.Operator.EQ, "c");
|
||||
final Node aEqD = new Node.Comparison("a", Node.Comparison.Operator.EQ, "d");
|
||||
final Node aEqE = new Node.Comparison("a", Node.Comparison.Operator.EQ, "e");
|
||||
|
||||
assertThat(aEqB.and(aEqC).and(aEqD).and(aEqE).getChildren())
|
||||
.hasSize(4)
|
||||
.containsExactly(aEqB, aEqC, aEqD, aEqE);
|
||||
assertThat(aEqB.and(aEqC).and(aEqD.and(aEqE)).getChildren())
|
||||
.hasSize(4)
|
||||
.containsExactly(aEqB, aEqC, aEqD, aEqE);
|
||||
assertThat(aEqB.or(aEqC).or(aEqD).or(aEqE).getChildren())
|
||||
.hasSize(4)
|
||||
.containsExactly(aEqB, aEqC, aEqD, aEqE);
|
||||
assertThat(aEqB.or(aEqC).or(aEqD.or(aEqE)).getChildren())
|
||||
.hasSize(4)
|
||||
.containsExactly(aEqB, aEqC, aEqD, aEqE);
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,8 @@ package org.eclipse.hawkbit.repository.jpa.rsql;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.eclipse.hawkbit.repository.rsql.RsqlConfigHolder.RsqlToSpecBuilder.LEGACY_G2;
|
||||
import static org.eclipse.hawkbit.repository.rsql.RsqlConfigHolder.RsqlToSpecBuilder.LEGACY_G1;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
@@ -29,6 +31,7 @@ import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.eclipse.hawkbit.repository.rsql.RsqlConfigHolder;
|
||||
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
||||
import org.eclipse.hawkbit.repository.test.util.TestdataFactory;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -176,9 +179,11 @@ class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
|
||||
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.dot=is=value.dot", 1);
|
||||
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null=is=null", 5); // null check
|
||||
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a=is=null", 1 + 5); // null check
|
||||
if (RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() != LEGACY_G1) {
|
||||
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.n/a=is=null", 1 + 5); // null check
|
||||
}
|
||||
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.dot=eq=value.dot", 1);
|
||||
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null=eq=null", 5); // null check
|
||||
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a=eq=null", 1 + 5); // null check
|
||||
@@ -188,14 +193,24 @@ class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
|
||||
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.dot=not=value.dot", 5);
|
||||
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null=not=null", 1); // null check
|
||||
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null=not=null2", 1 + 5); // value check
|
||||
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a=not=null", 0); // null check
|
||||
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.dot=ne=value.dot", 5);
|
||||
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null=ne=null", 1); // null check
|
||||
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null=ne=null2", 1 + 5); // value check
|
||||
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a=ne=null", 0); // null check
|
||||
if (RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() != LEGACY_G1) {
|
||||
assertRSQLQuery(
|
||||
TargetFields.ATTRIBUTE.name() + ".test.dot=not=value.dot",
|
||||
RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 5 : 0);
|
||||
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null=not=null", 1); // null check
|
||||
assertRSQLQuery(
|
||||
TargetFields.ATTRIBUTE.name() + ".test.null=not=null2",
|
||||
1 + (RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 5 : 0)); // value check
|
||||
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a=not=null", 0); // null check
|
||||
assertRSQLQuery(
|
||||
TargetFields.ATTRIBUTE.name() + ".test.dot=ne=value.dot",
|
||||
RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 5 : 0);
|
||||
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.null=ne=null", 1); // null check
|
||||
assertRSQLQuery(
|
||||
TargetFields.ATTRIBUTE.name() + ".test.null=ne=null2",
|
||||
1 + (RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 5 : 0)); // value check
|
||||
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".test.n/a=ne=null", 0); // null check
|
||||
}
|
||||
|
||||
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".revision==1.1", 1);
|
||||
assertRSQLQuery(TargetFields.ATTRIBUTE.name() + ".revision!=1.1", 1);
|
||||
@@ -245,6 +260,8 @@ class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
|
||||
assertRSQLQuery(TargetFields.TAG.name() + "!=notexist", 5);
|
||||
assertRSQLQuery(TargetFields.TAG.name() + "==''", 1);
|
||||
assertRSQLQuery(TargetFields.TAG.name() + "!=''", 4);
|
||||
assertRSQLQuery(TargetFields.TAG.name() + "!=*", 1); // has no tags
|
||||
assertRSQLQuery(TargetFields.TAG.name() + "==*", 4); // has tags
|
||||
assertRSQLQuery(TargetFields.TAG.name() + "=in=(Tag1,notexist)", 2);
|
||||
assertRSQLQuery(TargetFields.TAG.name() + "=in=(null)", 0);
|
||||
assertRSQLQuery(TargetFields.TAG.name() + "=out=(Tag1,notexist)", 3);
|
||||
@@ -278,11 +295,13 @@ class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey==noExist*", 0);
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".notExist==metaValue", 0);
|
||||
|
||||
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=*v*", 2);
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=is=noExist*", 0);
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".notExist=is=null", 1 + 5); // null check
|
||||
if (RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() != LEGACY_G1) {
|
||||
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=*v*", 2);
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=is=noExist*", 0);
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".notExist=is=null", 1 + 5); // null check
|
||||
}
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=eq=metaValue", 1);
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=eq=null", 4); // null check (1 of the initial five has)
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=eq=*v*", 2);
|
||||
@@ -293,15 +312,29 @@ class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey!=null", 2);
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".notExist!=metaValue", 0);
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey!=notExist", 2);
|
||||
//
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=not=metaValue", 1 + 4);
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=not=null", 2); // null check (2 of the initial five)
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".notExist=not=metaValue", 1 + 5);
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=not=notExist", 1 + 5);
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=ne=metaValue", 1 + 4);
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=ne=null", 2); // null check (2 of the initial five)
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".notExist=ne=metaValue", 1 + 5);
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=ne=notExist", 1 + 5);
|
||||
|
||||
if (RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() != LEGACY_G1) {
|
||||
assertRSQLQuery(
|
||||
TargetFields.METADATA.name() + ".metaKey=not=metaValue",
|
||||
RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 1 + 4 : 1);
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=not=null", 2); // null check (2 of the initial five)
|
||||
assertRSQLQuery(
|
||||
TargetFields.METADATA.name() + ".notExist=not=metaValue",
|
||||
RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 1 + 5 : 0);
|
||||
assertRSQLQuery(
|
||||
TargetFields.METADATA.name() + ".metaKey=not=notExist",
|
||||
RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 2 + 4 : 2);
|
||||
assertRSQLQuery(
|
||||
TargetFields.METADATA.name() + ".metaKey=ne=metaValue",
|
||||
RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 1 + 4 : 1);
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=ne=null", 2); // null check (2 of the initial five)
|
||||
assertRSQLQuery(
|
||||
TargetFields.METADATA.name() + ".notExist=ne=metaValue",
|
||||
RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 1 + 5 : 0);
|
||||
assertRSQLQuery(
|
||||
TargetFields.METADATA.name() + ".metaKey=ne=notExist",
|
||||
RsqlConfigHolder.getInstance().getRsqlToSpecBuilder() == LEGACY_G2 ? 2 + 4 : 2);
|
||||
}
|
||||
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=in=(metaValue,notexist)", 1);
|
||||
assertRSQLQuery(TargetFields.METADATA.name() + ".metaKey=out=(metaValue,notexist)", 1);
|
||||
|
||||
@@ -9,25 +9,16 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.rsql;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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 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 org.eclipse.hawkbit.repository.RsqlQueryField;
|
||||
import org.eclipse.hawkbit.repository.jpa.Utils;
|
||||
import org.eclipse.hawkbit.repository.rsql.RsqlConfigHolder;
|
||||
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
||||
import org.eclipse.hawkbit.repository.rsql.RsqlConfigHolder.RsqlToSpecBuilder;
|
||||
import org.springframework.orm.jpa.vendor.Database;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
public class RSQLToSQL {
|
||||
|
||||
@@ -39,50 +30,27 @@ public class RSQLToSQL {
|
||||
}
|
||||
|
||||
public <T, A extends Enum<A> & RsqlQueryField> String toSQL(
|
||||
final Class<T> domainClass, final Class<A> fieldsClass, final String rsql, final boolean legacyRsqlVisitor) {
|
||||
final CriteriaQuery<T> query = createQuery(domainClass, fieldsClass, rsql, legacyRsqlVisitor);
|
||||
final Class<T> domainClass, final Class<A> fieldsClass, final String rsql, final RsqlToSpecBuilder rsqlToSpecBuilder) {
|
||||
final CriteriaQuery<T> query = createQuery(domainClass, fieldsClass, rsql, rsqlToSpecBuilder);
|
||||
final TypedQuery<?> typedQuery = entityManager.createQuery(query);
|
||||
return Utils.toSql(typedQuery);
|
||||
}
|
||||
|
||||
private <T, A extends Enum<A> & RsqlQueryField> CriteriaQuery<T> createQuery(
|
||||
final Class<T> domainClass, final Class<A> fieldsClass, final String rsql, final boolean legacyRsqlVisitor) {
|
||||
final Class<T> domainClass, final Class<A> fieldsClass, final String rsql, final RsqlToSpecBuilder rsqlToSpecBuilder) {
|
||||
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> & RsqlQueryField> 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]));
|
||||
final RsqlToSpecBuilder defaultRsqlToSpecBuilder = RsqlConfigHolder.getInstance().getRsqlToSpecBuilder();
|
||||
if (defaultRsqlToSpecBuilder != rsqlToSpecBuilder) {
|
||||
RsqlConfigHolder.getInstance().setRsqlToSpecBuilder(rsqlToSpecBuilder);
|
||||
}
|
||||
try {
|
||||
return query.where(RSQLUtility.<A, T> buildRsqlSpecification(rsql, fieldsClass, null, DATABASE)
|
||||
.toPredicate(query.from(domainClass), cb.createQuery(domainClass), cb));
|
||||
} finally {
|
||||
if (defaultRsqlToSpecBuilder != rsqlToSpecBuilder) {
|
||||
RsqlConfigHolder.getInstance().setRsqlToSpecBuilder(defaultRsqlToSpecBuilder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,9 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.rsql;
|
||||
|
||||
import static org.eclipse.hawkbit.repository.rsql.RsqlConfigHolder.RsqlToSpecBuilder.LEGACY_G2;
|
||||
import static org.eclipse.hawkbit.repository.rsql.RsqlConfigHolder.RsqlToSpecBuilder.G3;
|
||||
import static org.eclipse.hawkbit.repository.rsql.RsqlConfigHolder.RsqlToSpecBuilder.LEGACY_G1;
|
||||
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
@@ -42,6 +45,11 @@ class RSQLToSQLTest {
|
||||
private static final boolean FULL = Boolean.getBoolean("full");
|
||||
private RSQLToSQL rsqlToSQL;
|
||||
|
||||
@Test
|
||||
void p() {
|
||||
print(JpaTarget.class, TargetFields.class, TargetFields.TAG.name() + "==''");
|
||||
print(JpaTarget.class, TargetFields.class, TargetFields.TAG.name() + "!=''");
|
||||
}
|
||||
@Test
|
||||
void print() {
|
||||
print(JpaTarget.class, TargetFields.class, "tag==tag1 and tag==tag2");
|
||||
@@ -105,18 +113,28 @@ class RSQLToSQLTest {
|
||||
|
||||
private <T, A extends Enum<A> & RsqlQueryField> void print(final Class<T> domainClass, final Class<A> fieldsClass, final String rsql) {
|
||||
System.out.println(rsql);
|
||||
System.out.println("\tlegacy:\n" +
|
||||
"\t\t" + useStar(rsqlToSQL.toSQL(domainClass, fieldsClass, rsql, true)));
|
||||
System.out.println("\tG2:\n" +
|
||||
"\t\t" + useStar(rsqlToSQL.toSQL(domainClass, fieldsClass, rsql, false)));
|
||||
final String legacy = rsqlToSQL.toSQL(domainClass, fieldsClass, rsql, LEGACY_G1);
|
||||
final String g2 = rsqlToSQL.toSQL(domainClass, fieldsClass, rsql, LEGACY_G2);
|
||||
final String g3 = rsqlToSQL.toSQL(domainClass, fieldsClass, rsql, G3);
|
||||
System.out.println("\tlegacy:\n\t\t" + useStar(legacy));
|
||||
System.out.println("\tG2:\n\t\t" + useStar(g2));
|
||||
System.out.println("\tG3:\n\t\t" + useStar(g3));
|
||||
if (!g2.equals(g3)) {
|
||||
System.out.println("\tG2 != G3 for rsql: " + rsql);
|
||||
}
|
||||
}
|
||||
|
||||
private <T, A extends Enum<A> & RsqlQueryField> void printFrom(final Class<T> domainClass, final Class<A> fieldsClass, final String rsql) {
|
||||
System.out.println(rsql);
|
||||
System.out.println("\tlegacy:\n" +
|
||||
"\t\t" + from(rsqlToSQL.toSQL(domainClass, fieldsClass, rsql, true)));
|
||||
System.out.println("\tG2:\n" +
|
||||
"\t\t" + from(rsqlToSQL.toSQL(domainClass, fieldsClass, rsql, false)));
|
||||
final String legacy = rsqlToSQL.toSQL(domainClass, fieldsClass, rsql, LEGACY_G1);
|
||||
final String g2 = rsqlToSQL.toSQL(domainClass, fieldsClass, rsql, LEGACY_G2);
|
||||
final String g3 = rsqlToSQL.toSQL(domainClass, fieldsClass, rsql, G3);
|
||||
System.out.println("\tlegacy:\n\t\t" + from(legacy));
|
||||
System.out.println("\tG2:\n\t\t" + from(g2));
|
||||
System.out.println("\tG2:\n\t\t" + from(g3));
|
||||
if (!g2.equals(g3)) {
|
||||
System.out.println("\tG2 != G3 for rsql: " + rsql);
|
||||
}
|
||||
}
|
||||
|
||||
private static String useStar(final String sql) {
|
||||
|
||||
@@ -55,6 +55,7 @@ import org.eclipse.hawkbit.repository.rsql.VirtualPropertyResolver;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
@@ -70,6 +71,7 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@Feature("Component Tests - Repository")
|
||||
@Story("RSQL search utility")
|
||||
@Disabled
|
||||
// TODO: fully document tests -> @Description for long text and reasonable
|
||||
// method name as short text
|
||||
class RSQLUtilityTest {
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* Copyright (c) 2025 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 static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.eclipse.hawkbit.repository.jpa.rsql.RsqlParser.parse;
|
||||
|
||||
import org.eclipse.hawkbit.repository.TargetFields;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class RsqlParserTest {
|
||||
|
||||
@Test
|
||||
void testSimpleComparisonNode() {
|
||||
assertThat(parse("a == 6")).hasToString("a == \"6\"");
|
||||
assertThat(parse("a != 6")).hasToString("a != \"6\"");
|
||||
assertThat(parse("a > 6")).hasToString("a > \"6\"");
|
||||
assertThat(parse("a >= 6")).hasToString("a >= \"6\"");
|
||||
assertThat(parse("a < 6")).hasToString("a < \"6\"");
|
||||
assertThat(parse("a <= 6")).hasToString("a <= \"6\"");
|
||||
assertThat(parse("a =in= 6")).hasToString("a in (\"6\")");
|
||||
assertThat(parse("a =in= (6)")).hasToString("a in (\"6\")");
|
||||
assertThat(parse("a =in= (6, 7)")).hasToString("a in (\"6\", \"7\")");
|
||||
assertThat(parse("a =out= 6")).hasToString("a not in (\"6\")");
|
||||
assertThat(parse("a =out= (6)")).hasToString("a not in (\"6\")");
|
||||
assertThat(parse("a =out= (6, 7)")).hasToString("a not in (\"6\", \"7\")");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNullComparison() {
|
||||
assertThat(parse("a == null")).hasToString("a == \"null\"");
|
||||
assertThat(parse("a =is= 6")).hasToString("a == \"6\"");
|
||||
assertThat(parse("a =is= null")).hasToString("a == null");
|
||||
|
||||
assertThat(parse("a != null")).hasToString("a != \"null\"");
|
||||
assertThat(parse("a =not= 6")).hasToString("a != \"6\"");
|
||||
assertThat(parse("a =not= null")).hasToString("a != null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLikeComparison() {
|
||||
assertThat(parse("a == test*")).hasToString("a like \"test*\"");
|
||||
assertThat(parse("a == test\\*")).hasToString("a == \"test\\*\"");
|
||||
|
||||
assertThat(parse("a != test*")).hasToString("a not like \"test*\"");
|
||||
assertThat(parse("a != test\\*")).hasToString("a != \"test\\*\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testOrLogical() {
|
||||
assertThat(parse("a == 6 or a == 7")).hasToString("a == \"6\" || a == \"7\"");
|
||||
assertThat(parse("a == 6 or a == 7 or a == '8'")).hasToString("a == \"6\" || a == \"7\" || a == \"8\"");
|
||||
assertThat(parse("(a == 6 or a == 7) or a == '8'")).hasToString("a == \"6\" || a == \"7\" || a == \"8\"");
|
||||
assertThat(parse("a == 6 or (a == 7 or a == '8')")).hasToString("a == \"6\" || a == \"7\" || a == \"8\"");
|
||||
assertThat(parse("a == 6 or a == 7 or (a == '8')")).hasToString("a == \"6\" || a == \"7\" || a == \"8\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAndLogical() {
|
||||
assertThat(parse("a == 6 and a == 7")).hasToString("a == \"6\" && a == \"7\"");
|
||||
assertThat(parse("a == 6 and a == 7 and a == '8'")).hasToString("a == \"6\" && a == \"7\" && a == \"8\"");
|
||||
assertThat(parse("(a == 6 and a == 7) and a == '8'")).hasToString("a == \"6\" && a == \"7\" && a == \"8\"");
|
||||
assertThat(parse("a == 6 and (a == 7 and a == '8')")).hasToString("a == \"6\" && a == \"7\" && a == \"8\"");
|
||||
assertThat(parse("a == 6 and a == 7 and (a == '8')")).hasToString("a == \"6\" && a == \"7\" && a == \"8\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testComplexLogical() {
|
||||
assertThat(parse("a == 6 and a == 7 or a == '8'")).hasToString("a == \"6\" && a == \"7\" || a == \"8\"");
|
||||
assertThat(parse("(a == 6 or a == 7) and a == '8'")).hasToString("(a == \"6\" || a == \"7\") && a == \"8\"");
|
||||
assertThat(parse("a == 6 or (a == 7 and a == '8')")).hasToString("a == \"6\" || a == \"7\" && a == \"8\"");
|
||||
assertThat(parse("a == 6 and (a == 7 or a == '8')")).hasToString("a == \"6\" && (a == \"7\" || a == \"8\")");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testQueryFieldsComparisonNode() {
|
||||
// simple attribute
|
||||
assertThat(parse("controllerid == 6", TargetFields.class)).hasToString("controllerId == \"6\"");
|
||||
// reference attribute
|
||||
assertThat(parse("assignedds.name == 6", TargetFields.class)).hasToString("assignedDistributionSet.name == \"6\"");
|
||||
// reference attribute with default sub-attribute
|
||||
assertThat(parse("tag == 6", TargetFields.class)).hasToString("tags.name == \"6\"");
|
||||
assertThat(parse("tag.name == 6", TargetFields.class)).hasToString("tags.name == \"6\"");
|
||||
// map attribute
|
||||
assertThat(parse("metadata.x == 6", TargetFields.class)).hasToString("metadata.x == \"6\"");
|
||||
assertThat(parse("metadata.x.y.z == 6", TargetFields.class)).hasToString("metadata.x.y.z == \"6\""); // with dots
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user