Skip to content

Commit 6e92f3e

Browse files
The raw tuple queries we fix :)
1 parent bf60749 commit 6e92f3e

File tree

2 files changed

+36
-8
lines changed

2 files changed

+36
-8
lines changed

spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryCreator.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import jakarta.persistence.criteria.CriteriaQuery;
2525
import jakarta.persistence.criteria.Expression;
2626
import jakarta.persistence.criteria.Predicate;
27+
import jakarta.persistence.metamodel.Attribute;
2728
import jakarta.persistence.metamodel.Bindable;
2829
import jakarta.persistence.metamodel.EntityType;
2930
import jakarta.persistence.metamodel.Metamodel;
@@ -33,6 +34,7 @@
3334
import java.util.Collection;
3435
import java.util.Iterator;
3536
import java.util.List;
37+
import java.util.stream.Collectors;
3638

3739
import org.springframework.data.domain.Sort;
3840
import org.springframework.data.jpa.domain.JpaSort;
@@ -215,12 +217,19 @@ private JpqlQueryBuilder.Select doSelect(Sort sort) {
215217

216218
if (returnedType.needsCustomConstruction()) {
217219

218-
Collection<String> requiredSelection = getRequiredSelection(sort, returnedType);
220+
Collection<String> requiredSelection = null;
221+
if (returnedType.getReturnedType().getPackageName().startsWith("java.util")
222+
|| returnedType.getReturnedType().getPackageName().startsWith("jakarta.persistence")) {
223+
requiredSelection = metamodel.managedType(returnedType.getDomainType()).getAttributes().stream()
224+
.map(Attribute::getName).collect(Collectors.toList());
225+
} else {
226+
requiredSelection = getRequiredSelection(sort, returnedType);
227+
}
219228

220229
List<PathAndOrigin> paths = new ArrayList<>(requiredSelection.size());
221230
for (String selection : requiredSelection) {
222-
paths.add(
223-
JpqlUtils.toExpressionRecursively(metamodel, entity, entityType, PropertyPath.from(selection, returnedType.getDomainType()), true));
231+
paths.add(JpqlUtils.toExpressionRecursively(metamodel, entity, entityType,
232+
PropertyPath.from(selection, returnedType.getDomainType()), true));
224233
}
225234

226235
if (useTupleQuery()) {
@@ -236,8 +245,8 @@ private JpqlQueryBuilder.Select doSelect(Sort sort) {
236245
if (entityType.hasSingleIdAttribute()) {
237246

238247
SingularAttribute<?, ?> id = entityType.getId(entityType.getIdType().getJavaType());
239-
return selectStep.select(
240-
JpqlUtils.toExpressionRecursively(metamodel, entity, entityType, PropertyPath.from(id.getName(), returnedType.getDomainType()), true));
248+
return selectStep.select(JpqlUtils.toExpressionRecursively(metamodel, entity, entityType,
249+
PropertyPath.from(id.getName(), returnedType.getDomainType()), true));
241250

242251
} else {
243252

spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryCreatorTests.java

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@
2424
import jakarta.persistence.Id;
2525
import jakarta.persistence.ManyToOne;
2626
import jakarta.persistence.OneToMany;
27+
import jakarta.persistence.Tuple;
2728
import jakarta.persistence.metamodel.Metamodel;
2829

2930
import java.util.ArrayList;
3031
import java.util.Date;
3132
import java.util.Iterator;
3233
import java.util.List;
34+
import java.util.Map;
3335
import java.util.function.Function;
3436

3537
import org.junit.jupiter.api.Disabled;
@@ -59,8 +61,8 @@
5961
*/
6062
class JpaQueryCreatorTests {
6163

62-
private static final TestMetaModel ORDER = TestMetaModel.hibernateModel(Order.class, LineItem.class, Product.class,
63-
Person.class);
64+
private static final TestMetaModel ORDER = TestMetaModel.hibernateModel(Order.class, LineItem.class, Product.class);
65+
private static final TestMetaModel PERSON = TestMetaModel.hibernateModel(Person.class);
6466

6567
static List<JpqlQueryTemplates> ignoreCaseTemplates = List.of(JpqlQueryTemplates.LOWER, JpqlQueryTemplates.UPPER);
6668

@@ -674,6 +676,22 @@ void interfaceProjection() {
674676
.validateQuery();
675677
}
676678

679+
@ParameterizedTest
680+
@ValueSource(classes = { Tuple.class, Map.class })
681+
void tupleProjection(Class<?> resultType) {
682+
683+
queryCreator(PERSON) //
684+
.forTree(Person.class, "findProjectionByFirstnameIs") //
685+
.returing(resultType) //
686+
.withParameters("chris") //
687+
.as(QueryCreatorTester::create) //
688+
.expectJpql("SELECT p.id id, p.firstname firstname, p.lastname lastname FROM %s p WHERE p.firstname = ?1",
689+
Person.class.getName()) //
690+
.validateQuery();
691+
}
692+
693+
// TODO: delete queries
694+
677695
QueryCreatorBuilder queryCreator(Metamodel metamodel) {
678696
return new DefaultCreatorBuilder(metamodel);
679697
}
@@ -764,7 +782,8 @@ static class LineItem {
764782
@jakarta.persistence.Entity
765783
static class Person {
766784
@Id Long id;
767-
String name;
785+
String firstname;
786+
String lastname;
768787
}
769788

770789
@jakarta.persistence.Entity

0 commit comments

Comments
 (0)