Skip to content

Commit 430d984

Browse files
committed
#109 - Fix simple type conversion for projection queries.
We now correctly consider built-in converters for simple types that are read through DatabaseClient. Simple type projections typically select a single column and expect a result stream of simple values such as selecting a count and retrieving a Mono<Long>.
1 parent 4a46692 commit 430d984

File tree

3 files changed

+146
-2
lines changed

3 files changed

+146
-2
lines changed

src/main/java/org/springframework/data/r2dbc/core/DefaultReactiveDataAccessStrategy.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ private static R2dbcConverter createConverter(Dialect dialect) {
7676
Assert.notNull(dialect, "Dialect must not be null");
7777

7878
R2dbcCustomConversions customConversions = new R2dbcCustomConversions(
79-
StoreConversions.of(dialect.getSimpleTypeHolder()), Collections.emptyList());
79+
StoreConversions.of(dialect.getSimpleTypeHolder(), R2dbcCustomConversions.STORE_CONVERTERS),
80+
Collections.emptyList());
8081

8182
RelationalMappingContext context = new RelationalMappingContext();
8283
context.setSimpleTypeHolder(customConversions.getSimpleTypeHolder());
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
* Copyright 2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.r2dbc.config;
17+
18+
import io.r2dbc.spi.ConnectionFactory;
19+
import lombok.AllArgsConstructor;
20+
import lombok.Data;
21+
import lombok.NoArgsConstructor;
22+
import reactor.core.publisher.Mono;
23+
import reactor.test.StepVerifier;
24+
25+
import org.junit.Before;
26+
import org.junit.Test;
27+
import org.junit.runner.RunWith;
28+
29+
import org.springframework.beans.factory.annotation.Autowired;
30+
import org.springframework.context.annotation.ComponentScan;
31+
import org.springframework.context.annotation.Configuration;
32+
import org.springframework.context.annotation.FilterType;
33+
import org.springframework.dao.DataAccessException;
34+
import org.springframework.data.annotation.Id;
35+
import org.springframework.data.r2dbc.core.DatabaseClient;
36+
import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories;
37+
import org.springframework.data.r2dbc.repository.query.Query;
38+
import org.springframework.data.r2dbc.testing.H2TestSupport;
39+
import org.springframework.data.relational.core.mapping.Table;
40+
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
41+
import org.springframework.jdbc.core.JdbcTemplate;
42+
import org.springframework.test.context.ContextConfiguration;
43+
import org.springframework.test.context.junit4.SpringRunner;
44+
45+
/**
46+
* Integration test for {@link DatabaseClient} and repositories using H2.
47+
*
48+
* @author Mark Paluch
49+
*/
50+
@RunWith(SpringRunner.class)
51+
@ContextConfiguration
52+
public class H2IntegrationTests {
53+
54+
private JdbcTemplate jdbc = new JdbcTemplate(H2TestSupport.createDataSource());
55+
56+
@Autowired DatabaseClient databaseClient;
57+
@Autowired H2Repository repository;
58+
59+
@Before
60+
public void before() {
61+
62+
try {
63+
jdbc.execute("DROP TABLE legoset");
64+
} catch (DataAccessException e) {}
65+
jdbc.execute(H2TestSupport.CREATE_TABLE_LEGOSET);
66+
}
67+
68+
@Test // gh-109
69+
public void shouldSelectCountWithDatabaseClient() {
70+
71+
jdbc.execute("INSERT INTO legoset (id, name, manual) VALUES(42055, 'SCHAUFELRADBAGGER', 12)");
72+
73+
databaseClient.execute().sql("SELECT COUNT(*) FROM legoset") //
74+
.as(Long.class) //
75+
.fetch() //
76+
.all() //
77+
.as(StepVerifier::create) //
78+
.expectNext(1L) //
79+
.verifyComplete();
80+
}
81+
82+
@Test // gh-109
83+
public void shouldSelectCountWithRepository() {
84+
85+
jdbc.execute("INSERT INTO legoset (id, name, manual) VALUES(42055, 'SCHAUFELRADBAGGER', 12)");
86+
87+
repository.selectCount() //
88+
.as(StepVerifier::create) //
89+
.expectNext(1L) //
90+
.verifyComplete();
91+
}
92+
93+
@Configuration
94+
@EnableR2dbcRepositories(considerNestedRepositories = true,
95+
includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = H2Repository.class),
96+
basePackageClasses = H2Repository.class)
97+
static class H2Configuration extends AbstractR2dbcConfiguration {
98+
99+
@Override
100+
public ConnectionFactory connectionFactory() {
101+
return H2TestSupport.createConnectionFactory();
102+
}
103+
}
104+
105+
interface H2Repository extends ReactiveCrudRepository<LegoSet, Integer> {
106+
107+
@Query("SELECT COUNT(*) FROM legoset")
108+
Mono<Long> selectCount();
109+
}
110+
111+
@Data
112+
@Table("legoset")
113+
@AllArgsConstructor
114+
@NoArgsConstructor
115+
static class LegoSet {
116+
@Id Integer id;
117+
String name;
118+
Integer manual;
119+
}
120+
}

src/test/java/org/springframework/data/r2dbc/core/AbstractDatabaseClientIntegrationTests.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import org.springframework.data.annotation.Id;
3434
import org.springframework.data.domain.PageRequest;
3535
import org.springframework.data.domain.Sort;
36-
import org.springframework.data.r2dbc.core.DatabaseClient;
3736
import org.springframework.data.r2dbc.query.Criteria;
3837
import org.springframework.data.r2dbc.query.Update;
3938
import org.springframework.data.r2dbc.testing.R2dbcIntegrationTestSupport;
@@ -340,6 +339,30 @@ public void selectExtracting() {
340339
.verifyComplete();
341340
}
342341

342+
@Test // gh-109
343+
public void selectSimpleTypeProjection() {
344+
345+
jdbc.execute("INSERT INTO legoset (id, name, manual) VALUES(42055, 'SCHAUFELRADBAGGER', 12)");
346+
347+
DatabaseClient databaseClient = DatabaseClient.create(connectionFactory);
348+
349+
databaseClient.execute().sql("SELECT COUNT(*) FROM legoset") //
350+
.as(Long.class) //
351+
.fetch() //
352+
.all() //
353+
.as(StepVerifier::create) //
354+
.expectNext(1L) //
355+
.verifyComplete();
356+
357+
databaseClient.execute().sql("SELECT name FROM legoset") //
358+
.as(String.class) //
359+
.fetch() //
360+
.one() //
361+
.as(StepVerifier::create) //
362+
.expectNext("SCHAUFELRADBAGGER") //
363+
.verifyComplete();
364+
}
365+
343366
@Test // gh-8
344367
public void selectWithCriteria() {
345368

0 commit comments

Comments
 (0)