#104 - Provide extension mechanism for R2dbcDialect resolution.
We now use Spring's spring.factories mechanism to register and lookup R2dbcDialectProvider implementations. This allows a pluggable model for third party implementations to ship R2dbcDialect support that can be auto-discovered. Original pull request: #127.
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
:revdate: {localdate}
|
||||
ifdef::backend-epub3[:front-cover-image: image:epub-cover.png[Front Cover,1050,1600]]
|
||||
:spring-data-commons-docs: ../../../../spring-data-commons/src/main/asciidoc
|
||||
:spring-data-r2dbc-javadoc: https://docs.spring.io/spring-data/r2dbc/docs/{version}/api
|
||||
:reactiveStreamsJavadoc: https://www.reactive-streams.org/reactive-streams-{reactiveStreamsVersion}-javadoc
|
||||
|
||||
(C) 2018-2019 The original authors.
|
||||
|
||||
@@ -193,7 +193,7 @@ Even in this simple example, there are few things to notice:
|
||||
|
||||
There is a https://github.com/spring-projects/spring-data-examples[GitHub repository with several examples] that you can download and play around with to get a feel for how the library works.
|
||||
|
||||
[[r2dbc.drivers]]
|
||||
[[r2dbc.connecting]]
|
||||
== Connecting to a Relational Database with Spring
|
||||
|
||||
One of the first tasks when using relational databases and Spring is to create a `io.r2dbc.spi.ConnectionFactory` object using the IoC container. The following example explains Java-based configuration.
|
||||
@@ -235,6 +235,11 @@ As of writing the following drivers are available:
|
||||
* https://github.com/r2dbc/r2dbc-mssql[Microsoft SQL Server] (`io.r2dbc:r2dbc-mssql`)
|
||||
* https://github.com/jasync-sql/jasync-sql[jasync-sql MySQL] (`com.github.jasync-sql:jasync-r2dbc-mysql`)
|
||||
|
||||
Spring Data R2DBC reacts to database specifics by inspecting `ConnectionFactoryMetadata` exposed by the `ConnectionFactory` and selects the appropriate database dialect accordingly.
|
||||
You can configure an own https://docs.spring.io/spring-data/r2dbc/docs/{version}/api/org/springframework/data/r2dbc/dialect/R2dbcDialect.html[`R2dbcDialect`] if the used driver is not yet known to Spring Data R2DBC.
|
||||
Spring Data R2DBC reacts to database specifics by inspecting the `ConnectionFactory` and selects the appropriate database dialect accordingly.
|
||||
You can configure an own {spring-data-r2dbc-javadoc}/api/org/springframework/data/r2dbc/dialect/R2dbcDialect.html[`R2dbcDialect`] if the used driver is not yet known to Spring Data R2DBC.
|
||||
|
||||
TIP: Dialects are resolved by {spring-data-r2dbc-javadoc}/org/springframework/data/r2dbc/dialect/DialectResolver.html[`DialectResolver`] from a `ConnectionFactory`, typically by inspecting `ConnectionFactoryMetadata`. +
|
||||
+
|
||||
You can let Spring auto-discover your `R2dbcDialect` by registering a class that implements `org.springframework.data.r2dbc.dialect.DialectResolver$R2dbcDialectProvider` through `META-INF/spring.factories`. +
|
||||
`DialectResolver` discovers dialect provider implementations from the class path using Spring's `SpringFactoriesLoader`.
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ import org.springframework.data.r2dbc.convert.R2dbcCustomConversions;
|
||||
import org.springframework.data.r2dbc.core.DatabaseClient;
|
||||
import org.springframework.data.r2dbc.core.DefaultReactiveDataAccessStrategy;
|
||||
import org.springframework.data.r2dbc.core.ReactiveDataAccessStrategy;
|
||||
import org.springframework.data.r2dbc.dialect.Database;
|
||||
import org.springframework.data.r2dbc.dialect.DialectResolver;
|
||||
import org.springframework.data.r2dbc.dialect.R2dbcDialect;
|
||||
import org.springframework.data.r2dbc.support.R2dbcExceptionSubclassTranslator;
|
||||
import org.springframework.data.r2dbc.support.R2dbcExceptionTranslator;
|
||||
@@ -87,12 +87,7 @@ public abstract class AbstractR2dbcConfiguration implements ApplicationContextAw
|
||||
* @throws UnsupportedOperationException if the {@link R2dbcDialect} cannot be determined.
|
||||
*/
|
||||
public R2dbcDialect getDialect(ConnectionFactory connectionFactory) {
|
||||
|
||||
return Database.findDatabase(connectionFactory)
|
||||
.orElseThrow(() -> new UnsupportedOperationException(
|
||||
String.format("Cannot determine a dialect for %s using %s. Please provide a Dialect.",
|
||||
connectionFactory.getMetadata().getName(), connectionFactory)))
|
||||
.defaultDialect();
|
||||
return DialectResolver.getDialect(connectionFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,7 +21,7 @@ import io.r2dbc.spi.ConnectionFactory;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.springframework.data.r2dbc.core.DatabaseClient.Builder;
|
||||
import org.springframework.data.r2dbc.dialect.Database;
|
||||
import org.springframework.data.r2dbc.dialect.DialectResolver;
|
||||
import org.springframework.data.r2dbc.dialect.R2dbcDialect;
|
||||
import org.springframework.data.r2dbc.support.R2dbcExceptionSubclassTranslator;
|
||||
import org.springframework.data.r2dbc.support.R2dbcExceptionTranslator;
|
||||
@@ -121,10 +121,7 @@ class DefaultDatabaseClientBuilder implements DatabaseClient.Builder {
|
||||
|
||||
if (accessStrategy == null) {
|
||||
|
||||
R2dbcDialect dialect = Database.findDatabase(this.connectionFactory)
|
||||
.orElseThrow(() -> new UnsupportedOperationException(
|
||||
"Cannot determine a Dialect. Configure the dialect by providing DefaultReactiveDataAccessStrategy(Dialect)"))
|
||||
.defaultDialect();
|
||||
R2dbcDialect dialect = DialectResolver.getDialect(this.connectionFactory);
|
||||
accessStrategy = new DefaultReactiveDataAccessStrategy(dialect);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
package org.springframework.data.r2dbc.dialect;
|
||||
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
import io.r2dbc.spi.ConnectionFactoryMetadata;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Enumeration of known Databases for offline {@link R2dbcDialect} resolution. R2DBC
|
||||
* {@link io.r2dbc.spi.ConnectionFactory} provides {@link io.r2dbc.spi.ConnectionFactoryMetadata metadata} that allows
|
||||
* resolving an appropriate {@link R2dbcDialect} if none was configured explicitly.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
public enum Database {
|
||||
|
||||
POSTGRES {
|
||||
@Override
|
||||
public String driverName() {
|
||||
return "PostgreSQL";
|
||||
}
|
||||
|
||||
@Override
|
||||
public R2dbcDialect defaultDialect() {
|
||||
return PostgresDialect.INSTANCE;
|
||||
}
|
||||
},
|
||||
|
||||
SQL_SERVER {
|
||||
@Override
|
||||
public String driverName() {
|
||||
return "Microsoft SQL Server";
|
||||
}
|
||||
|
||||
@Override
|
||||
public R2dbcDialect defaultDialect() {
|
||||
return SqlServerDialect.INSTANCE;
|
||||
}
|
||||
},
|
||||
|
||||
H2 {
|
||||
@Override
|
||||
public String driverName() {
|
||||
return "H2";
|
||||
}
|
||||
|
||||
@Override
|
||||
public R2dbcDialect defaultDialect() {
|
||||
return H2Dialect.INSTANCE;
|
||||
}
|
||||
},
|
||||
|
||||
MYSQL {
|
||||
@Override
|
||||
public String driverName() {
|
||||
return "MySQL";
|
||||
}
|
||||
|
||||
@Override
|
||||
public R2dbcDialect defaultDialect() {
|
||||
return MySqlDialect.INSTANCE;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Find a {@link Database} type using {@link ConnectionFactory} and its metadata.
|
||||
*
|
||||
* @param connectionFactory must not be {@literal null}.
|
||||
* @return the resolved {@link Database} or {@link Optional#empty()} if the database type cannot be determined from
|
||||
* {@link ConnectionFactory}.
|
||||
*/
|
||||
public static Optional<Database> findDatabase(ConnectionFactory connectionFactory) {
|
||||
|
||||
Assert.notNull(connectionFactory, "ConnectionFactory must not be null!");
|
||||
|
||||
ConnectionFactoryMetadata metadata = connectionFactory.getMetadata();
|
||||
|
||||
return Arrays.stream(values()).filter(it -> matches(metadata, it.driverName())).findFirst();
|
||||
}
|
||||
|
||||
private static boolean matches(ConnectionFactoryMetadata metadata, String databaseType) {
|
||||
return metadata.getName().toLowerCase(Locale.ENGLISH).contains(databaseType.toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the driver name.
|
||||
*
|
||||
* @return the driver name.
|
||||
* @see ConnectionFactoryMetadata#getName()
|
||||
*/
|
||||
public abstract String driverName();
|
||||
|
||||
/**
|
||||
* Returns the latest {@link R2dbcDialect} for the underlying database.
|
||||
*
|
||||
* @return the latest {@link R2dbcDialect} for the underlying database.
|
||||
*/
|
||||
public abstract R2dbcDialect defaultDialect();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright 2019 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.dialect;
|
||||
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
import io.r2dbc.spi.ConnectionFactoryMetadata;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
import org.springframework.dao.NonTransientDataAccessException;
|
||||
import org.springframework.util.LinkedCaseInsensitiveMap;
|
||||
|
||||
/**
|
||||
* Resolves a {@link R2dbcDialect} from a {@link ConnectionFactory} using {@link R2dbcDialectProvider}. Dialect
|
||||
* resolution uses Spring's {@link SpringFactoriesLoader spring.factories} to determine available extensions.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @see R2dbcDialect
|
||||
* @see SpringFactoriesLoader
|
||||
*/
|
||||
public class DialectResolver {
|
||||
|
||||
private static final List<R2dbcDialectProvider> DETECTORS = SpringFactoriesLoader
|
||||
.loadFactories(R2dbcDialectProvider.class, DialectResolver.class.getClassLoader());
|
||||
|
||||
// utility constructor.
|
||||
private DialectResolver() {}
|
||||
|
||||
/**
|
||||
* Retrieve a {@link R2dbcDialect} by inspecting {@link ConnectionFactory} and its metadata.
|
||||
*
|
||||
* @param connectionFactory must not be {@literal null}.
|
||||
* @return the resolved {@link R2dbcDialect} {@link NoDialectException} if the database type cannot be determined from
|
||||
* {@link ConnectionFactory}.
|
||||
* @throws NoDialectException if no {@link R2dbcDialect} can be found.
|
||||
*/
|
||||
public static R2dbcDialect getDialect(ConnectionFactory connectionFactory) {
|
||||
|
||||
return DETECTORS.stream() //
|
||||
.map(it -> it.getDialect(connectionFactory)) //
|
||||
.filter(Optional::isPresent) //
|
||||
.findFirst() //
|
||||
.flatMap(it -> it) //
|
||||
.orElseThrow(() -> {
|
||||
return new NoDialectException(
|
||||
String.format("Cannot determine a dialect for %s using %s. Please provide a Dialect.",
|
||||
connectionFactory.getMetadata().getName(), connectionFactory));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* SPI to extend Spring's default R2DBC Dialect discovery mechanism. Implementations of this interface are discovered
|
||||
* through Spring's {@link SpringFactoriesLoader} mechanism.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @see org.springframework.core.io.support.SpringFactoriesLoader
|
||||
*/
|
||||
public interface R2dbcDialectProvider {
|
||||
|
||||
/**
|
||||
* Returns a {@link R2dbcDialect} for a {@link ConnectionFactory}.
|
||||
*
|
||||
* @param connectionFactory the connection factory to be used with the {@link R2dbcDialect}.
|
||||
* @return {@link Optional} containing the {@link R2dbcDialect} if the {@link R2dbcDialectProvider} can provide a
|
||||
* dialect object, otherwise {@link Optional#empty()}.
|
||||
*/
|
||||
Optional<R2dbcDialect> getDialect(ConnectionFactory connectionFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception thrown when {@link DialectResolver} cannot resolve a {@link R2dbcDialect}.
|
||||
*/
|
||||
public static class NoDialectException extends NonTransientDataAccessException {
|
||||
|
||||
/**
|
||||
* Constructor for NoDialectFoundException.
|
||||
*
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public NoDialectException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Built-in dialects. Used typically as last {@link R2dbcDialectProvider} when other providers register with a higher
|
||||
* precedence.
|
||||
*
|
||||
* @see org.springframework.core.Ordered
|
||||
* @see org.springframework.core.annotation.AnnotationAwareOrderComparator
|
||||
*/
|
||||
static class BuiltInDialectProvider implements R2dbcDialectProvider {
|
||||
|
||||
private static final Map<String, R2dbcDialect> BUILTIN = new LinkedCaseInsensitiveMap<>(Locale.ENGLISH);
|
||||
|
||||
static {
|
||||
BUILTIN.put("H2", H2Dialect.INSTANCE);
|
||||
BUILTIN.put("Microsoft SQL Server", SqlServerDialect.INSTANCE);
|
||||
BUILTIN.put("MySQL", MySqlDialect.INSTANCE);
|
||||
BUILTIN.put("PostgreSQL", PostgresDialect.INSTANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<R2dbcDialect> getDialect(ConnectionFactory connectionFactory) {
|
||||
|
||||
ConnectionFactoryMetadata metadata = connectionFactory.getMetadata();
|
||||
R2dbcDialect r2dbcDialect = BUILTIN.get(metadata.getName());
|
||||
|
||||
if (r2dbcDialect != null) {
|
||||
return Optional.of(r2dbcDialect);
|
||||
}
|
||||
|
||||
for (String key : BUILTIN.keySet()) {
|
||||
if (metadata.getName().contains(key)) {
|
||||
return Optional.of(BUILTIN.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
1
src/main/resources/META-INF/spring.factories
Normal file
1
src/main/resources/META-INF/spring.factories
Normal file
@@ -0,0 +1 @@
|
||||
org.springframework.data.r2dbc.dialect.DialectResolver$R2dbcDialectProvider=org.springframework.data.r2dbc.dialect.DialectResolver.BuiltInDialectProvider
|
||||
@@ -1,56 +0,0 @@
|
||||
package org.springframework.data.r2dbc.dialect;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import io.r2dbc.h2.H2ConnectionConfiguration;
|
||||
import io.r2dbc.h2.H2ConnectionFactory;
|
||||
import io.r2dbc.mssql.MssqlConnectionConfiguration;
|
||||
import io.r2dbc.mssql.MssqlConnectionFactory;
|
||||
import io.r2dbc.postgresql.PostgresqlConnectionConfiguration;
|
||||
import io.r2dbc.postgresql.PostgresqlConnectionFactory;
|
||||
import io.r2dbc.spi.Connection;
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
import io.r2dbc.spi.ConnectionFactoryMetadata;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.reactivestreams.Publisher;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link Database}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class DatabaseUnitTests {
|
||||
|
||||
@Test // gh-20
|
||||
public void shouldResolveDatabaseType() {
|
||||
|
||||
PostgresqlConnectionFactory postgres = new PostgresqlConnectionFactory(PostgresqlConnectionConfiguration.builder()
|
||||
.host("localhost").database("foo").username("bar").password("password").build());
|
||||
MssqlConnectionFactory mssql = new MssqlConnectionFactory(MssqlConnectionConfiguration.builder().host("localhost")
|
||||
.database("foo").username("bar").password("password").build());
|
||||
H2ConnectionFactory h2 = new H2ConnectionFactory(H2ConnectionConfiguration.builder().inMemory("mem").build());
|
||||
|
||||
assertThat(Database.findDatabase(postgres)).contains(Database.POSTGRES);
|
||||
assertThat(Database.findDatabase(mssql)).contains(Database.SQL_SERVER);
|
||||
assertThat(Database.findDatabase(h2)).contains(Database.H2);
|
||||
}
|
||||
|
||||
@Test // gh-20
|
||||
public void shouldNotResolveUnknownDatabase() {
|
||||
assertThat(Database.findDatabase(new UnknownConnectionFactory())).isEmpty();
|
||||
}
|
||||
|
||||
static class UnknownConnectionFactory implements ConnectionFactory {
|
||||
|
||||
@Override
|
||||
public Publisher<? extends Connection> create() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectionFactoryMetadata getMetadata() {
|
||||
return () -> "foo";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package org.springframework.data.r2dbc.dialect;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import io.r2dbc.h2.H2ConnectionConfiguration;
|
||||
import io.r2dbc.h2.H2ConnectionFactory;
|
||||
import io.r2dbc.mssql.MssqlConnectionConfiguration;
|
||||
import io.r2dbc.mssql.MssqlConnectionFactory;
|
||||
import io.r2dbc.postgresql.PostgresqlConnectionConfiguration;
|
||||
import io.r2dbc.postgresql.PostgresqlConnectionFactory;
|
||||
import io.r2dbc.spi.Connection;
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
import io.r2dbc.spi.ConnectionFactoryMetadata;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.reactivestreams.Publisher;
|
||||
|
||||
import org.springframework.data.relational.core.dialect.LimitClause;
|
||||
import org.springframework.data.relational.core.sql.render.SelectRenderContext;
|
||||
|
||||
import com.github.jasync.r2dbc.mysql.JasyncConnectionFactory;
|
||||
import com.github.jasync.sql.db.mysql.pool.MySQLConnectionFactory;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link DialectResolver}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class DialectResolverUnitTests {
|
||||
|
||||
@Test // gh-20, gh-104
|
||||
public void shouldResolveDatabaseType() {
|
||||
|
||||
PostgresqlConnectionFactory postgres = new PostgresqlConnectionFactory(PostgresqlConnectionConfiguration.builder()
|
||||
.host("localhost").database("foo").username("bar").password("password").build());
|
||||
MssqlConnectionFactory mssql = new MssqlConnectionFactory(MssqlConnectionConfiguration.builder().host("localhost")
|
||||
.database("foo").username("bar").password("password").build());
|
||||
H2ConnectionFactory h2 = new H2ConnectionFactory(H2ConnectionConfiguration.builder().inMemory("mem").build());
|
||||
JasyncConnectionFactory mysql = new JasyncConnectionFactory(mock(MySQLConnectionFactory.class));
|
||||
|
||||
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
|
||||
public void shouldNotResolveUnknownDatabase() {
|
||||
assertThatThrownBy(() -> DialectResolver.getDialect(new ExternalConnectionFactory("unknown")))
|
||||
.isInstanceOf(DialectResolver.NoDialectException.class);
|
||||
}
|
||||
|
||||
@Test // gh-104
|
||||
public void shouldResolveExternalDialect() {
|
||||
assertThat(DialectResolver.getDialect(new ExternalConnectionFactory("external")))
|
||||
.isEqualTo(ExternalDialect.INSTANCE);
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
static class ExternalConnectionFactory implements ConnectionFactory {
|
||||
|
||||
private final String name;
|
||||
|
||||
@Override
|
||||
public Publisher<? extends Connection> create() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectionFactoryMetadata getMetadata() {
|
||||
return () -> this.name;
|
||||
}
|
||||
}
|
||||
|
||||
static class ExternalDialectProvider implements DialectResolver.R2dbcDialectProvider {
|
||||
|
||||
@Override
|
||||
public Optional<R2dbcDialect> getDialect(ConnectionFactory connectionFactory) {
|
||||
|
||||
if (connectionFactory.getMetadata().getName().equals("external")) {
|
||||
return Optional.of(ExternalDialect.INSTANCE);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
enum ExternalDialect implements R2dbcDialect {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public BindMarkersFactory getBindMarkersFactory() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LimitClause limit() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SelectRenderContext getSelectContext() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,8 @@ import org.springframework.data.annotation.PersistenceConstructor;
|
||||
import org.springframework.data.r2dbc.convert.MappingR2dbcConverter;
|
||||
import org.springframework.data.r2dbc.core.DefaultReactiveDataAccessStrategy;
|
||||
import org.springframework.data.r2dbc.core.TransactionalDatabaseClient;
|
||||
import org.springframework.data.r2dbc.dialect.Database;
|
||||
import org.springframework.data.r2dbc.dialect.DialectResolver;
|
||||
import org.springframework.data.r2dbc.dialect.R2dbcDialect;
|
||||
import org.springframework.data.r2dbc.repository.support.R2dbcRepositoryFactory;
|
||||
import org.springframework.data.r2dbc.testing.R2dbcIntegrationTestSupport;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
@@ -172,9 +173,9 @@ public abstract class AbstractR2dbcRepositoryIntegrationTests extends R2dbcInteg
|
||||
@Test
|
||||
public void shouldInsertItemsTransactional() {
|
||||
|
||||
Database database = Database.findDatabase(createConnectionFactory()).get();
|
||||
DefaultReactiveDataAccessStrategy dataAccessStrategy = new DefaultReactiveDataAccessStrategy(
|
||||
database.defaultDialect(), new MappingR2dbcConverter(mappingContext));
|
||||
R2dbcDialect dialect = DialectResolver.getDialect(createConnectionFactory());
|
||||
DefaultReactiveDataAccessStrategy dataAccessStrategy = new DefaultReactiveDataAccessStrategy(dialect,
|
||||
new MappingR2dbcConverter(mappingContext));
|
||||
TransactionalDatabaseClient client = TransactionalDatabaseClient.builder()
|
||||
.connectionFactory(createConnectionFactory()).dataAccessStrategy(dataAccessStrategy).build();
|
||||
|
||||
|
||||
1
src/test/resources/META-INF/spring.factories
Normal file
1
src/test/resources/META-INF/spring.factories
Normal file
@@ -0,0 +1 @@
|
||||
org.springframework.data.r2dbc.dialect.DialectResolver$R2dbcDialectProvider=org.springframework.data.r2dbc.dialect.DialectResolverUnitTests.ExternalDialectProvider
|
||||
Reference in New Issue
Block a user