Properly handle Sort's that start with a join alias.
JOIN clauses can have aliases as well, despite not using an AS reserved word. The HQL query parser needs to handle this. See #2960, #1066, #664 Original Pull Request: 2967
This commit is contained in:
@@ -282,6 +282,30 @@ class HqlQueryTransformer extends HqlQueryRenderer {
|
||||
return tokens;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<JpaQueryParsingToken> visitJoinPath(HqlParser.JoinPathContext ctx) {
|
||||
|
||||
List<JpaQueryParsingToken> tokens = super.visitJoinPath(ctx);
|
||||
|
||||
if (ctx.variable() != null) {
|
||||
transformerSupport.registerAlias(tokens.get(tokens.size() - 1).getToken());
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<JpaQueryParsingToken> visitJoinSubquery(HqlParser.JoinSubqueryContext ctx) {
|
||||
|
||||
List<JpaQueryParsingToken> tokens = super.visitJoinSubquery(ctx);
|
||||
|
||||
if (ctx.variable() != null) {
|
||||
transformerSupport.registerAlias(tokens.get(tokens.size() - 1).getToken());
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<JpaQueryParsingToken> visitAlias(HqlParser.AliasContext ctx) {
|
||||
|
||||
|
||||
@@ -131,11 +131,16 @@ class JpaQueryTransformerSupport {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the Sort references an alias
|
||||
// If the Sort references an alias directly
|
||||
if (projectionAliases.contains(order.getProperty())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the Sort property starts with an alias
|
||||
if (projectionAliases.stream().anyMatch(alias -> order.getProperty().startsWith(alias))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,6 +219,16 @@ class JpqlQueryTransformer extends JpqlQueryRenderer {
|
||||
return tokens;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<JpaQueryParsingToken> visitJoin(JpqlParser.JoinContext ctx) {
|
||||
|
||||
List<JpaQueryParsingToken> tokens = super.visitJoin(ctx);
|
||||
|
||||
transformerSupport.registerAlias(tokens.get(tokens.size() - 1).getToken());
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<JpaQueryParsingToken> visitConstructor_expression(JpqlParser.Constructor_expressionContext ctx) {
|
||||
|
||||
|
||||
@@ -245,12 +245,12 @@ class HqlQueryTransformerTests {
|
||||
""")).isEqualTo("o");
|
||||
}
|
||||
|
||||
@Test // DATAJPA-252
|
||||
@Test // DATAJPA-252, GH-664, GH-1066, GH-2960
|
||||
void doesNotPrefixOrderReferenceIfOuterJoinAliasDetected() {
|
||||
|
||||
String query = "select p from Person p left join p.address address";
|
||||
Sort sort = Sort.by("address.city");
|
||||
assertThat(createQueryFor(query, sort)).endsWith("order by p.address.city asc");
|
||||
assertThat(createQueryFor(query, sort)).endsWith("order by address.city asc");
|
||||
}
|
||||
|
||||
@Test // DATAJPA-252
|
||||
@@ -986,6 +986,26 @@ class HqlQueryTransformerTests {
|
||||
assertThat(createQueryFor(query, Sort.unsorted())).isEqualToIgnoringWhitespace(query);
|
||||
}
|
||||
|
||||
@Test // GH-664, GH-1066, GH-2960
|
||||
void sortingRecognizesJoinAliases() {
|
||||
|
||||
String query = "select p from Customer c join c.productOrder p where p.delayed = true";
|
||||
|
||||
assertThat(createQueryFor(query, Sort.by(Sort.Order.desc("lastName")))).isEqualToIgnoringWhitespace("""
|
||||
select p from Customer c
|
||||
join c.productOrder p
|
||||
where p.delayed = true
|
||||
order by c.lastName desc
|
||||
""");
|
||||
|
||||
assertThat(createQueryFor(query, Sort.by(Sort.Order.desc("p.lineItems")))).isEqualToIgnoringWhitespace("""
|
||||
select p from Customer c
|
||||
join c.productOrder p
|
||||
where p.delayed = true
|
||||
order by p.lineItems desc
|
||||
""");
|
||||
}
|
||||
|
||||
private void assertCountQuery(String originalQuery, String countQuery) {
|
||||
assertThat(createCountQueryFor(originalQuery)).isEqualTo(countQuery);
|
||||
}
|
||||
|
||||
@@ -235,12 +235,12 @@ class JpqlQueryTransformerTests {
|
||||
""")).isEqualTo("o");
|
||||
}
|
||||
|
||||
@Test // DATAJPA-252
|
||||
@Test // DATAJPA-252, GH-664, GH-1066, GH-2960
|
||||
void doesNotPrefixOrderReferenceIfOuterJoinAliasDetected() {
|
||||
|
||||
String query = "select p from Person p left join p.address address";
|
||||
Sort sort = Sort.by("address.city");
|
||||
assertThat(createQueryFor(query, sort)).endsWith("order by p.address.city asc");
|
||||
assertThat(createQueryFor(query, sort)).endsWith("order by address.city asc");
|
||||
}
|
||||
|
||||
@Test // DATAJPA-252
|
||||
@@ -742,6 +742,26 @@ class JpqlQueryTransformerTests {
|
||||
""", relationshipName, joinAlias, joinAlias));
|
||||
}
|
||||
|
||||
@Test // GH-664, GH-1066, GH-2960
|
||||
void sortingRecognizesJoinAliases() {
|
||||
|
||||
String query = "select p from Customer c join c.productOrder p where p.delayed = true";
|
||||
|
||||
assertThat(createQueryFor(query, Sort.by(Sort.Order.desc("lastName")))).isEqualToIgnoringWhitespace("""
|
||||
select p from Customer c
|
||||
join c.productOrder p
|
||||
where p.delayed = true
|
||||
order by c.lastName desc
|
||||
""");
|
||||
|
||||
assertThat(createQueryFor(query, Sort.by(Sort.Order.desc("p.lineItems")))).isEqualToIgnoringWhitespace("""
|
||||
select p from Customer c
|
||||
join c.productOrder p
|
||||
where p.delayed = true
|
||||
order by p.lineItems desc
|
||||
""");
|
||||
}
|
||||
|
||||
static Stream<Arguments> queriesWithReservedWordsAsIdentifiers() {
|
||||
|
||||
return Stream.of( //
|
||||
|
||||
Reference in New Issue
Block a user