#166 - Polishing.

Consider Dialect-specific converters also in DatabaseClient.create(…) factory. Reduce constant visibility. Add tests. Reformat code.

Original pull request: #168.
This commit is contained in:
Mark Paluch
2019-09-03 11:59:02 +02:00
parent 19f572f53b
commit ec8f540ed9
5 changed files with 76 additions and 20 deletions

View File

@@ -17,7 +17,9 @@ package org.springframework.data.r2dbc.config;
import io.r2dbc.spi.ConnectionFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.BeansException;
@@ -174,7 +176,11 @@ public abstract class AbstractR2dbcConfiguration implements ApplicationContextAw
protected StoreConversions getStoreConversions() {
R2dbcDialect dialect = getDialect(lookupConnectionFactory());
return StoreConversions.of(dialect.getSimpleTypeHolder(), dialect.getConverters(), R2dbcCustomConversions.STORE_CONVERTERS);
List<Object> converters = new ArrayList<>(dialect.getConverters());
converters.addAll(R2dbcCustomConversions.STORE_CONVERTERS);
return StoreConversions.of(dialect.getSimpleTypeHolder(), converters);
}
/**

View File

@@ -82,13 +82,23 @@ public class DefaultReactiveDataAccessStrategy implements ReactiveDataAccessStra
this(dialect, createConverter(dialect, converters));
}
/**
* Creates a new {@link R2dbcConverter} given {@link R2dbcDialect} and custom {@code converters}.
*
* @param dialect must not be {@literal null}.
* @param converters must not be {@literal null}.
* @return the {@link R2dbcConverter}.
*/
public static R2dbcConverter createConverter(R2dbcDialect dialect, Collection<?> converters) {
Assert.notNull(dialect, "Dialect must not be null");
Assert.notNull(converters, "Converters must not be null");
List<Object> storeConverters = new ArrayList<>(dialect.getConverters());
storeConverters.addAll(R2dbcCustomConversions.STORE_CONVERTERS);
R2dbcCustomConversions customConversions = new R2dbcCustomConversions(
StoreConversions.of(dialect.getSimpleTypeHolder(), R2dbcCustomConversions.STORE_CONVERTERS), converters);
StoreConversions.of(dialect.getSimpleTypeHolder(), storeConverters), storeConverters);
RelationalMappingContext context = new RelationalMappingContext();
context.setSimpleTypeHolder(customConversions.getSimpleTypeHolder());

View File

@@ -18,7 +18,6 @@ package org.springframework.data.r2dbc.dialect;
import java.net.InetAddress;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -26,6 +25,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import org.springframework.core.convert.converter.Converter;
/**
@@ -45,19 +45,11 @@ public class MySqlDialect extends org.springframework.data.relational.core.diale
public static final MySqlDialect INSTANCE = new MySqlDialect();
private static final BindMarkersFactory ANONYMOUS = BindMarkersFactory.anonymous("?");
/**
* MySql specific converters.
* MySQL specific converters.
*/
public static final List<Object> CONVERTERS;
static {
List<Object> converters = new ArrayList<>();
converters.add(ByteToBooleanConverter.INSTANCE);
CONVERTERS = Collections.unmodifiableList(converters);
}
private static final List<Object> CONVERTERS = Collections.singletonList(ByteToBooleanConverter.INSTANCE);
/*
* (non-Javadoc)
@@ -76,7 +68,7 @@ public class MySqlDialect extends org.springframework.data.relational.core.diale
public Collection<? extends Class<?>> getSimpleTypes() {
return SIMPLE_TYPES;
}
/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.dialect.R2dbcDialect#getConverters()
@@ -85,11 +77,10 @@ public class MySqlDialect extends org.springframework.data.relational.core.diale
public Collection<Object> getConverters() {
return CONVERTERS;
}
/**
* Simple singleton to convert {@link Byte}s to their {@link Boolean}
* representation. MySQL does not have a built in boolean type by default,
* so relies on using a byte instead. Non-zero values represent true.
* Simple singleton to convert {@link Byte}s to their {@link Boolean} representation. MySQL does not have a built-in
* boolean type by default, so relies on using a byte instead. Non-zero values represent {@literal true}.
*
* @author Michael Berry
*/
@@ -99,9 +90,11 @@ public class MySqlDialect extends org.springframework.data.relational.core.diale
@Override
public Boolean convert(Byte s) {
if (s == null) {
return null;
}
return s != 0;
}
}

View File

@@ -14,6 +14,7 @@ import org.springframework.data.relational.core.dialect.Dialect;
*
* @author Mark Paluch
* @author Jens Schauder
* @author Michael Berry
*/
public interface R2dbcDialect extends Dialect {
@@ -51,7 +52,7 @@ public interface R2dbcDialect extends Dialect {
/**
* Return a collection of converters for this dialect.
*
*
* @return a collection of converters for this dialect.
*/
default Collection<Object> getConverters() {

View File

@@ -15,14 +15,22 @@
*/
package org.springframework.data.r2dbc.core;
import static org.assertj.core.api.Assertions.*;
import io.r2dbc.spi.ConnectionFactory;
import lombok.Data;
import reactor.test.StepVerifier;
import javax.sql.DataSource;
import org.junit.ClassRule;
import org.junit.Test;
import org.springframework.dao.DataAccessException;
import org.springframework.data.r2dbc.testing.ExternalDatabase;
import org.springframework.data.r2dbc.testing.MySqlTestSupport;
import org.springframework.data.relational.core.mapping.Table;
import org.springframework.jdbc.core.JdbcTemplate;
/**
* Integration tests for {@link DatabaseClient} against MySQL.
@@ -47,4 +55,42 @@ public class MySqlDatabaseClientIntegrationTests extends AbstractDatabaseClientI
protected String getCreateTableStatement() {
return MySqlTestSupport.CREATE_TABLE_LEGOSET;
}
@Test // gh-166
public void considersBuiltInConverters() {
ConnectionFactory connectionFactory = createConnectionFactory();
JdbcTemplate jdbc = createJdbcTemplate(createDataSource());
try {
jdbc.execute("DROP TABLE boolean_mapping");
} catch (DataAccessException e) {}
jdbc.execute("CREATE TABLE boolean_mapping (id int, flag1 TINYINT, flag2 TINYINT)");
BooleanMapping mapping = new BooleanMapping();
mapping.setId(42);
mapping.setFlag1(true);
DatabaseClient databaseClient = DatabaseClient.create(connectionFactory);
databaseClient.insert().into(BooleanMapping.class).using(mapping).then() //
.as(StepVerifier::create) //
.verifyComplete();
databaseClient.select().from(BooleanMapping.class).fetch().first() //
.as(StepVerifier::create) //
.consumeNextWith(actual -> assertThat(actual.isFlag1()).isTrue()) //
.verifyComplete();
}
@Table("boolean_mapping")
@Data
static class BooleanMapping {
int id;
boolean flag1;
boolean flag2;
}
}