#305 - Consistently apply registered converters.

We now apply registered write converters to bindable values that are bound via bind(…) or provided through the Criteria/Update API.
This commit is contained in:
Mark Paluch
2020-02-17 12:48:47 +01:00
parent 6051ab11ae
commit 8828ebb11d
8 changed files with 280 additions and 13 deletions

View File

@@ -21,13 +21,23 @@ import io.r2dbc.spi.ConnectionFactory;
import lombok.Data;
import reactor.test.StepVerifier;
import java.util.Arrays;
import java.util.Collections;
import java.util.UUID;
import javax.sql.DataSource;
import org.junit.ClassRule;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.core.convert.converter.Converter;
import org.springframework.dao.DataAccessException;
import org.springframework.data.annotation.Id;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.convert.WritingConverter;
import org.springframework.data.r2dbc.dialect.MySqlDialect;
import org.springframework.data.r2dbc.query.Criteria;
import org.springframework.data.r2dbc.testing.ExternalDatabase;
import org.springframework.data.r2dbc.testing.MySqlTestSupport;
import org.springframework.data.relational.core.mapping.Table;
@@ -84,6 +94,58 @@ public class MySqlDatabaseClientIntegrationTests extends AbstractDatabaseClientI
.verifyComplete();
}
@Test // gh-305
public void shouldApplyCustomConverters() {
ConnectionFactory connectionFactory = createConnectionFactory();
JdbcTemplate jdbc = createJdbcTemplate(createDataSource());
ReactiveDataAccessStrategy strategy = new DefaultReactiveDataAccessStrategy(MySqlDialect.INSTANCE,
Arrays.asList(UuidToStringConverter.INSTANCE, StringToUuidConverter.INSTANCE));
try {
jdbc.execute("DROP TABLE uuid_type");
} catch (DataAccessException e) {}
jdbc.execute("CREATE TABLE uuid_type (id varchar(255), uuid_value varchar(255))");
UuidType uuidType = new UuidType();
uuidType.setId(UUID.randomUUID());
uuidType.setUuidValue(UUID.randomUUID());
DatabaseClient databaseClient = DatabaseClient.builder().connectionFactory(connectionFactory)
.dataAccessStrategy(strategy).build();
databaseClient.insert().into(UuidType.class).using(uuidType).then() //
.as(StepVerifier::create) //
.verifyComplete();
databaseClient.select().from(UuidType.class).matching(Criteria.where("id").is(uuidType.getId())) //
.fetch().first() //
.as(StepVerifier::create) //
.consumeNextWith(actual -> assertThat(actual.getUuidValue()).isEqualTo(uuidType.getUuidValue())) //
.verifyComplete();
uuidType.setUuidValue(null);
databaseClient.update().table(UuidType.class).using(uuidType).then() //
.as(StepVerifier::create) //
.verifyComplete();
databaseClient.execute("SELECT * FROM uuid_type WHERE id = ?") //
.bind(0, uuidType.getId()) //
.as(UuidType.class) //
.fetch().first() //
.as(StepVerifier::create) //
.consumeNextWith(actual -> assertThat(actual.getUuidValue()).isNull()) //
.verifyComplete();
databaseClient.execute("SELECT * FROM uuid_type WHERE id in (:ids)") //
.bind("ids", Collections.singleton(uuidType.getId())) //
.as(UuidType.class) //
.fetch().first() //
.as(StepVerifier::create) //
.consumeNextWith(actual -> assertThat(actual.getUuidValue()).isNull()) //
.verifyComplete();
}
@Ignore("https://github.com/mirromutth/r2dbc-mysql/issues/62")
@Test
@Override
@@ -96,7 +158,34 @@ public class MySqlDatabaseClientIntegrationTests extends AbstractDatabaseClientI
int id;
boolean flag1;
boolean flag2;
}
@Table("uuid_type")
@Data
static class UuidType {
@Id UUID id;
UUID uuidValue;
}
@WritingConverter
enum UuidToStringConverter implements Converter<UUID, String> {
INSTANCE;
@Override
public String convert(UUID uuid) {
return uuid.toString();
}
}
@ReadingConverter
enum StringToUuidConverter implements Converter<String, UUID> {
INSTANCE;
@Override
public UUID convert(String value) {
return UUID.fromString(value);
}
}
}

View File

@@ -0,0 +1,116 @@
/*
* Copyright 2020 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.r2dbc.core;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import java.util.Arrays;
import java.util.UUID;
import org.junit.Test;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.convert.WritingConverter;
import org.springframework.data.r2dbc.dialect.BindTarget;
import org.springframework.data.r2dbc.dialect.MySqlDialect;
import org.springframework.data.r2dbc.mapping.SettableValue;
import org.springframework.data.r2dbc.query.Criteria;
import org.springframework.data.r2dbc.query.Update;
/**
* Unit tests for {@link ReactiveDataAccessStrategy}.
*
* @author Mark Paluch
*/
public class ReactiveDataAccessStrategyTests {
BindTarget bindTarget = mock(BindTarget.class);
ReactiveDataAccessStrategy strategy = new DefaultReactiveDataAccessStrategy(MySqlDialect.INSTANCE,
Arrays.asList(UuidToStringConverter.INSTANCE, StringToUuidConverter.INSTANCE));
@Test // gh-305
public void shouldConvertSettableValue() {
UUID value = UUID.randomUUID();
assertThat(strategy.getBindValue(SettableValue.from(value))).isEqualTo(SettableValue.from(value.toString()));
assertThat(strategy.getBindValue(SettableValue.from(Condition.New))).isEqualTo(SettableValue.from("New"));
}
@Test // gh-305
public void shouldConvertEmptySettableValue() {
assertThat(strategy.getBindValue(SettableValue.empty(UUID.class))).isEqualTo(SettableValue.empty(String.class));
assertThat(strategy.getBindValue(SettableValue.empty(Condition.class)))
.isEqualTo(SettableValue.empty(String.class));
}
@Test // gh-305
public void shouldConvertCriteria() {
UUID value = UUID.randomUUID();
StatementMapper mapper = strategy.getStatementMapper();
StatementMapper.SelectSpec spec = mapper.createSelect("foo").withProjection("*")
.withCriteria(Criteria.where("id").is(value));
PreparedOperation<?> mappedObject = mapper.getMappedObject(spec);
mappedObject.bindTo(bindTarget);
verify(bindTarget).bind(0, value.toString());
}
@Test // gh-305
public void shouldConvertAssignment() {
UUID value = UUID.randomUUID();
StatementMapper mapper = strategy.getStatementMapper();
StatementMapper.UpdateSpec update = mapper.createUpdate("foo", Update.update("id", value));
PreparedOperation<?> mappedObject = mapper.getMappedObject(update);
mappedObject.bindTo(bindTarget);
verify(bindTarget).bind(0, value.toString());
}
@WritingConverter
enum UuidToStringConverter implements Converter<UUID, String> {
INSTANCE;
@Override
public String convert(UUID uuid) {
return uuid.toString();
}
}
@ReadingConverter
enum StringToUuidConverter implements Converter<String, UUID> {
INSTANCE;
@Override
public UUID convert(String value) {
return UUID.fromString(value);
}
}
enum Condition {
New, Used
}
}