Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide more expressive exception for projections without properties. #1896

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-relational-parent</artifactId>
<version>3.4.0-SNAPSHOT</version>
<version>3.4.0-1813-improve-error-message-SNAPSHOT</version>
<packaging>pom</packaging>

<name>Spring Data Relational Parent</name>
Expand Down
2 changes: 1 addition & 1 deletion spring-data-jdbc-distribution/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-relational-parent</artifactId>
<version>3.4.0-SNAPSHOT</version>
<version>3.4.0-1813-improve-error-message-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
4 changes: 2 additions & 2 deletions spring-data-jdbc/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<modelVersion>4.0.0</modelVersion>

<artifactId>spring-data-jdbc</artifactId>
<version>3.4.0-SNAPSHOT</version>
<version>3.4.0-1813-improve-error-message-SNAPSHOT</version>

<name>Spring Data JDBC</name>
<description>Spring Data module for JDBC repositories.</description>
Expand All @@ -15,7 +15,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-relational-parent</artifactId>
<version>3.4.0-SNAPSHOT</version>
<version>3.4.0-1813-improve-error-message-SNAPSHOT</version>
</parent>

<properties>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
import org.springframework.data.relational.core.query.Criteria;
import org.springframework.data.relational.core.sql.Column;
import org.springframework.data.relational.core.sql.EmptySelectListException;
import org.springframework.data.relational.core.sql.Expression;
import org.springframework.data.relational.core.sql.Expressions;
import org.springframework.data.relational.core.sql.Functions;
Expand Down Expand Up @@ -177,13 +178,23 @@ protected ParametrizedQuery complete(@Nullable Criteria criteria, Sort sort) {
completedBuildSelect = selectOrderBuilder.lock(this.lockMode.get().value());
}

Select select = completedBuildSelect.build();
Select select = getSelect(completedBuildSelect);

String sql = SqlRenderer.create(renderContextFactory.createRenderContext()).render(select);

return new ParametrizedQuery(sql, parameterSource);
}

private Select getSelect(SelectBuilder.BuildSelect completedBuildSelect) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the selection list empty in the first place? I'd assume that we pass-thru ReturnedType.InputProperties without checking whether these are empty.


try {
return completedBuildSelect.build();
} catch (EmptySelectListException cause) {
throw new IllegalStateException(
returnedType.getReturnedType().getName() + " does not define any properties to select", cause);
}
}

SelectBuilder.SelectOrdered applyOrderBy(Sort sort, RelationalPersistentEntity<?> entity, Table table,
SelectBuilder.SelectOrdered selectOrdered) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.ApplicationListener;
Expand All @@ -51,16 +50,7 @@
import org.springframework.core.io.ClassPathResource;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.data.annotation.Id;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.domain.Limit;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.ScrollPosition;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Window;
import org.springframework.data.domain.*;
import org.springframework.data.jdbc.core.mapping.AggregateReference;
import org.springframework.data.jdbc.repository.query.Modifying;
import org.springframework.data.jdbc.repository.query.Query;
Expand Down Expand Up @@ -572,6 +562,24 @@ public void partTreeQueryProjectionShouldReturnProjectedEntities() {
assertThat(result.get(0).getName()).isEqualTo("Entity Name");
}

@Test // GH-1813
public void partTreeQueryDynamicProjectionShouldReturnProjectedEntities() {

repository.save(createDummyEntity());

List<DummyProjection> result = repository.findDynamicProjectedByName("Entity Name", DummyProjection.class);

assertThat(result).hasSize(1);
assertThat(result.get(0).getName()).isEqualTo("Entity Name");
}

@Test // GH-1813
public void partTreeQueryDynamicProjectionWithBrokenProjectionShouldError() {

assertThatThrownBy(() -> repository.findDynamicProjectedByName("Entity Name", BrokenProjection.class))
.hasMessageContaining("BrokenProjection does not define any properties to select");
}

@Test // GH-971
public void pageQueryProjectionShouldReturnProjectedEntities() {

Expand Down Expand Up @@ -1428,6 +1436,8 @@ interface DummyEntityRepository extends CrudRepository<DummyEntity, Long>, Query

List<DummyProjection> findProjectedByName(String name);

<T> List<T> findDynamicProjectedByName(String name, Class<T> projection);

@Query(value = "SELECT * FROM DUMMY_ENTITY", rowMapperClass = CustomRowMapper.class)
List<DummyEntity> findAllWithCustomMapper();

Expand Down Expand Up @@ -1941,6 +1951,10 @@ interface DummyProjection {
String getName();
}

interface BrokenProjection {
String name();
}

static final class DtoProjection {
private final String name;

Expand Down
4 changes: 2 additions & 2 deletions spring-data-r2dbc/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<modelVersion>4.0.0</modelVersion>

<artifactId>spring-data-r2dbc</artifactId>
<version>3.4.0-SNAPSHOT</version>
<version>3.4.0-1813-improve-error-message-SNAPSHOT</version>

<name>Spring Data R2DBC</name>
<description>Spring Data module for R2DBC</description>
Expand All @@ -15,7 +15,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-relational-parent</artifactId>
<version>3.4.0-SNAPSHOT</version>
<version>3.4.0-1813-improve-error-message-SNAPSHOT</version>
</parent>

<properties>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
Expand All @@ -51,14 +50,12 @@
@ExtendWith(SpringExtension.class)
public class ProjectingRepositoryIntegrationTests {

@Autowired
private ImmutableObjectRepository repository;
@Autowired private ImmutableObjectRepository repository;
private JdbcTemplate jdbc;

@Configuration
@EnableR2dbcRepositories(
includeFilters = @ComponentScan.Filter(value = ImmutableObjectRepository.class, type = FilterType.ASSIGNABLE_TYPE),
considerNestedRepositories = true)
@EnableR2dbcRepositories(includeFilters = @ComponentScan.Filter(value = ImmutableObjectRepository.class,
type = FilterType.ASSIGNABLE_TYPE), considerNestedRepositories = true)
static class TestConfiguration extends AbstractR2dbcConfiguration {
@Override
public ConnectionFactory connectionFactory() {
Expand All @@ -74,9 +71,7 @@ void before() {

try {
this.jdbc.execute("DROP TABLE immutable_non_null");
}
catch (DataAccessException e) {
}
} catch (DataAccessException e) {}

this.jdbc.execute("CREATE TABLE immutable_non_null (id serial PRIMARY KEY, name varchar(255), email varchar(255))");
this.jdbc.execute("INSERT INTO immutable_non_null VALUES (42, 'Walter', 'heisenberg@the-white-family.com')");
Expand All @@ -100,8 +95,7 @@ protected ConnectionFactory createConnectionFactory() {
return H2TestSupport.createConnectionFactory();
}

@Test
// GH-1687
@Test // GH-1687
void shouldApplyProjectionDirectly() {

repository.findProjectionByEmail("heisenberg@the-white-family.com") //
Expand All @@ -111,8 +105,7 @@ void shouldApplyProjectionDirectly() {
}).verifyComplete();
}

@Test
// GH-1687
@Test // GH-1687
void shouldApplyEntityQueryProjectionDirectly() {

repository.findAllByEmail("heisenberg@the-white-family.com") //
Expand All @@ -134,8 +127,7 @@ interface ImmutableObjectRepository extends ReactiveCrudRepository<ImmutableNonN
@Table("immutable_non_null")
static class ImmutableNonNullEntity implements Person {

final @Nullable
@Id Integer id;
final @Nullable @Id Integer id;
final String name;
final String email;

Expand Down
4 changes: 2 additions & 2 deletions spring-data-relational/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
<modelVersion>4.0.0</modelVersion>

<artifactId>spring-data-relational</artifactId>
<version>3.4.0-SNAPSHOT</version>
<version>3.4.0-1813-improve-error-message-SNAPSHOT</version>

<name>Spring Data Relational</name>
<description>Spring Data Relational support</description>

<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-relational-parent</artifactId>
<version>3.4.0-SNAPSHOT</version>
<version>3.4.0-1813-improve-error-message-SNAPSHOT</version>
</parent>

<properties>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright 2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.data.relational.core.sql;

/**
* Exception denoting the absence of a select list from a query.
*
* @author Jens Schauder
* @since 3.4
*/
public class EmptySelectListException extends IllegalStateException {
public EmptySelectListException() {
super("SELECT does not declare a select list");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ private void doValidate(Select select) {
select.visit(this);

if (selectFieldCount == 0) {
throw new IllegalStateException("SELECT does not declare a select list");
throw new EmptySelectListException();
}

for (TableLike table : requiredBySelect) {
Expand Down
Loading