Build against Borca snapshots.
Remove MySQL support as the MySQL driver is not yet published. Update groupId for Postgres driver to org.postgresql. See #710
This commit is contained in:
10
pom.xml
10
pom.xml
@@ -33,7 +33,7 @@
|
||||
<r2dbc-spi-test.version>0.8.5.RELEASE</r2dbc-spi-test.version>
|
||||
<mssql-jdbc.version>7.1.2.jre8-preview</mssql-jdbc.version>
|
||||
<mariadb-jdbc.version>2.5.4</mariadb-jdbc.version>
|
||||
<r2dbc-releasetrain.version>Arabba-SR12</r2dbc-releasetrain.version>
|
||||
<r2dbc-releasetrain.version>Borca-BUILD-SNAPSHOT</r2dbc-releasetrain.version>
|
||||
<reactive-streams.version>1.0.3</reactive-streams.version>
|
||||
<netty>4.1.63.Final</netty>
|
||||
</properties>
|
||||
@@ -224,7 +224,7 @@
|
||||
<!-- R2DBC Drivers -->
|
||||
|
||||
<dependency>
|
||||
<groupId>io.r2dbc</groupId>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>r2dbc-postgresql</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
@@ -241,12 +241,6 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>dev.miku</groupId>
|
||||
<artifactId>r2dbc-mysql</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mariadb</groupId>
|
||||
<artifactId>r2dbc-mariadb</artifactId>
|
||||
|
||||
@@ -23,6 +23,8 @@ import java.util.UUID;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link DatabasePopulator} using H2.
|
||||
*
|
||||
@@ -40,6 +42,10 @@ class H2DatabasePopulatorIntegrationTests extends AbstractDatabaseInitialization
|
||||
return this.connectionFactory;
|
||||
}
|
||||
|
||||
Resource usersSchema() {
|
||||
return resource("users-schema-h2.sql");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRunScript() {
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import java.util.UUID;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
@@ -146,6 +147,11 @@ public class MariaDbDatabaseClientIntegrationTests extends AbstractDatabaseClien
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
@Disabled
|
||||
public void insertTypedObjectWithBinary() {}
|
||||
|
||||
@Table("boolean_mapping")
|
||||
@Data
|
||||
static class BooleanMapping {
|
||||
|
||||
@@ -1,186 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019-2021 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 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.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
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.testing.ExternalDatabase;
|
||||
import org.springframework.data.r2dbc.testing.MySqlTestSupport;
|
||||
import org.springframework.data.relational.core.mapping.Table;
|
||||
import org.springframework.data.relational.core.query.Criteria;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link DatabaseClient} against MySQL.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Mingyuan Wu
|
||||
*/
|
||||
public class MySqlDatabaseClientIntegrationTests extends AbstractDatabaseClientIntegrationTests {
|
||||
|
||||
@RegisterExtension public static final ExternalDatabase database = MySqlTestSupport.database();
|
||||
|
||||
@Override
|
||||
protected DataSource createDataSource() {
|
||||
return MySqlTestSupport.createDataSource(database);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConnectionFactory createConnectionFactory() {
|
||||
return MySqlTestSupport.createConnectionFactory(database);
|
||||
}
|
||||
|
||||
@Override
|
||||
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();
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
|
||||
@Table("boolean_mapping")
|
||||
@Data
|
||||
static class BooleanMapping {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019-2021 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 io.r2dbc.spi.ConnectionFactory;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
import org.springframework.data.r2dbc.testing.ExternalDatabase;
|
||||
import org.springframework.data.r2dbc.testing.MySqlTestSupport;
|
||||
import org.springframework.r2dbc.core.DatabaseClient;
|
||||
|
||||
/**
|
||||
* Transactional integration tests for {@link DatabaseClient} against MySQL.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class MySqlTransactionalDatabaseClientIntegrationTests
|
||||
extends AbstractTransactionalDatabaseClientIntegrationTests {
|
||||
|
||||
@RegisterExtension public static final ExternalDatabase database = MySqlTestSupport.database();
|
||||
|
||||
@Override
|
||||
protected DataSource createDataSource() {
|
||||
return MySqlTestSupport.createDataSource(database);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConnectionFactory createConnectionFactory() {
|
||||
return MySqlTestSupport.createConnectionFactory(database);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCreateTableStatement() {
|
||||
return MySqlTestSupport.CREATE_TABLE_LEGOSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Mono<Void> prepareForTransaction(DatabaseClient client) {
|
||||
|
||||
/*
|
||||
* We have to execute a sql statement first.
|
||||
* Otherwise MySql don't have a transaction id.
|
||||
* And we need to delay emitting the result so that MySql has time to write the transaction id, which is done in
|
||||
* batches every now and then.
|
||||
* @see: https://dev.mysql.com/doc/refman/5.7/en/innodb-information-schema-internal-data.html
|
||||
*/
|
||||
return client.sql(getInsertIntoLegosetStatement()) //
|
||||
.bind(0, 42055) //
|
||||
.bind(1, "SCHAUFELRADBAGGER") //
|
||||
.bindNull(2, Integer.class) //
|
||||
.fetch().rowsUpdated() //
|
||||
.delayElement(Duration.ofMillis(50)) //
|
||||
.then();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCurrentTransactionIdStatement() {
|
||||
return "SELECT tx.trx_id FROM information_schema.innodb_trx tx WHERE tx.trx_mysql_thread_id = connection_id()";
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,6 @@ package org.springframework.data.r2dbc.dialect;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import dev.miku.r2dbc.mysql.MySqlConnectionConfiguration;
|
||||
import dev.miku.r2dbc.mysql.MySqlConnectionFactory;
|
||||
import io.r2dbc.h2.H2ConnectionConfiguration;
|
||||
import io.r2dbc.h2.H2ConnectionFactory;
|
||||
import io.r2dbc.mssql.MssqlConnectionConfiguration;
|
||||
@@ -40,13 +38,10 @@ public class DialectResolverUnitTests {
|
||||
MssqlConnectionFactory mssql = new MssqlConnectionFactory(MssqlConnectionConfiguration.builder().host("localhost")
|
||||
.database("foo").username("bar").password("password").build());
|
||||
H2ConnectionFactory h2 = new H2ConnectionFactory(H2ConnectionConfiguration.builder().inMemory("mem").build());
|
||||
MySqlConnectionFactory mysql = MySqlConnectionFactory
|
||||
.from(MySqlConnectionConfiguration.builder().host("localhost").username("mysql").build());
|
||||
|
||||
assertThat(DialectResolver.getDialect(postgres)).isEqualTo(PostgresDialect.INSTANCE);
|
||||
assertThat(DialectResolver.getDialect(mssql)).isEqualTo(SqlServerDialect.INSTANCE);
|
||||
assertThat(DialectResolver.getDialect(h2)).isEqualTo(H2Dialect.INSTANCE);
|
||||
assertThat(DialectResolver.getDialect(mysql)).isEqualTo(MySqlDialect.INSTANCE);
|
||||
}
|
||||
|
||||
@Test // gh-20, gh-104
|
||||
|
||||
@@ -24,6 +24,7 @@ import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.Value;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Hooks;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
@@ -60,6 +61,10 @@ import org.springframework.transaction.reactive.TransactionalOperator;
|
||||
*/
|
||||
public abstract class AbstractR2dbcRepositoryIntegrationTests extends R2dbcIntegrationTestSupport {
|
||||
|
||||
static {
|
||||
Hooks.onOperatorDebug();
|
||||
}
|
||||
|
||||
@Autowired private LegoSetRepository repository;
|
||||
@Autowired private ConnectionFactory connectionFactory;
|
||||
protected JdbcTemplate jdbc;
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019-2021 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.repository;
|
||||
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan.Filter;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.FilterType;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration;
|
||||
import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories;
|
||||
import org.springframework.data.r2dbc.repository.support.R2dbcRepositoryFactory;
|
||||
import org.springframework.data.r2dbc.testing.ExternalDatabase;
|
||||
import org.springframework.data.r2dbc.testing.MySqlTestSupport;
|
||||
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link LegoSetRepository} using {@link R2dbcRepositoryFactory} against MySQL.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@ContextConfiguration
|
||||
public class MySqlR2dbcRepositoryIntegrationTests extends AbstractR2dbcRepositoryIntegrationTests {
|
||||
|
||||
@RegisterExtension public static final ExternalDatabase database = MySqlTestSupport.database();
|
||||
|
||||
@Autowired DateTestsRepository dateTestsRepository;
|
||||
|
||||
@Configuration
|
||||
@EnableR2dbcRepositories(considerNestedRepositories = true,
|
||||
includeFilters = { @Filter(classes = MySqlLegoSetRepository.class, type = FilterType.ASSIGNABLE_TYPE),
|
||||
@Filter(classes = DateTestsRepository.class, type = FilterType.ASSIGNABLE_TYPE) })
|
||||
static class IntegrationTestConfiguration extends AbstractR2dbcConfiguration {
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
public ConnectionFactory connectionFactory() {
|
||||
return MySqlTestSupport.createConnectionFactory(database);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DataSource createDataSource() {
|
||||
return MySqlTestSupport.createDataSource(database);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConnectionFactory createConnectionFactory() {
|
||||
return MySqlTestSupport.createConnectionFactory(database);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCreateTableStatement() {
|
||||
return MySqlTestSupport.CREATE_TABLE_LEGOSET_WITH_ID_GENERATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<? extends LegoSetRepository> getRepositoryInterfaceType() {
|
||||
return MySqlLegoSetRepository.class;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldUserJsr310Types() {
|
||||
|
||||
JdbcTemplate jdbcTemplate = createJdbcTemplate(createDataSource());
|
||||
|
||||
try {
|
||||
jdbcTemplate.execute("DROP TABLE date_tests");
|
||||
} catch (DataAccessException e) {}
|
||||
|
||||
jdbcTemplate.execute("CREATE TABLE date_tests (id int, created_timestamp TIMESTAMP, created_date datetime);");
|
||||
|
||||
dateTestsRepository.save(new DateTests(null, LocalDateTime.now(), LocalDateTime.now())).as(StepVerifier::create)
|
||||
.expectNextCount(1).verifyComplete();
|
||||
}
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
static class DateTests {
|
||||
@Id Integer id;
|
||||
LocalDateTime createdTimestamp;
|
||||
LocalDateTime createdDate;
|
||||
}
|
||||
|
||||
interface MySqlLegoSetRepository extends LegoSetRepository {
|
||||
|
||||
@Override
|
||||
@Query("SELECT name FROM legoset")
|
||||
Flux<Named> findAsProjection();
|
||||
|
||||
@Override
|
||||
@Query("SELECT * FROM legoset WHERE manual = :manual")
|
||||
Mono<LegoSet> findByManual(int manual);
|
||||
|
||||
@Override
|
||||
@Query("SELECT id FROM legoset")
|
||||
Flux<Integer> findAllIds();
|
||||
}
|
||||
|
||||
interface DateTestsRepository extends ReactiveCrudRepository<DateTests, Integer> {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 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.repository;
|
||||
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan.Filter;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.FilterType;
|
||||
import org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration;
|
||||
import org.springframework.data.r2dbc.convert.R2dbcCustomConversions;
|
||||
import org.springframework.data.r2dbc.mapping.R2dbcMappingContext;
|
||||
import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories;
|
||||
import org.springframework.data.r2dbc.testing.ExternalDatabase;
|
||||
import org.springframework.data.r2dbc.testing.MySqlTestSupport;
|
||||
import org.springframework.data.relational.core.mapping.NamingStrategy;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link LegoSetRepository} with table and column names that contain upper and lower case
|
||||
* characters against MySql.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@ContextConfiguration
|
||||
public class MySqlR2dbcRepositoryWithMixedCaseNamesIntegrationTests
|
||||
extends AbstractR2dbcRepositoryWithMixedCaseNamesIntegrationTests {
|
||||
|
||||
@RegisterExtension public static final ExternalDatabase database = MySqlTestSupport.database();
|
||||
|
||||
@Configuration
|
||||
@EnableR2dbcRepositories(considerNestedRepositories = true,
|
||||
includeFilters = @Filter(classes = { LegoSetRepository.class }, type = FilterType.ASSIGNABLE_TYPE))
|
||||
static class IntegrationTestConfiguration extends AbstractR2dbcConfiguration {
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
public ConnectionFactory connectionFactory() {
|
||||
return MySqlTestSupport.createConnectionFactory(database);
|
||||
}
|
||||
|
||||
@Override
|
||||
public R2dbcMappingContext r2dbcMappingContext(Optional<NamingStrategy> namingStrategy,
|
||||
R2dbcCustomConversions r2dbcCustomConversions) {
|
||||
|
||||
R2dbcMappingContext r2dbcMappingContext = super.r2dbcMappingContext(namingStrategy, r2dbcCustomConversions);
|
||||
r2dbcMappingContext.setForceQuote(true);
|
||||
|
||||
return r2dbcMappingContext;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DataSource createDataSource() {
|
||||
return MySqlTestSupport.createDataSource(database);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConnectionFactory createConnectionFactory() {
|
||||
return MySqlTestSupport.createConnectionFactory(database);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCreateTableStatement() {
|
||||
return MySqlTestSupport.CREATE_TABLE_LEGOSET_WITH_MIXED_CASE_NAMES;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDropTableStatement() {
|
||||
return MySqlTestSupport.DROP_TABLE_LEGOSET_WITH_MIXED_CASE_NAMES;
|
||||
}
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019-2021 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.testing;
|
||||
|
||||
import dev.miku.r2dbc.mysql.MySqlConnectionFactoryProvider;
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
import io.r2dbc.spi.ConnectionFactoryOptions;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.data.r2dbc.testing.ExternalDatabase.ProvidedDatabase;
|
||||
|
||||
import org.testcontainers.containers.MySQLContainer;
|
||||
|
||||
import com.mysql.cj.jdbc.MysqlDataSource;
|
||||
|
||||
/**
|
||||
* Utility class for testing against MySQL.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Bogdan Ilchyshyn
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
public class MySqlTestSupport {
|
||||
|
||||
private static ExternalDatabase testContainerDatabase;
|
||||
|
||||
public static String CREATE_TABLE_LEGOSET = "CREATE TABLE legoset (\n" //
|
||||
+ " id integer PRIMARY KEY,\n" //
|
||||
+ " version integer NULL,\n" //
|
||||
+ " name varchar(255) NOT NULL,\n" //
|
||||
+ " manual integer NULL\n," //
|
||||
+ " cert varbinary(255) NULL\n" //
|
||||
+ ") ENGINE=InnoDB;";
|
||||
|
||||
public static String CREATE_TABLE_LEGOSET_WITH_ID_GENERATION = "CREATE TABLE legoset (\n" //
|
||||
+ " id integer AUTO_INCREMENT PRIMARY KEY,\n" //
|
||||
+ " version integer NULL,\n" //
|
||||
+ " name varchar(255) NOT NULL,\n" //
|
||||
+ " flag boolean NULL,\n" //
|
||||
+ " manual integer NULL\n" //
|
||||
+ ") ENGINE=InnoDB;";
|
||||
|
||||
|
||||
public static final String CREATE_TABLE_LEGOSET_WITH_MIXED_CASE_NAMES = "CREATE TABLE `LegoSet` (\n" //
|
||||
+ " `Id` integer AUTO_INCREMENT PRIMARY KEY,\n" //
|
||||
+ " `Name` varchar(255) NOT NULL,\n" //
|
||||
+ " `Manual` integer NULL\n" //
|
||||
+ ") ENGINE=InnoDB;";
|
||||
|
||||
public static final String DROP_TABLE_LEGOSET_WITH_MIXED_CASE_NAMES = "DROP TABLE LegoSet";
|
||||
/**
|
||||
* Returns a database either hosted locally or running inside Docker.
|
||||
*
|
||||
* @return information about the database. Guaranteed to be not {@literal null}.
|
||||
*/
|
||||
public static ExternalDatabase database() {
|
||||
|
||||
if (Boolean.getBoolean("spring.data.r2dbc.test.preferLocalDatabase")) {
|
||||
|
||||
return getFirstWorkingDatabase( //
|
||||
MySqlTestSupport::local, //
|
||||
MySqlTestSupport::testContainer //
|
||||
);
|
||||
} else {
|
||||
|
||||
return getFirstWorkingDatabase( //
|
||||
MySqlTestSupport::testContainer, //
|
||||
MySqlTestSupport::local //
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
private static ExternalDatabase getFirstWorkingDatabase(Supplier<ExternalDatabase>... suppliers) {
|
||||
|
||||
return Stream.of(suppliers).map(Supplier::get) //
|
||||
.filter(ExternalDatabase::checkValidity) //
|
||||
.findFirst() //
|
||||
.orElse(ExternalDatabase.unavailable());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a locally provided database.
|
||||
*/
|
||||
private static ExternalDatabase local() {
|
||||
|
||||
return ProvidedDatabase.builder() //
|
||||
.hostname("localhost") //
|
||||
.port(3306) //
|
||||
.database("mysql") //
|
||||
.username("root") //
|
||||
.password("my-secret-pw") //
|
||||
.jdbcUrl("jdbc:mysql://localhost:3306/mysql?allowPublicKeyRetrieval=true") //
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a database provided via Testcontainers.
|
||||
*/
|
||||
private static ExternalDatabase testContainer() {
|
||||
|
||||
if (testContainerDatabase == null) {
|
||||
|
||||
try {
|
||||
MySQLContainer container = new MySQLContainer("mysql:8.0.24");
|
||||
container.start();
|
||||
|
||||
testContainerDatabase = ProvidedDatabase.builder(container) //
|
||||
.database(container.getDatabaseName()) //
|
||||
.username("root") //
|
||||
.build();
|
||||
} catch (IllegalStateException ise) {
|
||||
// docker not available.
|
||||
testContainerDatabase = ExternalDatabase.unavailable();
|
||||
}
|
||||
}
|
||||
|
||||
return testContainerDatabase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new R2DBC MySQL {@link ConnectionFactory} configured from the {@link ExternalDatabase}.
|
||||
*/
|
||||
public static ConnectionFactory createConnectionFactory(ExternalDatabase database) {
|
||||
|
||||
ConnectionFactoryOptions options = ConnectionUtils.createOptions("mysql", database);
|
||||
return new MySqlConnectionFactoryProvider().create(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link DataSource} configured from the {@link ExternalDatabase}.
|
||||
*/
|
||||
public static DataSource createDataSource(ExternalDatabase database) {
|
||||
|
||||
MysqlDataSource dataSource = new MysqlDataSource();
|
||||
|
||||
dataSource.setUser(database.getUsername());
|
||||
dataSource.setPassword(database.getPassword());
|
||||
dataSource.setURL(database.getJdbcUrl() + "?useSSL=false&allowPublicKeyRetrieval=true");
|
||||
|
||||
return dataSource;
|
||||
}
|
||||
}
|
||||
@@ -23,10 +23,12 @@ import io.r2dbc.spi.ConnectionMetadata;
|
||||
import io.r2dbc.spi.IsolationLevel;
|
||||
import io.r2dbc.spi.Result;
|
||||
import io.r2dbc.spi.Statement;
|
||||
import io.r2dbc.spi.TransactionDefinition;
|
||||
import io.r2dbc.spi.ValidationDepth;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -156,11 +158,17 @@ public class StatementRecorder implements ConnectionFactory {
|
||||
}
|
||||
|
||||
class RecorderConnection implements Connection {
|
||||
|
||||
@Override
|
||||
public Publisher<Void> beginTransaction() {
|
||||
return createStatement("BEGIN").execute().then();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Publisher<Void> beginTransaction(TransactionDefinition definition) {
|
||||
return createStatement("BEGIN " + definition).execute().then();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Publisher<Void> close() {
|
||||
return createStatement("CLOSE").execute().then();
|
||||
@@ -238,6 +246,16 @@ public class StatementRecorder implements ConnectionFactory {
|
||||
return createStatement("SET AUTOCOMMIT " + autoCommit).execute().then();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Publisher<Void> setLockWaitTimeout(Duration timeout) {
|
||||
return createStatement("SET LOCK WAIT TIMEOUT " + timeout).execute().then();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Publisher<Void> setStatementTimeout(Duration timeout) {
|
||||
return createStatement("SET STATEMENT TIMEOUT " + timeout).execute().then();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Publisher<Void> setTransactionIsolationLevel(IsolationLevel isolationLevel) {
|
||||
return createStatement("SET TRANSACTION ISOLATION LEVEL " + isolationLevel.asSql()).execute().then();
|
||||
@@ -307,6 +325,16 @@ public class StatementRecorder implements ConnectionFactory {
|
||||
public Flux<Result> execute() {
|
||||
return Flux.fromIterable(results).doOnSubscribe(subscription -> executedStatements.add(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuffer sb = new StringBuffer();
|
||||
sb.append(getClass().getSimpleName());
|
||||
sb.append(" [sql='").append(sql).append('\'');
|
||||
sb.append(", bindings=").append(bindings);
|
||||
sb.append(']');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
DROP TABLE users IF EXISTS;
|
||||
|
||||
CREATE TABLE users
|
||||
(
|
||||
id INTEGER NOT NULL AUTO_INCREMENT,
|
||||
first_name VARCHAR(50) NOT NULL,
|
||||
last_name VARCHAR(50) NOT NULL
|
||||
);
|
||||
Reference in New Issue
Block a user