Optimize G2 subqueries for != and out - remove unused joins in all cases (#1838)

At the moment such unused are removed for "tag!=1 and tag==2" but not for "tag==2 and tag!=1"

Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2024-09-10 14:48:59 +03:00
committed by GitHub
parent 62734e936a
commit 52912c3cca
2 changed files with 28 additions and 22 deletions

View File

@@ -63,7 +63,6 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & RsqlQueryField, T>
public static final Character LIKE_WILDCARD = '*'; public static final Character LIKE_WILDCARD = '*';
private static final char ESCAPE_CHAR = '\\'; private static final char ESCAPE_CHAR = '\\';
private static final String ESCAPE_CHAR_WITH_ASTERISK = ESCAPE_CHAR +"*"; private static final String ESCAPE_CHAR_WITH_ASTERISK = ESCAPE_CHAR +"*";
private static final List<String> NO_JOINS_OPERATOR = List.of("!=", "=out=");
private final Root<T> root; private final Root<T> root;
private final CriteriaQuery<?> query; private final CriteriaQuery<?> query;
@@ -76,7 +75,6 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & RsqlQueryField, T>
private boolean inOr; private boolean inOr;
private final Map<Class<?>, Path<Object>> javaTypeToPath = new HashMap<>(); private final Map<Class<?>, Path<Object>> javaTypeToPath = new HashMap<>();
private boolean joinsNeeded;
public JpaQueryRsqlVisitorG2(final Class<A> enumType, public JpaQueryRsqlVisitorG2(final Class<A> enumType,
final Root<T> root, final CriteriaQuery<?> query, final CriteriaBuilder cb, final Root<T> root, final CriteriaQuery<?> query, final CriteriaBuilder cb,
@@ -120,8 +118,6 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & RsqlQueryField, T>
transformedValues.add(convertValueIfNecessary(node, queryField.getEnumValue(), fieldPath, value)); transformedValues.add(convertValueIfNecessary(node, queryField.getEnumValue(), fieldPath, value));
} }
this.joinsNeeded = this.joinsNeeded || areJoinsNeeded(node);
return mapToPredicate(node, queryField, fieldPath, node.getArguments(), transformedValues); return mapToPredicate(node, queryField, fieldPath, node.getArguments(), transformedValues);
} }
@@ -219,8 +215,7 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & RsqlQueryField, T>
} }
} }
clearJoinsIfNotNeeded(); return toNotExistsSubQueryPredicate(queryField, fieldPath, expressionToCompare ->
return toNotExistsSubQueryPredicate(queryField, expressionToCompare ->
isPattern(transformedValueStr) ? // a pattern, use like isPattern(transformedValueStr) ? // a pattern, use like
like(expressionToCompare, toSQL(transformedValueStr)) : like(expressionToCompare, toSQL(transformedValueStr)) :
equal(expressionToCompare, transformedValueStr)); equal(expressionToCompare, transformedValueStr));
@@ -237,8 +232,7 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & RsqlQueryField, T>
return cb.or(cb.isNull(fieldPath), cb.not(in(pathOfString(fieldPath), transformedValues))); return cb.or(cb.isNull(fieldPath), cb.not(in(pathOfString(fieldPath), transformedValues)));
} }
clearJoinsIfNotNeeded(); return toNotExistsSubQueryPredicate(queryField, fieldPath, expressionToCompare -> in(expressionToCompare, transformedValues));
return toNotExistsSubQueryPredicate(queryField, expressionToCompare -> in(expressionToCompare, transformedValues));
} }
private Path<Object> getFieldPath(final Root<?> root, final QuertPath queryField) { private Path<Object> getFieldPath(final Root<?> root, final QuertPath queryField) {
@@ -267,9 +261,8 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & RsqlQueryField, T>
return root.get(fieldNameSplit); return root.get(fieldNameSplit);
} }
} // if a collection - it is a join } // if a collection - it is a join
if (inOr && root == this.root) { // try to reuse join of the same or level and no subquery if (inOr && root == this.root) { // try to reuse join of the same "or" level and no subquery
final Class<?> objectClass = attribute.getJavaType(); return javaTypeToPath.computeIfAbsent(attribute.getJavaType(), k -> root.join(fieldNameSplit, JoinType.LEFT));
return javaTypeToPath.computeIfAbsent(objectClass, k -> root.join(fieldNameSplit, JoinType.LEFT));
} else { } else {
return root.join(fieldNameSplit, JoinType.LEFT); return root.join(fieldNameSplit, JoinType.LEFT);
} }
@@ -338,12 +331,6 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & RsqlQueryField, T>
} }
} }
private void clearJoinsIfNotNeeded() {
if (!joinsNeeded) {
root.getJoins().clear();
}
}
private Predicate toNullOrNotEqualPredicate(final Path<Object> fieldPath, final Object transformedValue) { private Predicate toNullOrNotEqualPredicate(final Path<Object> fieldPath, final Object transformedValue) {
return cb.or( return cb.or(
cb.isNull(fieldPath), cb.isNull(fieldPath),
@@ -353,7 +340,13 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & RsqlQueryField, T>
} }
@SuppressWarnings({ "unchecked", "rawtypes" }) @SuppressWarnings({ "unchecked", "rawtypes" })
private Predicate toNotExistsSubQueryPredicate(final QuertPath queryField, final Function<Expression<String>, Predicate> subQueryPredicateProvider) { private Predicate toNotExistsSubQueryPredicate(final QuertPath queryField, final Path<Object> fieldPath, final Function<Expression<String>, Predicate> subQueryPredicateProvider) {
// if a subquery the field's parent joins are not actually used
if (!inOr) {
// so, if not in or (hence not reused) we remove them
root.getJoins().remove(fieldPath.getParentPath());
}
final Class<?> javaType = root.getJavaType(); final Class<?> javaType = root.getJavaType();
final Subquery<?> subquery = query.subquery(javaType); final Subquery<?> subquery = query.subquery(javaType);
final Root subqueryRoot = subquery.from(javaType); final Root subqueryRoot = subquery.from(javaType);
@@ -454,8 +447,4 @@ public class JpaQueryRsqlVisitorG2<A extends Enum<A> & RsqlQueryField, T>
return transformedValue.indexOf(LIKE_WILDCARD) != -1; return transformedValue.indexOf(LIKE_WILDCARD) != -1;
} }
} }
private static boolean areJoinsNeeded(final ComparisonNode node) {
return !NO_JOINS_OPERATOR.contains(node.getOperator().getSymbol());
}
} }

View File

@@ -52,6 +52,12 @@ public class RSQLToSQLTest {
print(JpaTarget.class, TargetFields.class, "(tag!=TAG1 or tag !=TAG2)"); print(JpaTarget.class, TargetFields.class, "(tag!=TAG1 or tag !=TAG2)");
} }
@Test
public void printPG() {
printFrom(JpaTarget.class, TargetFields.class, "tag!=TAG1 and tag==TAG2");
printFrom(JpaTarget.class, TargetFields.class, "tag==TAG1 and tag!=TAG2");
}
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> & RsqlQueryField> void print(final Class<T> domainClass, final Class<A> fieldsClass, final String rsql) {
System.out.println(rsql); System.out.println(rsql);
System.out.println("\tlegacy:\n" + System.out.println("\tlegacy:\n" +
@@ -59,4 +65,15 @@ public class RSQLToSQLTest {
System.out.println("\tG2:\n" + System.out.println("\tG2:\n" +
"\t\t" + rsqlToSQL.toSQL(domainClass, fieldsClass, rsql, false)); "\t\t" + rsqlToSQL.toSQL(domainClass, fieldsClass, rsql, false));
} }
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)));
}
private static String from(final String sql) {
return sql.substring(sql.indexOf("FROM"));
}
} }