From 32f1770529c5fd4916644e8f46afdcce953773b5 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 22 May 2019 10:07:18 +0200 Subject: [PATCH] #55 - Reuse Dialect support provided by Spring Data Relational. We now reuse the existing Dialect infrastructure provided by Spring Data Relational to enhance it for R2DBC specifics such as bind markers. Original pull request: #125. --- .../config/AbstractR2dbcConfiguration.java | 20 ++--- .../r2dbc/convert/MappingR2dbcConverter.java | 10 +-- .../data/r2dbc/convert/R2dbcConverter.java | 2 +- .../core/DefaultDatabaseClientBuilder.java | 4 +- .../DefaultReactiveDataAccessStrategy.java | 63 +++++----------- .../r2dbc/core/DefaultStatementMapper.java | 38 ++-------- .../core/ReactiveDataAccessStrategy.java | 5 +- .../data/r2dbc/core/StatementMapper.java | 4 +- .../data/r2dbc/dialect/ArrayColumns.java | 53 -------------- .../data/r2dbc/dialect/Database.java | 20 ++--- .../data/r2dbc/dialect/LimitClause.java | 42 ----------- .../data/r2dbc/dialect/MySqlDialect.java | 51 +------------ .../data/r2dbc/dialect/PostgresDialect.java | 73 ++++--------------- .../{Dialect.java => R2dbcDialect.java} | 22 +----- .../data/r2dbc/dialect/SqlServerDialect.java | 42 +---------- .../r2dbc/support/StatementRenderUtil.java | 66 ----------------- ...ReactiveDataAccessStrategyTestSupport.java | 4 +- .../dialect/PostgresDialectUnitTests.java | 1 + .../dialect/SqlServerDialectUnitTests.java | 1 + 19 files changed, 81 insertions(+), 440 deletions(-) delete mode 100644 src/main/java/org/springframework/data/r2dbc/dialect/ArrayColumns.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/dialect/LimitClause.java rename src/main/java/org/springframework/data/r2dbc/dialect/{Dialect.java => R2dbcDialect.java} (67%) delete mode 100644 src/main/java/org/springframework/data/r2dbc/support/StatementRenderUtil.java diff --git a/src/main/java/org/springframework/data/r2dbc/config/AbstractR2dbcConfiguration.java b/src/main/java/org/springframework/data/r2dbc/config/AbstractR2dbcConfiguration.java index f5c048c..2f50917 100644 --- a/src/main/java/org/springframework/data/r2dbc/config/AbstractR2dbcConfiguration.java +++ b/src/main/java/org/springframework/data/r2dbc/config/AbstractR2dbcConfiguration.java @@ -34,7 +34,7 @@ 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.Dialect; +import org.springframework.data.r2dbc.dialect.R2dbcDialect; import org.springframework.data.r2dbc.support.R2dbcExceptionSubclassTranslator; import org.springframework.data.r2dbc.support.R2dbcExceptionTranslator; import org.springframework.data.r2dbc.support.SqlStateR2dbcExceptionTranslator; @@ -78,15 +78,15 @@ public abstract class AbstractR2dbcConfiguration implements ApplicationContextAw public abstract ConnectionFactory connectionFactory(); /** - * Return a {@link Dialect} for the given {@link ConnectionFactory}. This method attempts to resolve a {@link Dialect} - * from {@link io.r2dbc.spi.ConnectionFactoryMetadata}. Override this method to specify a dialect instead of - * attempting to resolve one. + * Return a {@link R2dbcDialect} for the given {@link ConnectionFactory}. This method attempts to resolve a + * {@link R2dbcDialect} from {@link io.r2dbc.spi.ConnectionFactoryMetadata}. Override this method to specify a dialect + * instead of attempting to resolve one. * * @param connectionFactory the configured {@link ConnectionFactory}. - * @return the resolved {@link Dialect}. - * @throws UnsupportedOperationException if the {@link Dialect} cannot be determined. + * @return the resolved {@link R2dbcDialect}. + * @throws UnsupportedOperationException if the {@link R2dbcDialect} cannot be determined. */ - public Dialect getDialect(ConnectionFactory connectionFactory) { + public R2dbcDialect getDialect(ConnectionFactory connectionFactory) { return Database.findDatabase(connectionFactory) .orElseThrow(() -> new UnsupportedOperationException( @@ -172,13 +172,13 @@ public abstract class AbstractR2dbcConfiguration implements ApplicationContextAw } /** - * Returns the {@link Dialect}-specific {@link StoreConversions}. + * Returns the {@link R2dbcDialect}-specific {@link StoreConversions}. * - * @return the {@link Dialect}-specific {@link StoreConversions}. + * @return the {@link R2dbcDialect}-specific {@link StoreConversions}. */ protected StoreConversions getStoreConversions() { - Dialect dialect = getDialect(lookupConnectionFactory()); + R2dbcDialect dialect = getDialect(lookupConnectionFactory()); return StoreConversions.of(dialect.getSimpleTypeHolder(), R2dbcCustomConversions.STORE_CONVERTERS); } diff --git a/src/main/java/org/springframework/data/r2dbc/convert/MappingR2dbcConverter.java b/src/main/java/org/springframework/data/r2dbc/convert/MappingR2dbcConverter.java index 72e63f0..d337eba 100644 --- a/src/main/java/org/springframework/data/r2dbc/convert/MappingR2dbcConverter.java +++ b/src/main/java/org/springframework/data/r2dbc/convert/MappingR2dbcConverter.java @@ -38,11 +38,11 @@ import org.springframework.data.mapping.PreferredConstructor.Parameter; import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mapping.model.ConvertingPropertyAccessor; import org.springframework.data.mapping.model.ParameterValueProvider; -import org.springframework.data.r2dbc.dialect.ArrayColumns; import org.springframework.data.r2dbc.mapping.OutboundRow; import org.springframework.data.r2dbc.mapping.SettableValue; import org.springframework.data.relational.core.conversion.BasicRelationalConverter; import org.springframework.data.relational.core.conversion.RelationalConverter; +import org.springframework.data.relational.core.dialect.ArrayColumns; import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; import org.springframework.data.relational.core.mapping.RelationalPersistentProperty; import org.springframework.data.util.ClassTypeInformation; @@ -84,7 +84,7 @@ public class MappingR2dbcConverter extends BasicRelationalConverter implements R // Entity reading // ---------------------------------- - /* + /* * (non-Javadoc) * @see org.springframework.data.convert.EntityReader#read(java.lang.Class, S) */ @@ -93,7 +93,7 @@ public class MappingR2dbcConverter extends BasicRelationalConverter implements R return read(type, row, null); } - /* + /* * (non-Javadoc) * @see org.springframework.data.r2dbc.convert.R2dbcConverter#read(java.lang.Class, io.r2dbc.spi.Row, io.r2dbc.spi.RowMetadata) */ @@ -233,7 +233,7 @@ public class MappingR2dbcConverter extends BasicRelationalConverter implements R // Entity writing // ---------------------------------- - /* + /* * (non-Javadoc) * @see org.springframework.data.convert.EntityWriter#write(java.lang.Object, java.lang.Object) */ @@ -337,7 +337,7 @@ public class MappingR2dbcConverter extends BasicRelationalConverter implements R return Enum.class.isAssignableFrom(value.getClass()) ? ((Enum) value).name() : value; } - /* + /* * (non-Javadoc) * @see org.springframework.data.r2dbc.convert.R2dbcConverter#getArrayValue(org.springframework.data.r2dbc.dialect.ArrayColumns, org.springframework.data.relational.core.mapping.RelationalPersistentProperty, java.lang.Object) */ diff --git a/src/main/java/org/springframework/data/r2dbc/convert/R2dbcConverter.java b/src/main/java/org/springframework/data/r2dbc/convert/R2dbcConverter.java index ed9d345..81015a8 100644 --- a/src/main/java/org/springframework/data/r2dbc/convert/R2dbcConverter.java +++ b/src/main/java/org/springframework/data/r2dbc/convert/R2dbcConverter.java @@ -24,9 +24,9 @@ import org.springframework.core.convert.ConversionService; import org.springframework.data.convert.EntityReader; import org.springframework.data.convert.EntityWriter; import org.springframework.data.mapping.context.MappingContext; -import org.springframework.data.r2dbc.dialect.ArrayColumns; import org.springframework.data.r2dbc.mapping.OutboundRow; import org.springframework.data.relational.core.conversion.RelationalConverter; +import org.springframework.data.relational.core.dialect.ArrayColumns; import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; import org.springframework.data.relational.core.mapping.RelationalPersistentProperty; diff --git a/src/main/java/org/springframework/data/r2dbc/core/DefaultDatabaseClientBuilder.java b/src/main/java/org/springframework/data/r2dbc/core/DefaultDatabaseClientBuilder.java index 8edd56d..8853f5b 100644 --- a/src/main/java/org/springframework/data/r2dbc/core/DefaultDatabaseClientBuilder.java +++ b/src/main/java/org/springframework/data/r2dbc/core/DefaultDatabaseClientBuilder.java @@ -22,7 +22,7 @@ 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.Dialect; +import org.springframework.data.r2dbc.dialect.R2dbcDialect; import org.springframework.data.r2dbc.support.R2dbcExceptionSubclassTranslator; import org.springframework.data.r2dbc.support.R2dbcExceptionTranslator; import org.springframework.lang.Nullable; @@ -121,7 +121,7 @@ class DefaultDatabaseClientBuilder implements DatabaseClient.Builder { if (accessStrategy == null) { - Dialect dialect = Database.findDatabase(this.connectionFactory) + R2dbcDialect dialect = Database.findDatabase(this.connectionFactory) .orElseThrow(() -> new UnsupportedOperationException( "Cannot determine a Dialect. Configure the dialect by providing DefaultReactiveDataAccessStrategy(Dialect)")) .defaultDialect(); diff --git a/src/main/java/org/springframework/data/r2dbc/core/DefaultReactiveDataAccessStrategy.java b/src/main/java/org/springframework/data/r2dbc/core/DefaultReactiveDataAccessStrategy.java index 3385f88..e7ee999 100644 --- a/src/main/java/org/springframework/data/r2dbc/core/DefaultReactiveDataAccessStrategy.java +++ b/src/main/java/org/springframework/data/r2dbc/core/DefaultReactiveDataAccessStrategy.java @@ -23,9 +23,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.function.BiFunction; -import java.util.function.Function; -import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.dao.InvalidDataAccessResourceUsageException; import org.springframework.data.convert.CustomConversions.StoreConversions; import org.springframework.data.mapping.context.MappingContext; @@ -33,26 +31,19 @@ import org.springframework.data.r2dbc.convert.EntityRowMapper; import org.springframework.data.r2dbc.convert.MappingR2dbcConverter; import org.springframework.data.r2dbc.convert.R2dbcConverter; import org.springframework.data.r2dbc.convert.R2dbcCustomConversions; -import org.springframework.data.r2dbc.dialect.ArrayColumns; import org.springframework.data.r2dbc.dialect.BindMarkersFactory; -import org.springframework.data.r2dbc.dialect.Dialect; +import org.springframework.data.r2dbc.dialect.R2dbcDialect; import org.springframework.data.r2dbc.mapping.OutboundRow; import org.springframework.data.r2dbc.mapping.SettableValue; import org.springframework.data.r2dbc.query.UpdateMapper; -import org.springframework.data.relational.core.mapping.NamingStrategy; +import org.springframework.data.relational.core.dialect.ArrayColumns; +import org.springframework.data.relational.core.dialect.RenderContextFactory; import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; import org.springframework.data.relational.core.mapping.RelationalPersistentProperty; -import org.springframework.data.relational.core.mapping.Table; -import org.springframework.data.relational.core.sql.Select; -import org.springframework.data.relational.core.sql.render.NamingStrategies; -import org.springframework.data.relational.core.sql.render.RenderContext; -import org.springframework.data.relational.core.sql.render.RenderNamingStrategy; -import org.springframework.data.relational.core.sql.render.SelectRenderContext; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; -import org.springframework.util.StringUtils; /** * Default {@link ReactiveDataAccessStrategy} implementation. @@ -61,36 +52,36 @@ import org.springframework.util.StringUtils; */ public class DefaultReactiveDataAccessStrategy implements ReactiveDataAccessStrategy { - private final Dialect dialect; + private final R2dbcDialect dialect; private final R2dbcConverter converter; private final UpdateMapper updateMapper; private final MappingContext, ? extends RelationalPersistentProperty> mappingContext; private final StatementMapper statementMapper; /** - * Creates a new {@link DefaultReactiveDataAccessStrategy} given {@link Dialect} and optional + * Creates a new {@link DefaultReactiveDataAccessStrategy} given {@link R2dbcDialect} and optional * {@link org.springframework.core.convert.converter.Converter}s. * - * @param dialect the {@link Dialect} to use. + * @param dialect the {@link R2dbcDialect} to use. */ - public DefaultReactiveDataAccessStrategy(Dialect dialect) { + public DefaultReactiveDataAccessStrategy(R2dbcDialect dialect) { this(dialect, Collections.emptyList()); } /** - * Creates a new {@link DefaultReactiveDataAccessStrategy} given {@link Dialect} and optional + * Creates a new {@link DefaultReactiveDataAccessStrategy} given {@link R2dbcDialect} and optional * {@link org.springframework.core.convert.converter.Converter}s. * - * @param dialect the {@link Dialect} to use. + * @param dialect the {@link R2dbcDialect} to use. * @param converters custom converters to register, must not be {@literal null}. * @see R2dbcCustomConversions * @see org.springframework.core.convert.converter.Converter */ - public DefaultReactiveDataAccessStrategy(Dialect dialect, Collection converters) { + public DefaultReactiveDataAccessStrategy(R2dbcDialect dialect, Collection converters) { this(dialect, createConverter(dialect, converters)); } - private static R2dbcConverter createConverter(Dialect dialect, Collection converters) { + private static R2dbcConverter createConverter(R2dbcDialect dialect, Collection converters) { Assert.notNull(dialect, "Dialect must not be null"); Assert.notNull(converters, "Converters must not be null"); @@ -105,13 +96,13 @@ public class DefaultReactiveDataAccessStrategy implements ReactiveDataAccessStra } /** - * Creates a new {@link DefaultReactiveDataAccessStrategy} given {@link Dialect} and {@link R2dbcConverter}. + * Creates a new {@link DefaultReactiveDataAccessStrategy} given {@link R2dbcDialect} and {@link R2dbcConverter}. * - * @param dialect the {@link Dialect} to use. + * @param dialect the {@link R2dbcDialect} to use. * @param converter must not be {@literal null}. */ @SuppressWarnings("unchecked") - public DefaultReactiveDataAccessStrategy(Dialect dialect, R2dbcConverter converter) { + public DefaultReactiveDataAccessStrategy(R2dbcDialect dialect, R2dbcConverter converter) { Assert.notNull(dialect, "Dialect must not be null"); Assert.notNull(converter, "RelationalConverter must not be null"); @@ -122,29 +113,9 @@ public class DefaultReactiveDataAccessStrategy implements ReactiveDataAccessStra .getMappingContext(); this.dialect = dialect; - RenderContext renderContext = new RenderContext() { - @Override - public RenderNamingStrategy getNamingStrategy() { - return NamingStrategies.asIs(); - } - - @Override - public SelectRenderContext getSelect() { - return new SelectRenderContext() { - @Override - public Function afterSelectList() { - return it -> ""; - } - - @Override - public Function afterOrderBy(boolean hasOrderBy) { - return it -> ""; - } - }; - } - }; - - this.statementMapper = new DefaultStatementMapper(dialect, renderContext, this.updateMapper, this.mappingContext); + RenderContextFactory factory = new RenderContextFactory(dialect); + this.statementMapper = new DefaultStatementMapper(dialect, factory.createRenderContext(), this.updateMapper, + this.mappingContext); } /* diff --git a/src/main/java/org/springframework/data/r2dbc/core/DefaultStatementMapper.java b/src/main/java/org/springframework/data/r2dbc/core/DefaultStatementMapper.java index ae2d806..9bff339 100644 --- a/src/main/java/org/springframework/data/r2dbc/core/DefaultStatementMapper.java +++ b/src/main/java/org/springframework/data/r2dbc/core/DefaultStatementMapper.java @@ -20,7 +20,6 @@ import lombok.RequiredArgsConstructor; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.OptionalLong; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; @@ -28,28 +27,14 @@ import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.r2dbc.dialect.BindMarkers; import org.springframework.data.r2dbc.dialect.BindTarget; import org.springframework.data.r2dbc.dialect.Bindings; -import org.springframework.data.r2dbc.dialect.Dialect; +import org.springframework.data.r2dbc.dialect.R2dbcDialect; import org.springframework.data.r2dbc.query.BoundAssignments; import org.springframework.data.r2dbc.query.BoundCondition; import org.springframework.data.r2dbc.query.UpdateMapper; -import org.springframework.data.r2dbc.support.StatementRenderUtil; import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; import org.springframework.data.relational.core.mapping.RelationalPersistentProperty; -import org.springframework.data.relational.core.sql.AssignValue; -import org.springframework.data.relational.core.sql.Assignment; -import org.springframework.data.relational.core.sql.Column; -import org.springframework.data.relational.core.sql.Delete; -import org.springframework.data.relational.core.sql.DeleteBuilder; -import org.springframework.data.relational.core.sql.Insert; -import org.springframework.data.relational.core.sql.InsertBuilder; +import org.springframework.data.relational.core.sql.*; import org.springframework.data.relational.core.sql.InsertBuilder.InsertValuesWithBuild; -import org.springframework.data.relational.core.sql.OrderByField; -import org.springframework.data.relational.core.sql.Select; -import org.springframework.data.relational.core.sql.SelectBuilder; -import org.springframework.data.relational.core.sql.StatementBuilder; -import org.springframework.data.relational.core.sql.Table; -import org.springframework.data.relational.core.sql.Update; -import org.springframework.data.relational.core.sql.UpdateBuilder; import org.springframework.data.relational.core.sql.render.RenderContext; import org.springframework.data.relational.core.sql.render.SqlRenderer; import org.springframework.lang.Nullable; @@ -63,7 +48,7 @@ import org.springframework.util.Assert; @RequiredArgsConstructor class DefaultStatementMapper implements StatementMapper { - private final Dialect dialect; + private final R2dbcDialect dialect; private final RenderContext renderContext; private final UpdateMapper updateMapper; private final MappingContext, ? extends RelationalPersistentProperty> mappingContext; @@ -116,26 +101,15 @@ class DefaultStatementMapper implements StatementMapper { selectBuilder.orderBy(createOrderByFields(table, mappedSort)); } - OptionalLong limit; - OptionalLong offset; - if (selectSpec.getPage().isPaged()) { Pageable page = selectSpec.getPage(); - limit = OptionalLong.of(page.getPageSize()); - offset = OptionalLong.of(page.getOffset()); - } else { - limit = OptionalLong.empty(); - offset = OptionalLong.empty(); + + selectBuilder.limitOffset(page.getPageSize(), page.getOffset()); } Select select = selectBuilder.build(); - return new DefaultPreparedOperation