From dbc4365eef11e8245f8e758b00ca2d7ee960e334 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 28 Jan 2022 10:16:54 +0100 Subject: [PATCH] Remove deprecated `DatabaseClient`, `connectionfactory` package and other deprecated code Removal of the connectionfactory package and deprecated core classes that were migrated into Spring Framework R2DBC. Closes #712 --- src/main/asciidoc/reference/mapping.adoc | 6 +- .../data/r2dbc/BadSqlGrammarException.java | 60 - .../r2dbc/InvalidResultAccessException.java | 82 - .../r2dbc/UncategorizedR2dbcException.java | 60 - .../ConnectionFactoryUtils.java | 206 -- .../connectionfactory/ConnectionHandle.java | 47 - .../connectionfactory/ConnectionHolder.java | 171 -- .../connectionfactory/ConnectionProxy.java | 43 - .../DelegatingConnectionFactory.java | 90 - .../R2dbcTransactionManager.java | 83 - .../SimpleConnectionHandle.java | 58 - .../SingleConnectionConnectionFactory.java | 295 --- .../SmartConnectionFactory.java | 46 - ...ransactionAwareConnectionFactoryProxy.java | 198 -- .../init/CannotReadScriptException.java | 41 - .../init/CompositeDatabasePopulator.java | 102 - .../init/ConnectionFactoryInitializer.java | 113 -- .../init/DatabasePopulator.java | 45 - .../init/DatabasePopulatorUtils.java | 61 - .../init/ResourceDatabasePopulator.java | 283 --- .../init/ScriptException.java | 49 - .../init/ScriptParseException.java | 58 - .../init/ScriptStatementFailedException.java | 57 - .../connectionfactory/init/ScriptUtils.java | 540 ------ .../init/UncategorizedScriptException.java | 49 - .../connectionfactory/init/package-info.java | 7 - .../AbstractRoutingConnectionFactory.java | 248 --- .../BeanFactoryConnectionFactoryLookup.java | 93 - .../lookup/ConnectionFactoryLookup.java | 39 - ...nnectionFactoryLookupFailureException.java | 50 - .../lookup/MapConnectionFactoryLookup.java | 124 -- .../lookup/SingleConnectionFactoryLookup.java | 56 - .../lookup/package-info.java | 7 - .../r2dbc/connectionfactory/package-info.java | 7 - .../r2dbc/convert/ColumnMapRowMapper.java | 90 - .../data/r2dbc/core/BindParameterSource.java | 2 +- .../data/r2dbc/core/ConnectionAccessor.java | 63 - .../data/r2dbc/core/DatabaseClient.java | 929 --------- .../r2dbc/core/DefaultDatabaseClient.java | 1704 ----------------- .../core/DefaultDatabaseClientBuilder.java | 187 -- .../data/r2dbc/core/DefaultFetchSpec.java | 91 - .../DefaultReactiveDataAccessStrategy.java | 33 +- .../data/r2dbc/core/DefaultSqlResult.java | 154 -- .../r2dbc/core/DefaultStatementMapper.java | 7 +- .../data/r2dbc/core/ExecuteFunction.java | 48 - .../data/r2dbc/core/FetchSpec.java | 28 - .../r2dbc/core/MapBindParameterSource.java | 15 +- .../r2dbc/core/NamedParameterExpander.java | 10 +- .../data/r2dbc/core/NamedParameterUtils.java | 9 +- .../data/r2dbc/core/PreparedOperation.java | 54 - .../data/r2dbc/core/QueryOperation.java | 44 - .../data/r2dbc/core/R2dbcEntityTemplate.java | 183 +- .../core/ReactiveDataAccessStrategy.java | 20 +- .../data/r2dbc/core/RowsFetchSpec.java | 52 - .../data/r2dbc/core/SqlProvider.java | 40 - .../r2dbc/core/StatementFilterFunction.java | 66 - .../r2dbc/core/StatementFilterFunctions.java | 48 - .../data/r2dbc/core/StatementMapper.java | 27 - .../data/r2dbc/core/UpdatedRowsFetchSpec.java | 35 - .../data/r2dbc/dialect/BindMarker.java | 44 - .../data/r2dbc/dialect/BindMarkers.java | 39 - .../r2dbc/dialect/BindMarkersAdapter.java | 85 - .../r2dbc/dialect/BindMarkersFactory.java | 165 -- .../data/r2dbc/dialect/BindTarget.java | 64 - .../data/r2dbc/dialect/Bindings.java | 289 --- .../data/r2dbc/dialect/MutableBindings.java | 135 -- .../data/r2dbc/mapping/SettableValue.java | 154 -- .../data/r2dbc/query/Criteria.java | 705 ------- .../data/r2dbc/query/QueryMapper.java | 38 +- .../data/r2dbc/query/Update.java | 99 - .../data/r2dbc/query/UpdateMapper.java | 40 +- .../config/EnableR2dbcRepositories.java | 15 +- ...R2dbcRepositoryConfigurationExtension.java | 9 +- .../ExpressionEvaluatingParameterBinder.java | 2 - .../query/StringBasedR2dbcQuery.java | 10 +- .../repository/support/BindSpecAdapter.java | 103 - .../support/SimpleR2dbcRepository.java | 23 - ...tractFallbackR2dbcExceptionTranslator.java | 125 -- .../R2dbcExceptionSubclassTranslator.java | 95 - .../support/R2dbcExceptionTranslator.java | 61 - .../SqlErrorCodeR2dbcExceptionTranslator.java | 277 --- .../SqlStateR2dbcExceptionTranslator.java | 148 -- .../data/r2dbc/core/CriteriaStepExtensions.kt | 49 - .../r2dbc/core/DatabaseClientExtensions.kt | 169 -- .../r2dbc/core/RowsFetchSpecExtensions.kt | 62 - .../core/UpdatedRowsFetchSpecExtensions.kt | 26 - .../DelegatingConnectionFactoryUnitTests.java | 60 - ...eConnectionConnectionFactoryUnitTests.java | 121 -- ...nAwareConnectionFactoryProxyUnitTests.java | 163 -- .../AbstractDatabaseInitializationTests.java | 134 -- .../init/CompositeDatabasePopulatorTests.java | 112 -- ...ConnectionFactoryInitializerUnitTests.java | 70 - .../H2DatabasePopulatorIntegrationTests.java | 57 - .../ResourceDatabasePopulatorUnitTests.java | 110 -- .../init/ScriptUtilsUnitTests.java | 205 -- ...ractRoutingConnectionFactoryUnitTests.java | 190 -- ...ctoryConnectionFactoryLookupUnitTests.java | 81 - .../lookup/DummyConnectionFactory.java | 42 - .../MapConnectionFactoryLookupUnitTests.java | 102 - ...bstractDatabaseClientIntegrationTests.java | 527 ----- ...ctionalDatabaseClientIntegrationTests.java | 329 ---- .../core/DefaultDatabaseClientUnitTests.java | 575 ------ .../H2DatabaseClientIntegrationTests.java | 48 - ...MariaDbDatabaseClientIntegrationTests.java | 186 -- ...ctionalDatabaseClientIntegrationTests.java | 78 - .../MySqlDatabaseClientIntegrationTests.java | 186 -- ...ctionalDatabaseClientIntegrationTests.java | 79 - .../core/NamedParameterUtilsUnitTests.java | 468 ----- .../OracleDatabaseClientIntegrationTests.java | 57 - ...ostgresDatabaseClientIntegrationTests.java | 51 - .../r2dbc/core/PostgresIntegrationTests.java | 78 +- ...ctionalDatabaseClientIntegrationTests.java | 41 - .../core/ReactiveDataAccessStrategyTests.java | 19 +- .../ReactiveDeleteOperationUnitTests.java | 5 +- .../ReactiveInsertOperationUnitTests.java | 5 +- .../ReactiveSelectOperationUnitTests.java | 5 +- .../ReactiveUpdateOperationUnitTests.java | 7 +- ...lServerDatabaseClientIntegrationTests.java | 50 - ...ctionalDatabaseClientIntegrationTests.java | 46 - .../r2dbc/core/StatementMapperUnitTests.java | 2 +- .../data/r2dbc/dialect/BindingsUnitTests.java | 150 -- .../dialect/DialectResolverUnitTests.java | 1 + .../r2dbc/mapping/SettableValueUnitTests.java | 56 - .../r2dbc/query/QueryMapperUnitTests.java | 8 +- .../r2dbc/query/UpdateMapperUnitTests.java | 8 +- ...stractR2dbcRepositoryIntegrationTests.java | 2 +- ...cExceptionSubclassTranslatorUnitTests.java | 144 -- ...CodeR2dbcExceptionTranslatorUnitTests.java | 158 -- ...tateR2dbcExceptionTranslatorUnitTests.java | 86 - .../r2dbc/core/CriteriaStepExtensionsTests.kt | 76 - .../core/DatabaseClientExtensionsTests.kt | 320 ---- .../core/RowsFetchSpecExtensionsTests.kt | 174 -- .../UpdatedRowsFetchSpecExtensionsTests.kt | 47 - .../CoroutineRepositoryUnitTests.kt | 9 +- 134 files changed, 86 insertions(+), 15886 deletions(-) delete mode 100644 src/main/java/org/springframework/data/r2dbc/BadSqlGrammarException.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/InvalidResultAccessException.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/UncategorizedR2dbcException.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/ConnectionFactoryUtils.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/ConnectionHandle.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/ConnectionHolder.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/ConnectionProxy.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/DelegatingConnectionFactory.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/R2dbcTransactionManager.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/SimpleConnectionHandle.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/SingleConnectionConnectionFactory.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/SmartConnectionFactory.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/TransactionAwareConnectionFactoryProxy.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/init/CannotReadScriptException.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/init/CompositeDatabasePopulator.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/init/ConnectionFactoryInitializer.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/init/DatabasePopulator.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/init/DatabasePopulatorUtils.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/init/ResourceDatabasePopulator.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/init/ScriptException.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/init/ScriptParseException.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/init/ScriptStatementFailedException.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/init/ScriptUtils.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/init/UncategorizedScriptException.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/init/package-info.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/lookup/AbstractRoutingConnectionFactory.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/lookup/BeanFactoryConnectionFactoryLookup.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/lookup/ConnectionFactoryLookup.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/lookup/ConnectionFactoryLookupFailureException.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/lookup/MapConnectionFactoryLookup.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/lookup/SingleConnectionFactoryLookup.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/lookup/package-info.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/connectionfactory/package-info.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/convert/ColumnMapRowMapper.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/core/ConnectionAccessor.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/core/DatabaseClient.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/core/DefaultDatabaseClient.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/core/DefaultDatabaseClientBuilder.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/core/DefaultFetchSpec.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/core/DefaultSqlResult.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/core/ExecuteFunction.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/core/FetchSpec.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/core/PreparedOperation.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/core/QueryOperation.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/core/RowsFetchSpec.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/core/SqlProvider.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/core/StatementFilterFunction.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/core/StatementFilterFunctions.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/core/UpdatedRowsFetchSpec.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/dialect/BindMarker.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/dialect/BindMarkers.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/dialect/BindMarkersAdapter.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/dialect/BindMarkersFactory.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/dialect/BindTarget.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/dialect/Bindings.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/dialect/MutableBindings.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/mapping/SettableValue.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/query/Criteria.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/query/Update.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/repository/support/BindSpecAdapter.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/support/AbstractFallbackR2dbcExceptionTranslator.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/support/R2dbcExceptionSubclassTranslator.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/support/R2dbcExceptionTranslator.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/support/SqlErrorCodeR2dbcExceptionTranslator.java delete mode 100644 src/main/java/org/springframework/data/r2dbc/support/SqlStateR2dbcExceptionTranslator.java delete mode 100644 src/main/kotlin/org/springframework/data/r2dbc/core/CriteriaStepExtensions.kt delete mode 100644 src/main/kotlin/org/springframework/data/r2dbc/core/DatabaseClientExtensions.kt delete mode 100644 src/main/kotlin/org/springframework/data/r2dbc/core/RowsFetchSpecExtensions.kt delete mode 100644 src/main/kotlin/org/springframework/data/r2dbc/core/UpdatedRowsFetchSpecExtensions.kt delete mode 100644 src/test/java/org/springframework/data/r2dbc/connectionfactory/DelegatingConnectionFactoryUnitTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/connectionfactory/SingleConnectionConnectionFactoryUnitTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/connectionfactory/TransactionAwareConnectionFactoryProxyUnitTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/connectionfactory/init/AbstractDatabaseInitializationTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/connectionfactory/init/CompositeDatabasePopulatorTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/connectionfactory/init/ConnectionFactoryInitializerUnitTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/connectionfactory/init/H2DatabasePopulatorIntegrationTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/connectionfactory/init/ResourceDatabasePopulatorUnitTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/connectionfactory/init/ScriptUtilsUnitTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/connectionfactory/lookup/AbstractRoutingConnectionFactoryUnitTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/connectionfactory/lookup/BeanFactoryConnectionFactoryLookupUnitTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/connectionfactory/lookup/DummyConnectionFactory.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/connectionfactory/lookup/MapConnectionFactoryLookupUnitTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/core/AbstractDatabaseClientIntegrationTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/core/AbstractTransactionalDatabaseClientIntegrationTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/core/DefaultDatabaseClientUnitTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/core/H2DatabaseClientIntegrationTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/core/MariaDbDatabaseClientIntegrationTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/core/MariaDbTransactionalDatabaseClientIntegrationTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/core/MySqlDatabaseClientIntegrationTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/core/MySqlTransactionalDatabaseClientIntegrationTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/core/NamedParameterUtilsUnitTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/core/OracleDatabaseClientIntegrationTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/core/PostgresDatabaseClientIntegrationTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/core/PostgresTransactionalDatabaseClientIntegrationTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/core/SqlServerDatabaseClientIntegrationTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/core/SqlServerTransactionalDatabaseClientIntegrationTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/dialect/BindingsUnitTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/mapping/SettableValueUnitTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/support/R2dbcExceptionSubclassTranslatorUnitTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/support/SqlErrorCodeR2dbcExceptionTranslatorUnitTests.java delete mode 100644 src/test/java/org/springframework/data/r2dbc/support/SqlStateR2dbcExceptionTranslatorUnitTests.java delete mode 100644 src/test/kotlin/org/springframework/data/r2dbc/core/CriteriaStepExtensionsTests.kt delete mode 100644 src/test/kotlin/org/springframework/data/r2dbc/core/DatabaseClientExtensionsTests.kt delete mode 100644 src/test/kotlin/org/springframework/data/r2dbc/core/RowsFetchSpecExtensionsTests.kt delete mode 100644 src/test/kotlin/org/springframework/data/r2dbc/core/UpdatedRowsFetchSpecExtensionsTests.kt diff --git a/src/main/asciidoc/reference/mapping.adoc b/src/main/asciidoc/reference/mapping.adoc index e270796e5..a9f17e6d4 100644 --- a/src/main/asciidoc/reference/mapping.adoc +++ b/src/main/asciidoc/reference/mapping.adoc @@ -283,9 +283,9 @@ public class PersonWriteConverter implements Converter { public OutboundRow convert(Person source) { OutboundRow row = new OutboundRow(); - row.put("id", SettableValue.from(source.getId())); - row.put("name", SettableValue.from(source.getFirstName())); - row.put("age", SettableValue.from(source.getAge())); + row.put("id", Parameter.from(source.getId())); + row.put("name", Parameter.from(source.getFirstName())); + row.put("age", Parameter.from(source.getAge())); return row; } } diff --git a/src/main/java/org/springframework/data/r2dbc/BadSqlGrammarException.java b/src/main/java/org/springframework/data/r2dbc/BadSqlGrammarException.java deleted file mode 100644 index e9393ed1c..000000000 --- a/src/main/java/org/springframework/data/r2dbc/BadSqlGrammarException.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2018-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; - -import io.r2dbc.spi.R2dbcException; - -/** - * Exception thrown when SQL specified is invalid. Such exceptions always have a {@link io.r2dbc.spi.R2dbcException} - * root cause. - *

- * It would be possible to have subclasses for no such table, no such column etc. A custom - * {@link org.springframework.data.r2dbc.support.R2dbcExceptionTranslator} could create such more specific exceptions, - * without affecting code using this class. - * - * @author Mark Paluch - * @deprecated since 1.2, use directly Spring R2DBC's {@link org.springframework.r2dbc.BadSqlGrammarException} instead. - */ -@Deprecated -public class BadSqlGrammarException extends org.springframework.r2dbc.BadSqlGrammarException { - - private static final long serialVersionUID = 3814579246913482054L; - - /** - * Creates a new {@link BadSqlGrammarException}. - * - * @param task name of current task. - * @param sql the offending SQL statement. - * @param ex the root cause. - */ - public BadSqlGrammarException(String task, String sql, R2dbcException ex) { - super(task, sql, ex); - } - - /** - * Return the wrapped {@link R2dbcException}. - */ - public R2dbcException getR2dbcException() { - return (R2dbcException) getCause(); - } - - /** - * Return the SQL that caused the problem. - */ - public String getSql() { - return super.getSql(); - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/InvalidResultAccessException.java b/src/main/java/org/springframework/data/r2dbc/InvalidResultAccessException.java deleted file mode 100644 index b11e167d1..000000000 --- a/src/main/java/org/springframework/data/r2dbc/InvalidResultAccessException.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2018-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; - -import io.r2dbc.spi.R2dbcException; - -import org.springframework.dao.InvalidDataAccessResourceUsageException; -import org.springframework.lang.Nullable; - -/** - * Exception thrown when a {@link io.r2dbc.spi.Result} has been accessed in an invalid fashion. Such exceptions always - * have a {@link io.r2dbc.spi.R2dbcException} root cause. - *

- * This typically happens when an invalid {@link org.springframework.data.r2dbc.core.FetchSpec} column index or name has - * been specified. - * - * @author Mark Paluch - * @see BadSqlGrammarException - * @deprecated since 1.2, not in use anymore. - */ -@SuppressWarnings("serial") -@Deprecated -public class InvalidResultAccessException extends InvalidDataAccessResourceUsageException { - - private final @Nullable String sql; - - /** - * Creates a new {@link InvalidResultAccessException}. - * - * @param task name of current task. - * @param sql the offending SQL statement. - * @param ex the root cause. - */ - public InvalidResultAccessException(String task, @Nullable String sql, R2dbcException ex) { - - super(task + "; invalid Result access for SQL [" + sql + "]", ex); - - this.sql = sql; - } - - /** - * Creates a new {@link InvalidResultAccessException}. - * - * @param ex the root cause. - */ - public InvalidResultAccessException(R2dbcException ex) { - - super(ex.getMessage(), ex); - - this.sql = null; - } - - /** - * Return the wrapped {@link R2dbcException}. - */ - public R2dbcException getR2dbcException() { - return (R2dbcException) getCause(); - } - - /** - * Return the SQL that caused the problem. - * - * @return the offending SQL, if known. - */ - @Nullable - public String getSql() { - return this.sql; - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/UncategorizedR2dbcException.java b/src/main/java/org/springframework/data/r2dbc/UncategorizedR2dbcException.java deleted file mode 100644 index 092d9d2de..000000000 --- a/src/main/java/org/springframework/data/r2dbc/UncategorizedR2dbcException.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2018-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; - -import io.r2dbc.spi.R2dbcException; - -import org.springframework.lang.Nullable; - -/** - * Exception thrown when we can't classify a {@link R2dbcException} into one of our generic data access exceptions. - * - * @author Mark Paluch - * @deprecated since 1.2, use Spring R2DBC's {@link org.springframework.r2dbc.UncategorizedR2dbcException} instead. - */ -@Deprecated -public class UncategorizedR2dbcException extends org.springframework.r2dbc.UncategorizedR2dbcException { - - private static final long serialVersionUID = 361587356435210266L; - - /** - * Creates a new {@link UncategorizedR2dbcException}. - * - * @param task name of current task - * @param sql the offending SQL statement - * @param ex the root cause - */ - public UncategorizedR2dbcException(String task, @Nullable String sql, R2dbcException ex) { - super(task, sql, ex); - } - - /** - * Returns the original {@link R2dbcException}. - * - * @return the original {@link R2dbcException}. - */ - public R2dbcException getR2dbcException() { - return (R2dbcException) getCause(); - } - - /** - * Return the SQL that led to the problem (if known). - */ - @Nullable - public String getSql() { - return super.getSql(); - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/ConnectionFactoryUtils.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/ConnectionFactoryUtils.java deleted file mode 100644 index 72817c54d..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/ConnectionFactoryUtils.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright 2018-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.connectionfactory; - -import io.r2dbc.spi.Connection; -import io.r2dbc.spi.ConnectionFactory; -import reactor.core.publisher.Mono; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.dao.DataAccessResourceFailureException; -import org.springframework.lang.Nullable; -import org.springframework.transaction.reactive.TransactionSynchronizationManager; -import org.springframework.util.Assert; - -/** - * Helper class that provides static methods for obtaining R2DBC Connections from a - * {@link io.r2dbc.spi.ConnectionFactory}. - *

- * Used internally by Spring's {@link org.springframework.data.r2dbc.core.DatabaseClient}, Spring's R2DBC operation - * objects. Can also be used directly in application code. - * - * @author Mark Paluch - * @author Christoph Strobl - * @deprecated since 1.2 in favor of Spring R2DBC. Use - * {@link org.springframework.r2dbc.connection.ConnectionFactoryUtils} instead. - */ -@Deprecated -public abstract class ConnectionFactoryUtils { - - /** - * Order value for ReactiveTransactionSynchronization objects that clean up R2DBC Connections. - */ - public static final int CONNECTION_SYNCHRONIZATION_ORDER = 1000; - - private static final Log logger = LogFactory.getLog(ConnectionFactoryUtils.class); - - private ConnectionFactoryUtils() {} - - /** - * Obtain a {@link io.r2dbc.spi.Connection} from the given {@link io.r2dbc.spi.ConnectionFactory}. Translates - * exceptions into the Spring hierarchy of unchecked generic data access exceptions, simplifying calling code and - * making any exception that is thrown more meaningful. - *

- * Is aware of a corresponding Connection bound to the current {@link reactor.util.context.Context}. Will bind a - * Connection to the {@link reactor.util.context.Context} if transaction synchronization is active. - * - * @param connectionFactory the {@link io.r2dbc.spi.ConnectionFactory} to obtain {@link io.r2dbc.spi.Connection - * Connections} from. - * @return a R2DBC Connection from the given {@link io.r2dbc.spi.ConnectionFactory}. - * @throws DataAccessResourceFailureException if the attempt to get a {@link io.r2dbc.spi.Connection} failed. - * @see #releaseConnection - */ - public static Mono getConnection(ConnectionFactory connectionFactory) { - return org.springframework.r2dbc.connection.ConnectionFactoryUtils.getConnection(connectionFactory); - } - - /** - * Actually obtain a R2DBC Connection from the given {@link io.r2dbc.spi.ConnectionFactory}. Same as - * {@link #getConnection}, but preserving the original exceptions. - *

- * Is aware of a corresponding Connection bound to the current {@link reactor.util.context.Context}. Will bind a - * Connection to the {@link reactor.util.context.Context} if transaction synchronization is active. - * - * @param connectionFactory the {@link io.r2dbc.spi.ConnectionFactory} to obtain Connections from. - * @return a R2DBC {@link io.r2dbc.spi.Connection} from the given {@link io.r2dbc.spi.ConnectionFactory}. - */ - public static Mono doGetConnection(ConnectionFactory connectionFactory) { - return org.springframework.r2dbc.connection.ConnectionFactoryUtils.doGetConnection(connectionFactory); - } - - /** - * Close the given {@link io.r2dbc.spi.Connection}, obtained from the given {@link io.r2dbc.spi.ConnectionFactory}, if - * it is not managed externally (that is, not bound to the thread). - * - * @param con the {@link io.r2dbc.spi.Connection} to close if necessary. - * @param connectionFactory the {@link io.r2dbc.spi.ConnectionFactory} that the Connection was obtained from. - * @see #getConnection - */ - public static Mono releaseConnection(io.r2dbc.spi.Connection con, ConnectionFactory connectionFactory) { - - return doReleaseConnection(con, connectionFactory) - .onErrorMap(e -> new DataAccessResourceFailureException("Failed to close R2DBC Connection", e)); - } - - /** - * Actually close the given {@link io.r2dbc.spi.Connection}, obtained from the given - * {@link io.r2dbc.spi.ConnectionFactory}. Same as {@link #releaseConnection}, but preserving the original exception. - * - * @param connection the {@link io.r2dbc.spi.Connection} to close if necessary. - * @param connectionFactory the {@link io.r2dbc.spi.ConnectionFactory} that the Connection was obtained from. - * @see #doGetConnection - */ - public static Mono doReleaseConnection(io.r2dbc.spi.Connection connection, - ConnectionFactory connectionFactory) { - - return org.springframework.r2dbc.connection.ConnectionFactoryUtils.doReleaseConnection(connection, - connectionFactory); - } - - /** - * Close the {@link io.r2dbc.spi.Connection}. Translates exceptions into the Spring hierarchy of unchecked generic - * data access exceptions, simplifying calling code and making any exception that is thrown more meaningful. - * - * @param connection the {@link io.r2dbc.spi.Connection} to close. - * @param connectionFactory the {@link io.r2dbc.spi.ConnectionFactory} that the {@link io.r2dbc.spi.Connection} was - * obtained from. - * @return a R2DBC Connection from the given {@link io.r2dbc.spi.ConnectionFactory}. - * @throws DataAccessResourceFailureException if the attempt to get a {@link io.r2dbc.spi.Connection} failed - */ - public static Mono closeConnection(Connection connection, ConnectionFactory connectionFactory) { - - Assert.notNull(connection, "Connection must not be null!"); - Assert.notNull(connectionFactory, "ConnectionFactory must not be null!"); - - return doCloseConnection(connection, connectionFactory) - .onErrorMap(e -> new DataAccessResourceFailureException("Failed to obtain R2DBC Connection", e)); - } - - /** - * Close the {@link io.r2dbc.spi.Connection}, unless a {@link SmartConnectionFactory} doesn't want us to. - * - * @param connection the {@link io.r2dbc.spi.Connection} to close if necessary. - * @param connectionFactory the {@link io.r2dbc.spi.ConnectionFactory} that the Connection was obtained from. - * @see Connection#close() - * @see SmartConnectionFactory#shouldClose(Connection) - */ - public static Mono doCloseConnection(Connection connection, @Nullable ConnectionFactory connectionFactory) { - - if (!(connectionFactory instanceof SmartConnectionFactory) - || ((SmartConnectionFactory) connectionFactory).shouldClose(connection)) { - - if (logger.isDebugEnabled()) { - logger.debug("Closing R2DBC Connection"); - } - - return Mono.from(connection.close()); - } - - return Mono.empty(); - } - - /** - * Obtain the {@link io.r2dbc.spi.ConnectionFactory} from the current subscriber {@link reactor.util.context.Context}. - * - * @param connectionFactory the {@link io.r2dbc.spi.ConnectionFactory} that the Connection was obtained from. - * @see TransactionSynchronizationManager - */ - public static Mono currentConnectionFactory(ConnectionFactory connectionFactory) { - - return org.springframework.r2dbc.connection.ConnectionFactoryUtils.currentConnectionFactory(connectionFactory); - } - - /** - * Return the innermost target {@link io.r2dbc.spi.Connection} of the given {@link io.r2dbc.spi.Connection}. If the - * given {@link io.r2dbc.spi.Connection} is a proxy, it will be unwrapped until a non-proxy - * {@link io.r2dbc.spi.Connection} is found. Otherwise, the passed-in Connection will be returned as-is. - * - * @param con the {@link io.r2dbc.spi.Connection} proxy to unwrap - * @return the innermost target Connection, or the passed-in one if no proxy - * @see ConnectionProxy#getTargetConnection() - */ - public static Connection getTargetConnection(Connection con) { - - Connection conToUse = con; - while (conToUse instanceof ConnectionProxy) { - conToUse = ((ConnectionProxy) conToUse).getTargetConnection(); - } - return conToUse; - } - - /** - * Determine the connection synchronization order to use for the given {@link io.r2dbc.spi.ConnectionFactory}. - * Decreased for every level of nesting that a {@link io.r2dbc.spi.ConnectionFactory} has, checked through the level - * of {@link DelegatingConnectionFactory} nesting. - * - * @param connectionFactory the {@link io.r2dbc.spi.ConnectionFactory} to check. - * @return the connection synchronization order to use. - * @see #CONNECTION_SYNCHRONIZATION_ORDER - */ - private static int getConnectionSynchronizationOrder(ConnectionFactory connectionFactory) { - - int order = CONNECTION_SYNCHRONIZATION_ORDER; - ConnectionFactory current = connectionFactory; - while (current instanceof DelegatingConnectionFactory) { - order--; - current = ((DelegatingConnectionFactory) current).getTargetConnectionFactory(); - } - return order; - } - -} diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/ConnectionHandle.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/ConnectionHandle.java deleted file mode 100644 index 128ed20f8..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/ConnectionHandle.java +++ /dev/null @@ -1,47 +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.connectionfactory; - -import io.r2dbc.spi.Connection; - -/** - * Simple interface to be implemented by handles for a R2DBC Connection. - * - * @author Mark Paluch - * @see SimpleConnectionHandle - * @see ConnectionHolder - * @deprecated since 1.2 in favor of Spring R2DBC without replacement. - */ -@FunctionalInterface -@Deprecated -public interface ConnectionHandle { - - /** - * Fetch the R2DBC Connection that this handle refers to. - */ - Connection getConnection(); - - /** - * Release the R2DBC Connection that this handle refers to. Assumes a non-blocking implementation without - * synchronization. - *

- * The default implementation is empty, assuming that the lifecycle of the connection is managed externally. - * - * @param connection the R2DBC Connection to release - */ - default void releaseConnection(Connection connection) { - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/ConnectionHolder.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/ConnectionHolder.java deleted file mode 100644 index 9f9164d9c..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/ConnectionHolder.java +++ /dev/null @@ -1,171 +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.connectionfactory; - -import io.r2dbc.spi.Connection; -import io.r2dbc.spi.ConnectionFactory; -import org.springframework.lang.Nullable; -import org.springframework.transaction.support.ResourceHolderSupport; -import org.springframework.util.Assert; - -/** - * Resource holder wrapping a R2DBC {@link Connection}. {@link R2dbcTransactionManager} binds instances of this class to - * the thread, for a specific {@link ConnectionFactory}. - *

- * Inherits rollback-only support for nested R2DBC transactions and reference count functionality from the base class. - *

- * Note: This is an SPI class, not intended to be used by applications. - * - * @author Mark Paluch - * @author Christoph Strobl - * @see R2dbcTransactionManager - * @see ConnectionFactoryUtils - * @deprecated since 1.2 in favor of Spring R2DBC. Use {@link org.springframework.r2dbc.connection.ConnectionHolder} - * instead. - */ -@Deprecated -public class ConnectionHolder extends ResourceHolderSupport { - - @Nullable private ConnectionHandle connectionHandle; - - @Nullable private Connection currentConnection; - - private boolean transactionActive; - - /** - * Create a new ConnectionHolder for the given R2DBC {@link Connection}, wrapping it with a - * {@link SimpleConnectionHandle}, assuming that there is no ongoing transaction. - * - * @param connection the R2DBC {@link Connection} to hold - * @see SimpleConnectionHandle - * @see #ConnectionHolder(Connection, boolean) - */ - public ConnectionHolder(Connection connection) { - this(connection, false); - } - - /** - * Create a new ConnectionHolder for the given R2DBC {@link Connection}, wrapping it with a - * {@link SimpleConnectionHandle}. - * - * @param connection the R2DBC {@link Connection} to hold - * @param transactionActive whether the given {@link Connection} is involved in an ongoing transaction - * @see SimpleConnectionHandle - */ - public ConnectionHolder(Connection connection, boolean transactionActive) { - - this.connectionHandle = new SimpleConnectionHandle(connection); - this.transactionActive = transactionActive; - } - - /** - * Return the ConnectionHandle held by this ConnectionHolder. - */ - @Nullable - public ConnectionHandle getConnectionHandle() { - return this.connectionHandle; - } - - /** - * Return whether this holder currently has a {@link Connection}. - */ - protected boolean hasConnection() { - return (this.connectionHandle != null); - } - - /** - * Set whether this holder represents an active, R2DBC-managed transaction. - * - * @see R2dbcTransactionManager - */ - protected void setTransactionActive(boolean transactionActive) { - this.transactionActive = transactionActive; - } - - /** - * Return whether this holder represents an active, R2DBC-managed transaction. - */ - protected boolean isTransactionActive() { - return this.transactionActive; - } - - /** - * Override the existing Connection handle with the given {@link Connection}. Reset the handle if given - * {@literal null}. - *

- * Used for releasing the {@link Connection} on suspend (with a {@literal null} argument) and setting a fresh - * {@link Connection} on resume. - */ - protected void setConnection(@Nullable Connection connection) { - if (this.currentConnection != null) { - if (this.connectionHandle != null) { - this.connectionHandle.releaseConnection(this.currentConnection); - } - this.currentConnection = null; - } - if (connection != null) { - this.connectionHandle = new SimpleConnectionHandle(connection); - } else { - this.connectionHandle = null; - } - } - - /** - * Return the current {@link Connection} held by this {@link ConnectionHolder}. - *

- * This will be the same {@link Connection} until {@code released} gets called on the {@link ConnectionHolder}, which - * will reset the held {@link Connection}, fetching a new {@link Connection} on demand. - * - * @see ConnectionHandle#getConnection() - * @see #released() - */ - public Connection getConnection() { - - Assert.notNull(this.connectionHandle, "Active Connection is required"); - if (this.currentConnection == null) { - this.currentConnection = this.connectionHandle.getConnection(); - } - return this.currentConnection; - } - - /** - * Releases the current {@link Connection} held by this {@link ConnectionHolder}. - *

- * This is necessary for {@link ConnectionHandle}s that expect "Connection borrowing", where each returned - * {@link Connection} is only temporarily leased and needs to be returned once the data operation is done, to make the - * Connection available for other operations within the same transaction. - */ - @Override - public void released() { - super.released(); - if (!isOpen() && this.currentConnection != null) { - if (this.connectionHandle != null) { - this.connectionHandle.releaseConnection(this.currentConnection); - } - this.currentConnection = null; - } - } - - /* - * (non-Javadoc) - * @see org.springframework.transaction.support.ResourceHolderSupport#clear() - */ - @Override - public void clear() { - super.clear(); - this.transactionActive = false; - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/ConnectionProxy.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/ConnectionProxy.java deleted file mode 100644 index badec6518..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/ConnectionProxy.java +++ /dev/null @@ -1,43 +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.connectionfactory; - -import io.r2dbc.spi.Connection; -import io.r2dbc.spi.Wrapped; - -/** - * Sub interface of {@link Connection} to be implemented by Connection proxies. Allows access to the underlying target - * Connection. - *

- * This interface can be checked when there is a need to cast to a native R2DBC {@link Connection}. - * - * @author Mark Paluch - * @author Christoph Strobl - * @deprecated since 1.2 in favor of Spring R2DBC. Use R2DBC's {@link Wrapped} mechanism instead. - */ -@Deprecated -public interface ConnectionProxy extends Connection, Wrapped { - - /** - * Return the target {@link Connection} of this proxy. - *

- * This will typically be the native driver {@link Connection} or a wrapper from a connection pool. - * - * @return the underlying Connection (never {@literal null}) - * @throws IllegalStateException in case the connection has already been closed. - */ - Connection getTargetConnection(); -} diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/DelegatingConnectionFactory.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/DelegatingConnectionFactory.java deleted file mode 100644 index 63192ece3..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/DelegatingConnectionFactory.java +++ /dev/null @@ -1,90 +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.connectionfactory; - -import io.r2dbc.spi.Connection; -import io.r2dbc.spi.ConnectionFactory; -import io.r2dbc.spi.ConnectionFactoryMetadata; -import io.r2dbc.spi.Wrapped; -import reactor.core.publisher.Mono; - -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; - -/** - * R2DBC {@link ConnectionFactory} implementation that delegates all calls to a given target {@link ConnectionFactory}. - *

- * This class is meant to be subclassed, with subclasses overriding only those methods (such as {@link #create()}) that - * should not simply delegate to the target {@link ConnectionFactory}. - * - * @author Mark Paluch - * @see #create - * @deprecated since 1.2 in favor of Spring R2DBC. Use - * {@link org.springframework.r2dbc.connection.DelegatingConnectionFactory} instead. - */ -@Deprecated -public class DelegatingConnectionFactory implements ConnectionFactory, Wrapped { - - private final ConnectionFactory targetConnectionFactory; - - public DelegatingConnectionFactory(ConnectionFactory targetConnectionFactory) { - - Assert.notNull(targetConnectionFactory, "ConnectionFactory must not be null"); - this.targetConnectionFactory = targetConnectionFactory; - } - - /* - * (non-Javadoc) - * @see io.r2dbc.spi.ConnectionFactory#create() - */ - @Override - public Mono create() { - return Mono.from(targetConnectionFactory.create()); - } - - /** - * Return the target {@link ConnectionFactory} that this {@link ConnectionFactory} should delegate to. - */ - @Nullable - public ConnectionFactory getTargetConnectionFactory() { - return this.targetConnectionFactory; - } - - /* - * (non-Javadoc) - * @see io.r2dbc.spi.ConnectionFactory#getMetadata() - */ - @Override - public ConnectionFactoryMetadata getMetadata() { - return obtainTargetConnectionFactory().getMetadata(); - } - - /* - * (non-Javadoc) - * @see io.r2dbc.spi.Wrapped#unwrap() - */ - @Override - public ConnectionFactory unwrap() { - return obtainTargetConnectionFactory(); - } - - /** - * Obtain the target {@link ConnectionFactory} for actual use (never {@literal null}). - */ - protected ConnectionFactory obtainTargetConnectionFactory() { - return getTargetConnectionFactory(); - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/R2dbcTransactionManager.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/R2dbcTransactionManager.java deleted file mode 100644 index 417214956..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/R2dbcTransactionManager.java +++ /dev/null @@ -1,83 +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.connectionfactory; - -import io.r2dbc.spi.Connection; -import io.r2dbc.spi.ConnectionFactory; - -import org.springframework.beans.factory.InitializingBean; -import org.springframework.data.r2dbc.core.DatabaseClient; - -/** - * {@link org.springframework.transaction.ReactiveTransactionManager} implementation for a single R2DBC - * {@link ConnectionFactory}. This class is capable of working in any environment with any R2DBC driver, as long as the - * setup uses a {@link ConnectionFactory} as its {@link Connection} factory mechanism. Binds a R2DBC {@link Connection} - * from the specified {@link ConnectionFactory} to the current subscriber context, potentially allowing for one - * context-bound {@link Connection} per {@link ConnectionFactory}. - *

- * Note: The {@link ConnectionFactory} that this transaction manager operates on needs to return independent - * {@link Connection}s. The {@link Connection}s may come from a pool (the typical case), but the - * {@link ConnectionFactory} must not return scoped scoped {@link Connection}s or the like. This transaction manager - * will associate {@link Connection} with context-bound transactions itself, according to the specified propagation - * behavior. It assumes that a separate, independent {@link Connection} can be obtained even during an ongoing - * transaction. - *

- * Application code is required to retrieve the R2DBC Connection via - * {@link ConnectionFactoryUtils#getConnection(ConnectionFactory)} instead of a standard R2DBC-style - * {@link ConnectionFactory#create()} call. Spring classes such as {@link DatabaseClient} use this strategy implicitly. - * If not used in combination with this transaction manager, the {@link ConnectionFactoryUtils} lookup strategy behaves - * exactly like the native {@link ConnectionFactory} lookup; it can thus be used in a portable fashion. - *

- * Alternatively, you can allow application code to work with the standard R2DBC lookup pattern - * {@link ConnectionFactory#create()}, for example for code that is not aware of Spring at all. In that case, define a - * {@link TransactionAwareConnectionFactoryProxy} for your target {@link ConnectionFactory}, and pass that proxy - * {@link ConnectionFactory} to your DAOs, which will automatically participate in Spring-managed transactions when - * accessing it. - *

- * This transaction manager triggers flush callbacks on registered transaction synchronizations (if synchronization is - * generally active), assuming resources operating on the underlying R2DBC {@link Connection}. - * - * @author Mark Paluch - * @see ConnectionFactoryUtils#getConnection(ConnectionFactory) - * @see ConnectionFactoryUtils#releaseConnection - * @see TransactionAwareConnectionFactoryProxy - * @see DatabaseClient - * @deprecated since 1.2 in favor of Spring R2DBC. Use - * {@link org.springframework.r2dbc.connection.R2dbcTransactionManager} instead. - */ -@Deprecated -public class R2dbcTransactionManager extends org.springframework.r2dbc.connection.R2dbcTransactionManager - implements InitializingBean { - - /** - * Create a new @link ConnectionFactoryTransactionManager} instance. A ConnectionFactory has to be set to be able to - * use it. - * - * @see #setConnectionFactory - */ - public R2dbcTransactionManager() {} - - /** - * Create a new {@link R2dbcTransactionManager} instance. - * - * @param connectionFactory the R2DBC ConnectionFactory to manage transactions for - */ - public R2dbcTransactionManager(ConnectionFactory connectionFactory) { - this(); - setConnectionFactory(connectionFactory); - afterPropertiesSet(); - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/SimpleConnectionHandle.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/SimpleConnectionHandle.java deleted file mode 100644 index 02f43d38e..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/SimpleConnectionHandle.java +++ /dev/null @@ -1,58 +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.connectionfactory; - -import io.r2dbc.spi.Connection; - -import org.springframework.util.Assert; - -/** - * Simple implementation of the {@link ConnectionHandle} interface, containing a given R2DBC Connection. - * - * @author Mark Paluch - * @author Christoph Strobl - * @deprecated since 1.2 in favor of Spring R2DBC. Use {@link org.springframework.r2dbc.connection} instead. - */ -@Deprecated -public class SimpleConnectionHandle implements ConnectionHandle { - - private final Connection connection; - - /** - * Create a new SimpleConnectionHandle for the given Connection. - * - * @param connection the R2DBC Connection - */ - SimpleConnectionHandle(Connection connection) { - - Assert.notNull(connection, "Connection must not be null"); - this.connection = connection; - } - - /** - * Return the specified Connection as-is. - */ - @Override - public Connection getConnection() { - return this.connection; - } - - @Override - public String toString() { - return "SimpleConnectionHandle: " + this.connection; - } - -} diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/SingleConnectionConnectionFactory.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/SingleConnectionConnectionFactory.java deleted file mode 100644 index 0fb2fb11f..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/SingleConnectionConnectionFactory.java +++ /dev/null @@ -1,295 +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.connectionfactory; - -import io.r2dbc.spi.Connection; -import io.r2dbc.spi.ConnectionFactories; -import io.r2dbc.spi.ConnectionFactory; -import io.r2dbc.spi.ConnectionFactoryMetadata; -import reactor.core.publisher.Mono; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.util.concurrent.atomic.AtomicReference; - -import org.reactivestreams.Publisher; - -import org.springframework.beans.factory.DisposableBean; -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; - -/** - * Implementation of {@link SmartConnectionFactory} that wraps a single R2DBC Connection which is not closed after use. - * Obviously, this is not multi-threading capable. - *

- * Note that at shutdown, someone should close the underlying Connection via the {@code close()} method. Client code - * will never call close on the Connection handle if it is SmartDataSource-aware (e.g. uses - * {@link ConnectionFactoryUtils#releaseConnection(io.r2dbc.spi.Connection, ConnectionFactory)}). - *

- * If client code will call {@link Connection#close()} in the assumption of a pooled Connection, like when using - * persistence tools, set "suppressClose" to "true". This will return a close-suppressing proxy instead of the physical - * Connection. - *

- * This is primarily intended for testing. For example, it enables easy testing outside an application server, for code - * that expects to work on a {@link ConnectionFactory}. - * - * @author Mark Paluch - * @see #create() - * @see io.r2dbc.spi.Connection#close() - * @see ConnectionFactoryUtils#releaseConnection(io.r2dbc.spi.Connection, ConnectionFactory) - * @deprecated since 1.2 in favor of Spring R2DBC. Use - * {@link org.springframework.r2dbc.connection.SingleConnectionFactory} instead. - */ -@Deprecated -public class SingleConnectionConnectionFactory extends DelegatingConnectionFactory - implements SmartConnectionFactory, DisposableBean { - - /** Create a close-suppressing proxy?. */ - private boolean suppressClose; - - /** Override auto-commit state?. */ - private @Nullable Boolean autoCommit; - - /** Wrapped Connection. */ - private final AtomicReference target = new AtomicReference<>(); - - /** Proxy Connection. */ - private @Nullable Connection connection; - - private final Mono connectionEmitter; - - /** - * Constructor for bean-style configuration. - */ - public SingleConnectionConnectionFactory(ConnectionFactory targetConnectionFactory) { - super(targetConnectionFactory); - this.connectionEmitter = super.create().cache(); - } - - /** - * Create a new {@link SingleConnectionConnectionFactory} using a R2DBC connection URL. - * - * @param url the R2DBC URL to use for accessing {@link ConnectionFactory} discovery. - * @param suppressClose if the returned {@link Connection} should be a close-suppressing proxy or the physical - * {@link Connection}. - * @see ConnectionFactories#get(String) - */ - public SingleConnectionConnectionFactory(String url, boolean suppressClose) { - super(ConnectionFactories.get(url)); - this.suppressClose = suppressClose; - this.connectionEmitter = super.create().cache(); - } - - /** - * Create a new {@link SingleConnectionConnectionFactory} with a given {@link Connection} and - * {@link ConnectionFactoryMetadata}. - * - * @param target underlying target {@link Connection}. - * @param metadata {@link ConnectionFactory} metadata to be associated with this {@link ConnectionFactory}. - * @param suppressClose if the {@link Connection} should be wrapped with a {@link Connection} that suppresses - * {@code close()} calls (to allow for normal {@code close()} usage in applications that expect a pooled - * {@link Connection} but do not know our {@link SmartConnectionFactory} interface). - */ - public SingleConnectionConnectionFactory(Connection target, ConnectionFactoryMetadata metadata, - boolean suppressClose) { - super(new ConnectionFactory() { - @Override - public Publisher create() { - return Mono.just(target); - } - - @Override - public ConnectionFactoryMetadata getMetadata() { - return metadata; - } - }); - Assert.notNull(target, "Connection must not be null"); - Assert.notNull(metadata, "ConnectionFactoryMetadata must not be null"); - this.target.set(target); - this.connectionEmitter = Mono.just(target); - this.suppressClose = suppressClose; - this.connection = (suppressClose ? getCloseSuppressingConnectionProxy(target) : target); - } - - /** - * Set whether the returned {@link Connection} should be a close-suppressing proxy or the physical {@link Connection}. - */ - public void setSuppressClose(boolean suppressClose) { - this.suppressClose = suppressClose; - } - - /** - * Return whether the returned {@link Connection} will be a close-suppressing proxy or the physical - * {@link Connection}. - */ - protected boolean isSuppressClose() { - return this.suppressClose; - } - - /** - * Set whether the returned {@link Connection}'s "autoCommit" setting should be overridden. - */ - public void setAutoCommit(boolean autoCommit) { - this.autoCommit = autoCommit; - } - - /** - * Return whether the returned {@link Connection}'s "autoCommit" setting should be overridden. - * - * @return the "autoCommit" value, or {@code null} if none to be applied - */ - @Nullable - protected Boolean getAutoCommitValue() { - return this.autoCommit; - } - - @Override - public Mono create() { - - Connection connection = this.target.get(); - - return connectionEmitter.map(it -> { - - if (connection == null) { - this.target.compareAndSet(connection, it); - this.connection = (isSuppressClose() ? getCloseSuppressingConnectionProxy(it) : it); - } - - return this.connection; - }).flatMap(this::prepareConnection); - } - - /** - * This is a single Connection: Do not close it when returning to the "pool". - */ - @Override - public boolean shouldClose(Connection con) { - return (con != this.connection && con != this.target.get()); - } - - /** - * Close the underlying {@link Connection}. The provider of this {@link ConnectionFactory} needs to care for proper - * shutdown. - *

- * As this bean implements {@link DisposableBean}, a bean factory will automatically invoke this on destruction of its - * cached singletons. - */ - @Override - public void destroy() { - resetConnection().block(); - } - - /** - * Reset the underlying shared Connection, to be reinitialized on next access. - */ - public Mono resetConnection() { - - Connection connection = this.target.get(); - - if (connection == null) { - return Mono.empty(); - } - - return Mono.defer(() -> { - - if (this.target.compareAndSet(connection, null)) { - - this.connection = null; - - return Mono.from(connection.close()); - } - - return Mono.empty(); - }); - } - - /** - * Prepare the {@link Connection} before using it. Applies {@link #getAutoCommitValue() auto-commit} settings if - * configured. - * - * @param connection the requested {@link Connection}. - * @return the prepared {@link Connection}. - */ - protected Mono prepareConnection(Connection connection) { - - Boolean autoCommit = getAutoCommitValue(); - if (autoCommit != null) { - return Mono.from(connection.setAutoCommit(autoCommit)).thenReturn(connection); - } - - return Mono.just(connection); - } - - /** - * Wrap the given {@link Connection} with a proxy that delegates every method call to it but suppresses close calls. - * - * @param target the original {@link Connection} to wrap. - * @return the wrapped Connection. - */ - protected Connection getCloseSuppressingConnectionProxy(Connection target) { - return (Connection) Proxy.newProxyInstance(ConnectionProxy.class.getClassLoader(), - new Class[] { ConnectionProxy.class }, new CloseSuppressingInvocationHandler(target)); - } - - /** - * Invocation handler that suppresses close calls on R2DBC Connections. - * - * @see io.r2dbc.spi.Connection#close() - */ - private static class CloseSuppressingInvocationHandler implements InvocationHandler { - - private final io.r2dbc.spi.Connection target; - - CloseSuppressingInvocationHandler(io.r2dbc.spi.Connection target) { - this.target = target; - } - - @Override - @Nullable - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - // Invocation on ConnectionProxy interface coming in... - - if (method.getName().equals("equals")) { - // Only consider equal when proxies are identical. - return proxy == args[0]; - } else if (method.getName().equals("hashCode")) { - // Use hashCode of PersistenceManager proxy. - return System.identityHashCode(proxy); - } else if (method.getName().equals("unwrap")) { - return target; - } else if (method.getName().equals("close")) { - // Handle close method: suppress, not valid. - return Mono.empty(); - } else if (method.getName().equals("getTargetConnection")) { - // Handle getTargetConnection method: return underlying Connection. - return this.target; - } - - // Invoke method on target Connection. - try { - Object retVal = method.invoke(this.target, args); - - return retVal; - } catch (InvocationTargetException ex) { - throw ex.getTargetException(); - } - } - } - -} diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/SmartConnectionFactory.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/SmartConnectionFactory.java deleted file mode 100644 index 3fa75ca34..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/SmartConnectionFactory.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2018-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.connectionfactory; - -import io.r2dbc.spi.Connection; -import io.r2dbc.spi.ConnectionFactory; - -/** - * Extension of the {@code io.r2dbc.spi.ConnectionFactory} interface, to be implemented by special connection factories - * that return R2DBC Connections in an unwrapped fashion. - *

- * Classes using this interface can query whether or not the {@link Connection} should be closed after an operation. - * Spring's {@link ConnectionFactoryUtils} automatically perform such a check. - * - * @author Mark Paluch - * @see ConnectionFactoryUtils#closeConnection - * @deprecated since 1.2 in favor of Spring R2DBC without replacement. - */ -@Deprecated -public interface SmartConnectionFactory extends ConnectionFactory { - - /** - * Should we close this {@link io.r2dbc.spi.Connection}, obtained from this {@code io.r2dbc.spi.ConnectionFactory}? - *

- * Code that uses Connections from a SmartConnectionFactory should always perform a check via this method before - * invoking {@code close()}. - * - * @param connection the {@link io.r2dbc.spi.Connection} to check. - * @return whether the given {@link Connection} should be closed. - * @see io.r2dbc.spi.Connection#close() - */ - boolean shouldClose(Connection connection); -} diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/TransactionAwareConnectionFactoryProxy.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/TransactionAwareConnectionFactoryProxy.java deleted file mode 100644 index 4448ed9c3..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/TransactionAwareConnectionFactoryProxy.java +++ /dev/null @@ -1,198 +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.connectionfactory; - -import io.r2dbc.spi.Connection; -import io.r2dbc.spi.ConnectionFactory; -import io.r2dbc.spi.Wrapped; -import reactor.core.publisher.Mono; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; - -import org.springframework.data.r2dbc.core.DatabaseClient; -import org.springframework.lang.Nullable; -import org.springframework.util.ReflectionUtils; - -/** - * Proxy for a target R2DBC {@link ConnectionFactory}, adding awareness of Spring-managed transactions. - *

- * Data access code that should remain unaware of Spring's data access support can work with this proxy to seamlessly - * participate in Spring-managed transactions. Note that the transaction manager, for example - * {@link R2dbcTransactionManager}, still needs to work with the underlying {@link ConnectionFactory}, not with - * this proxy. - *

- * Make sure that {@link TransactionAwareConnectionFactoryProxy} is the outermost {@link ConnectionFactory} of a - * chain of {@link ConnectionFactory} proxies/adapters. {@link TransactionAwareConnectionFactoryProxy} can delegate - * either directly to the target connection pool or to some intermediary proxy/adapter. - *

- * Delegates to {@link ConnectionFactoryUtils} for automatically participating in thread-bound transactions, for example - * managed by {@link R2dbcTransactionManager}. {@link #create()} calls and {@code close} calls on returned - * {@link Connection} will behave properly within a transaction, i.e. always operate on the transactional Connection. If - * not within a transaction, normal {@link ConnectionFactory} behavior applies. - *

- * This proxy allows data access code to work with the plain R2DBC API. However, if possible, use Spring's - * {@link ConnectionFactoryUtils} or {@link DatabaseClient} to get transaction participation even without a proxy for - * the target {@link ConnectionFactory}, avoiding the need to define such a proxy in the first place. - *

- * NOTE: This {@link ConnectionFactory} proxy needs to return wrapped {@link Connection}s (which implement the - * {@link ConnectionProxy} interface) in order to handle close calls properly. Use {@link Wrapped#unwrap()} to retrieve - * the native R2DBC Connection. - * - * @author Mark Paluch - * @author Christoph Strobl - * @see ConnectionFactory#create - * @see Connection#close - * @see ConnectionFactoryUtils#doGetConnection - * @see ConnectionFactoryUtils#doReleaseConnection - * @deprecated since 1.2 in favor of Spring R2DBC. Use - * {@link org.springframework.r2dbc.connection.TransactionAwareConnectionFactoryProxy} instead. - */ -@Deprecated -public class TransactionAwareConnectionFactoryProxy extends DelegatingConnectionFactory { - - /** - * Create a new {@link TransactionAwareConnectionFactoryProxy}. - * - * @param targetConnectionFactory the target {@link ConnectionFactory}. - * @throws IllegalArgumentException if given {@link ConnectionFactory} is {@literal null}. - */ - public TransactionAwareConnectionFactoryProxy(ConnectionFactory targetConnectionFactory) { - super(targetConnectionFactory); - } - - /** - * Delegates to {@link ConnectionFactoryUtils} for automatically participating in Spring-managed transactions. - *

- * The returned {@link ConnectionFactory} handle implements the {@link ConnectionProxy} interface, allowing to - * retrieve the underlying target {@link Connection}. - * - * @return a transactional {@link Connection} if any, a new one else. - * @see ConnectionFactoryUtils#doGetConnection - * @see ConnectionProxy#getTargetConnection - */ - @Override - public Mono create() { - return getTransactionAwareConnectionProxy(obtainTargetConnectionFactory()); - } - - /** - * Wraps the given {@link Connection} with a proxy that delegates every method call to it but delegates - * {@code close()} calls to {@link ConnectionFactoryUtils}. - * - * @param targetConnectionFactory the {@link ConnectionFactory} that the {@link Connection} came from. - * @return the wrapped {@link Connection}. - * @see Connection#close() - * @see ConnectionFactoryUtils#doReleaseConnection - */ - protected Mono getTransactionAwareConnectionProxy(ConnectionFactory targetConnectionFactory) { - return ConnectionFactoryUtils.getConnection(targetConnectionFactory) - .map(it -> proxyConnection(it, targetConnectionFactory)); - } - - private static Connection proxyConnection(Connection connection, ConnectionFactory targetConnectionFactory) { - - return (Connection) Proxy.newProxyInstance(ConnectionProxy.class.getClassLoader(), - new Class[] { ConnectionProxy.class }, - new TransactionAwareInvocationHandler(connection, targetConnectionFactory)); - } - - /** - * Invocation handler that delegates close calls on R2DBC Connections to {@link ConnectionFactoryUtils} for being - * aware of context-bound transactions. - */ - private static class TransactionAwareInvocationHandler implements InvocationHandler { - - private final Connection connection; - - private final ConnectionFactory targetConnectionFactory; - - private boolean closed = false; - - TransactionAwareInvocationHandler(Connection connection, ConnectionFactory targetConnectionFactory) { - - this.connection = connection; - this.targetConnectionFactory = targetConnectionFactory; - } - - /* - * (non-Javadoc) - * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[]) - */ - @Override - @Nullable - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - - if (ReflectionUtils.isObjectMethod(method)) { - - if (ReflectionUtils.isToStringMethod(method)) { - return proxyToString(proxy); - } - - if (ReflectionUtils.isEqualsMethod(method)) { - return (proxy == args[0]); - } - - if (ReflectionUtils.isHashCodeMethod(method)) { - return System.identityHashCode(proxy); - } - } - - // Invocation on ConnectionProxy interface coming in... - switch (method.getName()) { - - case "unwrap": - return this.connection; - case "close": - // Handle close method: only close if not within a transaction. - return ConnectionFactoryUtils.doReleaseConnection(this.connection, this.targetConnectionFactory) - .doOnSubscribe(n -> this.closed = true); - case "isClosed": - return this.closed; - } - - if (this.closed) { - throw new IllegalStateException("Connection handle already closed"); - } - - if (method.getName().equals("getTargetConnection")) { - // Handle getTargetConnection method: return underlying Connection. - return this.connection; - } - - // Invoke method on target Connection. - try { - return method.invoke(this.connection, args); - } catch (InvocationTargetException ex) { - throw ex.getTargetException(); - } - } - - private String proxyToString(@Nullable Object proxy) { - - // Allow for differentiating between the proxy and the raw Connection. - StringBuilder sb = new StringBuilder("Transaction-aware proxy for target Connection "); - if (this.connection != null) { - sb.append("[").append(this.connection.toString()).append("]"); - } else { - sb.append(" from ConnectionFactory [").append(this.targetConnectionFactory).append("]"); - } - return sb.toString(); - } - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/CannotReadScriptException.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/CannotReadScriptException.java deleted file mode 100644 index b7e9a7f1d..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/CannotReadScriptException.java +++ /dev/null @@ -1,41 +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.connectionfactory.init; - -import org.springframework.core.io.support.EncodedResource; - -/** - * Thrown by {@link ScriptUtils} if an SQL script cannot be read. - * - * @author Mark Paluch - * @deprecated since 1.2 in favor of Spring R2DBC. Use - * {@link org.springframework.r2dbc.connection.init.CannotReadScriptException} instead. - */ -@Deprecated -public class CannotReadScriptException extends ScriptException { - - private static final long serialVersionUID = 7253084944991764250L; - - /** - * Creates a new {@link CannotReadScriptException}. - * - * @param resource the resource that cannot be read from. - * @param cause the underlying cause of the resource access failure. - */ - public CannotReadScriptException(EncodedResource resource, Throwable cause) { - super("Cannot read SQL script from " + resource, cause); - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/CompositeDatabasePopulator.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/CompositeDatabasePopulator.java deleted file mode 100644 index aa334de75..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/CompositeDatabasePopulator.java +++ /dev/null @@ -1,102 +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.connectionfactory.init; - -import io.r2dbc.spi.Connection; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; - -import org.springframework.util.Assert; - -/** - * Composite {@link DatabasePopulator} that delegates to a list of given {@link DatabasePopulator} implementations, - * executing all scripts. - * - * @author Mark Paluch - * @deprecated since 1.2 in favor of Spring R2DBC. Use - * {@link org.springframework.r2dbc.connection.init.CompositeDatabasePopulator} instead. - */ -@Deprecated -public class CompositeDatabasePopulator implements DatabasePopulator { - - private final List populators = new ArrayList<>(4); - - /** - * Creates an empty {@link CompositeDatabasePopulator}. - * - * @see #setPopulators - * @see #addPopulators - */ - public CompositeDatabasePopulator() {} - - /** - * Creates a {@link CompositeDatabasePopulator}. with the given populators. - * - * @param populators one or more populators to delegate to. - */ - public CompositeDatabasePopulator(Collection populators) { - - Assert.notNull(populators, "Collection of DatabasePopulator must not be null!"); - - this.populators.addAll(populators); - } - - /** - * Creates a {@link CompositeDatabasePopulator} with the given populators. - * - * @param populators one or more populators to delegate to. - */ - public CompositeDatabasePopulator(DatabasePopulator... populators) { - - Assert.notNull(populators, "DatabasePopulators must not be null!"); - - this.populators.addAll(Arrays.asList(populators)); - } - - /** - * Specify one or more populators to delegate to. - */ - public void setPopulators(DatabasePopulator... populators) { - - Assert.notNull(populators, "DatabasePopulators must not be null!"); - - this.populators.clear(); - this.populators.addAll(Arrays.asList(populators)); - } - - /** - * Add one or more populators to the list of delegates. - */ - public void addPopulators(DatabasePopulator... populators) { - - Assert.notNull(populators, "DatabasePopulators must not be null!"); - - this.populators.addAll(Arrays.asList(populators)); - } - - @Override - public Mono populate(Connection connection) throws ScriptException { - - Assert.notNull(connection, "Connection must not be null!"); - - return Flux.fromIterable(this.populators).concatMap(it -> it.populate(connection)).then(); - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/ConnectionFactoryInitializer.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/ConnectionFactoryInitializer.java deleted file mode 100644 index 6aef6bd23..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/ConnectionFactoryInitializer.java +++ /dev/null @@ -1,113 +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.connectionfactory.init; - -import io.r2dbc.spi.ConnectionFactory; - -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; - -/** - * Used to {@link #setDatabasePopulator set up} a database during initialization and {@link #setDatabaseCleaner clean - * up} a database during destruction. - * - * @author Mark Paluch - * @see DatabasePopulator - * @deprecated since 1.2 in favor of Spring R2DBC. Use - * {@link org.springframework.r2dbc.connection.init.ConnectionFactoryInitializer} instead. - */ -@Deprecated -public class ConnectionFactoryInitializer implements InitializingBean, DisposableBean { - - private @Nullable ConnectionFactory connectionFactory; - - private @Nullable DatabasePopulator databasePopulator; - - private @Nullable DatabasePopulator databaseCleaner; - - private boolean enabled = true; - - /** - * The {@link ConnectionFactory} for the database to populate when this component is initialized and to clean up when - * this component is shut down. - *

- * This property is mandatory with no default provided. - * - * @param connectionFactory the R2DBC {@link ConnectionFactory}. - */ - public void setConnectionFactory(ConnectionFactory connectionFactory) { - this.connectionFactory = connectionFactory; - } - - /** - * Set the {@link DatabasePopulator} to execute during the bean initialization phase. - * - * @param databasePopulator the {@link DatabasePopulator} to use during initialization - * @see #setDatabaseCleaner - */ - public void setDatabasePopulator(DatabasePopulator databasePopulator) { - this.databasePopulator = databasePopulator; - } - - /** - * Set the {@link DatabasePopulator} to execute during the bean destruction phase, cleaning up the database and - * leaving it in a known state for others. - * - * @param databaseCleaner the {@link DatabasePopulator} to use during destruction - * @see #setDatabasePopulator - */ - public void setDatabaseCleaner(DatabasePopulator databaseCleaner) { - this.databaseCleaner = databaseCleaner; - } - - /** - * Flag to explicitly enable or disable the {@link #setDatabasePopulator database populator} and - * {@link #setDatabaseCleaner database cleaner}. - * - * @param enabled {@literal true} if the database populator and database cleaner should be called on startup and - * shutdown, respectively - */ - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - /** - * Use the {@link #setDatabasePopulator database populator} to set up the database. - */ - @Override - public void afterPropertiesSet() { - execute(this.databasePopulator); - } - - /** - * Use the {@link #setDatabaseCleaner database cleaner} to clean up the database. - */ - @Override - public void destroy() { - execute(this.databaseCleaner); - } - - private void execute(@Nullable DatabasePopulator populator) { - - Assert.state(this.connectionFactory != null, "ConnectionFactory must be set"); - - if (this.enabled && populator != null) { - DatabasePopulatorUtils.execute(populator, this.connectionFactory).block(); - } - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/DatabasePopulator.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/DatabasePopulator.java deleted file mode 100644 index 4159b14f3..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/DatabasePopulator.java +++ /dev/null @@ -1,45 +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.connectionfactory.init; - -import io.r2dbc.spi.Connection; -import reactor.core.publisher.Mono; - -/** - * Strategy used to populate, initialize, or clean up a database. - * - * @author Mark Paluch - * @see ResourceDatabasePopulator - * @see DatabasePopulatorUtils - * @see ConnectionFactoryInitializer - * @deprecated since 1.2 in favor of Spring R2DBC. Use - * {@link org.springframework.r2dbc.connection.init.DatabasePopulator} instead. - */ -@FunctionalInterface -@Deprecated -public interface DatabasePopulator { - - /** - * Populate, initialize, or clean up the database using the provided R2DBC {@link Connection}. - * - * @param connection the R2DBC connection to use to populate the db; already configured and ready to use, must not be - * {@literal null}. - * @return {@link Mono} that initiates script execution and is notified upon completion. - * @throws ScriptException in all other error cases - * @see DatabasePopulatorUtils#execute - */ - Mono populate(Connection connection) throws ScriptException; -} diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/DatabasePopulatorUtils.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/DatabasePopulatorUtils.java deleted file mode 100644 index 2c0419875..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/DatabasePopulatorUtils.java +++ /dev/null @@ -1,61 +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.connectionfactory.init; - -import io.r2dbc.spi.Connection; -import io.r2dbc.spi.ConnectionFactory; -import reactor.core.publisher.Mono; - -import org.springframework.dao.DataAccessException; -import org.springframework.data.r2dbc.connectionfactory.ConnectionFactoryUtils; -import org.springframework.util.Assert; - -/** - * Utility methods for executing a {@link DatabasePopulator}. - * - * @author Mark Paluch - * @deprecated since 1.2 in favor of Spring R2DBC. Use - * {@link org.springframework.r2dbc.connection.init.DatabasePopulator#populate(ConnectionFactory)} instead. - */ -@Deprecated -public abstract class DatabasePopulatorUtils { - - // utility constructor - private DatabasePopulatorUtils() {} - - /** - * Execute the given {@link DatabasePopulator} against the given {@link io.r2dbc.spi.ConnectionFactory}. - * - * @param populator the {@link DatabasePopulator} to execute. - * @param connectionFactory the {@link ConnectionFactory} to execute against. - * @return {@link Mono} that initiates {@link DatabasePopulator#populate(Connection)} and is notified upon completion. - */ - public static Mono execute(DatabasePopulator populator, ConnectionFactory connectionFactory) - throws DataAccessException { - - Assert.notNull(populator, "DatabasePopulator must not be null"); - Assert.notNull(connectionFactory, "ConnectionFactory must not be null"); - - return Mono.usingWhen(ConnectionFactoryUtils.getConnection(connectionFactory), // - populator::populate, // - it -> ConnectionFactoryUtils.releaseConnection(it, connectionFactory), // - (it, err) -> ConnectionFactoryUtils.releaseConnection(it, connectionFactory), - it -> ConnectionFactoryUtils.releaseConnection(it, connectionFactory)) - .onErrorMap(ex -> !(ex instanceof ScriptException), ex -> { - return new UncategorizedScriptException("Failed to execute database script", ex); - }); - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/ResourceDatabasePopulator.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/ResourceDatabasePopulator.java deleted file mode 100644 index 9947bbfc3..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/ResourceDatabasePopulator.java +++ /dev/null @@ -1,283 +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.connectionfactory.init; - -import io.r2dbc.spi.Connection; -import io.r2dbc.spi.ConnectionFactory; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.springframework.core.io.Resource; -import org.springframework.core.io.buffer.DataBufferFactory; -import org.springframework.core.io.buffer.DefaultDataBufferFactory; -import org.springframework.core.io.support.EncodedResource; -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; - -/** - * Populates, initializes, or cleans up a database using SQL scripts defined in external resources. - *

- * - * @author Mark Paluch - * @see DatabasePopulatorUtils - * @see ScriptUtils - * @deprecated since 1.2 in favor of Spring R2DBC. Use - * {@link org.springframework.r2dbc.connection.init.ResourceDatabasePopulator} instead. - */ -@Deprecated -public class ResourceDatabasePopulator implements DatabasePopulator { - - List scripts = new ArrayList<>(); - - private @Nullable Charset sqlScriptEncoding; - - private String separator = ScriptUtils.DEFAULT_STATEMENT_SEPARATOR; - - private String commentPrefix = ScriptUtils.DEFAULT_COMMENT_PREFIX; - - private String blockCommentStartDelimiter = ScriptUtils.DEFAULT_BLOCK_COMMENT_START_DELIMITER; - - private String blockCommentEndDelimiter = ScriptUtils.DEFAULT_BLOCK_COMMENT_END_DELIMITER; - - private boolean continueOnError = false; - - private boolean ignoreFailedDrops = false; - - private DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory(); - - /** - * Creates a new {@link ResourceDatabasePopulator} with default settings. - */ - public ResourceDatabasePopulator() {} - - /** - * Creates a new {@link ResourceDatabasePopulator} with default settings for the supplied scripts. - * - * @param scripts the scripts to execute to initialize or clean up the database (never {@literal null}) - */ - public ResourceDatabasePopulator(Resource... scripts) { - setScripts(scripts); - } - - /** - * Creates a new {@link ResourceDatabasePopulator} with the supplied values. - * - * @param continueOnError flag to indicate that all failures in SQL should be logged but not cause a failure - * @param ignoreFailedDrops flag to indicate that a failed SQL {@code DROP} statement can be ignored - * @param sqlScriptEncoding the encoding for the supplied SQL scripts (may be {@literal null} or empty to - * indicate platform encoding) - * @param scripts the scripts to execute to initialize or clean up the database, must not be {@literal null}. - */ - public ResourceDatabasePopulator(boolean continueOnError, boolean ignoreFailedDrops, - @Nullable String sqlScriptEncoding, Resource... scripts) { - - this.continueOnError = continueOnError; - this.ignoreFailedDrops = ignoreFailedDrops; - setSqlScriptEncoding(sqlScriptEncoding); - setScripts(scripts); - } - - /** - * Add a script to execute to initialize or clean up the database. - * - * @param script the path to an SQL script, must not be {@literal null}. - */ - public void addScript(Resource script) { - Assert.notNull(script, "Script must not be null"); - this.scripts.add(script); - } - - /** - * Add multiple scripts to execute to initialize or clean up the database. - * - * @param scripts the scripts to execute, must not be {@literal null}. - */ - public void addScripts(Resource... scripts) { - assertContentsOfScriptArray(scripts); - this.scripts.addAll(Arrays.asList(scripts)); - } - - /** - * Set the scripts to execute to initialize or clean up the database, replacing any previously added scripts. - * - * @param scripts the scripts to execute, must not be {@literal null}. - */ - public void setScripts(Resource... scripts) { - assertContentsOfScriptArray(scripts); - // Ensure that the list is modifiable - this.scripts = new ArrayList<>(Arrays.asList(scripts)); - } - - private void assertContentsOfScriptArray(Resource... scripts) { - Assert.notNull(scripts, "Scripts array must not be null"); - Assert.noNullElements(scripts, "Scripts array must not contain null elements"); - } - - /** - * Specify the encoding for the configured SQL scripts, if different from the platform encoding. - * - * @param sqlScriptEncoding the encoding used in scripts (may be {@literal null} or empty to indicate platform - * encoding). - * @see #addScript(Resource) - */ - public void setSqlScriptEncoding(@Nullable String sqlScriptEncoding) { - setSqlScriptEncoding(StringUtils.hasText(sqlScriptEncoding) ? Charset.forName(sqlScriptEncoding) : null); - } - - /** - * Specify the encoding for the configured SQL scripts, if different from the platform encoding. - * - * @param sqlScriptEncoding the encoding used in scripts (may be {@literal null} to indicate platform encoding). - * @see #addScript(Resource) - */ - public void setSqlScriptEncoding(@Nullable Charset sqlScriptEncoding) { - this.sqlScriptEncoding = sqlScriptEncoding; - } - - /** - * Specify the statement separator, if a custom one. - *

- * Defaults to {@code ";"} if not specified and falls back to {@code "\n"} as a last resort; may be set to - * {@link ScriptUtils#EOF_STATEMENT_SEPARATOR} to signal that each script contains a single statement without a - * separator. - * - * @param separator the script statement separator. - */ - public void setSeparator(String separator) { - this.separator = separator; - } - - /** - * Set the prefix that identifies single-line comments within the SQL scripts. - *

- * Defaults to {@code "--"}. - * - * @param commentPrefix the prefix for single-line comments - */ - public void setCommentPrefix(String commentPrefix) { - this.commentPrefix = commentPrefix; - } - - /** - * Set the start delimiter that identifies block comments within the SQL scripts. - *

- * Defaults to {@code "/*"}. - * - * @param blockCommentStartDelimiter the start delimiter for block comments (never {@literal null} or empty). - * @see #setBlockCommentEndDelimiter - */ - public void setBlockCommentStartDelimiter(String blockCommentStartDelimiter) { - - Assert.hasText(blockCommentStartDelimiter, "BlockCommentStartDelimiter must not be null or empty"); - - this.blockCommentStartDelimiter = blockCommentStartDelimiter; - } - - /** - * Set the end delimiter that identifies block comments within the SQL scripts. - *

- * Defaults to {@code "*/"}. - * - * @param blockCommentEndDelimiter the end delimiter for block comments (never {@literal null} or empty) - * @see #setBlockCommentStartDelimiter - */ - public void setBlockCommentEndDelimiter(String blockCommentEndDelimiter) { - - Assert.hasText(blockCommentEndDelimiter, "BlockCommentEndDelimiter must not be null or empty"); - - this.blockCommentEndDelimiter = blockCommentEndDelimiter; - } - - /** - * Flag to indicate that all failures in SQL should be logged but not cause a failure. - *

- * Defaults to {@literal false}. - * - * @param continueOnError {@literal true} if script execution should continue on error. - */ - public void setContinueOnError(boolean continueOnError) { - this.continueOnError = continueOnError; - } - - /** - * Flag to indicate that a failed SQL {@code DROP} statement can be ignored. - *

- * This is useful for a non-embedded database whose SQL dialect does not support an {@code IF EXISTS} clause in a - * {@code DROP} statement. - *

- * The default is {@literal false} so that if the populator runs accidentally, it will fail fast if a script starts - * with a {@code DROP} statement. - * - * @param ignoreFailedDrops {@literal true} if failed drop statements should be ignored. - */ - public void setIgnoreFailedDrops(boolean ignoreFailedDrops) { - this.ignoreFailedDrops = ignoreFailedDrops; - } - - /** - * Set the {@link DataBufferFactory} to use for {@link Resource} loading. - *

- * Defaults to {@link DefaultDataBufferFactory}. - * - * @param dataBufferFactory the {@link DataBufferFactory} to use, must not be {@literal null}. - */ - public void setDataBufferFactory(DataBufferFactory dataBufferFactory) { - - Assert.notNull(dataBufferFactory, "DataBufferFactory must not be null!"); - - this.dataBufferFactory = dataBufferFactory; - } - - @Override - public Mono populate(Connection connection) throws ScriptException { - - Assert.notNull(connection, "Connection must not be null"); - - return Flux.fromIterable(this.scripts).concatMap(it -> { - - EncodedResource encodedScript = new EncodedResource(it, this.sqlScriptEncoding); - - return ScriptUtils.executeSqlScript(connection, encodedScript, this.dataBufferFactory, this.continueOnError, - this.ignoreFailedDrops, this.commentPrefix, this.separator, this.blockCommentStartDelimiter, - this.blockCommentEndDelimiter); - }).then(); - } - - /** - * Execute this {@link ResourceDatabasePopulator} against the given {@link ConnectionFactory}. - *

- * Delegates to {@link DatabasePopulatorUtils#execute}. - * - * @param connectionFactory the {@link ConnectionFactory} to execute against, must not be {@literal null}.. - * @return {@link Mono} tthat initiates script execution and is notified upon completion. - * @throws ScriptException if an error occurs. - * @see #populate(Connection) - */ - public Mono execute(ConnectionFactory connectionFactory) throws ScriptException { - return DatabasePopulatorUtils.execute(this, connectionFactory); - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/ScriptException.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/ScriptException.java deleted file mode 100644 index 892ec0542..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/ScriptException.java +++ /dev/null @@ -1,49 +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.connectionfactory.init; - -import org.springframework.dao.DataAccessException; -import org.springframework.lang.Nullable; - -/** - * Root of the hierarchy of data access exceptions that are related to processing of SQL scripts. - * - * @author Mark Paluch - * @deprecated since 1.2 in favor of Spring R2DBC. Use {@link org.springframework.r2dbc.connection.init.ScriptException} - * instead. - */ -@Deprecated -public abstract class ScriptException extends DataAccessException { - - /** - * Creates a new {@link ScriptException}. - * - * @param message the detail message. - */ - public ScriptException(String message) { - super(message); - } - - /** - * Creates a new {@link ScriptException}. - * - * @param message the detail message. - * @param cause the root cause. - */ - public ScriptException(String message, @Nullable Throwable cause) { - super(message, cause); - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/ScriptParseException.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/ScriptParseException.java deleted file mode 100644 index f03064bed..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/ScriptParseException.java +++ /dev/null @@ -1,58 +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.connectionfactory.init; - -import org.springframework.core.io.support.EncodedResource; -import org.springframework.lang.Nullable; - -/** - * Thrown by {@link ScriptUtils} if an SQL script cannot be properly parsed. - * - * @author Mark Paluch - * @deprecated since 1.2 in favor of Spring R2DBC. Use - * {@link org.springframework.r2dbc.connection.init.ScriptParseException} instead. - */ -@Deprecated -public class ScriptParseException extends ScriptException { - - private static final long serialVersionUID = 6130513243627087332L; - - /** - * Creates a new {@link ScriptParseException}. - * - * @param message detailed message. - * @param resource the resource from which the SQL script was read. - */ - public ScriptParseException(String message, @Nullable EncodedResource resource) { - super(buildMessage(message, resource)); - } - - /** - * Creates a new {@link ScriptParseException}. - * - * @param message detailed message. - * @param resource the resource from which the SQL script was read. - * @param cause the underlying cause of the failure. - */ - public ScriptParseException(String message, @Nullable EncodedResource resource, @Nullable Throwable cause) { - super(buildMessage(message, resource), cause); - } - - private static String buildMessage(String message, @Nullable EncodedResource resource) { - return String.format("Failed to parse SQL script from resource [%s]: %s", - (resource == null ? "" : resource), message); - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/ScriptStatementFailedException.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/ScriptStatementFailedException.java deleted file mode 100644 index 0cf85b410..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/ScriptStatementFailedException.java +++ /dev/null @@ -1,57 +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.connectionfactory.init; - -import org.springframework.core.io.support.EncodedResource; - -/** - * Thrown by {@link ScriptUtils} if a statement in an SQL script failed when executing it against the target database. - * - * @author Mark Paluch - * @deprecated since 1.2 in favor of Spring R2DBC. Use - * {@link org.springframework.r2dbc.connection.init.ScriptStatementFailedException} instead. - */ -@Deprecated -public class ScriptStatementFailedException extends ScriptException { - - private static final long serialVersionUID = 912676424615782262L; - - /** - * Creates a new {@link ScriptStatementFailedException}. - * - * @param statement the actual SQL statement that failed. - * @param statementNumber the statement number in the SQL script (i.e., the n'th statement present in the resource). - * @param encodedResource the resource from which the SQL statement was read. - * @param cause the underlying cause of the failure. - */ - public ScriptStatementFailedException(String statement, int statementNumber, EncodedResource encodedResource, - Throwable cause) { - super(buildErrorMessage(statement, statementNumber, encodedResource), cause); - } - - /** - * Build an error message for an SQL script execution failure, based on the supplied arguments. - * - * @param statement the actual SQL statement that failed. - * @param statementNumber the statement number in the SQL script (i.e., the n'th statement present in the resource). - * @param encodedResource the resource from which the SQL statement was read. - * @return an error message suitable for an exception's detail message or logging. - */ - public static String buildErrorMessage(String statement, int statementNumber, EncodedResource encodedResource) { - return String.format("Failed to execute SQL script statement #%s of %s: %s", statementNumber, encodedResource, - statement); - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/ScriptUtils.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/ScriptUtils.java deleted file mode 100644 index 5bb07bf57..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/ScriptUtils.java +++ /dev/null @@ -1,540 +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.connectionfactory.init; - -import io.r2dbc.spi.Connection; -import io.r2dbc.spi.Result; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.LineNumberReader; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.reactivestreams.Publisher; - -import org.springframework.core.io.Resource; -import org.springframework.core.io.buffer.DataBufferFactory; -import org.springframework.core.io.buffer.DataBufferUtils; -import org.springframework.core.io.buffer.DefaultDataBufferFactory; -import org.springframework.core.io.support.EncodedResource; -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; - -/** - * Generic utility methods for working with SQL scripts. - *

- * Mainly for internal use within the framework. - * - * @author Mark Paluch - * @deprecated since 1.2 in favor of Spring R2DBC. Use {@link org.springframework.r2dbc.connection.init.ScriptUtils} - * instead. - */ -@Deprecated -public abstract class ScriptUtils { - - /** - * Default statement separator within SQL scripts: {@code ";"}. - */ - public static final String DEFAULT_STATEMENT_SEPARATOR = ";"; - - /** - * Fallback statement separator within SQL scripts: {@code "\n"}. - *

- * Used if neither a custom separator nor the {@link #DEFAULT_STATEMENT_SEPARATOR} is present in a given script. - */ - public static final String FALLBACK_STATEMENT_SEPARATOR = "\n"; - - /** - * End of file (EOF) SQL statement separator: {@code "^^^ END OF SCRIPT ^^^"}. - *

- * This value may be supplied as the {@code separator} to - * {@link #executeSqlScript(Connection, EncodedResource, DataBufferFactory, boolean, boolean, String, String, String, String)} - * to denote that an SQL script contains a single statement (potentially spanning multiple lines) with no explicit - * statement separator. Note that such a script should not actually contain this value; it is merely a - * virtual statement separator. - */ - public static final String EOF_STATEMENT_SEPARATOR = "^^^ END OF SCRIPT ^^^"; - - /** - * Default prefix for single-line comments within SQL scripts: {@code "--"}. - */ - public static final String DEFAULT_COMMENT_PREFIX = "--"; - - /** - * Default start delimiter for block comments within SQL scripts: {@code "/*"}. - */ - public static final String DEFAULT_BLOCK_COMMENT_START_DELIMITER = "/*"; - - /** - * Default end delimiter for block comments within SQL scripts: "*/". - */ - public static final String DEFAULT_BLOCK_COMMENT_END_DELIMITER = "*/"; - - private static final Log logger = LogFactory.getLog(ScriptUtils.class); - - // utility constructor - private ScriptUtils() {} - - /** - * Split an SQL script into separate statements delimited by the provided separator character. Each individual - * statement will be added to the provided {@link List}. - *

- * Within the script, {@value #DEFAULT_COMMENT_PREFIX} will be used as the comment prefix; any text beginning with the - * comment prefix and extending to the end of the line will be omitted from the output. Similarly, - * {@value #DEFAULT_BLOCK_COMMENT_START_DELIMITER} and {@value #DEFAULT_BLOCK_COMMENT_END_DELIMITER} will be used as - * the start and end block comment delimiters: any text enclosed in a block comment will be omitted - * from the output. In addition, multiple adjacent whitespace characters will be collapsed into a single space. - * - * @param script the SQL script. - * @param separator character separating each statement (typically a ';'). - * @param statements the list that will contain the individual statements . - * @throws ScriptException if an error occurred while splitting the SQL script. - * @see #splitSqlScript(String, String, List) - * @see #splitSqlScript(EncodedResource, String, String, String, String, String, List) - */ - static void splitSqlScript(String script, char separator, List statements) throws ScriptException { - splitSqlScript(script, String.valueOf(separator), statements); - } - - /** - * Split an SQL script into separate statements delimited by the provided separator string. Each individual statement - * will be added to the provided {@link List}. - *

- * Within the script, {@value #DEFAULT_COMMENT_PREFIX} will be used as the comment prefix; any text beginning with the - * comment prefix and extending to the end of the line will be omitted from the output. Similarly, - * {@value #DEFAULT_BLOCK_COMMENT_START_DELIMITER} and {@value #DEFAULT_BLOCK_COMMENT_END_DELIMITER} will be used as - * the start and end block comment delimiters: any text enclosed in a block comment will be omitted - * from the output. In addition, multiple adjacent whitespace characters will be collapsed into a single space. - * - * @param script the SQL script. - * @param separator text separating each statement (typically a ';' or newline character). - * @param statements the list that will contain the individual statements. - * @throws ScriptException if an error occurred while splitting the SQL script. - * @see #splitSqlScript(String, char, List) - * @see #splitSqlScript(EncodedResource, String, String, String, String, String, List) - */ - static void splitSqlScript(String script, String separator, List statements) throws ScriptException { - splitSqlScript(null, script, separator, DEFAULT_COMMENT_PREFIX, DEFAULT_BLOCK_COMMENT_START_DELIMITER, - DEFAULT_BLOCK_COMMENT_END_DELIMITER, statements); - } - - /** - * Split an SQL script into separate statements delimited by the provided separator string. Each individual statement - * will be added to the provided {@link List}. - *

- * Within the script, the provided {@code commentPrefix} will be honored: any text beginning with the comment prefix - * and extending to the end of the line will be omitted from the output. Similarly, the provided - * {@code blockCommentStartDelimiter} and {@code blockCommentEndDelimiter} delimiters will be honored: any text - * enclosed in a block comment will be omitted from the output. In addition, multiple adjacent whitespace characters - * will be collapsed into a single space. - * - * @param resource the resource from which the script was read. - * @param script the SQL script. - * @param separator text separating each statement (typically a ';' or newline character). - * @param commentPrefix the prefix that identifies SQL line comments (typically "--"). - * @param blockCommentStartDelimiter the start block comment delimiter. Must not be {@literal null} or empty. - * @param blockCommentEndDelimiter the end block comment delimiter. Must not be {@literal null} or empty. - * @param statements the list that will contain the individual statements. - * @throws ScriptException if an error occurred while splitting the SQL script. - */ - private static void splitSqlScript(@Nullable EncodedResource resource, String script, String separator, - String commentPrefix, String blockCommentStartDelimiter, String blockCommentEndDelimiter, List statements) - throws ScriptException { - - Assert.hasText(script, "'script' must not be null or empty"); - Assert.notNull(separator, "'separator' must not be null"); - Assert.hasText(commentPrefix, "'commentPrefix' must not be null or empty"); - Assert.hasText(blockCommentStartDelimiter, "'blockCommentStartDelimiter' must not be null or empty"); - Assert.hasText(blockCommentEndDelimiter, "'blockCommentEndDelimiter' must not be null or empty"); - - StringBuilder sb = new StringBuilder(); - boolean inSingleQuote = false; - boolean inDoubleQuote = false; - boolean inEscape = false; - - for (int i = 0; i < script.length(); i++) { - char c = script.charAt(i); - if (inEscape) { - inEscape = false; - sb.append(c); - continue; - } - // MySQL style escapes - if (c == '\\') { - inEscape = true; - sb.append(c); - continue; - } - if (!inDoubleQuote && (c == '\'')) { - inSingleQuote = !inSingleQuote; - } else if (!inSingleQuote && (c == '"')) { - inDoubleQuote = !inDoubleQuote; - } - if (!inSingleQuote && !inDoubleQuote) { - if (script.startsWith(separator, i)) { - // We've reached the end of the current statement - if (sb.length() > 0) { - statements.add(sb.toString()); - sb = new StringBuilder(); - } - i += separator.length() - 1; - continue; - } else if (script.startsWith(commentPrefix, i)) { - // Skip over any content from the start of the comment to the EOL - int indexOfNextNewline = script.indexOf('\n', i); - if (indexOfNextNewline > i) { - i = indexOfNextNewline; - continue; - } else { - // If there's no EOL, we must be at the end of the script, so stop here. - break; - } - } else if (script.startsWith(blockCommentStartDelimiter, i)) { - // Skip over any block comments - int indexOfCommentEnd = script.indexOf(blockCommentEndDelimiter, i); - if (indexOfCommentEnd > i) { - i = indexOfCommentEnd + blockCommentEndDelimiter.length() - 1; - continue; - } else { - throw new ScriptParseException("Missing block comment end delimiter: " + blockCommentEndDelimiter, - resource); - } - } else if (c == ' ' || c == '\r' || c == '\n' || c == '\t') { - // Avoid multiple adjacent whitespace characters - if (sb.length() > 0 && sb.charAt(sb.length() - 1) != ' ') { - c = ' '; - } else { - continue; - } - } - } - sb.append(c); - } - - if (StringUtils.hasText(sb)) { - statements.add(sb.toString()); - } - } - - /** - * Read a script without blocking from the given resource, using "{@code --}" as the comment prefix and "{@code ;}" as - * the statement separator, and build a String containing the lines. - * - * @param resource the {@link EncodedResource} to be read. - * @param dataBufferFactory the buffer factory for non-blocking script loading. - * @return {@link String} containing the script lines. - * @see DefaultDataBufferFactory - */ - public static Mono readScript(EncodedResource resource, DataBufferFactory dataBufferFactory) { - return readScript(resource, dataBufferFactory, DEFAULT_COMMENT_PREFIX, DEFAULT_STATEMENT_SEPARATOR, - DEFAULT_BLOCK_COMMENT_END_DELIMITER); - } - - /** - * Read a script without blocking from the provided resource, using the supplied comment prefix and statement - * separator, and build a {@link String} and build a String containing the lines. - *

- * Lines beginning with the comment prefix are excluded from the results; however, line comments anywhere - * else — for example, within a statement — will be included in the results. - * - * @param resource the {@link EncodedResource} containing the script to be processed. - * @param commentPrefix the prefix that identifies comments in the SQL script (typically "--"). - * @param separator the statement separator in the SQL script (typically ";"). - * @param blockCommentEndDelimiter the end block comment delimiter. - * @return a {@link Mono} of {@link String} containing the script lines that completes once the resource was loaded. - */ - private static Mono readScript(EncodedResource resource, DataBufferFactory dataBufferFactory, - @Nullable String commentPrefix, @Nullable String separator, @Nullable String blockCommentEndDelimiter) { - - return DataBufferUtils.join(DataBufferUtils.read(resource.getResource(), dataBufferFactory, 8192)) - .handle((it, sink) -> { - - try (InputStream is = it.asInputStream()) { - - InputStreamReader in = resource.getCharset() != null ? new InputStreamReader(is, resource.getCharset()) - : new InputStreamReader(is); - LineNumberReader lnr = new LineNumberReader(in); - String script = readScript(lnr, commentPrefix, separator, blockCommentEndDelimiter); - - sink.next(script); - sink.complete(); - } catch (Exception e) { - sink.error(e); - } finally { - DataBufferUtils.release(it); - } - }); - } - - /** - * Read a script from the provided {@link LineNumberReader}, using the supplied comment prefix and statement - * separator, and build a {@link String} containing the lines. - *

- * Lines beginning with the comment prefix are excluded from the results; however, line comments anywhere - * else — for example, within a statement — will be included in the results. - * - * @param lineNumberReader the {@link LineNumberReader} containing the script to be processed. - * @param lineCommentPrefix the prefix that identifies comments in the SQL script (typically "--"). - * @param separator the statement separator in the SQL script (typically ";"). - * @param blockCommentEndDelimiter the end block comment delimiter. - * @return a {@link String} containing the script lines. - * @throws IOException in case of I/O errors - */ - private static String readScript(LineNumberReader lineNumberReader, @Nullable String lineCommentPrefix, - @Nullable String separator, @Nullable String blockCommentEndDelimiter) throws IOException { - - String currentStatement = lineNumberReader.readLine(); - StringBuilder scriptBuilder = new StringBuilder(); - while (currentStatement != null) { - if ((blockCommentEndDelimiter != null && currentStatement.contains(blockCommentEndDelimiter)) - || (lineCommentPrefix != null && !currentStatement.startsWith(lineCommentPrefix))) { - if (scriptBuilder.length() > 0) { - scriptBuilder.append('\n'); - } - scriptBuilder.append(currentStatement); - } - currentStatement = lineNumberReader.readLine(); - } - appendSeparatorToScriptIfNecessary(scriptBuilder, separator); - return scriptBuilder.toString(); - } - - private static void appendSeparatorToScriptIfNecessary(StringBuilder scriptBuilder, @Nullable String separator) { - if (separator == null) { - return; - } - String trimmed = separator.trim(); - if (trimmed.length() == separator.length()) { - return; - } - // separator ends in whitespace, so we might want to see if the script is trying - // to end the same way - if (scriptBuilder.lastIndexOf(trimmed) == scriptBuilder.length() - trimmed.length()) { - scriptBuilder.append(separator.substring(trimmed.length())); - } - } - - /** - * Does the provided SQL script contain the specified delimiter? - * - * @param script the SQL script - * @param delim the string delimiting each statement - typically a ';' character - */ - static boolean containsSqlScriptDelimiters(String script, String delim) { - - boolean inLiteral = false; - boolean inEscape = false; - - for (int i = 0; i < script.length(); i++) { - char c = script.charAt(i); - if (inEscape) { - inEscape = false; - continue; - } - // MySQL style escapes - if (c == '\\') { - inEscape = true; - continue; - } - if (c == '\'') { - inLiteral = !inLiteral; - } - if (!inLiteral && script.startsWith(delim, i)) { - return true; - } - } - - return false; - } - - /** - * Execute the given SQL script using default settings for statement separators, comment delimiters, and exception - * handling flags. - *

- * Statement separators and comments will be removed before executing individual statements within the supplied - * script. - *

- * Warning: this method does not release the provided {@link Connection}. - * - * @param connection the R2DBC connection to use to execute the script; already configured and ready to use. - * @param resource the resource to load the SQL script from; encoded with the current platform's default encoding. - * @return {@link Mono} that initiates script execution and is notified upon completion. - * @throws ScriptException if an error occurred while executing the SQL script. - * @see #executeSqlScript(Connection, EncodedResource, DataBufferFactory, boolean, boolean, String, String, String, - * String) - * @see #DEFAULT_STATEMENT_SEPARATOR - * @see #DEFAULT_COMMENT_PREFIX - * @see #DEFAULT_BLOCK_COMMENT_START_DELIMITER - * @see #DEFAULT_BLOCK_COMMENT_END_DELIMITER - * @see org.springframework.data.r2dbc.connectionfactory.ConnectionFactoryUtils#getConnection - * @see org.springframework.data.r2dbc.connectionfactory.ConnectionFactoryUtils#releaseConnection - */ - public static Mono executeSqlScript(Connection connection, Resource resource) throws ScriptException { - return executeSqlScript(connection, new EncodedResource(resource)); - } - - /** - * Execute the given SQL script using default settings for statement separators, comment delimiters, and exception - * handling flags. - *

- * Statement separators and comments will be removed before executing individual statements within the supplied - * script. - *

- * Warning: this method does not release the provided {@link Connection}. - * - * @param connection the R2DBC connection to use to execute the script; already configured and ready to use. - * @param resource the resource (potentially associated with a specific encoding) to load the SQL script from. - * @return {@link Mono} that initiates script execution and is notified upon completion. - * @throws ScriptException if an error occurred while executing the SQL script. - * @see #executeSqlScript(Connection, EncodedResource, DataBufferFactory, boolean, boolean, String, String, String, - * String) - * @see #DEFAULT_STATEMENT_SEPARATOR - * @see #DEFAULT_COMMENT_PREFIX - * @see #DEFAULT_BLOCK_COMMENT_START_DELIMITER - * @see #DEFAULT_BLOCK_COMMENT_END_DELIMITER - * @see org.springframework.data.r2dbc.connectionfactory.ConnectionFactoryUtils#getConnection - * @see org.springframework.data.r2dbc.connectionfactory.ConnectionFactoryUtils#releaseConnection - */ - public static Mono executeSqlScript(Connection connection, EncodedResource resource) throws ScriptException { - return executeSqlScript(connection, resource, new DefaultDataBufferFactory(), false, false, DEFAULT_COMMENT_PREFIX, - DEFAULT_STATEMENT_SEPARATOR, DEFAULT_BLOCK_COMMENT_START_DELIMITER, DEFAULT_BLOCK_COMMENT_END_DELIMITER); - } - - /** - * Execute the given SQL script. - *

- * Statement separators and comments will be removed before executing individual statements within the supplied - * script. - *

- * Warning: this method does not release the provided {@link Connection}. - * - * @param connection the R2DBC connection to use to execute the script; already configured and ready to use. - * @param dataBufferFactory the buffer factory for non-blocking script loading. - * @param resource the resource (potentially associated with a specific encoding) to load the SQL script from. - * @param continueOnError whether or not to continue without throwing an exception in the event of an error. - * @param ignoreFailedDrops whether or not to continue in the event of specifically an error on a {@code DROP} - * statement. - * @param commentPrefix the prefix that identifies single-line comments in the SQL script (typically "--"). - * @param separator the script statement separator; defaults to {@value #DEFAULT_STATEMENT_SEPARATOR} if not specified - * and falls back to {@value #FALLBACK_STATEMENT_SEPARATOR} as a last resort; may be set to - * {@value #EOF_STATEMENT_SEPARATOR} to signal that the script contains a single statement without a - * separator. - * @param blockCommentStartDelimiter the start block comment delimiter. - * @param blockCommentEndDelimiter the end block comment delimiter. - * @return {@link Mono} that initiates script execution and is notified upon completion. - * @throws ScriptException if an error occurred while executing the SQL script. - * @see #DEFAULT_STATEMENT_SEPARATOR - * @see #FALLBACK_STATEMENT_SEPARATOR - * @see #EOF_STATEMENT_SEPARATOR - * @see org.springframework.data.r2dbc.connectionfactory.ConnectionFactoryUtils#getConnection - * @see org.springframework.data.r2dbc.connectionfactory.ConnectionFactoryUtils#releaseConnection - */ - public static Mono executeSqlScript(Connection connection, EncodedResource resource, - DataBufferFactory dataBufferFactory, boolean continueOnError, boolean ignoreFailedDrops, String commentPrefix, - @Nullable String separator, String blockCommentStartDelimiter, String blockCommentEndDelimiter) - throws ScriptException { - - if (logger.isDebugEnabled()) { - logger.debug("Executing SQL script from " + resource); - } - - long startTime = System.currentTimeMillis(); - - Mono script = readScript(resource, dataBufferFactory, commentPrefix, separator, blockCommentEndDelimiter) - .onErrorMap(IOException.class, ex -> new CannotReadScriptException(resource, ex)); - - AtomicInteger statementNumber = new AtomicInteger(); - - Flux executeScript = script.flatMapIterable(it -> { - return splitStatements(it, resource, commentPrefix, separator, blockCommentStartDelimiter, - blockCommentEndDelimiter); - }).concatMap(statement -> { - - statementNumber.incrementAndGet(); - return runStatement(statement, connection, resource, continueOnError, ignoreFailedDrops, statementNumber); - }); - - if (logger.isDebugEnabled()) { - - executeScript = executeScript.doOnComplete(() -> { - - long elapsedTime = System.currentTimeMillis() - startTime; - logger.debug("Executed SQL script from " + resource + " in " + elapsedTime + " ms."); - }); - } - - return executeScript.onErrorMap(ex -> !(ex instanceof ScriptException), - ex -> new UncategorizedScriptException("Failed to execute database script from resource [" + resource + "]", - ex)) - .then(); - } - - private static List splitStatements(String script, EncodedResource resource, String commentPrefix, - @Nullable String separator, String blockCommentStartDelimiter, String blockCommentEndDelimiter) { - - String separatorToUse = separator; - if (separatorToUse == null) { - separatorToUse = DEFAULT_STATEMENT_SEPARATOR; - } - if (!EOF_STATEMENT_SEPARATOR.equals(separatorToUse) && !containsSqlScriptDelimiters(script, separatorToUse)) { - separatorToUse = FALLBACK_STATEMENT_SEPARATOR; - } - - List statements = new ArrayList<>(); - splitSqlScript(resource, script, separatorToUse, commentPrefix, blockCommentStartDelimiter, - blockCommentEndDelimiter, statements); - - return statements; - } - - private static Publisher runStatement(String statement, Connection connection, - EncodedResource resource, boolean continueOnError, boolean ignoreFailedDrops, AtomicInteger statementNumber) { - - Mono execution = Flux.from(connection.createStatement(statement).execute()) // - .flatMap(Result::getRowsUpdated) // - .collect(Collectors.summingLong(it -> it)); - - if (logger.isDebugEnabled()) { - execution = execution.doOnNext(rowsAffected -> { - logger.debug(rowsAffected + " returned as update count for SQL: " + statement); - }); - } - - return execution.onErrorResume(ex -> { - - boolean dropStatement = StringUtils.startsWithIgnoreCase(statement.trim(), "drop"); - if (continueOnError || (dropStatement && ignoreFailedDrops)) { - if (logger.isDebugEnabled()) { - logger.debug(ScriptStatementFailedException.buildErrorMessage(statement, statementNumber.get(), resource), - ex); - } - } else { - return Mono.error(new ScriptStatementFailedException(statement, statementNumber.get(), resource, ex)); - } - - return Mono.empty(); - }).then(); - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/UncategorizedScriptException.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/UncategorizedScriptException.java deleted file mode 100644 index 793c3baa6..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/UncategorizedScriptException.java +++ /dev/null @@ -1,49 +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.connectionfactory.init; - -/** - * Thrown when we cannot determine anything more specific than "something went wrong while processing an SQL script": - * for example, a {@link io.r2dbc.spi.R2dbcException} from R2DBC that we cannot pinpoint more precisely. - * - * @author Mark Paluch - * @deprecated since 1.2 in favor of Spring R2DBC. Use - * {@link org.springframework.r2dbc.connection.init.UncategorizedScriptException} instead. - */ -@Deprecated -public class UncategorizedScriptException extends ScriptException { - - private static final long serialVersionUID = -3196706179230349902L; - - /** - * Creates a new {@link UncategorizedScriptException}. - * - * @param message detailed message. - */ - public UncategorizedScriptException(String message) { - super(message); - } - - /** - * Creates a new {@link UncategorizedScriptException}. - * - * @param message detailed message. - * @param cause the root cause. - */ - public UncategorizedScriptException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/package-info.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/package-info.java deleted file mode 100644 index d76b48246..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/init/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Provides extensible support for initializing databases through scripts. Deprecated since 1.2 in favor of Spring - * R2DBC. Use {@link org.springframework.r2dbc.connection.init} instead. - */ -@org.springframework.lang.NonNullApi -@org.springframework.lang.NonNullFields -package org.springframework.data.r2dbc.connectionfactory.init; diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/lookup/AbstractRoutingConnectionFactory.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/lookup/AbstractRoutingConnectionFactory.java deleted file mode 100644 index 2f651e8f3..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/lookup/AbstractRoutingConnectionFactory.java +++ /dev/null @@ -1,248 +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.connectionfactory.lookup; - -import io.r2dbc.spi.Connection; -import io.r2dbc.spi.ConnectionFactory; -import io.r2dbc.spi.ConnectionFactoryMetadata; -import reactor.core.publisher.Mono; - -import java.util.HashMap; -import java.util.Map; - -import org.springframework.beans.factory.InitializingBean; -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; - -/** - * Abstract {@link ConnectionFactory} implementation that routes {@link #create()} calls to one of various target - * {@link ConnectionFactory factories} based on a lookup key. The latter is typically (but not necessarily) determined - * from some subscriber context. - *

- * Allows to configure a {@link #setDefaultTargetConnectionFactory(Object) default ConnectionFactory} as fallback. - *

- * Calls to {@link #getMetadata()} are routed to the {@link #setDefaultTargetConnectionFactory(Object) default - * ConnectionFactory} if configured. - * - * @author Mark Paluch - * @author Jens Schauder - * @see #setTargetConnectionFactories - * @see #setDefaultTargetConnectionFactory - * @see #determineCurrentLookupKey() - * @deprecated since 1.2 in favor of Spring R2DBC. Use - * {@link org.springframework.r2dbc.connection.lookup.AbstractRoutingConnectionFactory} instead. - */ -@Deprecated -public abstract class AbstractRoutingConnectionFactory implements ConnectionFactory, InitializingBean { - - private static final Object FALLBACK_MARKER = new Object(); - - private @Nullable Map targetConnectionFactories; - - private @Nullable Object defaultTargetConnectionFactory; - - private boolean lenientFallback = true; - - private ConnectionFactoryLookup connectionFactoryLookup = new MapConnectionFactoryLookup(); - - private @Nullable Map resolvedConnectionFactories; - - private @Nullable ConnectionFactory resolvedDefaultConnectionFactory; - - /** - * Specify the map of target {@link ConnectionFactory ConnectionFactories}, with the lookup key as key. The mapped - * value can either be a corresponding {@link ConnectionFactory} instance or a connection factory name String (to be - * resolved via a {@link #setConnectionFactoryLookup ConnectionFactoryLookup}). - *

- * The key can be of arbitrary type; this class implements the generic lookup process only. The concrete key - * representation will be handled by {@link #resolveSpecifiedLookupKey(Object)} and - * {@link #determineCurrentLookupKey()}. - */ - public void setTargetConnectionFactories(Map targetConnectionFactories) { - this.targetConnectionFactories = targetConnectionFactories; - } - - /** - * Specify the default target {@link ConnectionFactory}, if any. - *

- * The mapped value can either be a corresponding {@link ConnectionFactory} instance or a connection factory name - * {@link String} (to be resolved via a {@link #setConnectionFactoryLookup ConnectionFactoryLookup}). - *

- * This {@link ConnectionFactory} will be used as target if none of the keyed {@link #setTargetConnectionFactories - * targetConnectionFactories} match the {@link #determineCurrentLookupKey() current lookup key}. - */ - public void setDefaultTargetConnectionFactory(Object defaultTargetConnectionFactory) { - this.defaultTargetConnectionFactory = defaultTargetConnectionFactory; - } - - /** - * Specify whether to apply a lenient fallback to the default {@link ConnectionFactory} if no specific - * {@link ConnectionFactory} could be found for the current lookup key. - *

- * Default is {@literal true}, accepting lookup keys without a corresponding entry in the target - * {@link ConnectionFactory} map - simply falling back to the default {@link ConnectionFactory} in that case. - *

- * Switch this flag to {@literal false} if you would prefer the fallback to only apply when no lookup key was emitted. - * Lookup keys without a {@link ConnectionFactory} entry will then lead to an {@link IllegalStateException}. - * - * @see #setTargetConnectionFactories - * @see #setDefaultTargetConnectionFactory - * @see #determineCurrentLookupKey() - */ - public void setLenientFallback(boolean lenientFallback) { - this.lenientFallback = lenientFallback; - } - - /** - * Set the {@link ConnectionFactoryLookup} implementation to use for resolving connection factory name Strings in the - * {@link #setTargetConnectionFactories targetConnectionFactories} map. - */ - public void setConnectionFactoryLookup(ConnectionFactoryLookup connectionFactoryLookup) { - - Assert.notNull(connectionFactoryLookup, "ConnectionFactoryLookup must not be null!"); - - this.connectionFactoryLookup = connectionFactoryLookup; - } - - /* - * (non-Javadoc) - * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() - */ - @Override - public void afterPropertiesSet() { - - Assert.notNull(this.targetConnectionFactories, "Property 'targetConnectionFactories' must not be null!"); - - this.resolvedConnectionFactories = new HashMap<>(this.targetConnectionFactories.size()); - this.targetConnectionFactories.forEach((key, value) -> { - Object lookupKey = resolveSpecifiedLookupKey(key); - ConnectionFactory connectionFactory = resolveSpecifiedConnectionFactory(value); - this.resolvedConnectionFactories.put(lookupKey, connectionFactory); - }); - - if (this.defaultTargetConnectionFactory != null) { - this.resolvedDefaultConnectionFactory = resolveSpecifiedConnectionFactory(this.defaultTargetConnectionFactory); - } - } - - /** - * Resolve the given lookup key object, as specified in the {@link #setTargetConnectionFactories - * targetConnectionFactories} map, into the actual lookup key to be used for matching with the - * {@link #determineCurrentLookupKey() current lookup key}. - *

- * The default implementation simply returns the given key as-is. - * - * @param lookupKey the lookup key object as specified by the user. - * @return the lookup key as needed for matching. - */ - protected Object resolveSpecifiedLookupKey(Object lookupKey) { - return lookupKey; - } - - /** - * Resolve the specified connection factory object into a {@link ConnectionFactory} instance. - *

- * The default implementation handles {@link ConnectionFactory} instances and connection factory names (to be resolved - * via a {@link #setConnectionFactoryLookup ConnectionFactoryLookup}). - * - * @param connectionFactory the connection factory value object as specified in the - * {@link #setTargetConnectionFactories targetConnectionFactories} map. - * @return the resolved {@link ConnectionFactory} (never {@literal null}). - * @throws IllegalArgumentException in case of an unsupported value type. - */ - protected ConnectionFactory resolveSpecifiedConnectionFactory(Object connectionFactory) - throws IllegalArgumentException { - - if (connectionFactory instanceof ConnectionFactory) { - return (ConnectionFactory) connectionFactory; - } else if (connectionFactory instanceof String) { - return this.connectionFactoryLookup.getConnectionFactory((String) connectionFactory); - } else { - - throw new IllegalArgumentException( - "Illegal connection factory value - only 'io.r2dbc.spi.ConnectionFactory' and 'String' supported: " - + connectionFactory); - } - } - - /* - * (non-Javadoc) - * @see io.r2dbc.spi.ConnectionFactory#create() - */ - @Override - public Mono create() { - - return determineTargetConnectionFactory() // - .map(ConnectionFactory::create) // - .flatMap(Mono::from); - } - - /* - * (non-Javadoc) - * @see io.r2dbc.spi.ConnectionFactory#getMetadata() - */ - @Override - public ConnectionFactoryMetadata getMetadata() { - - if (this.resolvedDefaultConnectionFactory != null) { - return this.resolvedDefaultConnectionFactory.getMetadata(); - } - - throw new UnsupportedOperationException( - "No default ConnectionFactory configured to retrieve ConnectionFactoryMetadata"); - } - - /** - * Retrieve the current target {@link ConnectionFactory}. Determines the {@link #determineCurrentLookupKey() current - * lookup key}, performs a lookup in the {@link #setTargetConnectionFactories targetConnectionFactories} map, falls - * back to the specified {@link #setDefaultTargetConnectionFactory default target ConnectionFactory} if necessary. - * - * @see #determineCurrentLookupKey() - * @return {@link Mono} emitting the current {@link ConnectionFactory} as per {@link #determineCurrentLookupKey()}. - */ - protected Mono determineTargetConnectionFactory() { - - Assert.state(this.resolvedConnectionFactories != null, "ConnectionFactory router not initialized"); - - Mono lookupKey = determineCurrentLookupKey().defaultIfEmpty(FALLBACK_MARKER); - - return lookupKey.handle((key, sink) -> { - - ConnectionFactory connectionFactory = this.resolvedConnectionFactories.get(key); - - if (connectionFactory == null && (key == FALLBACK_MARKER || this.lenientFallback)) { - connectionFactory = this.resolvedDefaultConnectionFactory; - } - - if (connectionFactory == null) { - sink.error(new IllegalStateException(String.format( - "Cannot determine target ConnectionFactory for lookup key '%s'", key == FALLBACK_MARKER ? null : key))); - return; - } - - sink.next(connectionFactory); - }); - } - - /** - * Determine the current lookup key. This will typically be implemented to check a subscriber context. Allows for - * arbitrary keys. The returned key needs to match the stored lookup key type, as resolved by the - * {@link #resolveSpecifiedLookupKey} method. - * - * @return {@link Mono} emitting the lookup key. May complete without emitting a value if no lookup key available. - */ - protected abstract Mono determineCurrentLookupKey(); -} diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/lookup/BeanFactoryConnectionFactoryLookup.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/lookup/BeanFactoryConnectionFactoryLookup.java deleted file mode 100644 index 021e702f2..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/lookup/BeanFactoryConnectionFactoryLookup.java +++ /dev/null @@ -1,93 +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.connectionfactory.lookup; - -import io.r2dbc.spi.ConnectionFactory; - -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanFactoryAware; -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; - -/** - * {@link ConnectionFactoryLookup} implementation based on a Spring {@link BeanFactory}. - *

- * Will lookup Spring managed beans identified by bean name, expecting them to be of type {@link ConnectionFactory}. - * - * @author Mark Paluch - * @see BeanFactory - * @deprecated since 1.2 in favor of Spring R2DBC. Use - * {@link org.springframework.r2dbc.connection.lookup.BeanFactoryConnectionFactoryLookup} instead. - */ -@Deprecated -public class BeanFactoryConnectionFactoryLookup implements ConnectionFactoryLookup, BeanFactoryAware { - - @Nullable private BeanFactory beanFactory; - - /** - * Creates a new {@link BeanFactoryConnectionFactoryLookup} instance. - *

- * The {@link BeanFactory} to access must be set via {@code setBeanFactory}. - * - * @see #setBeanFactory - */ - public BeanFactoryConnectionFactoryLookup() {} - - /** - * Create a new instance of the {@link BeanFactoryConnectionFactoryLookup} class. - *

- * Use of this constructor is redundant if this object is being created by a Spring IoC container, as the supplied - * {@link BeanFactory} will be replaced by the {@link BeanFactory} that creates it (see the {@link BeanFactoryAware} - * contract). So only use this constructor if you are using this class outside the context of a Spring IoC container. - * - * @param beanFactory the bean factory to be used to lookup {@link ConnectionFactory ConnectionFactories}. - */ - public BeanFactoryConnectionFactoryLookup(BeanFactory beanFactory) { - - Assert.notNull(beanFactory, "BeanFactory must not be null!"); - - this.beanFactory = beanFactory; - } - - /* - * (non-Javadoc) - * @see org.springframework.beans.factory.BeanFactoryAware#setBeanFactory(org.springframework.beans.factory.BeanFactory) - */ - @Override - public void setBeanFactory(BeanFactory beanFactory) { - this.beanFactory = beanFactory; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.connectionfactory.lookup.ConnectionFactoryLookup#getConnectionFactory(java.lang.String) - */ - @Override - public ConnectionFactory getConnectionFactory(String connectionFactoryName) - throws ConnectionFactoryLookupFailureException { - - Assert.state(this.beanFactory != null, "BeanFactory must not be null!"); - - try { - return this.beanFactory.getBean(connectionFactoryName, ConnectionFactory.class); - } catch (BeansException ex) { - throw new ConnectionFactoryLookupFailureException( - String.format("Failed to look up ConnectionFactory bean with name '%s'", connectionFactoryName), ex); - } - } - -} diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/lookup/ConnectionFactoryLookup.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/lookup/ConnectionFactoryLookup.java deleted file mode 100644 index e4f67b988..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/lookup/ConnectionFactoryLookup.java +++ /dev/null @@ -1,39 +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.connectionfactory.lookup; - -import io.r2dbc.spi.ConnectionFactory; - -/** - * Strategy interface for looking up {@link ConnectionFactory} by name. - * - * @author Mark Paluch - * @deprecated since 1.2 in favor of Spring R2DBC. Use - * {@link org.springframework.r2dbc.connection.lookup.ConnectionFactoryLookup} instead. - */ -@FunctionalInterface -@Deprecated -public interface ConnectionFactoryLookup { - - /** - * Retrieve the {@link ConnectionFactory} identified by the given name. - * - * @param connectionFactoryName the name of the {@link ConnectionFactory}. - * @return the {@link ConnectionFactory} (never {@literal null}). - * @throws ConnectionFactoryLookupFailureException if the lookup failed. - */ - ConnectionFactory getConnectionFactory(String connectionFactoryName) throws ConnectionFactoryLookupFailureException; -} diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/lookup/ConnectionFactoryLookupFailureException.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/lookup/ConnectionFactoryLookupFailureException.java deleted file mode 100644 index 11dee6e38..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/lookup/ConnectionFactoryLookupFailureException.java +++ /dev/null @@ -1,50 +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.connectionfactory.lookup; - -import org.springframework.dao.NonTransientDataAccessException; - -/** - * Exception to be thrown by a {@link ConnectionFactoryLookup} implementation, indicating that the specified - * {@link io.r2dbc.spi.ConnectionFactory} could not be obtained. - * - * @author Mark Paluch - * @deprecated since 1.2 in favor of Spring R2DBC. Use - * {@link org.springframework.r2dbc.connection.lookup.ConnectionFactoryLookupFailureException} instead. - */ -@SuppressWarnings("serial") -@Deprecated -public class ConnectionFactoryLookupFailureException extends NonTransientDataAccessException { - - /** - * Constructor for {@link ConnectionFactoryLookupFailureException}. - * - * @param msg the detail message. - */ - public ConnectionFactoryLookupFailureException(String msg) { - super(msg); - } - - /** - * Constructor for {@link ConnectionFactoryLookupFailureException}. - * - * @param msg the detail message. - * @param cause the root cause. - */ - public ConnectionFactoryLookupFailureException(String msg, Throwable cause) { - super(msg, cause); - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/lookup/MapConnectionFactoryLookup.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/lookup/MapConnectionFactoryLookup.java deleted file mode 100644 index f08e1ce74..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/lookup/MapConnectionFactoryLookup.java +++ /dev/null @@ -1,124 +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.connectionfactory.lookup; - -import io.r2dbc.spi.ConnectionFactory; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import org.springframework.util.Assert; - -/** - * Simple {@link ConnectionFactoryLookup} implementation that relies on a map for doing lookups. - *

- * Useful for testing environments or applications that need to match arbitrary {@link String} names to target - * {@link ConnectionFactory} objects. - * - * @author Mark Paluch - * @author Jens Schauder - * @deprecated since 1.2 in favor of Spring R2DBC. Use - * {@link org.springframework.r2dbc.connection.lookup.MapConnectionFactoryLookup} instead. - */ -@Deprecated -public class MapConnectionFactoryLookup implements ConnectionFactoryLookup { - - private final Map connectionFactories = new HashMap<>(); - - /** - * Create a new instance of the {@link MapConnectionFactoryLookup} class. - */ - public MapConnectionFactoryLookup() {} - - /** - * Create a new instance of the {@link MapConnectionFactoryLookup} class. - * - * @param connectionFactories the {@link Map} of {@link ConnectionFactory}. The keys are {@link String Strings}, the - * values are actual {@link ConnectionFactory} instances. - */ - public MapConnectionFactoryLookup(Map connectionFactories) { - setConnectionFactories(connectionFactories); - } - - /** - * Create a new instance of the {@link MapConnectionFactoryLookup} class. - * - * @param connectionFactoryName the name under which the supplied {@link ConnectionFactory} is to be added - * @param connectionFactory the {@link ConnectionFactory} to be added - */ - public MapConnectionFactoryLookup(String connectionFactoryName, ConnectionFactory connectionFactory) { - addConnectionFactory(connectionFactoryName, connectionFactory); - } - - /** - * Set the {@link Map} of {@link ConnectionFactory ConnectionFactories}. The keys are {@link String Strings}, the - * values are actual {@link ConnectionFactory} instances. - *

- * If the supplied {@link Map} is {@literal null}, then this method call effectively has no effect. - * - * @param connectionFactories said {@link Map} of {@link ConnectionFactory connectionFactories} - */ - public void setConnectionFactories(Map connectionFactories) { - - Assert.notNull(connectionFactories, "ConnectionFactories must not be null!"); - - this.connectionFactories.putAll(connectionFactories); - } - - /** - * Get the {@link Map} of {@link ConnectionFactory ConnectionFactories} maintained by this object. - *

- * The returned {@link Map} is {@link Collections#unmodifiableMap(Map) unmodifiable}. - * - * @return {@link Map} of {@link ConnectionFactory connectionFactory} (never {@literal null}). - */ - public Map getConnectionFactories() { - return Collections.unmodifiableMap(this.connectionFactories); - } - - /** - * Add the supplied {@link ConnectionFactory} to the map of {@link ConnectionFactory ConnectionFactorys} maintained by - * this object. - * - * @param connectionFactoryName the name under which the supplied {@link ConnectionFactory} is to be added - * @param connectionFactory the {@link ConnectionFactory} to be so added - */ - public void addConnectionFactory(String connectionFactoryName, ConnectionFactory connectionFactory) { - - Assert.notNull(connectionFactoryName, "ConnectionFactory name must not be null!"); - Assert.notNull(connectionFactory, "ConnectionFactory must not be null!"); - - this.connectionFactories.put(connectionFactoryName, connectionFactory); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.connectionfactory.lookup.ConnectionFactoryLookup#getConnectionFactory(java.lang.String) - */ - @Override - public ConnectionFactory getConnectionFactory(String connectionFactoryName) - throws ConnectionFactoryLookupFailureException { - - Assert.notNull(connectionFactoryName, "ConnectionFactory name must not be null!"); - - return this.connectionFactories.computeIfAbsent(connectionFactoryName, key -> { - - throw new ConnectionFactoryLookupFailureException( - "No ConnectionFactory with name '" + connectionFactoryName + "' registered"); - }); - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/lookup/SingleConnectionFactoryLookup.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/lookup/SingleConnectionFactoryLookup.java deleted file mode 100644 index e9554d9be..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/lookup/SingleConnectionFactoryLookup.java +++ /dev/null @@ -1,56 +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.connectionfactory.lookup; - -import io.r2dbc.spi.ConnectionFactory; - -import org.springframework.util.Assert; - -/** - * An implementation of {@link ConnectionFactoryLookup} that simply wraps a single given {@link ConnectionFactory}, - * returned for any connection factory name. - * - * @author Mark Paluch - * @deprecated since 1.2 in favor of Spring R2DBC. Use - * {@link org.springframework.r2dbc.connection.lookup.SingleConnectionFactoryLookup} instead. - */ -@Deprecated -public class SingleConnectionFactoryLookup implements ConnectionFactoryLookup { - - private final ConnectionFactory connectionFactory; - - /** - * Create a new instance of the {@link SingleConnectionFactoryLookup} class. - * - * @param connectionFactory the single {@link ConnectionFactory} to wrap. - */ - public SingleConnectionFactoryLookup(ConnectionFactory connectionFactory) { - - Assert.notNull(connectionFactory, "ConnectionFactory must not be null!"); - - this.connectionFactory = connectionFactory; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.connectionfactory.lookup.ConnectionFactoryLookup#getConnectionFactory(java.lang.String) - */ - @Override - public ConnectionFactory getConnectionFactory(String connectionFactoryName) - throws ConnectionFactoryLookupFailureException { - return this.connectionFactory; - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/lookup/package-info.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/lookup/package-info.java deleted file mode 100644 index e3b102797..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/lookup/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Provides a strategy for looking up R2DBC ConnectionFactories by name. Deprecated since 1.2 in favor of Spring R2DBC. - * Use {@link org.springframework.r2dbc.connection.lookup} instead. - */ -@org.springframework.lang.NonNullApi -@org.springframework.lang.NonNullFields -package org.springframework.data.r2dbc.connectionfactory.lookup; diff --git a/src/main/java/org/springframework/data/r2dbc/connectionfactory/package-info.java b/src/main/java/org/springframework/data/r2dbc/connectionfactory/package-info.java deleted file mode 100644 index b55ff510c..000000000 --- a/src/main/java/org/springframework/data/r2dbc/connectionfactory/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Connection and ConnectionFactory specifics for R2DBC. Deprecated since 1.2 in favor of Spring R2DBC. Use - * {@link org.springframework.r2dbc.connection} instead. - */ -@org.springframework.lang.NonNullApi -@org.springframework.lang.NonNullFields -package org.springframework.data.r2dbc.connectionfactory; diff --git a/src/main/java/org/springframework/data/r2dbc/convert/ColumnMapRowMapper.java b/src/main/java/org/springframework/data/r2dbc/convert/ColumnMapRowMapper.java deleted file mode 100644 index 67a6a894e..000000000 --- a/src/main/java/org/springframework/data/r2dbc/convert/ColumnMapRowMapper.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2018-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.convert; - -import io.r2dbc.spi.ColumnMetadata; -import io.r2dbc.spi.Row; -import io.r2dbc.spi.RowMetadata; - -import java.util.Map; -import java.util.function.BiFunction; - -import org.springframework.lang.Nullable; -import org.springframework.util.LinkedCaseInsensitiveMap; - -/** - * {@link BiFunction Mapping function} implementation that creates a {@link Map} for each row, representing all columns - * as key-value pairs: one entry for each column, with the column name as key. - *

- * The {@link Map} implementation to use and the key to use for each column in the column Map can be customized through - * overriding {@link #createColumnMap} and {@link #getColumnKey}, respectively. - *

- * Note: By default, {@link ColumnMapRowMapper} will try to build a linked {@link Map} with case-insensitive - * keys, to preserve column order as well as allow any casing to be used for column names. This requires Commons - * Collections on the classpath (which will be autodetected). Else, the fallback is a standard linked - * {@link java.util.HashMap}, which will still preserve column order but requires the application to specify the column - * names in the same casing as exposed by the driver. - * - * @author Mark Paluch - * @deprecated since 1.2, use Spring R2DBC's {@link org.springframework.r2dbc.core.ColumnMapRowMapper} directly. - */ -public class ColumnMapRowMapper extends org.springframework.r2dbc.core.ColumnMapRowMapper { - - public final static ColumnMapRowMapper INSTANCE = new ColumnMapRowMapper(); - - @Override - public Map apply(Row row, RowMetadata rowMetadata) { - return super.apply(row, rowMetadata); - } - - /** - * Create a {@link Map} instance to be used as column map. - *

- * By default, a linked case-insensitive Map will be created. - * - * @param columnCount the column count, to be used as initial capacity for the Map. - * @return the new {@link Map} instance. - * @see LinkedCaseInsensitiveMap - */ - protected Map createColumnMap(int columnCount) { - return super.createColumnMap(columnCount); - } - - /** - * Determine the key to use for the given column in the column {@link Map}. - * - * @param columnName the column name as returned by the {@link Row}. - * @return the column key to use. - * @see ColumnMetadata#getName() - */ - protected String getColumnKey(String columnName) { - return super.getColumnKey(columnName); - } - - /** - * Retrieve a R2DBC object value for the specified column. - *

- * The default implementation uses the {@link Row#get(int)} method. - * - * @param row is the {@link Row} holding the data. - * @param index is the column index. - * @return the Object returned. - */ - @Nullable - protected Object getColumnValue(Row row, int index) { - return super.getColumnValue(row, index); - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/core/BindParameterSource.java b/src/main/java/org/springframework/data/r2dbc/core/BindParameterSource.java index e4f8122ba..a7f5de42b 100644 --- a/src/main/java/org/springframework/data/r2dbc/core/BindParameterSource.java +++ b/src/main/java/org/springframework/data/r2dbc/core/BindParameterSource.java @@ -32,7 +32,7 @@ import org.springframework.lang.Nullable; * @deprecated since 1.2, without replacement. */ @Deprecated -public interface BindParameterSource { +interface BindParameterSource { /** * Determine whether there is a value for the specified named parameter. diff --git a/src/main/java/org/springframework/data/r2dbc/core/ConnectionAccessor.java b/src/main/java/org/springframework/data/r2dbc/core/ConnectionAccessor.java deleted file mode 100644 index faa758c3d..000000000 --- a/src/main/java/org/springframework/data/r2dbc/core/ConnectionAccessor.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2018-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.Connection; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import java.util.function.Function; - -import org.springframework.dao.DataAccessException; - -/** - * Interface declaring methods that accept callback {@link Function} to operate within the scope of a - * {@link Connection}. Callback functions operate on a provided connection and must not close the connection as the - * connections may be pooled or be subject to other kinds of resource management. - *

- * Callback functions are responsible for creating a {@link org.reactivestreams.Publisher} that defines the scope of how - * long the allocated {@link Connection} is valid. Connections are released after the publisher terminates. - * - * @author Mark Paluch - * @deprecated since 1.2, use Spring R2DBC's {@link org.springframework.r2dbc.core.DatabaseClient} support instead. - */ -public interface ConnectionAccessor extends org.springframework.r2dbc.core.ConnectionAccessor { - - /** - * Execute a callback {@link Function} within a {@link Connection} scope. The function is responsible for creating a - * {@link Mono}. The connection is released after the {@link Mono} terminates (or the subscription is cancelled). - * Connection resources must not be passed outside of the {@link Function} closure, otherwise resources may get - * defunct. - * - * @param action must not be {@literal null}. - * @return the resulting {@link Mono}. - * @throws DataAccessException - */ - Mono inConnection(Function> action) throws DataAccessException; - - /** - * Execute a callback {@link Function} within a {@link Connection} scope. The function is responsible for creating a - * {@link Flux}. The connection is released after the {@link Flux} terminates (or the subscription is cancelled). - * Connection resources must not be passed outside of the {@link Function} closure, otherwise resources may get - * defunct. - * - * @param action must not be {@literal null}. - * @return the resulting {@link Flux}. - * @throws DataAccessException - */ - Flux inConnectionMany(Function> action) throws DataAccessException; - -} diff --git a/src/main/java/org/springframework/data/r2dbc/core/DatabaseClient.java b/src/main/java/org/springframework/data/r2dbc/core/DatabaseClient.java deleted file mode 100644 index 3e605d48e..000000000 --- a/src/main/java/org/springframework/data/r2dbc/core/DatabaseClient.java +++ /dev/null @@ -1,929 +0,0 @@ -/* - * Copyright 2018-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 io.r2dbc.spi.Row; -import io.r2dbc.spi.RowMetadata; -import io.r2dbc.spi.Statement; -import reactor.core.publisher.Mono; - -import java.util.Arrays; -import java.util.Map; -import java.util.function.BiFunction; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Supplier; - -import org.reactivestreams.Publisher; - -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Sort; -import org.springframework.data.projection.ProjectionFactory; -import org.springframework.data.r2dbc.mapping.SettableValue; -import org.springframework.data.r2dbc.query.Update; -import org.springframework.data.r2dbc.support.R2dbcExceptionTranslator; -import org.springframework.data.relational.core.query.CriteriaDefinition; -import org.springframework.data.relational.core.sql.SqlIdentifier; -import org.springframework.util.Assert; - -/** - * A non-blocking, reactive client for performing database calls requests with Reactive Streams back pressure. Provides - * a higher level, common API over R2DBC client libraries. - *

- * Use one of the static factory methods {@link #create(ConnectionFactory)} or obtain a {@link DatabaseClient#builder()} - * to create an instance. - * - * @author Mark Paluch - * @author Bogdan Ilchyshyn - * @deprecated since 1.2, use Spring R2DBC's {@link org.springframework.r2dbc.core.DatabaseClient} support instead. - */ -@Deprecated -public interface DatabaseClient { - - /** - * Return the {@link ConnectionFactory} that this client uses. - * - * @return the connection factory. - * @since 1.2 - */ - ConnectionFactory getConnectionFactory(); - - /** - * Specify a static {@code sql} string to execute. Contract for specifying a SQL call along with options leading to - * the exchange. The SQL string can contain either native parameter bind markers or named parameters (e.g. - * {@literal :foo, :bar}) when {@link NamedParameterExpander} is enabled. - * - * @param sql must not be {@literal null} or empty. - * @return a new {@link GenericExecuteSpec}. - * @see NamedParameterExpander - * @see DatabaseClient.Builder#namedParameters(boolean) - */ - GenericExecuteSpec execute(String sql); - - /** - * Specify a {@link Supplier SQL supplier} that provides SQL to execute. Contract for specifying a SQL call along with - * options leading to the exchange. The SQL string can contain either native parameter bind markers or named - * parameters (e.g. {@literal :foo, :bar}) when {@link NamedParameterExpander} is enabled. - *

- * Accepts {@link PreparedOperation} as SQL and binding {@link Supplier}. - *

- * - * @param sqlSupplier must not be {@literal null}. - * @return a new {@link GenericExecuteSpec}. - * @see NamedParameterExpander - * @see DatabaseClient.Builder#namedParameters(boolean) - * @see PreparedOperation - */ - GenericExecuteSpec execute(Supplier sqlSupplier); - - /** - * Prepare an SQL SELECT call. - */ - SelectFromSpec select(); - - /** - * Prepare an SQL INSERT call. - */ - InsertIntoSpec insert(); - - /** - * Prepare an SQL UPDATE call. - */ - UpdateTableSpec update(); - - /** - * Prepare an SQL DELETE call. - */ - DeleteFromSpec delete(); - - /** - * Return a builder to mutate properties of this database client. - */ - DatabaseClient.Builder mutate(); - - // Static, factory methods - - /** - * Creates a {@code DatabaseClient} that will use the provided {@link io.r2dbc.spi.ConnectionFactory}. - * - * @param factory The {@code ConnectionFactory} to use for obtaining connections. - * @return a new {@code DatabaseClient}. Guaranteed to be not {@literal null}. - */ - static DatabaseClient create(ConnectionFactory factory) { - return new DefaultDatabaseClientBuilder().connectionFactory(factory).build(); - } - - /** - * Obtain a {@code DatabaseClient} builder. - */ - static DatabaseClient.Builder builder() { - return new DefaultDatabaseClientBuilder(); - } - - /** - * A mutable builder for creating a {@link DatabaseClient}. - */ - interface Builder { - - /** - * Configures the {@link ConnectionFactory R2DBC connector}. - * - * @param factory must not be {@literal null}. - * @return {@code this} {@link Builder}. - */ - Builder connectionFactory(ConnectionFactory factory); - - /** - * Configures a {@link R2dbcExceptionTranslator}. - * - * @param exceptionTranslator must not be {@literal null}. - * @return {@code this} {@link Builder}. - */ - Builder exceptionTranslator(R2dbcExceptionTranslator exceptionTranslator); - - /** - * Configures a {@link ExecuteFunction} to execute {@link Statement} objects. - * - * @param executeFunction must not be {@literal null}. - * @return {@code this} {@link Builder}. - * @since 1.1 - * @see Statement#execute() - */ - Builder executeFunction(ExecuteFunction executeFunction); - - /** - * Configures a {@link ReactiveDataAccessStrategy}. - * - * @param accessStrategy must not be {@literal null}. - * @return {@code this} {@link Builder}. - */ - Builder dataAccessStrategy(ReactiveDataAccessStrategy accessStrategy); - - /** - * Configures whether to use named parameter expansion. Defaults to {@literal true}. - * - * @param enabled {@literal true} to use named parameter expansion. {@literal false} to disable named parameter - * expansion. - * @return {@code this} {@link Builder}. - * @see NamedParameterExpander - */ - Builder namedParameters(boolean enabled); - - /** - * Configures the {@link org.springframework.data.projection.ProjectionFactory projection factory}. - * - * @param factory must not be {@literal null}. - * @return {@code this} {@link Builder}. - * @since 1.1 - */ - Builder projectionFactory(ProjectionFactory factory); - - /** - * Configures a {@link Consumer} to configure this builder. - * - * @param builderConsumer must not be {@literal null}. - * @return {@code this} {@link Builder}. - */ - Builder apply(Consumer builderConsumer); - - /** - * Builder the {@link DatabaseClient} instance. - */ - DatabaseClient build(); - } - - /** - * Contract for specifying a SQL call along with options leading to the exchange. - */ - interface GenericExecuteSpec extends BindSpec, StatementFilterSpec { - - /** - * Define the target type the result should be mapped to.
- * Skip this step if you are anyway fine with the default conversion. - * - * @param resultType must not be {@literal null}. - * @param result type. - */ - TypedExecuteSpec as(Class resultType); - - /** - * Configure a result mapping {@link java.util.function.Function function}. - * - * @param mappingFunction must not be {@literal null}. - * @param result type. - * @return a {@link FetchSpec} for configuration what to fetch. Guaranteed to be not {@literal null}. - */ - RowsFetchSpec map(Function mappingFunction); - - /** - * Configure a result mapping {@link java.util.function.BiFunction function}. - * - * @param mappingFunction must not be {@literal null}. - * @param result type. - * @return a {@link FetchSpec} for configuration what to fetch. Guaranteed to be not {@literal null}. - */ - RowsFetchSpec map(BiFunction mappingFunction); - - /** - * Perform the SQL call and retrieve the result. - */ - FetchSpec> fetch(); - - /** - * Perform the SQL call and return a {@link Mono} that completes without result on statement completion. - * - * @return a {@link Mono} ignoring its payload (actively dropping). - */ - Mono then(); - } - - /** - * Contract for specifying a SQL call along with options leading to the exchange. - */ - interface TypedExecuteSpec extends BindSpec>, StatementFilterSpec> { - - /** - * Define the target type the result should be mapped to.
- * Skip this step if you are anyway fine with the default conversion. - * - * @param resultType must not be {@literal null}. - * @param result type. - */ - TypedExecuteSpec as(Class resultType); - - /** - * Configure a result mapping {@link java.util.function.Function function}. - * - * @param mappingFunction must not be {@literal null}. - * @param result type. - * @return a {@link FetchSpec} for configuration what to fetch. Guaranteed to be not {@literal null}. - */ - RowsFetchSpec map(Function mappingFunction); - - /** - * Configure a result mapping {@link java.util.function.BiFunction function}. - * - * @param mappingFunction must not be {@literal null}. - * @param result type. - * @return a {@link FetchSpec} for configuration what to fetch. Guaranteed to be not {@literal null}. - */ - RowsFetchSpec map(BiFunction mappingFunction); - - /** - * Perform the SQL call and retrieve the result. - */ - FetchSpec fetch(); - - /** - * Perform the SQL call and return a {@link Mono} that completes without result on statement completion. - * - * @return a {@link Mono} ignoring its payload (actively dropping). - */ - Mono then(); - } - - /** - * Contract for specifying {@code SELECT} options leading to the exchange. - */ - interface SelectFromSpec { - - /** - * Specify the source {@code table} to select from. - * - * @param table must not be {@literal null} or empty. - * @return a {@link GenericSelectSpec} for further configuration of the select. Guaranteed to be not - * {@literal null}. - * @see SqlIdentifier#unquoted(String) - */ - default GenericSelectSpec from(String table) { - return from(SqlIdentifier.unquoted(table)); - } - - /** - * Specify the source {@code table} to select from. - * - * @param table must not be {@literal null} or empty. - * @return a {@link GenericSelectSpec} for further configuration of the select. Guaranteed to be not - * {@literal null}. - * @since 1.1 - */ - GenericSelectSpec from(SqlIdentifier table); - - /** - * Specify the source table to select from to using the {@link Class entity class}. - * - * @param table must not be {@literal null}. - * @return a {@link TypedSelectSpec} for further configuration of the select. Guaranteed to be not {@literal null}. - */ - TypedSelectSpec from(Class table); - } - - /** - * Contract for specifying {@code INSERT} options leading to the exchange. - */ - interface InsertIntoSpec { - - /** - * Specify the target {@code table} to insert into. - * - * @param table must not be {@literal null} or empty. - * @return a {@link GenericInsertSpec} for further configuration of the insert. Guaranteed to be not - * {@literal null}. - * @see SqlIdentifier#unquoted(String) - */ - default GenericInsertSpec> into(String table) { - return into(SqlIdentifier.unquoted(table)); - } - - /** - * Specify the target {@code table} to insert into. - * - * @param table must not be {@literal null} or empty. - * @return a {@link GenericInsertSpec} for further configuration of the insert. Guaranteed to be not - * {@literal null}. - * @since 1.1 - */ - GenericInsertSpec> into(SqlIdentifier table); - - /** - * Specify the target table to insert to using the {@link Class entity class}. - * - * @param table must not be {@literal null}. - * @return a {@link TypedInsertSpec} for further configuration of the insert. Guaranteed to be not {@literal null}. - */ - TypedInsertSpec into(Class table); - } - - /** - * Contract for specifying {@code UPDATE} options leading to the exchange. - */ - interface UpdateTableSpec { - - /** - * Specify the target {@code table} to update. - * - * @param table must not be {@literal null} or empty. - * @return a {@link GenericUpdateSpec} for further configuration of the update. Guaranteed to be not - * {@literal null}. - * @see SqlIdentifier#unquoted(String) - */ - default GenericUpdateSpec table(String table) { - return table(SqlIdentifier.unquoted(table)); - } - - /** - * Specify the target {@code table} to update. - * - * @param table must not be {@literal null} or empty. - * @return a {@link GenericUpdateSpec} for further configuration of the update. Guaranteed to be not - * {@literal null}. - * @since 1.1 - */ - GenericUpdateSpec table(SqlIdentifier table); - - /** - * Specify the target table to update to using the {@link Class entity class}. - * - * @param table must not be {@literal null}. - * @return a {@link TypedUpdateSpec} for further configuration of the update. Guaranteed to be not {@literal null}. - */ - TypedUpdateSpec table(Class table); - } - - /** - * Contract for specifying {@code DELETE} options leading to the exchange. - */ - interface DeleteFromSpec { - - /** - * Specify the source {@code table} to delete from. - * - * @param table must not be {@literal null} or empty. - * @return a {@link DeleteMatchingSpec} for further configuration of the delete. Guaranteed to be not - * {@literal null}. - * @see SqlIdentifier#unquoted(String) - */ - default DeleteMatchingSpec from(String table) { - return from(SqlIdentifier.unquoted(table)); - } - - /** - * Specify the source {@code table} to delete from. - * - * @param table must not be {@literal null} or empty. - * @return a {@link DeleteMatchingSpec} for further configuration of the delete. Guaranteed to be not - * {@literal null}. - * @since 1.1 - */ - DeleteMatchingSpec from(SqlIdentifier table); - - /** - * Specify the source table to delete from to using the {@link Class entity class}. - * - * @param table must not be {@literal null}. - * @return a {@link TypedDeleteSpec} for further configuration of the delete. Guaranteed to be not {@literal null}. - */ - TypedDeleteSpec from(Class table); - } - - /** - * Contract for specifying {@code SELECT} options leading to the exchange. - */ - interface GenericSelectSpec extends SelectSpec { - - /** - * Define the target type the result should be mapped to.
- * Skip this step if you are anyway fine with the default conversion. - * - * @param resultType must not be {@literal null}. - * @param result type. - */ - TypedSelectSpec as(Class resultType); - - /** - * Configure a result mapping {@link java.util.function.Function function}. - * - * @param mappingFunction must not be {@literal null}. - * @param result type. - * @return a {@link FetchSpec} for configuration what to fetch. Guaranteed to be not {@literal null}. - */ - RowsFetchSpec map(Function mappingFunction); - - /** - * Configure a result mapping {@link java.util.function.BiFunction function}. - * - * @param mappingFunction must not be {@literal null}. - * @param result type. - * @return a {@link FetchSpec} for configuration what to fetch. Guaranteed to be not {@literal null}. - */ - RowsFetchSpec map(BiFunction mappingFunction); - - /** - * Perform the SQL call and retrieve the result. - */ - FetchSpec> fetch(); - } - - /** - * Contract for specifying {@code SELECT} options leading to the exchange. - */ - interface TypedSelectSpec extends SelectSpec> { - - /** - * Define the target type the result should be mapped to.
- * Skip this step if you are anyway fine with the default conversion. - * - * @param resultType must not be {@literal null}. - * @param result type. - */ - RowsFetchSpec as(Class resultType); - - /** - * Configure a result mapping {@link java.util.function.Function function}. - * - * @param mappingFunction must not be {@literal null}. - * @param result type. - * @return a {@link FetchSpec} for configuration what to fetch. Guaranteed to be not {@literal null}. - */ - RowsFetchSpec map(Function mappingFunction); - - /** - * Configure a result mapping {@link java.util.function.BiFunction function}. - * - * @param mappingFunction must not be {@literal null}. - * @param result type. - * @return a {@link FetchSpec} for configuration what to fetch. Guaranteed to be not {@literal null}. - */ - RowsFetchSpec map(BiFunction mappingFunction); - - /** - * Perform the SQL call and retrieve the result. - */ - FetchSpec fetch(); - } - - /** - * Contract for specifying {@code SELECT} options leading to the exchange. - */ - interface SelectSpec> { - - /** - * Configure projected fields. - * - * @param selectedFields must not be {@literal null}. - * @see SqlIdentifier#unquoted(String) - */ - default S project(String... selectedFields) { - return project(Arrays.stream(selectedFields).map(SqlIdentifier::unquoted).toArray(SqlIdentifier[]::new)); - } - - /** - * Configure projected fields. - * - * @param selectedFields must not be {@literal null}. - * @since 1.1 - */ - S project(SqlIdentifier... selectedFields); - - /** - * Configure a filter {@link CriteriaDefinition}. - * - * @param criteria must not be {@literal null}. - */ - S matching(CriteriaDefinition criteria); - - /** - * Configure {@link Sort}. - * - * @param sort must not be {@literal null}. - */ - S orderBy(Sort sort); - - /** - * Configure {@link Sort}. - * - * @param orders must not be {@literal null}. - */ - default S orderBy(Sort.Order... orders) { - return orderBy(Sort.by(orders)); - } - - /** - * Configure pagination. Overrides {@link Sort} if the {@link Pageable} contains a {@link Sort} object. - * - * @param pageable must not be {@literal null}. - */ - S page(Pageable pageable); - } - - /** - * Contract for specifying {@code INSERT} options leading to the exchange. - * - * @param Result type of tabular insert results. - */ - interface GenericInsertSpec extends InsertSpec { - - /** - * Specify a field and non-{@literal null} value to insert. {@code value} can be either a scalar value or - * {@link SettableValue}. - * - * @param field must not be {@literal null} or empty. - * @param value the field value to set, must not be {@literal null}. Can be either a scalar value or - * {@link SettableValue}. - * @see SqlIdentifier#unquoted(String) - */ - default GenericInsertSpec value(String field, Object value) { - return value(SqlIdentifier.unquoted(field), value); - } - - /** - * Specify a field and non-{@literal null} value to insert. {@code value} can be either a scalar value or - * {@link SettableValue}. - * - * @param field must not be {@literal null} or empty. - * @param value the field value to set, must not be {@literal null}. Can be either a scalar value or - * {@link SettableValue}. - */ - GenericInsertSpec value(SqlIdentifier field, Object value); - - /** - * Specify a {@literal null} value to insert. - * - * @param field must not be {@literal null} or empty. - * @param type must not be {@literal null}. - * @see SqlIdentifier#unquoted(String) - */ - default GenericInsertSpec nullValue(String field, Class type) { - return nullValue(SqlIdentifier.unquoted(field), type); - } - - /** - * Specify a {@literal null} value to insert. - * - * @param field must not be {@literal null} or empty. - * @param type must not be {@literal null}. - * @since 1.1 - */ - default GenericInsertSpec nullValue(SqlIdentifier field, Class type) { - return value(field, SettableValue.empty(type)); - } - } - - /** - * Contract for specifying {@code INSERT} options leading the exchange. - */ - interface TypedInsertSpec { - - /** - * Insert the given {@code objectToInsert}. - * - * @param objectToInsert the object of which the attributes will provide the values for the insert. Must not be - * {@literal null}. - * @return a {@link InsertSpec} for further configuration of the insert. Guaranteed to be not {@literal null}. - */ - InsertSpec> using(T objectToInsert); - - /** - * Use the given {@code tableName} as insert target. - * - * @param tableName must not be {@literal null} or empty. - * @return a {@link TypedInsertSpec} for further configuration of the insert. Guaranteed to be not {@literal null}. - * @see SqlIdentifier#unquoted(String) - */ - default TypedInsertSpec table(String tableName) { - return table(SqlIdentifier.unquoted(tableName)); - } - - /** - * Use the given {@code tableName} as insert target. - * - * @param tableName must not be {@literal null} or empty. - * @return a {@link TypedInsertSpec} for further configuration of the insert. Guaranteed to be not {@literal null}. - * @since 1.1 - */ - TypedInsertSpec table(SqlIdentifier tableName); - - /** - * Insert the given {@link Publisher} to insert one or more objects. Inserts only a single object when calling - * {@link FetchSpec#one()} or {@link FetchSpec#first()}. - * - * @param objectToInsert a publisher providing the objects of which the attributes will provide the values for the - * insert. Must not be {@literal null}. - * @return a {@link InsertSpec} for further configuration of the insert. Guaranteed to be not {@literal null}. - * @see InsertSpec#fetch() - */ - InsertSpec> using(Publisher objectToInsert); - } - - /** - * Contract for specifying {@code INSERT} options leading to the exchange. - * - * @param Result type of tabular insert results. - */ - interface InsertSpec { - - /** - * Configure a result mapping {@link java.util.function.Function function}. - * - * @param mappingFunction must not be {@literal null}. - * @param result type. - * @return a {@link FetchSpec} for configuration what to fetch. Guaranteed to be not {@literal null}. - */ - RowsFetchSpec map(Function mappingFunction); - - /** - * Configure a result mapping {@link java.util.function.BiFunction function}. - * - * @param mappingFunction must not be {@literal null}. - * @param result type. - * @return a {@link FetchSpec} for configuration what to fetch. Guaranteed to be not {@literal null}. - */ - RowsFetchSpec map(BiFunction mappingFunction); - - /** - * Perform the SQL call and retrieve the result. - */ - FetchSpec fetch(); - - /** - * Perform the SQL call and return a {@link Mono} that completes without result on statement completion. - * - * @return a {@link Mono} ignoring its payload (actively dropping). - */ - Mono then(); - } - - /** - * Contract for specifying {@code UPDATE} options leading to the exchange. - */ - interface GenericUpdateSpec { - - /** - * Specify an {@link Update} object containing assignments. - * - * @param update must not be {@literal null}. - * @deprecated since 1.1, use {@link #using(org.springframework.data.relational.core.query.Update)}. - */ - @Deprecated - UpdateMatchingSpec using(Update update); - - /** - * Specify an {@link Update} object containing assignments. - * - * @param update must not be {@literal null}. - * @since 1.1 - */ - UpdateMatchingSpec using(org.springframework.data.relational.core.query.Update update); - } - - /** - * Contract for specifying {@code UPDATE} options leading to the exchange. - */ - interface TypedUpdateSpec { - - /** - * Update the given {@code objectToUpdate}. - * - * @param objectToUpdate the object of which the attributes will provide the values for the update and the primary - * key. Must not be {@literal null}. - * @return a {@link UpdateMatchingSpec} for further configuration of the update. Guaranteed to be not {@literal null}. - */ - UpdateMatchingSpec using(T objectToUpdate); - - /** - * Use the given {@code tableName} as update target. - * - * @param tableName must not be {@literal null} or empty. - * @return a {@link TypedUpdateSpec} for further configuration of the update. Guaranteed to be not {@literal null}. - * @see SqlIdentifier#unquoted(String) - */ - default TypedUpdateSpec table(String tableName) { - return table(SqlIdentifier.unquoted(tableName)); - } - - /** - * Use the given {@code tableName} as update target. - * - * @param tableName must not be {@literal null} or empty. - * @return a {@link TypedUpdateSpec} for further configuration of the update. Guaranteed to be not {@literal null}. - * @since 1.1 - */ - TypedUpdateSpec table(SqlIdentifier tableName); - } - - /** - * Contract for specifying {@code UPDATE} options leading to the exchange. - */ - interface UpdateMatchingSpec extends UpdateSpec { - - /** - * Configure a filter {@link CriteriaDefinition}. - * - * @param criteria must not be {@literal null}. - */ - UpdateSpec matching(CriteriaDefinition criteria); - } - - /** - * Contract for specifying {@code UPDATE} options leading to the exchange. - */ - interface UpdateSpec { - - /** - * Perform the SQL call and retrieve the result. - */ - UpdatedRowsFetchSpec fetch(); - - /** - * Perform the SQL call and return a {@link Mono} that completes without result on statement completion. - * - * @return a {@link Mono} ignoring its payload (actively dropping). - */ - Mono then(); - } - - /** - * Contract for specifying {@code DELETE} options leading to the exchange. - */ - interface TypedDeleteSpec extends DeleteSpec { - - /** - * Use the given {@code tableName} as delete target. - * - * @param tableName must not be {@literal null} or empty. - * @return a {@link TypedDeleteSpec} for further configuration of the delete. Guaranteed to be not {@literal null}. - * @see SqlIdentifier#unquoted(String) - */ - default TypedDeleteSpec table(String tableName) { - return table(SqlIdentifier.unquoted(tableName)); - } - - /** - * Use the given {@code tableName} as delete target. - * - * @param tableName must not be {@literal null} or empty. - * @return a {@link TypedDeleteSpec} for further configuration of the delete. Guaranteed to be not {@literal null}. - * @since 1.1 - */ - TypedDeleteSpec table(SqlIdentifier tableName); - - /** - * Configure a filter {@link CriteriaDefinition}. - * - * @param criteria must not be {@literal null}. - */ - DeleteSpec matching(CriteriaDefinition criteria); - } - - /** - * Contract for specifying {@code DELETE} options leading to the exchange. - */ - interface DeleteMatchingSpec extends DeleteSpec { - - /** - * Configure a filter {@link CriteriaDefinition}. - * - * @param criteria must not be {@literal null}. - */ - DeleteSpec matching(CriteriaDefinition criteria); - } - - /** - * Contract for specifying {@code DELETE} options leading to the exchange. - */ - interface DeleteSpec { - - /** - * Perform the SQL call and retrieve the result. - */ - UpdatedRowsFetchSpec fetch(); - - /** - * Perform the SQL call and return a {@link Mono} that completes without result on statement completion. - * - * @return a {@link Mono} ignoring its payload (actively dropping). - */ - Mono then(); - } - - /** - * Contract for specifying parameter bindings. - */ - interface BindSpec> { - - /** - * Bind a non-{@literal null} value to a parameter identified by its {@code index}. {@code value} can be either a - * scalar value or {@link SettableValue}. - * - * @param index zero based index to bind the parameter to. - * @param value must not be {@literal null}. Can be either a scalar value or {@link SettableValue}. - */ - S bind(int index, Object value); - - /** - * Bind a {@literal null} value to a parameter identified by its {@code index}. - * - * @param index zero based index to bind the parameter to. - * @param type must not be {@literal null}. - */ - S bindNull(int index, Class type); - - /** - * Bind a non-{@literal null} value to a parameter identified by its {@code name}. {@code value} can be either a - * scalar value or {@link SettableValue}. - * - * @param name must not be {@literal null} or empty. - * @param value must not be {@literal null}. Can be either a scalar value or {@link SettableValue}. - */ - S bind(String name, Object value); - - /** - * Bind a {@literal null} value to a parameter identified by its {@code name}. - * - * @param name must not be {@literal null} or empty. - * @param type must not be {@literal null}. - */ - S bindNull(String name, Class type); - } - - /** - * Contract for applying a {@link StatementFilterFunction}. - * - * @since 1.1 - */ - interface StatementFilterSpec> { - - /** - * Add the given filter to the end of the filter chain. - * - * @param filter the filter to be added to the chain. - */ - default S filter(Function filter) { - - Assert.notNull(filter, "Statement FilterFunction must not be null!"); - - return filter((statement, next) -> next.execute(filter.apply(statement))); - } - - /** - * Add the given filter to the end of the filter chain. - * - * @param filter the filter to be added to the chain. - */ - S filter(StatementFilterFunction filter); - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/core/DefaultDatabaseClient.java b/src/main/java/org/springframework/data/r2dbc/core/DefaultDatabaseClient.java deleted file mode 100644 index 16a083d2f..000000000 --- a/src/main/java/org/springframework/data/r2dbc/core/DefaultDatabaseClient.java +++ /dev/null @@ -1,1704 +0,0 @@ -/* - * Copyright 2018-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.Connection; -import io.r2dbc.spi.ConnectionFactory; -import io.r2dbc.spi.R2dbcException; -import io.r2dbc.spi.Result; -import io.r2dbc.spi.Row; -import io.r2dbc.spi.RowMetadata; -import io.r2dbc.spi.Statement; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.BiFunction; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.stream.Collectors; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.reactivestreams.Publisher; - -import org.springframework.dao.DataAccessException; -import org.springframework.dao.InvalidDataAccessApiUsageException; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Sort; -import org.springframework.data.projection.ProjectionFactory; -import org.springframework.data.r2dbc.UncategorizedR2dbcException; -import org.springframework.data.r2dbc.connectionfactory.ConnectionFactoryUtils; -import org.springframework.data.r2dbc.connectionfactory.ConnectionProxy; -import org.springframework.data.r2dbc.convert.ColumnMapRowMapper; -import org.springframework.data.r2dbc.dialect.BindTarget; -import org.springframework.data.r2dbc.mapping.OutboundRow; -import org.springframework.data.r2dbc.mapping.SettableValue; -import org.springframework.data.r2dbc.query.Update; -import org.springframework.data.r2dbc.support.R2dbcExceptionTranslator; -import org.springframework.data.relational.core.query.Criteria; -import org.springframework.data.relational.core.query.CriteriaDefinition; -import org.springframework.data.relational.core.sql.SqlIdentifier; -import org.springframework.lang.Nullable; -import org.springframework.r2dbc.core.Parameter; -import org.springframework.r2dbc.core.PreparedOperation; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; - -/** - * Default implementation of {@link DatabaseClient}. - * - * @author Mark Paluch - * @author Mingyuan Wu - * @author Bogdan Ilchyshyn - * @deprecated since 1.2. - */ -@Deprecated -class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor { - - private final Log logger = LogFactory.getLog(getClass()); - - private final ConnectionFactory connector; - - private final R2dbcExceptionTranslator exceptionTranslator; - - private final ExecuteFunction executeFunction; - - private final ReactiveDataAccessStrategy dataAccessStrategy; - - private final boolean namedParameters; - - private final DefaultDatabaseClientBuilder builder; - - private final ProjectionFactory projectionFactory; - - DefaultDatabaseClient(ConnectionFactory connector, R2dbcExceptionTranslator exceptionTranslator, - ExecuteFunction executeFunction, ReactiveDataAccessStrategy dataAccessStrategy, boolean namedParameters, - ProjectionFactory projectionFactory, DefaultDatabaseClientBuilder builder) { - - this.connector = connector; - this.exceptionTranslator = exceptionTranslator; - this.executeFunction = executeFunction; - this.dataAccessStrategy = dataAccessStrategy; - this.namedParameters = namedParameters; - this.projectionFactory = projectionFactory; - this.builder = builder; - } - - @Override - public ConnectionFactory getConnectionFactory() { - return this.connector; - } - - @Override - public Builder mutate() { - return this.builder; - } - - @Override - public SelectFromSpec select() { - return new DefaultSelectFromSpec(); - } - - @Override - public InsertIntoSpec insert() { - return new DefaultInsertIntoSpec(); - } - - @Override - public UpdateTableSpec update() { - return new DefaultUpdateTableSpec(); - } - - @Override - public DeleteFromSpec delete() { - return new DefaultDeleteFromSpec(); - } - - @Override - public GenericExecuteSpec execute(String sql) { - - Assert.hasText(sql, "SQL must not be null or empty!"); - - return execute(() -> sql); - } - - @Override - public GenericExecuteSpec execute(Supplier sqlSupplier) { - - Assert.notNull(sqlSupplier, "SQL Supplier must not be null!"); - - return createGenericExecuteSpec(sqlSupplier); - } - - /** - * Execute a callback {@link Function} within a {@link Connection} scope. The function is responsible for creating a - * {@link Mono}. The connection is released after the {@link Mono} terminates (or the subscription is cancelled). - * Connection resources must not be passed outside of the {@link Function} closure, otherwise resources may get - * defunct. - * - * @param action must not be {@literal null}. - * @return the resulting {@link Mono}. - * @throws DataAccessException when during construction of the {@link Mono} a problem occurs. - */ - @Override - public Mono inConnection(Function> action) throws DataAccessException { - - Assert.notNull(action, "Callback object must not be null"); - - Mono connectionMono = getConnection() - .map(it -> new ConnectionCloseHolder(it, this::closeConnection)); - - return Mono.usingWhen(connectionMono, it -> { - - // Create close-suppressing Connection proxy - Connection connectionToUse = createConnectionProxy(it.connection); - - return doInConnection(connectionToUse, action); - }, ConnectionCloseHolder::close, (it, err) -> it.close(), ConnectionCloseHolder::close) // - .onErrorMap(R2dbcException.class, ex -> translateException("execute", getSql(action), ex)); - } - - /** - * Execute a callback {@link Function} within a {@link Connection} scope. The function is responsible for creating a - * {@link Flux}. The connection is released after the {@link Flux} terminates (or the subscription is cancelled). - * Connection resources must not be passed outside of the {@link Function} closure, otherwise resources may get - * defunct. - * - * @param action must not be {@literal null}. - * @return the resulting {@link Flux}. - * @throws DataAccessException when during construction of the {@link Mono} a problem occurs. - */ - @Override - public Flux inConnectionMany(Function> action) throws DataAccessException { - - Assert.notNull(action, "Callback object must not be null"); - - Mono connectionMono = getConnection() - .map(it -> new ConnectionCloseHolder(it, this::closeConnection)); - - return Flux.usingWhen(connectionMono, it -> { - - // Create close-suppressing Connection proxy, also preparing returned Statements. - Connection connectionToUse = createConnectionProxy(it.connection); - - return doInConnectionMany(connectionToUse, action); - }, ConnectionCloseHolder::close, (it, err) -> it.close(), ConnectionCloseHolder::close) // - .onErrorMap(R2dbcException.class, ex -> translateException("executeMany", getSql(action), ex)); - } - - /** - * Obtain a {@link Connection}. - * - * @return a {@link Mono} able to emit a {@link Connection}. - */ - protected Mono getConnection() { - return ConnectionFactoryUtils.getConnection(obtainConnectionFactory()); - } - - /** - * Obtain the {@link ReactiveDataAccessStrategy}. - * - * @return a the ReactiveDataAccessStrategy. - */ - protected ReactiveDataAccessStrategy getDataAccessStrategy() { - return dataAccessStrategy; - } - - /** - * Release the {@link Connection}. - * - * @param connection to close. - * @return a {@link Publisher} that completes successfully when the connection is closed. - */ - protected Publisher closeConnection(Connection connection) { - - return ConnectionFactoryUtils.currentConnectionFactory(obtainConnectionFactory()).then() - .onErrorResume(Exception.class, e -> Mono.from(connection.close())); - } - - /** - * Obtain the {@link ConnectionFactory} for actual use. - * - * @return the ConnectionFactory (never {@literal null}) - * @throws IllegalStateException in case of no DataSource set - */ - protected ConnectionFactory obtainConnectionFactory() { - return this.connector; - } - - /** - * Create a close-suppressing proxy for the given R2DBC Connection. Called by the {@code execute} method. - * - * @param con the R2DBC Connection to create a proxy for - * @return the Connection proxy - */ - protected Connection createConnectionProxy(Connection con) { - return (Connection) Proxy.newProxyInstance(ConnectionProxy.class.getClassLoader(), - new Class[] { ConnectionProxy.class }, new CloseSuppressingInvocationHandler(con)); - } - - /** - * Translate the given {@link R2dbcException} into a generic {@link DataAccessException}. - * - * @param task readable text describing the task being attempted. - * @param sql SQL query or update that caused the problem (may be {@literal null}). - * @param ex the offending {@link R2dbcException}. - * @return a DataAccessException wrapping the {@link R2dbcException} (never {@literal null}). - */ - protected DataAccessException translateException(String task, @Nullable String sql, R2dbcException ex) { - - DataAccessException dae = this.exceptionTranslator.translate(task, sql, ex); - return dae != null ? dae : new UncategorizedR2dbcException(task, sql, ex); - } - - /** - * Customization hook. - */ - protected DefaultTypedExecuteSpec createTypedExecuteSpec(Map byIndex, - Map byName, Supplier sqlSupplier, StatementFilterFunction filterFunction, - Class typeToRead) { - return new DefaultTypedExecuteSpec<>(byIndex, byName, sqlSupplier, filterFunction, typeToRead); - } - - /** - * Customization hook. - */ - protected ExecuteSpecSupport createGenericExecuteSpec(Map byIndex, - Map byName, Supplier sqlSupplier, StatementFilterFunction filterFunction) { - return new DefaultGenericExecuteSpec(byIndex, byName, sqlSupplier, filterFunction); - } - - /** - * Customization hook. - */ - protected DefaultGenericExecuteSpec createGenericExecuteSpec(Supplier sqlSupplier) { - return new DefaultGenericExecuteSpec(sqlSupplier); - } - - private void bindByName(Statement statement, Map byName) { - - byName.forEach((name, o) -> { - - SettableValue converted = dataAccessStrategy.getBindValue(o); - if (converted.getValue() != null) { - - statement.bind(name, converted.getValue()); - } else { - statement.bindNull(name, converted.getType()); - } - }); - } - - private void bindByIndex(Statement statement, Map byIndex) { - - byIndex.forEach((i, o) -> { - - SettableValue converted = dataAccessStrategy.getBindValue(o); - if (converted.getValue() != null) { - statement.bind(i, converted.getValue()); - } else { - statement.bindNull(i, converted.getType()); - } - }); - } - - /** - * Base class for {@link DatabaseClient.GenericExecuteSpec} implementations. - */ - class ExecuteSpecSupport { - - final Map byIndex; - final Map byName; - final Supplier sqlSupplier; - final StatementFilterFunction filterFunction; - - ExecuteSpecSupport(Supplier sqlSupplier) { - - this.byIndex = Collections.emptyMap(); - this.byName = Collections.emptyMap(); - this.sqlSupplier = sqlSupplier; - this.filterFunction = StatementFilterFunctions.empty(); - } - - ExecuteSpecSupport(Map byIndex, Map byName, - Supplier sqlSupplier, StatementFilterFunction filterFunction) { - - this.byIndex = byIndex; - this.byName = byName; - this.sqlSupplier = sqlSupplier; - this.filterFunction = filterFunction; - } - - FetchSpec exchange(Supplier sqlSupplier, BiFunction mappingFunction) { - - String sql = getRequiredSql(sqlSupplier); - - Function statementFactory = it -> { - - if (logger.isDebugEnabled()) { - logger.debug("Executing SQL statement [" + sql + "]"); - } - - if (sqlSupplier instanceof PreparedOperation) { - - Statement statement = it.createStatement(sql); - BindTarget bindTarget = new StatementWrapper(statement); - ((PreparedOperation) sqlSupplier).bindTo(bindTarget); - - return statement; - } - - if (namedParameters) { - - Map remainderByName = new LinkedHashMap<>(this.byName); - Map remainderByIndex = new LinkedHashMap<>(this.byIndex); - PreparedOperation operation = dataAccessStrategy.processNamedParameters(sql, (index, name) -> { - - if (byName.containsKey(name)) { - remainderByName.remove(name); - return dataAccessStrategy.getBindValue(byName.get(name)); - } - - if (byIndex.containsKey(index)) { - remainderByIndex.remove(index); - return dataAccessStrategy.getBindValue(byIndex.get(index)); - } - - return null; - }); - - String expanded = getRequiredSql(operation); - if (logger.isTraceEnabled()) { - logger.trace("Expanded SQL [" + expanded + "]"); - } - - Statement statement = it.createStatement(expanded); - BindTarget bindTarget = new StatementWrapper(statement); - - operation.bindTo(bindTarget); - - bindByName(statement, remainderByName); - bindByIndex(statement, remainderByIndex); - - return statement; - } - - Statement statement = it.createStatement(sql); - - bindByIndex(statement, this.byIndex); - bindByName(statement, this.byName); - - return statement; - }; - - Function> resultFunction = toFunction(sql, filterFunction, statementFactory); - - return new DefaultSqlResult<>(DefaultDatabaseClient.this, // - sql, // - resultFunction, // - it -> sumRowsUpdated(resultFunction, it), // - mappingFunction); - } - - public ExecuteSpecSupport bind(int index, Object value) { - - assertNotPreparedOperation(); - Assert.notNull(value, () -> String.format("Value at index %d must not be null. Use bindNull(…) instead.", index)); - - Map byIndex = new LinkedHashMap<>(this.byIndex); - - if (value instanceof SettableValue) { - byIndex.put(index, (SettableValue) value); - } else { - byIndex.put(index, SettableValue.fromOrEmpty(value, value.getClass())); - } - - return createInstance(byIndex, this.byName, this.sqlSupplier, this.filterFunction); - } - - public ExecuteSpecSupport bindNull(int index, Class type) { - - assertNotPreparedOperation(); - - Map byIndex = new LinkedHashMap<>(this.byIndex); - byIndex.put(index, SettableValue.empty(type)); - - return createInstance(byIndex, this.byName, this.sqlSupplier, this.filterFunction); - } - - public ExecuteSpecSupport bind(String name, Object value) { - - assertNotPreparedOperation(); - - Assert.hasText(name, "Parameter name must not be null or empty!"); - Assert.notNull(value, - () -> String.format("Value for parameter %s must not be null. Use bindNull(…) instead.", name)); - - Map byName = new LinkedHashMap<>(this.byName); - - if (value instanceof SettableValue) { - byName.put(name, (SettableValue) value); - } else { - byName.put(name, SettableValue.fromOrEmpty(value, value.getClass())); - } - - return createInstance(this.byIndex, byName, this.sqlSupplier, this.filterFunction); - } - - public ExecuteSpecSupport bindNull(String name, Class type) { - - assertNotPreparedOperation(); - Assert.hasText(name, "Parameter name must not be null or empty!"); - - Map byName = new LinkedHashMap<>(this.byName); - byName.put(name, SettableValue.empty(type)); - - return createInstance(this.byIndex, byName, this.sqlSupplier, this.filterFunction); - } - - public ExecuteSpecSupport filter(StatementFilterFunction filter) { - - Assert.notNull(filter, "Statement FilterFunction must not be null!"); - - return createInstance(this.byIndex, byName, this.sqlSupplier, this.filterFunction.andThen(filter)); - } - - private void assertNotPreparedOperation() { - if (this.sqlSupplier instanceof PreparedOperation) { - throw new InvalidDataAccessApiUsageException("Cannot add bindings to a PreparedOperation"); - } - } - - protected ExecuteSpecSupport createInstance(Map byIndex, Map byName, - Supplier sqlSupplier, StatementFilterFunction filterFunction) { - return new ExecuteSpecSupport(byIndex, byName, sqlSupplier, filterFunction); - } - } - - /** - * Default {@link DatabaseClient.GenericExecuteSpec} implementation. - */ - protected class DefaultGenericExecuteSpec extends ExecuteSpecSupport implements GenericExecuteSpec { - - DefaultGenericExecuteSpec(Map byIndex, Map byName, - Supplier sqlSupplier, StatementFilterFunction filterFunction) { - super(byIndex, byName, sqlSupplier, filterFunction); - } - - DefaultGenericExecuteSpec(Supplier sqlSupplier) { - super(sqlSupplier); - } - - @Override - public TypedExecuteSpec as(Class resultType) { - - Assert.notNull(resultType, "Result type must not be null!"); - - return createTypedExecuteSpec(this.byIndex, this.byName, this.sqlSupplier, this.filterFunction, resultType); - } - - @Override - public FetchSpec map(Function mappingFunction) { - - Assert.notNull(mappingFunction, "Mapping function must not be null!"); - - return exchange(this.sqlSupplier, (row, rowMetadata) -> mappingFunction.apply(row)); - } - - @Override - public FetchSpec map(BiFunction mappingFunction) { - - Assert.notNull(mappingFunction, "Mapping function must not be null!"); - - return exchange(this.sqlSupplier, mappingFunction); - } - - @Override - public FetchSpec> fetch() { - return exchange(this.sqlSupplier, ColumnMapRowMapper.INSTANCE); - } - - @Override - public Mono then() { - return fetch().rowsUpdated().then(); - } - - @Override - public DefaultGenericExecuteSpec bind(int index, Object value) { - return (DefaultGenericExecuteSpec) super.bind(index, value); - } - - @Override - public DefaultGenericExecuteSpec bindNull(int index, Class type) { - return (DefaultGenericExecuteSpec) super.bindNull(index, type); - } - - @Override - public DefaultGenericExecuteSpec bind(String name, Object value) { - return (DefaultGenericExecuteSpec) super.bind(name, value); - } - - @Override - public DefaultGenericExecuteSpec bindNull(String name, Class type) { - return (DefaultGenericExecuteSpec) super.bindNull(name, type); - } - - @Override - public DefaultGenericExecuteSpec filter(StatementFilterFunction filter) { - return (DefaultGenericExecuteSpec) super.filter(filter); - } - - @Override - protected ExecuteSpecSupport createInstance(Map byIndex, Map byName, - Supplier sqlSupplier, StatementFilterFunction filterFunction) { - return createGenericExecuteSpec(byIndex, byName, sqlSupplier, filterFunction); - } - } - - /** - * Default {@link DatabaseClient.GenericExecuteSpec} implementation. - */ - @SuppressWarnings("unchecked") - protected class DefaultTypedExecuteSpec extends ExecuteSpecSupport implements TypedExecuteSpec { - - private final Class typeToRead; - private final BiFunction mappingFunction; - - DefaultTypedExecuteSpec(Map byIndex, Map byName, - Supplier sqlSupplier, StatementFilterFunction filterFunction, Class typeToRead) { - - super(byIndex, byName, sqlSupplier, filterFunction); - - this.typeToRead = typeToRead; - - if (typeToRead.isInterface()) { - this.mappingFunction = ColumnMapRowMapper.INSTANCE - .andThen(map -> projectionFactory.createProjection(typeToRead, map)); - } else { - this.mappingFunction = dataAccessStrategy.getRowMapper(typeToRead); - } - } - - @Override - public TypedExecuteSpec as(Class resultType) { - - Assert.notNull(resultType, "Result type must not be null!"); - - return createTypedExecuteSpec(this.byIndex, this.byName, this.sqlSupplier, this.filterFunction, resultType); - } - - @Override - public FetchSpec map(Function mappingFunction) { - - Assert.notNull(mappingFunction, "Mapping function must not be null!"); - - return exchange(this.sqlSupplier, (row, rowMetadata) -> mappingFunction.apply(row)); - } - - @Override - public FetchSpec map(BiFunction mappingFunction) { - - Assert.notNull(mappingFunction, "Mapping function must not be null!"); - - return exchange(this.sqlSupplier, mappingFunction); - } - - @Override - public FetchSpec fetch() { - return exchange(this.sqlSupplier, this.mappingFunction); - } - - @Override - public Mono then() { - return fetch().rowsUpdated().then(); - } - - @Override - public DefaultTypedExecuteSpec bind(int index, Object value) { - return (DefaultTypedExecuteSpec) super.bind(index, value); - } - - @Override - public DefaultTypedExecuteSpec bindNull(int index, Class type) { - return (DefaultTypedExecuteSpec) super.bindNull(index, type); - } - - @Override - public DefaultTypedExecuteSpec bind(String name, Object value) { - return (DefaultTypedExecuteSpec) super.bind(name, value); - } - - @Override - public DefaultTypedExecuteSpec bindNull(String name, Class type) { - return (DefaultTypedExecuteSpec) super.bindNull(name, type); - } - - @Override - public DefaultTypedExecuteSpec filter(StatementFilterFunction filter) { - return (DefaultTypedExecuteSpec) super.filter(filter); - } - - @Override - protected DefaultTypedExecuteSpec createInstance(Map byIndex, - Map byName, Supplier sqlSupplier, StatementFilterFunction filterFunction) { - return createTypedExecuteSpec(byIndex, byName, sqlSupplier, filterFunction, this.typeToRead); - } - } - - /** - * Default {@link DatabaseClient.SelectFromSpec} implementation. - */ - class DefaultSelectFromSpec implements SelectFromSpec { - - @Override - public GenericSelectSpec from(SqlIdentifier table) { - return new DefaultGenericSelectSpec(table); - } - - @Override - public TypedSelectSpec from(Class table) { - - assertRegularClass(table); - - return new DefaultTypedSelectSpec<>(table); - } - } - - /** - * Base class for {@link DatabaseClient.GenericExecuteSpec} implementations. - */ - private abstract class DefaultSelectSpecSupport { - - final SqlIdentifier table; - final List projectedFields; - final @Nullable CriteriaDefinition criteria; - final Sort sort; - final Pageable page; - - DefaultSelectSpecSupport(SqlIdentifier table) { - - Assert.notNull(table, "Table name must not be null!"); - - this.table = table; - this.projectedFields = Collections.emptyList(); - this.criteria = null; - this.sort = Sort.unsorted(); - this.page = Pageable.unpaged(); - } - - DefaultSelectSpecSupport(SqlIdentifier table, List projectedFields, - @Nullable CriteriaDefinition criteria, Sort sort, Pageable page) { - this.table = table; - this.projectedFields = projectedFields; - this.criteria = criteria; - this.sort = sort; - this.page = page; - } - - public DefaultSelectSpecSupport project(SqlIdentifier... selectedFields) { - Assert.notNull(selectedFields, "Projection fields must not be null!"); - - List projectedFields = new ArrayList<>(this.projectedFields.size() + selectedFields.length); - projectedFields.addAll(this.projectedFields); - projectedFields.addAll(Arrays.asList(selectedFields)); - - return createInstance(this.table, projectedFields, this.criteria, this.sort, this.page); - } - - public DefaultSelectSpecSupport where(CriteriaDefinition whereCriteria) { - - Assert.notNull(whereCriteria, "Criteria must not be null!"); - - return createInstance(this.table, this.projectedFields, whereCriteria, this.sort, this.page); - } - - public DefaultSelectSpecSupport orderBy(Sort sort) { - - Assert.notNull(sort, "Sort must not be null!"); - - return createInstance(this.table, this.projectedFields, this.criteria, sort, this.page); - } - - public DefaultSelectSpecSupport page(Pageable page) { - - Assert.notNull(page, "Pageable must not be null!"); - - return createInstance(this.table, this.projectedFields, this.criteria, this.sort, page); - } - - FetchSpec execute(PreparedOperation preparedOperation, BiFunction mappingFunction) { - - String sql = getRequiredSql(preparedOperation); - Function selectFunction = wrapPreparedOperation(sql, preparedOperation); - Function> resultFunction = toFunction(sql, StatementFilterFunctions.empty(), - selectFunction); - - return new DefaultSqlResult<>(DefaultDatabaseClient.this, // - sql, // - resultFunction, // - it -> Mono.error(new UnsupportedOperationException("Not available for SELECT")), // - mappingFunction); - } - - protected abstract DefaultSelectSpecSupport createInstance(SqlIdentifier table, List projectedFields, - @Nullable CriteriaDefinition criteria, Sort sort, Pageable page); - } - - private class DefaultGenericSelectSpec extends DefaultSelectSpecSupport implements GenericSelectSpec { - - DefaultGenericSelectSpec(SqlIdentifier table, List projectedFields, - @Nullable CriteriaDefinition criteria, Sort sort, Pageable page) { - super(table, projectedFields, criteria, sort, page); - } - - DefaultGenericSelectSpec(SqlIdentifier table) { - super(table); - } - - @Override - public TypedSelectSpec as(Class resultType) { - - Assert.notNull(resultType, "Result type must not be null!"); - - BiFunction rowMapper; - - if (resultType.isInterface()) { - rowMapper = ColumnMapRowMapper.INSTANCE.andThen(map -> projectionFactory.createProjection(resultType, map)); - } else { - rowMapper = dataAccessStrategy.getRowMapper(resultType); - } - - return new DefaultTypedSelectSpec<>(this.table, this.projectedFields, this.criteria, this.sort, this.page, - resultType, rowMapper); - } - - @Override - public FetchSpec map(Function mappingFunction) { - - Assert.notNull(mappingFunction, "Mapping function must not be null!"); - - return exchange((row, rowMetadata) -> mappingFunction.apply(row)); - } - - @Override - public FetchSpec map(BiFunction mappingFunction) { - - Assert.notNull(mappingFunction, "Mapping function must not be null!"); - - return exchange(mappingFunction); - } - - @Override - public DefaultGenericSelectSpec project(SqlIdentifier... selectedFields) { - return (DefaultGenericSelectSpec) super.project(selectedFields); - } - - @Override - public DefaultGenericSelectSpec matching(CriteriaDefinition criteria) { - return (DefaultGenericSelectSpec) super.where(criteria); - } - - @Override - public DefaultGenericSelectSpec orderBy(Sort sort) { - return (DefaultGenericSelectSpec) super.orderBy(sort); - } - - @Override - public DefaultGenericSelectSpec page(Pageable pageable) { - return (DefaultGenericSelectSpec) super.page(pageable); - } - - @Override - public FetchSpec> fetch() { - return exchange(ColumnMapRowMapper.INSTANCE); - } - - private FetchSpec exchange(BiFunction mappingFunction) { - - StatementMapper mapper = dataAccessStrategy.getStatementMapper(); - - StatementMapper.SelectSpec selectSpec = mapper.createSelect(this.table) - .withProjection(this.projectedFields.toArray(new SqlIdentifier[0])).withSort(this.sort).withPage(this.page); - - if (this.criteria != null) { - selectSpec = selectSpec.withCriteria(this.criteria); - } - - PreparedOperation operation = mapper.getMappedObject(selectSpec); - return execute(operation, mappingFunction); - } - - @Override - protected DefaultGenericSelectSpec createInstance(SqlIdentifier table, List projectedFields, - @Nullable CriteriaDefinition criteria, Sort sort, Pageable page) { - return new DefaultGenericSelectSpec(table, projectedFields, criteria, sort, page); - } - } - - /** - * Default implementation of {@link DatabaseClient.TypedInsertSpec}. - */ - @SuppressWarnings("unchecked") - private class DefaultTypedSelectSpec extends DefaultSelectSpecSupport implements TypedSelectSpec { - - private final Class typeToRead; - private final BiFunction mappingFunction; - - DefaultTypedSelectSpec(Class typeToRead) { - - super(dataAccessStrategy.getTableName(typeToRead)); - - this.typeToRead = typeToRead; - this.mappingFunction = dataAccessStrategy.getRowMapper(typeToRead); - } - - DefaultTypedSelectSpec(SqlIdentifier table, List projectedFields, - @Nullable CriteriaDefinition criteria, Sort sort, Pageable page, Class typeToRead, - BiFunction mappingFunction) { - - super(table, projectedFields, criteria, sort, page); - - this.typeToRead = typeToRead; - this.mappingFunction = mappingFunction; - } - - @Override - public FetchSpec as(Class resultType) { - - Assert.notNull(resultType, "Result type must not be null!"); - - BiFunction rowMapper; - - if (resultType.isInterface()) { - rowMapper = dataAccessStrategy.getRowMapper(typeToRead) - .andThen(r -> projectionFactory.createProjection(resultType, r)); - } else { - rowMapper = dataAccessStrategy.getRowMapper(resultType); - } - - return exchange(rowMapper); - } - - @Override - public FetchSpec map(Function mappingFunction) { - - Assert.notNull(mappingFunction, "Mapping function must not be null!"); - - return exchange((row, rowMetadata) -> mappingFunction.apply(row)); - } - - @Override - public FetchSpec map(BiFunction mappingFunction) { - - Assert.notNull(mappingFunction, "Mapping function must not be null!"); - - return exchange(mappingFunction); - } - - @Override - public DefaultTypedSelectSpec project(SqlIdentifier... selectedFields) { - return (DefaultTypedSelectSpec) super.project(selectedFields); - } - - @Override - public DefaultTypedSelectSpec matching(CriteriaDefinition criteria) { - return (DefaultTypedSelectSpec) super.where(criteria); - } - - @Override - public DefaultTypedSelectSpec orderBy(Sort sort) { - return (DefaultTypedSelectSpec) super.orderBy(sort); - } - - @Override - public DefaultTypedSelectSpec page(Pageable pageable) { - return (DefaultTypedSelectSpec) super.page(pageable); - } - - @Override - public FetchSpec fetch() { - return exchange(this.mappingFunction); - } - - private FetchSpec exchange(BiFunction mappingFunction) { - - List columns; - StatementMapper mapper = dataAccessStrategy.getStatementMapper().forType(this.typeToRead); - - if (this.projectedFields.isEmpty()) { - columns = dataAccessStrategy.getAllColumns(this.typeToRead); - } else { - columns = this.projectedFields; - } - - StatementMapper.SelectSpec selectSpec = mapper.createSelect(this.table) - .withProjection(columns.toArray(new SqlIdentifier[0])).withPage(this.page).withSort(this.sort); - - if (this.criteria != null) { - selectSpec = selectSpec.withCriteria(this.criteria); - } - - PreparedOperation operation = mapper.getMappedObject(selectSpec); - - return execute(operation, mappingFunction); - } - - @Override - protected DefaultTypedSelectSpec createInstance(SqlIdentifier table, List projectedFields, - @Nullable CriteriaDefinition criteria, Sort sort, Pageable page) { - return new DefaultTypedSelectSpec<>(table, projectedFields, criteria, sort, page, this.typeToRead, - this.mappingFunction); - } - } - - /** - * Default {@link DatabaseClient.InsertIntoSpec} implementation. - */ - class DefaultInsertIntoSpec implements InsertIntoSpec { - - @Override - public GenericInsertSpec> into(SqlIdentifier table) { - return new DefaultGenericInsertSpec<>(table, Collections.emptyMap(), ColumnMapRowMapper.INSTANCE); - } - - @Override - public TypedInsertSpec into(Class table) { - - assertRegularClass(table); - - return new DefaultTypedInsertSpec<>(table, ColumnMapRowMapper.INSTANCE); - } - } - - /** - * Default implementation of {@link DatabaseClient.GenericInsertSpec}. - */ - class DefaultGenericInsertSpec implements GenericInsertSpec { - - private final SqlIdentifier table; - private final Map byName; - private final BiFunction mappingFunction; - - DefaultGenericInsertSpec(SqlIdentifier table, Map byName, - BiFunction mappingFunction) { - this.table = table; - this.byName = byName; - this.mappingFunction = mappingFunction; - } - - @Override - public GenericInsertSpec value(SqlIdentifier field, Object value) { - - Assert.notNull(field, "Field must not be null!"); - - Map byName = new LinkedHashMap<>(this.byName); - - if (value instanceof SettableValue) { - byName.put(field, (SettableValue) value); - } else { - byName.put(field, SettableValue.fromOrEmpty(value, value.getClass())); - } - - return new DefaultGenericInsertSpec<>(this.table, byName, this.mappingFunction); - } - - @Override - public FetchSpec map(Function mappingFunction) { - - Assert.notNull(mappingFunction, "Mapping function must not be null!"); - - return exchange((row, rowMetadata) -> mappingFunction.apply(row)); - } - - @Override - public FetchSpec map(BiFunction mappingFunction) { - - Assert.notNull(mappingFunction, "Mapping function must not be null!"); - - return exchange(mappingFunction); - } - - @Override - public FetchSpec fetch() { - return exchange(this.mappingFunction); - } - - @Override - public Mono then() { - return fetch().rowsUpdated().then(); - } - - private FetchSpec exchange(BiFunction mappingFunction) { - - StatementMapper mapper = dataAccessStrategy.getStatementMapper(); - StatementMapper.InsertSpec insert = mapper.createInsert(this.table); - - for (SqlIdentifier column : this.byName.keySet()) { - insert = insert.withColumn(column, this.byName.get(column)); - } - - PreparedOperation operation = mapper.getMappedObject(insert); - return exchangeInsert(mappingFunction, operation); - } - } - - /** - * Default implementation of {@link DatabaseClient.TypedInsertSpec}. - */ - class DefaultTypedInsertSpec implements TypedInsertSpec, InsertSpec { - - private final Class typeToInsert; - private final SqlIdentifier table; - private final Publisher objectToInsert; - private final BiFunction mappingFunction; - - DefaultTypedInsertSpec(Class typeToInsert, BiFunction mappingFunction) { - - this.typeToInsert = typeToInsert; - this.table = dataAccessStrategy.getTableName(typeToInsert); - this.objectToInsert = Mono.empty(); - this.mappingFunction = mappingFunction; - } - - DefaultTypedInsertSpec(Class typeToInsert, SqlIdentifier table, Publisher objectToInsert, - BiFunction mappingFunction) { - this.typeToInsert = typeToInsert; - this.table = table; - this.objectToInsert = objectToInsert; - this.mappingFunction = mappingFunction; - } - - @Override - public TypedInsertSpec table(SqlIdentifier tableName) { - - Assert.notNull(tableName, "Table name must not be null!"); - - return new DefaultTypedInsertSpec<>(this.typeToInsert, tableName, this.objectToInsert, this.mappingFunction); - } - - @Override - @SuppressWarnings({ "rawtypes", "unchecked" }) - public InsertSpec using(T objectToInsert) { - - Assert.notNull(objectToInsert, "Object to insert must not be null!"); - - return new DefaultTypedInsertSpec<>(this.typeToInsert, this.table, Mono.just(objectToInsert), - this.mappingFunction); - } - - @Override - @SuppressWarnings({ "rawtypes", "unchecked" }) - public InsertSpec using(Publisher objectToInsert) { - - Assert.notNull(objectToInsert, "Publisher to insert must not be null!"); - - return new DefaultTypedInsertSpec<>(this.typeToInsert, this.table, objectToInsert, this.mappingFunction); - } - - @Override - public FetchSpec map(Function mappingFunction) { - - Assert.notNull(mappingFunction, "Mapping function must not be null!"); - - return exchange((row, rowMetadata) -> mappingFunction.apply(row)); - } - - @Override - public FetchSpec map(BiFunction mappingFunction) { - - Assert.notNull(mappingFunction, "Mapping function must not be null!"); - - return exchange(mappingFunction); - } - - @Override - public FetchSpec fetch() { - return exchange(this.mappingFunction); - } - - @Override - public Mono then() { - return Mono.from(this.objectToInsert).flatMapMany(toInsert -> exchange(toInsert, (row, md) -> row).all()).then(); - } - - private FetchSpec exchange(BiFunction mappingFunction) { - - return new FetchSpec() { - @Override - public Mono one() { - return Mono.from(objectToInsert).flatMap(toInsert -> exchange(toInsert, mappingFunction).one()); - } - - @Override - public Mono first() { - return Mono.from(objectToInsert).flatMap(toInsert -> exchange(toInsert, mappingFunction).first()); - } - - @Override - public Flux all() { - return Flux.from(objectToInsert).flatMap(toInsert -> exchange(toInsert, mappingFunction).all()); - } - - @Override - public Mono rowsUpdated() { - return Mono.from(objectToInsert).flatMapMany(toInsert -> exchange(toInsert, mappingFunction).rowsUpdated()) - .collect(Collectors.summingInt(Integer::intValue)); - } - }; - } - - private FetchSpec exchange(Object toInsert, BiFunction mappingFunction) { - - OutboundRow outboundRow = dataAccessStrategy.getOutboundRow(toInsert); - - StatementMapper mapper = dataAccessStrategy.getStatementMapper(); - StatementMapper.InsertSpec insert = mapper.createInsert(this.table); - - for (SqlIdentifier column : outboundRow.keySet()) { - Parameter settableValue = outboundRow.get(column); - if (settableValue.hasValue()) { - insert = insert.withColumn(column, settableValue); - } - } - - PreparedOperation operation = mapper.getMappedObject(insert); - return exchangeInsert(mappingFunction, operation); - } - } - - /** - * Default {@link DatabaseClient.UpdateTableSpec} implementation. - */ - class DefaultUpdateTableSpec implements UpdateTableSpec { - - @Override - public GenericUpdateSpec table(SqlIdentifier table) { - return new DefaultGenericUpdateSpec(null, table, null, null); - } - - @Override - public TypedUpdateSpec table(Class table) { - - assertRegularClass(table); - - return new DefaultTypedUpdateSpec<>(table, null, null, null); - } - } - - class DefaultGenericUpdateSpec implements GenericUpdateSpec, UpdateMatchingSpec { - - private final @Nullable Class typeToUpdate; - private final @Nullable SqlIdentifier table; - private final @Nullable org.springframework.data.relational.core.query.Update assignments; - private final @Nullable CriteriaDefinition where; - - DefaultGenericUpdateSpec(@Nullable Class typeToUpdate, @Nullable SqlIdentifier table, - @Nullable org.springframework.data.relational.core.query.Update assignments, - @Nullable CriteriaDefinition where) { - this.typeToUpdate = typeToUpdate; - this.table = table; - this.assignments = assignments; - this.where = where; - } - - @Override - public UpdateMatchingSpec using(Update update) { - - Assert.notNull(update, "Update must not be null"); - - return new DefaultGenericUpdateSpec(this.typeToUpdate, this.table, - org.springframework.data.relational.core.query.Update.from(update.getAssignments()), this.where); - } - - @Override - public UpdateMatchingSpec using(org.springframework.data.relational.core.query.Update update) { - - Assert.notNull(update, "Update must not be null"); - - return new DefaultGenericUpdateSpec(this.typeToUpdate, this.table, update, this.where); - } - - @Override - public UpdateSpec matching(CriteriaDefinition criteria) { - - Assert.notNull(criteria, "Criteria must not be null"); - - return new DefaultGenericUpdateSpec(this.typeToUpdate, this.table, this.assignments, criteria); - } - - @Override - public UpdatedRowsFetchSpec fetch() { - - SqlIdentifier table; - - if (StringUtils.isEmpty(this.table)) { - - Assert.state(this.typeToUpdate != null, "Type to update must not be null!"); - - table = dataAccessStrategy.getTableName(this.typeToUpdate); - } else { - table = this.table; - } - - return exchange(table); - } - - @Override - public Mono then() { - return fetch().rowsUpdated().then(); - } - - private UpdatedRowsFetchSpec exchange(SqlIdentifier table) { - - StatementMapper mapper = dataAccessStrategy.getStatementMapper(); - - if (this.typeToUpdate != null) { - mapper = mapper.forType(this.typeToUpdate); - } - - Assert.state(this.assignments != null, "Update assignments must not be null!"); - - StatementMapper.UpdateSpec update = mapper.createUpdate(table, this.assignments); - - if (this.where != null) { - update = update.withCriteria(this.where); - } - - PreparedOperation operation = mapper.getMappedObject(update); - - return exchangeUpdate(operation); - } - } - - class DefaultTypedUpdateSpec implements TypedUpdateSpec, UpdateMatchingSpec { - - private final Class typeToUpdate; - private final @Nullable SqlIdentifier table; - private final @Nullable T objectToUpdate; - private final @Nullable CriteriaDefinition where; - - DefaultTypedUpdateSpec(Class typeToUpdate, @Nullable SqlIdentifier table, @Nullable T objectToUpdate, - @Nullable CriteriaDefinition where) { - - this.typeToUpdate = typeToUpdate; - this.table = table; - this.objectToUpdate = objectToUpdate; - this.where = where; - } - - @Override - public UpdateMatchingSpec using(T objectToUpdate) { - - Assert.notNull(objectToUpdate, "Object to update must not be null"); - - return new DefaultTypedUpdateSpec<>(this.typeToUpdate, this.table, objectToUpdate, this.where); - } - - @Override - public TypedUpdateSpec table(SqlIdentifier tableName) { - - Assert.notNull(tableName, "Table name must not be null!"); - - return new DefaultTypedUpdateSpec<>(this.typeToUpdate, tableName, this.objectToUpdate, this.where); - } - - @Override - public UpdateSpec matching(CriteriaDefinition criteria) { - - Assert.notNull(criteria, "Criteria must not be null!"); - - return new DefaultTypedUpdateSpec<>(this.typeToUpdate, this.table, this.objectToUpdate, criteria); - } - - @Override - public UpdatedRowsFetchSpec fetch() { - - SqlIdentifier table; - - if (StringUtils.isEmpty(this.table)) { - table = dataAccessStrategy.getTableName(this.typeToUpdate); - } else { - table = this.table; - } - - return exchange(table); - } - - @Override - public Mono then() { - return fetch().rowsUpdated().then(); - } - - private UpdatedRowsFetchSpec exchange(SqlIdentifier table) { - - StatementMapper mapper = dataAccessStrategy.getStatementMapper(); - Map columns = dataAccessStrategy.getOutboundRow(this.objectToUpdate); - List ids = dataAccessStrategy.getIdentifierColumns(this.typeToUpdate); - - if (ids.isEmpty()) { - throw new IllegalStateException("No identifier columns in " + this.typeToUpdate.getName() + "!"); - } - Object id = columns.remove(ids.get(0)); // do not update the Id column. - - org.springframework.data.relational.core.query.Update update = null; - - for (SqlIdentifier column : columns.keySet()) { - if (update == null) { - update = org.springframework.data.relational.core.query.Update.update(dataAccessStrategy.toSql(column), - columns.get(column)); - } else { - update = update.set(dataAccessStrategy.toSql(column), columns.get(column)); - } - } - - Criteria updateCriteria = org.springframework.data.relational.core.query.Criteria - .where(dataAccessStrategy.toSql(ids.get(0))).is(id); - if (this.where != null) { - updateCriteria = updateCriteria.and(this.where); - } - - PreparedOperation operation = mapper - .getMappedObject(mapper.createUpdate(table, update).withCriteria(updateCriteria)); - - return exchangeUpdate(operation); - } - } - - /** - * Default {@link DatabaseClient.DeleteFromSpec} implementation. - */ - class DefaultDeleteFromSpec implements DeleteFromSpec { - - @Override - public DefaultDeleteSpec from(SqlIdentifier table) { - return new DefaultDeleteSpec<>(null, table, null); - } - - @Override - public DefaultDeleteSpec from(Class table) { - - assertRegularClass(table); - - return new DefaultDeleteSpec<>(table, null, null); - } - } - - /** - * Default implementation of {@link DatabaseClient.TypedInsertSpec}. - */ - class DefaultDeleteSpec implements DeleteMatchingSpec, TypedDeleteSpec { - - private final @Nullable Class typeToDelete; - private final @Nullable SqlIdentifier table; - private final @Nullable CriteriaDefinition where; - - DefaultDeleteSpec(@Nullable Class typeToDelete, @Nullable SqlIdentifier table, - @Nullable CriteriaDefinition where) { - this.typeToDelete = typeToDelete; - this.table = table; - this.where = where; - } - - @Override - public DeleteSpec matching(CriteriaDefinition criteria) { - - Assert.notNull(criteria, "Criteria must not be null!"); - - return new DefaultDeleteSpec<>(this.typeToDelete, this.table, criteria); - } - - @Override - public TypedDeleteSpec table(SqlIdentifier tableName) { - - Assert.notNull(tableName, "Table name must not be null!"); - - return new DefaultDeleteSpec<>(this.typeToDelete, tableName, this.where); - } - - @Override - public UpdatedRowsFetchSpec fetch() { - - SqlIdentifier table; - - if (StringUtils.isEmpty(this.table)) { - - Assert.state(this.typeToDelete != null, "Type to delete must not be null!"); - - table = dataAccessStrategy.getTableName(this.typeToDelete); - } else { - table = this.table; - } - - return exchange(table); - } - - @Override - public Mono then() { - return fetch().rowsUpdated().then(); - } - - private UpdatedRowsFetchSpec exchange(SqlIdentifier table) { - - StatementMapper mapper = dataAccessStrategy.getStatementMapper(); - - if (this.typeToDelete != null) { - mapper = mapper.forType(this.typeToDelete); - } - - StatementMapper.DeleteSpec delete = mapper.createDelete(table); - - if (this.where != null) { - delete = delete.withCriteria(this.where); - } - - PreparedOperation operation = mapper.getMappedObject(delete); - - return exchangeUpdate(operation); - } - } - - private FetchSpec exchangeInsert(BiFunction mappingFunction, - PreparedOperation operation) { - - String sql = getRequiredSql(operation); - Function insertFunction = wrapPreparedOperation(sql, operation) - .andThen(Statement::returnGeneratedValues); - Function> resultFunction = toFunction(sql, StatementFilterFunctions.empty(), - insertFunction); - - return new DefaultSqlResult<>(this, // - sql, // - resultFunction, // - it -> sumRowsUpdated(resultFunction, it), // - mappingFunction); - } - - private UpdatedRowsFetchSpec exchangeUpdate(PreparedOperation operation) { - - String sql = getRequiredSql(operation); - Function executeFunction = wrapPreparedOperation(sql, operation); - Function> resultFunction = toFunction(sql, StatementFilterFunctions.empty(), - executeFunction); - - return new DefaultSqlResult<>(this, // - sql, // - resultFunction, // - it -> sumRowsUpdated(resultFunction, it), // - (row, rowMetadata) -> rowMetadata); - } - - private static Mono sumRowsUpdated(Function> resultFunction, Connection it) { - - return resultFunction.apply(it) // - .flatMap(Result::getRowsUpdated) // - .collect(Collectors.summingInt(Integer::intValue)); - } - - private Function wrapPreparedOperation(String sql, PreparedOperation operation) { - - return it -> { - - if (this.logger.isDebugEnabled()) { - this.logger.debug("Executing SQL statement [" + sql + "]"); - } - - Statement statement = it.createStatement(sql); - operation.bindTo(new StatementWrapper(statement)); - - return statement; - }; - } - - private Function> toFunction(String sql, StatementFilterFunction filterFunction, - Function statementFactory) { - - return it -> { - - Flux from = Flux.defer(() -> { - - Statement statement = statementFactory.apply(it); - return filterFunction.filter(statement, executeFunction); - }).cast(Result.class); - return from.checkpoint("SQL \"" + sql + "\" [DatabaseClient]"); - }; - } - - private static Flux doInConnectionMany(Connection connection, Function> action) { - - try { - return action.apply(connection); - } catch (R2dbcException e) { - - String sql = getSql(action); - return Flux.error(new UncategorizedR2dbcException("doInConnectionMany", sql, e)); - } - } - - private static Mono doInConnection(Connection connection, Function> action) { - - try { - return action.apply(connection); - } catch (R2dbcException e) { - - String sql = getSql(action); - return Mono.error(new UncategorizedR2dbcException("doInConnection", sql, e)); - } - } - - /** - * Determine SQL from potential provider object. - * - * @param sqlProvider object that's potentially a SqlProvider - * @return the SQL string, or {@literal null} - * @see SqlProvider - */ - @Nullable - private static String getSql(Object sqlProvider) { - - if (sqlProvider instanceof SqlProvider) { - return ((SqlProvider) sqlProvider).getSql(); - } else { - return null; - } - } - - private static String getRequiredSql(Supplier sqlSupplier) { - - String sql = sqlSupplier.get(); - Assert.state(StringUtils.hasText(sql), "SQL returned by SQL supplier must not be empty!"); - return sql; - } - - private static void assertRegularClass(Class table) { - - Assert.notNull(table, "Entity type must not be null"); - Assert.isTrue(!table.isInterface() && !table.isEnum(), - () -> String.format("Entity type %s must be a class", table.getName())); - } - - /** - * Invocation handler that suppresses close calls on R2DBC Connections. Also prepares returned Statement - * (Prepared/CallbackStatement) objects. - * - * @see Connection#close() - */ - private static class CloseSuppressingInvocationHandler implements InvocationHandler { - - private final Connection target; - - CloseSuppressingInvocationHandler(Connection target) { - this.target = target; - } - - @Override - @Nullable - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - // Invocation on ConnectionProxy interface coming in... - - if (method.getName().equals("equals")) { - // Only consider equal when proxies are identical. - return proxy == args[0]; - } else if (method.getName().equals("hashCode")) { - // Use hashCode of PersistenceManager proxy. - return System.identityHashCode(proxy); - } else if (method.getName().equals("unwrap")) { - return target; - } else if (method.getName().equals("close")) { - // Handle close method: suppress, not valid. - return Mono.error(new UnsupportedOperationException("Close is not supported!")); - } else if (method.getName().equals("getTargetConnection")) { - // Handle getTargetConnection method: return underlying Connection. - return this.target; - } - - // Invoke method on target Connection. - try { - return method.invoke(this.target, args); - } catch (InvocationTargetException ex) { - throw ex.getTargetException(); - } - } - } - - /** - * Holder for a connection that makes sure the close action is invoked atomically only once. - */ - static class ConnectionCloseHolder extends AtomicBoolean { - - private static final long serialVersionUID = -8994138383301201380L; - - final Connection connection; - final Function> closeFunction; - - ConnectionCloseHolder(Connection connection, Function> closeFunction) { - this.connection = connection; - this.closeFunction = closeFunction; - } - - Mono close() { - - return Mono.defer(() -> { - - if (compareAndSet(false, true)) { - return Mono.from(this.closeFunction.apply(this.connection)); - } - - return Mono.empty(); - }); - } - } - - static class StatementWrapper implements BindTarget { - - final Statement statement; - - StatementWrapper(Statement statement) { - this.statement = statement; - } - - @Override - public void bind(String identifier, Object value) { - this.statement.bind(identifier, value); - } - - @Override - public void bind(int index, Object value) { - this.statement.bind(index, value); - } - - @Override - public void bindNull(String identifier, Class type) { - this.statement.bindNull(identifier, type); - } - - @Override - public void bindNull(int index, Class type) { - this.statement.bindNull(index, type); - } - } - -} diff --git a/src/main/java/org/springframework/data/r2dbc/core/DefaultDatabaseClientBuilder.java b/src/main/java/org/springframework/data/r2dbc/core/DefaultDatabaseClientBuilder.java deleted file mode 100644 index 03c269537..000000000 --- a/src/main/java/org/springframework/data/r2dbc/core/DefaultDatabaseClientBuilder.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright 2018-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 io.r2dbc.spi.Statement; - -import java.util.function.Consumer; - -import org.springframework.data.projection.ProjectionFactory; -import org.springframework.data.r2dbc.core.DatabaseClient.Builder; -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; -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; - -/** - * Default implementation of {@link DatabaseClient.Builder}. - * - * @author Mark Paluch - */ -class DefaultDatabaseClientBuilder implements DatabaseClient.Builder { - - private @Nullable ConnectionFactory connectionFactory; - - private @Nullable R2dbcExceptionTranslator exceptionTranslator; - - private ExecuteFunction executeFunction = Statement::execute; - - private ReactiveDataAccessStrategy accessStrategy; - - private boolean namedParameters = true; - - private ProjectionFactory projectionFactory; - - DefaultDatabaseClientBuilder() {} - - DefaultDatabaseClientBuilder(DefaultDatabaseClientBuilder other) { - - Assert.notNull(other, "DefaultDatabaseClientBuilder must not be null!"); - - this.connectionFactory = other.connectionFactory; - this.exceptionTranslator = other.exceptionTranslator; - this.executeFunction = other.executeFunction; - this.accessStrategy = other.accessStrategy; - this.namedParameters = other.namedParameters; - this.projectionFactory = other.projectionFactory; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.DatabaseClient.Builder#connectionFactory(io.r2dbc.spi.ConnectionFactory) - */ - @Override - public Builder connectionFactory(ConnectionFactory factory) { - - Assert.notNull(factory, "ConnectionFactory must not be null!"); - - this.connectionFactory = factory; - return this; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.DatabaseClient.Builder#exceptionTranslator(org.springframework.data.r2dbc.support.R2dbcExceptionTranslator) - */ - @Override - public Builder exceptionTranslator(R2dbcExceptionTranslator exceptionTranslator) { - - Assert.notNull(exceptionTranslator, "R2dbcExceptionTranslator must not be null!"); - - this.exceptionTranslator = exceptionTranslator; - return this; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.DatabaseClient.Builder#executeFunction(org.springframework.data.r2dbc.core.ExecuteFunction) - */ - @Override - public Builder executeFunction(ExecuteFunction executeFunction) { - - Assert.notNull(executeFunction, "ExecuteFunction must not be null!"); - - this.executeFunction = executeFunction; - return this; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.DatabaseClient.Builder#dataAccessStrategy(org.springframework.data.r2dbc.function.ReactiveDataAccessStrategy) - */ - @Override - public Builder dataAccessStrategy(ReactiveDataAccessStrategy accessStrategy) { - - Assert.notNull(accessStrategy, "ReactiveDataAccessStrategy must not be null!"); - - this.accessStrategy = accessStrategy; - return this; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.DatabaseClient.Builder#namedParameters(boolean) - */ - @Override - public Builder namedParameters(boolean enabled) { - - this.namedParameters = enabled; - return this; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.DatabaseClient.Builder#projectionFactory(ProjectionFactory) - */ - @Override - public Builder projectionFactory(ProjectionFactory factory) { - - Assert.notNull(factory, "ProjectionFactory must not be null!"); - - this.projectionFactory = factory; - return this; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.DatabaseClient.Builder#build() - */ - @Override - public DatabaseClient build() { - - R2dbcExceptionTranslator exceptionTranslator = this.exceptionTranslator; - - if (exceptionTranslator == null) { - exceptionTranslator = new R2dbcExceptionSubclassTranslator(); - } - - ReactiveDataAccessStrategy accessStrategy = this.accessStrategy; - - if (accessStrategy == null) { - - R2dbcDialect dialect = DialectResolver.getDialect(this.connectionFactory); - accessStrategy = new DefaultReactiveDataAccessStrategy(dialect); - } - - return new DefaultDatabaseClient(this.connectionFactory, exceptionTranslator, executeFunction, accessStrategy, - namedParameters, projectionFactory, new DefaultDatabaseClientBuilder(this)); - } - - /* - * (non-Javadoc) - * @see java.lang.Object#clone() - */ - @Override - public DatabaseClient.Builder clone() { - return new DefaultDatabaseClientBuilder(this); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.DatabaseClient.Builder#apply(java.util.function.Consumer) - */ - @Override - public DatabaseClient.Builder apply(Consumer builderConsumer) { - Assert.notNull(builderConsumer, "BuilderConsumer must not be null"); - - builderConsumer.accept(this); - return this; - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/core/DefaultFetchSpec.java b/src/main/java/org/springframework/data/r2dbc/core/DefaultFetchSpec.java deleted file mode 100644 index 7ffc0eda5..000000000 --- a/src/main/java/org/springframework/data/r2dbc/core/DefaultFetchSpec.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2018-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.Connection; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import java.util.function.Function; - -import org.springframework.dao.IncorrectResultSizeDataAccessException; - -/** - * Default implementation of {@link FetchSpec}. - * - * @author Mark Paluch - */ -class DefaultFetchSpec implements FetchSpec { - - private final ConnectionAccessor connectionAccessor; - private final String sql; - private final Function> resultFunction; - private final Function> updatedRowsFunction; - - DefaultFetchSpec(ConnectionAccessor connectionAccessor, String sql, Function> resultFunction, - Function> updatedRowsFunction) { - this.connectionAccessor = connectionAccessor; - this.sql = sql; - this.resultFunction = resultFunction; - this.updatedRowsFunction = updatedRowsFunction; - } - - /* (non-Javadoc) - * @see org.springframework.data.r2dbc.function.FetchSpec#one() - */ - @Override - public Mono one() { - - return all().buffer(2) // - .flatMap(it -> { - - if (it.isEmpty()) { - return Mono.empty(); - } - - if (it.size() > 1) { - return Mono.error(new IncorrectResultSizeDataAccessException( - String.format("Query [%s] returned non unique result.", this.sql), 1)); - } - - return Mono.just(it.get(0)); - }).next(); - } - - /* (non-Javadoc) - * @see org.springframework.data.r2dbc.function.FetchSpec#first() - */ - @Override - public Mono first() { - return all().next(); - } - - /* (non-Javadoc) - * @see org.springframework.data.r2dbc.function.FetchSpec#all() - */ - @Override - public Flux all() { - return connectionAccessor.inConnectionMany(resultFunction); - } - - /* (non-Javadoc) - * @see org.springframework.data.r2dbc.function.FetchSpec#rowsUpdated() - */ - @Override - public Mono rowsUpdated() { - return connectionAccessor.inConnection(updatedRowsFunction); - } -} 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 c218aac97..b688709ce 100644 --- a/src/main/java/org/springframework/data/r2dbc/core/DefaultReactiveDataAccessStrategy.java +++ b/src/main/java/org/springframework/data/r2dbc/core/DefaultReactiveDataAccessStrategy.java @@ -36,7 +36,6 @@ import org.springframework.data.r2dbc.convert.R2dbcCustomConversions; import org.springframework.data.r2dbc.dialect.R2dbcDialect; import org.springframework.data.r2dbc.mapping.OutboundRow; import org.springframework.data.r2dbc.mapping.R2dbcMappingContext; -import org.springframework.data.r2dbc.mapping.SettableValue; import org.springframework.data.r2dbc.query.UpdateMapper; import org.springframework.data.r2dbc.support.ArrayUtils; import org.springframework.data.relational.core.dialect.ArrayColumns; @@ -46,6 +45,7 @@ import org.springframework.data.relational.core.mapping.RelationalPersistentProp import org.springframework.data.relational.core.sql.SqlIdentifier; import org.springframework.lang.Nullable; import org.springframework.r2dbc.core.Parameter; +import org.springframework.r2dbc.core.PreparedOperation; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.CollectionUtils; @@ -64,7 +64,7 @@ public class DefaultReactiveDataAccessStrategy implements ReactiveDataAccessStra private final UpdateMapper updateMapper; private final MappingContext, ? extends RelationalPersistentProperty> mappingContext; private final StatementMapper statementMapper; - private final NamedParameterExpander expander; + private final NamedParameterExpander expander = new NamedParameterExpander(); /** * Creates a new {@link DefaultReactiveDataAccessStrategy} given {@link R2dbcDialect} and optional @@ -115,24 +115,11 @@ public class DefaultReactiveDataAccessStrategy implements ReactiveDataAccessStra * @param dialect the {@link R2dbcDialect} to use. * @param converter must not be {@literal null}. */ - public DefaultReactiveDataAccessStrategy(R2dbcDialect dialect, R2dbcConverter converter) { - this(dialect, converter, new NamedParameterExpander()); - } - - /** - * Creates a new {@link DefaultReactiveDataAccessStrategy} given {@link R2dbcDialect} and {@link R2dbcConverter}. - * - * @param dialect the {@link R2dbcDialect} to use. - * @param converter must not be {@literal null}. - * @param expander must not be {@literal null}. - */ @SuppressWarnings("unchecked") - public DefaultReactiveDataAccessStrategy(R2dbcDialect dialect, R2dbcConverter converter, - NamedParameterExpander expander) { + public DefaultReactiveDataAccessStrategy(R2dbcDialect dialect, R2dbcConverter converter) { Assert.notNull(dialect, "Dialect must not be null"); Assert.notNull(converter, "RelationalConverter must not be null"); - Assert.notNull(expander, "NamedParameterExpander must not be null"); this.converter = converter; this.updateMapper = new UpdateMapper(dialect, converter); @@ -143,7 +130,6 @@ public class DefaultReactiveDataAccessStrategy implements ReactiveDataAccessStra RenderContextFactory factory = new RenderContextFactory(dialect); this.statementMapper = new DefaultStatementMapper(dialect, factory.createRenderContext(), this.updateMapper, this.mappingContext); - this.expander = expander; } /* @@ -270,15 +256,6 @@ public class DefaultReactiveDataAccessStrategy implements ReactiveDataAccessStra actualType); } - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.ReactiveDataAccessStrategy#getBindValue(SettableValue) - */ - @Override - public SettableValue getBindValue(SettableValue value) { - return this.updateMapper.getBindValue(value); - } - /* * (non-Javadoc) * @see org.springframework.data.r2dbc.function.ReactiveDataAccessStrategy#getBindValue(Parameter) @@ -306,10 +283,10 @@ public class DefaultReactiveDataAccessStrategy implements ReactiveDataAccessStra List parameterNames = this.expander.getParameterNames(query); - Map namedBindings = new LinkedHashMap<>(parameterNames.size()); + Map namedBindings = new LinkedHashMap<>(parameterNames.size()); for (String parameterName : parameterNames) { - SettableValue value = parameterProvider.getParameter(parameterNames.indexOf(parameterName), parameterName); + Parameter value = parameterProvider.getParameter(parameterNames.indexOf(parameterName), parameterName); if (value == null) { throw new InvalidDataAccessApiUsageException( diff --git a/src/main/java/org/springframework/data/r2dbc/core/DefaultSqlResult.java b/src/main/java/org/springframework/data/r2dbc/core/DefaultSqlResult.java deleted file mode 100644 index 9ff9d393e..000000000 --- a/src/main/java/org/springframework/data/r2dbc/core/DefaultSqlResult.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2018-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.Connection; -import io.r2dbc.spi.Result; -import io.r2dbc.spi.Row; -import io.r2dbc.spi.RowMetadata; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import java.util.function.BiFunction; -import java.util.function.Function; - - -/** - * Default {@link SqlResult} implementation. - * - * @author Mark Paluch - */ -class DefaultSqlResult implements FetchSpec { - - private final static FetchSpec EMPTY = new FetchSpec() { - - @Override - public Mono one() { - return Mono.empty(); - } - - @Override - public Mono first() { - return Mono.empty(); - } - - @Override - public Flux all() { - return Flux.empty(); - } - - @Override - public Mono rowsUpdated() { - return Mono.just(0); - } - }; - - private final ConnectionAccessor connectionAccessor; - private final String sql; - private final Function> resultFunction; - private final Function> updatedRowsFunction; - private final FetchSpec fetchSpec; - - DefaultSqlResult(ConnectionAccessor connectionAccessor, String sql, Function> resultFunction, - Function> updatedRowsFunction, BiFunction mappingFunction) { - - this.sql = sql; - this.connectionAccessor = connectionAccessor; - this.resultFunction = resultFunction; - this.updatedRowsFunction = updatedRowsFunction; - - this.fetchSpec = new DefaultFetchSpec<>(connectionAccessor, sql, new SqlFunction>() { - @Override - public Flux apply(Connection connection) { - return resultFunction.apply(connection).flatMap(result -> result.map(mappingFunction)); - } - - @Override - public String getSql() { - return sql; - } - }, new SqlFunction>() { - @Override - public Mono apply(Connection connection) { - return updatedRowsFunction.apply(connection); - } - - @Override - public String getSql() { - return sql; - } - }); - } - - /** - * Returns an empty {@link SqlResult}. - * - * @param value type of the {@code SqlResult}. - * @return a {@code SqlResult}. - */ - @SuppressWarnings("unchecked") - public static FetchSpec empty() { - return (FetchSpec) EMPTY; - } - - /* (non-Javadoc) - * @see org.springframework.data.r2dbc.function.SqlResult#map(java.util.function.BiFunction) - */ - public FetchSpec map(BiFunction mappingFunction) { - return new DefaultSqlResult<>(connectionAccessor, sql, resultFunction, updatedRowsFunction, mappingFunction); - } - - /* (non-Javadoc) - * @see org.springframework.data.r2dbc.function.FetchSpec#one() - */ - @Override - public Mono one() { - return fetchSpec.one(); - } - - /* (non-Javadoc) - * @see org.springframework.data.r2dbc.function.FetchSpec#first() - */ - @Override - public Mono first() { - return fetchSpec.first(); - } - - /* (non-Javadoc) - * @see org.springframework.data.r2dbc.function.FetchSpec#all() - */ - @Override - public Flux all() { - return fetchSpec.all(); - } - - /* (non-Javadoc) - * @see org.springframework.data.r2dbc.function.FetchSpec#rowsUpdated() - */ - @Override - public Mono rowsUpdated() { - return fetchSpec.rowsUpdated(); - } - - /** - * Union type combining {@link Function} and {@link SqlProvider} to expose the SQL that is related to the underlying - * action. - * - * @param the type of the input to the function. - * @param the type of the result of the function. - */ - interface SqlFunction extends Function, SqlProvider {} -} 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 34c2d155b..470f38e97 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 java.util.List; import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.r2dbc.convert.R2dbcConverter; -import org.springframework.data.r2dbc.dialect.BindTarget; import org.springframework.data.r2dbc.dialect.R2dbcDialect; import org.springframework.data.r2dbc.query.BoundAssignments; import org.springframework.data.r2dbc.query.BoundCondition; @@ -34,7 +33,9 @@ import org.springframework.data.relational.core.sql.InsertBuilder.InsertValuesWi import org.springframework.data.relational.core.sql.render.RenderContext; import org.springframework.data.relational.core.sql.render.SqlRenderer; import org.springframework.lang.Nullable; +import org.springframework.r2dbc.core.PreparedOperation; import org.springframework.r2dbc.core.binding.BindMarkers; +import org.springframework.r2dbc.core.binding.BindTarget; import org.springframework.r2dbc.core.binding.Bindings; import org.springframework.util.Assert; @@ -349,10 +350,6 @@ class DefaultStatementMapper implements StatementMapper { this.bindings.apply(to); } - @Override - public void bindTo(org.springframework.r2dbc.core.binding.BindTarget to) { - this.bindings.apply(to); - } } class DefaultTypedStatementMapper implements TypedStatementMapper { diff --git a/src/main/java/org/springframework/data/r2dbc/core/ExecuteFunction.java b/src/main/java/org/springframework/data/r2dbc/core/ExecuteFunction.java deleted file mode 100644 index 771f03585..000000000 --- a/src/main/java/org/springframework/data/r2dbc/core/ExecuteFunction.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2020-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.Result; -import io.r2dbc.spi.Statement; - -import java.util.function.BiFunction; - -import org.reactivestreams.Publisher; - -/** - * Represents a function that executes a {@link io.r2dbc.spi.Statement} for a (delayed) {@link io.r2dbc.spi.Result} - * stream. - *

- * Note that discarded {@link Result} objects must be consumed according to the R2DBC spec via either - * {@link Result#getRowsUpdated()} or {@link Result#map(BiFunction)}. - * - * @author Mark Paluch - * @since 1.1 - * @see Statement#execute() - * @deprecated since 1.2, use Spring's {@link org.springframework.r2dbc.core.ExecuteFunction} support instead. - */ -@Deprecated -@FunctionalInterface -public interface ExecuteFunction extends org.springframework.r2dbc.core.ExecuteFunction { - - /** - * Execute the given {@link Statement} for a stream of {@link Result}s. - * - * @param statement the request to execute. - * @return the delayed result stream. - */ - Publisher execute(Statement statement); -} diff --git a/src/main/java/org/springframework/data/r2dbc/core/FetchSpec.java b/src/main/java/org/springframework/data/r2dbc/core/FetchSpec.java deleted file mode 100644 index 751b38d14..000000000 --- a/src/main/java/org/springframework/data/r2dbc/core/FetchSpec.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2018-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; - -/** - * Contract for fetching results. - * - * @param row result type. - * @author Mark Paluch - * @see RowsFetchSpec - * @see UpdatedRowsFetchSpec - * @deprecated since 1.2, use Spring's {@link org.springframework.r2dbc.core.FetchSpec} support instead. - */ -@Deprecated -public interface FetchSpec extends RowsFetchSpec, UpdatedRowsFetchSpec {} diff --git a/src/main/java/org/springframework/data/r2dbc/core/MapBindParameterSource.java b/src/main/java/org/springframework/data/r2dbc/core/MapBindParameterSource.java index 50110c9ee..8559214a4 100644 --- a/src/main/java/org/springframework/data/r2dbc/core/MapBindParameterSource.java +++ b/src/main/java/org/springframework/data/r2dbc/core/MapBindParameterSource.java @@ -18,13 +18,13 @@ package org.springframework.data.r2dbc.core; import java.util.LinkedHashMap; import java.util.Map; -import org.springframework.data.r2dbc.mapping.SettableValue; import org.springframework.data.util.Streamable; +import org.springframework.r2dbc.core.Parameter; import org.springframework.util.Assert; /** * {@link BindParameterSource} implementation that holds a given {@link Map} of parameters encapsulated as - * {@link SettableValue}. + * {@link Parameter}. *

* This class is intended for passing in a simple Map of parameter values to the methods of the * {@link NamedParameterExpander} class. @@ -32,10 +32,9 @@ import org.springframework.util.Assert; * @author Mark Paluch * @deprecated since 1.2, use Spring's org.springframework.r2dbc.core.MapBindParameterSource support instead. */ -@Deprecated class MapBindParameterSource implements BindParameterSource { - private final Map values; + private final Map values; /** * Creates a new empty {@link MapBindParameterSource}. @@ -45,11 +44,11 @@ class MapBindParameterSource implements BindParameterSource { } /** - * Creates a new {@link MapBindParameterSource} given {@link Map} of {@link SettableValue}. + * Creates a new {@link MapBindParameterSource} given {@link Map} of {@link Parameter}. * * @param values the parameter mapping. */ - MapBindParameterSource(Map values) { + MapBindParameterSource(Map values) { Assert.notNull(values, "Values must not be null"); @@ -68,7 +67,7 @@ class MapBindParameterSource implements BindParameterSource { Assert.notNull(paramName, "Parameter name must not be null!"); Assert.notNull(value, "Value must not be null!"); - this.values.put(paramName, SettableValue.fromOrEmpty(value, value.getClass())); + this.values.put(paramName, Parameter.fromOrEmpty(value, value.getClass())); return this; } @@ -93,7 +92,7 @@ class MapBindParameterSource implements BindParameterSource { Assert.notNull(paramName, "Parameter name must not be null!"); - SettableValue settableValue = this.values.get(paramName); + Parameter settableValue = this.values.get(paramName); if (settableValue != null) { return settableValue.getType(); } diff --git a/src/main/java/org/springframework/data/r2dbc/core/NamedParameterExpander.java b/src/main/java/org/springframework/data/r2dbc/core/NamedParameterExpander.java index 49269afa0..771074686 100644 --- a/src/main/java/org/springframework/data/r2dbc/core/NamedParameterExpander.java +++ b/src/main/java/org/springframework/data/r2dbc/core/NamedParameterExpander.java @@ -22,7 +22,8 @@ import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.data.r2dbc.dialect.BindMarkersFactory; +import org.springframework.r2dbc.core.PreparedOperation; +import org.springframework.r2dbc.core.binding.BindMarkersFactory; /** * SQL translation support allowing the use of named parameters rather than native placeholders. @@ -39,7 +40,7 @@ import org.springframework.data.r2dbc.dialect.BindMarkersFactory; * @deprecated since 1.2, without replacement. */ @Deprecated -public class NamedParameterExpander { +class NamedParameterExpander { /** * Default maximum number of entries for the SQL cache: 256. @@ -126,11 +127,6 @@ public class NamedParameterExpander { */ public PreparedOperation expand(String sql, BindMarkersFactory bindMarkersFactory, BindParameterSource paramSource) { - return expand(sql, (org.springframework.r2dbc.core.binding.BindMarkersFactory) bindMarkersFactory, paramSource); - } - - PreparedOperation expand(String sql, - org.springframework.r2dbc.core.binding.BindMarkersFactory bindMarkersFactory, BindParameterSource paramSource) { ParsedSql parsedSql = getParsedSql(sql); diff --git a/src/main/java/org/springframework/data/r2dbc/core/NamedParameterUtils.java b/src/main/java/org/springframework/data/r2dbc/core/NamedParameterUtils.java index 7e0ef4756..8c604b05c 100644 --- a/src/main/java/org/springframework/data/r2dbc/core/NamedParameterUtils.java +++ b/src/main/java/org/springframework/data/r2dbc/core/NamedParameterUtils.java @@ -26,10 +26,11 @@ import java.util.Set; import java.util.TreeMap; import org.springframework.dao.InvalidDataAccessApiUsageException; -import org.springframework.data.r2dbc.dialect.BindTarget; +import org.springframework.r2dbc.core.PreparedOperation; import org.springframework.r2dbc.core.binding.BindMarker; import org.springframework.r2dbc.core.binding.BindMarkers; import org.springframework.r2dbc.core.binding.BindMarkersFactory; +import org.springframework.r2dbc.core.binding.BindTarget; import org.springframework.util.Assert; /** @@ -581,13 +582,9 @@ abstract class NamedParameterUtils { return this.expandedSql; } - @Override - public void bindTo(BindTarget target) { - bindTo((org.springframework.r2dbc.core.binding.BindTarget) target); - } @Override - public void bindTo(org.springframework.r2dbc.core.binding.BindTarget target) { + public void bindTo(BindTarget target) { for (String namedParameter : this.parameterSource.getParameterNames()) { diff --git a/src/main/java/org/springframework/data/r2dbc/core/PreparedOperation.java b/src/main/java/org/springframework/data/r2dbc/core/PreparedOperation.java deleted file mode 100644 index 33da44096..000000000 --- a/src/main/java/org/springframework/data/r2dbc/core/PreparedOperation.java +++ /dev/null @@ -1,54 +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 java.util.function.Supplier; - -import org.springframework.data.r2dbc.dialect.BindTarget; - -/** - * Extension to {@link QueryOperation} for a prepared SQL query {@link Supplier} with bound parameters. Contains - * parameter bindings that can be {@link #bindTo bound} bound to a {@link BindTarget}. - *

- * Can be executed with {@link org.springframework.data.r2dbc.core.DatabaseClient}. - *

- * - * @param underlying operation source. - * @author Mark Paluch - * @see org.springframework.data.r2dbc.core.DatabaseClient#execute(Supplier) - * @deprecated since 1.2, use Spring R2DBC's {@link org.springframework.r2dbc.core.PreparedOperation} support instead. - */ -@Deprecated -public interface PreparedOperation extends QueryOperation, org.springframework.r2dbc.core.PreparedOperation { - - /** - * @return the query source, such as a statement/criteria object. - */ - T getSource(); - - /** - * Apply bindings to {@link BindTarget}. - * - * @param target the target to apply bindings to. - */ - void bindTo(BindTarget target); - - @Override - default String get() { - return toQuery(); - } - -} diff --git a/src/main/java/org/springframework/data/r2dbc/core/QueryOperation.java b/src/main/java/org/springframework/data/r2dbc/core/QueryOperation.java deleted file mode 100644 index 2abce7253..000000000 --- a/src/main/java/org/springframework/data/r2dbc/core/QueryOperation.java +++ /dev/null @@ -1,44 +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 java.util.function.Supplier; - -/** - * Interface declaring a query operation that can be represented with a query string. This interface is typically - * implemented by classes representing a SQL operation such as {@code SELECT}, {@code INSERT}, and such. - * - * @author Mark Paluch - * @see PreparedOperation - * @deprecated since 1.2, use Spring R2DBC's {@link org.springframework.r2dbc.core.QueryOperation} support instead. - */ -@FunctionalInterface -@Deprecated -public interface QueryOperation extends Supplier, org.springframework.r2dbc.core.QueryOperation { - - /** - * Returns the string-representation of this operation to be used with {@link io.r2dbc.spi.Statement} creation. - * - * @return the operation as SQL string. - * @see io.r2dbc.spi.Connection#createStatement(String) - */ - String toQuery(); - - @Override - default String get() { - return toQuery(); - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/core/R2dbcEntityTemplate.java b/src/main/java/org/springframework/data/r2dbc/core/R2dbcEntityTemplate.java index 0f2c51510..dd936ae4c 100644 --- a/src/main/java/org/springframework/data/r2dbc/core/R2dbcEntityTemplate.java +++ b/src/main/java/org/springframework/data/r2dbc/core/R2dbcEntityTemplate.java @@ -15,7 +15,6 @@ */ package org.springframework.data.r2dbc.core; -import io.r2dbc.spi.Connection; import io.r2dbc.spi.ConnectionFactory; import io.r2dbc.spi.Row; import io.r2dbc.spi.RowMetadata; @@ -29,7 +28,6 @@ import java.util.Map; import java.util.Optional; import java.util.function.BiFunction; import java.util.function.Function; -import java.util.function.Supplier; import java.util.stream.Collectors; import org.reactivestreams.Publisher; @@ -72,11 +70,9 @@ import org.springframework.data.relational.core.sql.Table; import org.springframework.data.util.ProxyUtils; import org.springframework.lang.Nullable; import org.springframework.r2dbc.core.DatabaseClient; -import org.springframework.r2dbc.core.FetchSpec; import org.springframework.r2dbc.core.Parameter; import org.springframework.r2dbc.core.PreparedOperation; import org.springframework.r2dbc.core.RowsFetchSpec; -import org.springframework.r2dbc.core.StatementFilterFunction; import org.springframework.util.Assert; /** @@ -131,21 +127,10 @@ public class R2dbcEntityTemplate implements R2dbcEntityOperations, BeanFactoryAw * @param dialect the dialect to use, must not be {@literal null}. * @since 1.2 */ - public R2dbcEntityTemplate(org.springframework.r2dbc.core.DatabaseClient databaseClient, R2dbcDialect dialect) { + public R2dbcEntityTemplate(DatabaseClient databaseClient, R2dbcDialect dialect) { this(databaseClient, new DefaultReactiveDataAccessStrategy(dialect)); } - /** - * Create a new {@link R2dbcEntityTemplate} given {@link DatabaseClient}. - * - * @param databaseClient must not be {@literal null}. - * @deprecated since 1.2, use {@link #R2dbcEntityTemplate(DatabaseClient, R2dbcDialect)} instead. - */ - @Deprecated - public R2dbcEntityTemplate(org.springframework.data.r2dbc.core.DatabaseClient databaseClient) { - this(databaseClient, getDataAccessStrategy(databaseClient)); - } - /** * Create a new {@link R2dbcEntityTemplate} given {@link DatabaseClient}, {@link R2dbcDialect} and * {@link R2dbcConverter}. @@ -155,8 +140,7 @@ public class R2dbcEntityTemplate implements R2dbcEntityOperations, BeanFactoryAw * @param converter the dialect to use, must not be {@literal null}. * @since 1.2 */ - public R2dbcEntityTemplate(org.springframework.r2dbc.core.DatabaseClient databaseClient, R2dbcDialect dialect, - R2dbcConverter converter) { + public R2dbcEntityTemplate(DatabaseClient databaseClient, R2dbcDialect dialect, R2dbcConverter converter) { this(databaseClient, new DefaultReactiveDataAccessStrategy(dialect, converter)); } @@ -166,7 +150,7 @@ public class R2dbcEntityTemplate implements R2dbcEntityOperations, BeanFactoryAw * @param databaseClient must not be {@literal null}. * @since 1.2 */ - public R2dbcEntityTemplate(org.springframework.r2dbc.core.DatabaseClient databaseClient, + public R2dbcEntityTemplate(DatabaseClient databaseClient, ReactiveDataAccessStrategy strategy) { Assert.notNull(databaseClient, "DatabaseClient must not be null"); @@ -178,18 +162,6 @@ public class R2dbcEntityTemplate implements R2dbcEntityOperations, BeanFactoryAw this.projectionFactory = new SpelAwareProxyProjectionFactory(); } - /** - * Create a new {@link R2dbcEntityTemplate} given {@link DatabaseClient} and {@link ReactiveDataAccessStrategy}. - * - * @param databaseClient must not be {@literal null}. - * @deprecated since 1.2, use {@link #R2dbcEntityTemplate(DatabaseClient, ReactiveDataAccessStrategy)} instead. - */ - @Deprecated - public R2dbcEntityTemplate(org.springframework.data.r2dbc.core.DatabaseClient databaseClient, - ReactiveDataAccessStrategy strategy) { - this(new DatabaseClientAdapter(databaseClient), strategy); - } - /* * (non-Javadoc) * @see org.springframework.data.r2dbc.core.R2dbcEntityOperations#getDatabaseClient() @@ -641,11 +613,9 @@ public class R2dbcEntityTemplate implements R2dbcEntityOperations, BeanFactoryAw } return statement.returnGeneratedValues(dataAccessStrategy.renderForGeneratedValues(identifierColumns.get(0))); - }) - .map(this.dataAccessStrategy.getConverter().populateIdIfNecessary(entity)) // + }).map(this.dataAccessStrategy.getConverter().populateIdIfNecessary(entity)) // .all() // - .last(entity) - .flatMap(saved -> maybeCallAfterSave(saved, outboundRow, tableName)); + .last(entity).flatMap(saved -> maybeCallAfterSave(saved, outboundRow, tableName)); } @SuppressWarnings("unchecked") @@ -914,149 +884,6 @@ public class R2dbcEntityTemplate implements R2dbcEntityOperations, BeanFactoryAw return executeSpec.map(rowMapper); } - private static ReactiveDataAccessStrategy getDataAccessStrategy( - org.springframework.data.r2dbc.core.DatabaseClient databaseClient) { - - Assert.notNull(databaseClient, "DatabaseClient must not be null"); - - if (databaseClient instanceof DefaultDatabaseClient) { - - DefaultDatabaseClient client = (DefaultDatabaseClient) databaseClient; - return client.getDataAccessStrategy(); - } - - throw new IllegalStateException("Cannot obtain ReactiveDataAccessStrategy"); - } - - /** - * Adapter to adapt our deprecated {@link org.springframework.data.r2dbc.core.DatabaseClient} into Spring R2DBC - * {@link DatabaseClient}. - */ - private static class DatabaseClientAdapter implements DatabaseClient { - - private final org.springframework.data.r2dbc.core.DatabaseClient delegate; - - private DatabaseClientAdapter(org.springframework.data.r2dbc.core.DatabaseClient delegate) { - - Assert.notNull(delegate, "DatabaseClient must not be null"); - - this.delegate = delegate; - } - - @Override - public ConnectionFactory getConnectionFactory() { - return delegate.getConnectionFactory(); - } - - @Override - public GenericExecuteSpec sql(String sql) { - return new GenericExecuteSpecAdapter(delegate.execute(sql)); - } - - @Override - public GenericExecuteSpec sql(Supplier sqlSupplier) { - return new GenericExecuteSpecAdapter(delegate.execute(sqlSupplier)); - } - - @Override - public Mono inConnection(Function> action) throws DataAccessException { - return ((ConnectionAccessor) delegate).inConnection(action); - } - - @Override - public Flux inConnectionMany(Function> action) throws DataAccessException { - return ((ConnectionAccessor) delegate).inConnectionMany(action); - } - - static class GenericExecuteSpecAdapter implements GenericExecuteSpec { - - private final org.springframework.data.r2dbc.core.DatabaseClient.GenericExecuteSpec delegate; - - public GenericExecuteSpecAdapter(org.springframework.data.r2dbc.core.DatabaseClient.GenericExecuteSpec delegate) { - this.delegate = delegate; - } - - @Override - public GenericExecuteSpec bind(int index, Object value) { - return new GenericExecuteSpecAdapter(delegate.bind(index, value)); - } - - @Override - public GenericExecuteSpec bindNull(int index, Class type) { - return new GenericExecuteSpecAdapter(delegate.bindNull(index, type)); - } - - @Override - public GenericExecuteSpec bind(String name, Object value) { - return new GenericExecuteSpecAdapter(delegate.bind(name, value)); - } - - @Override - public GenericExecuteSpec bindNull(String name, Class type) { - return new GenericExecuteSpecAdapter(delegate.bindNull(name, type)); - } - - @Override - public GenericExecuteSpec filter(StatementFilterFunction filter) { - return new GenericExecuteSpecAdapter(delegate.filter(filter::filter)); - } - - @Override - public RowsFetchSpec map(BiFunction mappingFunction) { - return new RowFetchSpecAdapter<>(delegate.map(mappingFunction)); - } - - @Override - public FetchSpec> fetch() { - return new FetchSpecAdapter<>(delegate.fetch()); - } - - @Override - public Mono then() { - return delegate.then(); - } - } - - private static class RowFetchSpecAdapter implements RowsFetchSpec { - - private final org.springframework.data.r2dbc.core.RowsFetchSpec delegate; - - RowFetchSpecAdapter(org.springframework.data.r2dbc.core.RowsFetchSpec delegate) { - this.delegate = delegate; - } - - @Override - public Mono one() { - return delegate.one(); - } - - @Override - public Mono first() { - return delegate.first(); - } - - @Override - public Flux all() { - return delegate.all(); - } - } - - private static class FetchSpecAdapter extends RowFetchSpecAdapter implements FetchSpec { - - private final org.springframework.data.r2dbc.core.FetchSpec delegate; - - FetchSpecAdapter(org.springframework.data.r2dbc.core.FetchSpec delegate) { - super(delegate); - this.delegate = delegate; - } - - @Override - public Mono rowsUpdated() { - return delegate.rowsUpdated(); - } - } - } - /** * {@link RowsFetchSpec} adapter emitting values from {@link Optional} if they exist. * diff --git a/src/main/java/org/springframework/data/r2dbc/core/ReactiveDataAccessStrategy.java b/src/main/java/org/springframework/data/r2dbc/core/ReactiveDataAccessStrategy.java index 9bfac8b61..cd0d0114c 100644 --- a/src/main/java/org/springframework/data/r2dbc/core/ReactiveDataAccessStrategy.java +++ b/src/main/java/org/springframework/data/r2dbc/core/ReactiveDataAccessStrategy.java @@ -23,7 +23,6 @@ import java.util.function.BiFunction; import org.springframework.data.r2dbc.convert.R2dbcConverter; import org.springframework.data.r2dbc.mapping.OutboundRow; -import org.springframework.data.r2dbc.mapping.SettableValue; import org.springframework.data.relational.core.sql.IdentifierProcessing; import org.springframework.data.relational.core.sql.SqlIdentifier; import org.springframework.lang.Nullable; @@ -33,8 +32,8 @@ import org.springframework.util.Assert; /** * Data access strategy that generalizes convenience operations using mapped entities. Typically used internally by - * {@link DatabaseClient} and repository support. SQL creation is limited to single-table operations and single-column - * primary keys. + * {@link R2dbcEntityOperations} and repository support. SQL creation is limited to single-table operations and + * single-column primary keys. * * @author Mark Paluch * @author Jens Schauder @@ -65,17 +64,6 @@ public interface ReactiveDataAccessStrategy { */ OutboundRow getOutboundRow(Object object); - /** - * Return a potentially converted {@link SettableValue} for strategies that support type conversion. - * - * @param value must not be {@literal null}. - * @return - * @since 1.1 - * @deprecated since 1.2, use {@link #getBindValue(Parameter)} instead. - */ - @Deprecated - SettableValue getBindValue(SettableValue value); - /** * Return a potentially converted {@link Parameter} for strategies that support type conversion. * @@ -159,7 +147,7 @@ public interface ReactiveDataAccessStrategy { interface NamedParameterProvider { /** - * Returns the {@link SettableValue value} for a parameter identified either by name or by index. + * Returns the {@link Parameter value} for a parameter identified either by name or by index. * * @param index parameter index according the parameter discovery order. * @param name name of the parameter. @@ -167,7 +155,7 @@ public interface ReactiveDataAccessStrategy { * {@link org.springframework.dao.InvalidDataAccessApiUsageException} in named parameter processing. */ @Nullable - SettableValue getParameter(int index, String name); + Parameter getParameter(int index, String name); } } diff --git a/src/main/java/org/springframework/data/r2dbc/core/RowsFetchSpec.java b/src/main/java/org/springframework/data/r2dbc/core/RowsFetchSpec.java deleted file mode 100644 index 3dad86fd5..000000000 --- a/src/main/java/org/springframework/data/r2dbc/core/RowsFetchSpec.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2018-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 reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -/** - * Contract for fetching tabular results. - * - * @param row result type. - * @author Mark Paluch - * @deprecated since 1.2, use Spring's {@link org.springframework.r2dbc.core.RowsFetchSpec} support instead. - */ -@Deprecated -public interface RowsFetchSpec { - - /** - * Get exactly zero or one result. - * - * @return {@link Mono#empty()} if no match found. Never {@literal null}. - * @throws org.springframework.dao.IncorrectResultSizeDataAccessException if more than one match found. - */ - Mono one(); - - /** - * Get the first or no result. - * - * @return {@link Mono#empty()} if no match found. Never {@literal null}. - */ - Mono first(); - - /** - * Get all matching elements. - * - * @return never {@literal null}. - */ - Flux all(); -} diff --git a/src/main/java/org/springframework/data/r2dbc/core/SqlProvider.java b/src/main/java/org/springframework/data/r2dbc/core/SqlProvider.java deleted file mode 100644 index 9cd6c35dd..000000000 --- a/src/main/java/org/springframework/data/r2dbc/core/SqlProvider.java +++ /dev/null @@ -1,40 +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 org.springframework.lang.Nullable; - -/** - * Interface to be implemented by objects that can provide SQL strings. - *

- * Typically implemented by objects that want to expose the SQL they use to create their statements, to allow for better - * contextual information in case of exceptions. - * - * @author Juergen Hoeller - * @author Mark Paluch - * @deprecated since 1.2, use Spring's {@link org.springframework.r2dbc.core.SqlProvider} support instead. - */ -@Deprecated -public interface SqlProvider extends org.springframework.r2dbc.core.SqlProvider { - - /** - * Return the SQL string for this object, i.e. typically the SQL used for creating statements. - * - * @return the SQL string, or {@literal null}. - */ - @Nullable - String getSql(); -} diff --git a/src/main/java/org/springframework/data/r2dbc/core/StatementFilterFunction.java b/src/main/java/org/springframework/data/r2dbc/core/StatementFilterFunction.java deleted file mode 100644 index 1bd8e93e6..000000000 --- a/src/main/java/org/springframework/data/r2dbc/core/StatementFilterFunction.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2020-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.Result; -import io.r2dbc.spi.Statement; - -import org.reactivestreams.Publisher; - -import org.springframework.util.Assert; - -/** - * Represents a function that filters an {@link ExecuteFunction execute function}. - *

- * The filter is executed when a {@link org.reactivestreams.Subscriber} subscribes to the {@link Publisher} returned by - * the {@link DatabaseClient}. - * - * @author Mark Paluch - * @since 1.1 - * @see ExecuteFunction - * @deprecated since 1.2, use Spring's {@link org.springframework.r2dbc.core.StatementFilterFunction} support instead. - */ -@Deprecated -@FunctionalInterface -public interface StatementFilterFunction { - - /** - * Apply this filter to the given {@link Statement} and {@link ExecuteFunction}. - *

- * The given {@link ExecuteFunction} represents the next entity in the chain, to be invoked via - * {@link ExecuteFunction#execute(Statement)} invoked} in order to proceed with the exchange, or not invoked to - * shortcut the chain. - * - * @param statement the current {@link Statement}. - * @param next the next exchange function in the chain. - * @return the filtered {@link Result}s. - */ - Publisher filter(Statement statement, ExecuteFunction next); - - /** - * Return a composed filter function that first applies this filter, and then applies the given {@code "after"} - * filter. - * - * @param afterFilter the filter to apply after this filter. - * @return the composed filter. - */ - default StatementFilterFunction andThen(StatementFilterFunction afterFilter) { - - Assert.notNull(afterFilter, "StatementFilterFunction must not be null"); - - return (request, next) -> filter(request, afterRequest -> afterFilter.filter(afterRequest, next)); - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/core/StatementFilterFunctions.java b/src/main/java/org/springframework/data/r2dbc/core/StatementFilterFunctions.java deleted file mode 100644 index 2e08f9b3f..000000000 --- a/src/main/java/org/springframework/data/r2dbc/core/StatementFilterFunctions.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2020-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.Result; -import io.r2dbc.spi.Statement; - -import org.reactivestreams.Publisher; - -/** - * Collection of default {@link StatementFilterFunction}s. - * - * @author Mark Paluch - * @since 1.1 - * @deprecated since 1.2, use Spring's org.springframework.r2dbc.core.StatementFilterFunctions support instead. - */ -@Deprecated -enum StatementFilterFunctions implements StatementFilterFunction { - - EMPTY_FILTER; - - @Override - public Publisher filter(Statement statement, ExecuteFunction next) { - return next.execute(statement); - } - - /** - * Return an empty {@link StatementFilterFunction} that delegates to {@link ExecuteFunction}. - * - * @return an empty {@link StatementFilterFunction} that delegates to {@link ExecuteFunction}. - */ - public static StatementFilterFunction empty() { - return EMPTY_FILTER; - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/core/StatementMapper.java b/src/main/java/org/springframework/data/r2dbc/core/StatementMapper.java index 24a4805e4..8e1d913dd 100644 --- a/src/main/java/org/springframework/data/r2dbc/core/StatementMapper.java +++ b/src/main/java/org/springframework/data/r2dbc/core/StatementMapper.java @@ -30,7 +30,6 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.r2dbc.convert.R2dbcConverter; import org.springframework.data.r2dbc.dialect.R2dbcDialect; -import org.springframework.data.r2dbc.mapping.SettableValue; import org.springframework.data.relational.core.query.Criteria; import org.springframework.data.relational.core.query.CriteriaDefinition; import org.springframework.data.relational.core.sql.Expression; @@ -477,19 +476,6 @@ public interface StatementMapper { return new InsertSpec(table, Collections.emptyMap()); } - /** - * Associate a column with a {@link SettableValue} and create a new {@link InsertSpec}. - * - * @param column - * @param value - * @return the {@link InsertSpec}. - * @deprecated since 1.2, use {@link #withColumn(String, Parameter)} instead. - */ - @Deprecated - public InsertSpec withColumn(String column, SettableValue value) { - return withColumn(SqlIdentifier.unquoted(column), value); - } - /** * Associate a column with a {@link Parameter} and create a new {@link InsertSpec}. * @@ -502,19 +488,6 @@ public interface StatementMapper { return withColumn(SqlIdentifier.unquoted(column), value); } - /** - * Associate a column with a {@link SettableValue} and create a new {@link InsertSpec}. - * - * @param column - * @param value - * @return the {@link InsertSpec}. - * @deprecated since 1.2, use {@link #withColumn(SqlIdentifier, Parameter)} instead. - */ - @Deprecated - public InsertSpec withColumn(SqlIdentifier column, SettableValue value) { - return withColumn(column, value.toParameter()); - } - /** * Associate a column with a {@link Parameter} and create a new {@link InsertSpec}. * diff --git a/src/main/java/org/springframework/data/r2dbc/core/UpdatedRowsFetchSpec.java b/src/main/java/org/springframework/data/r2dbc/core/UpdatedRowsFetchSpec.java deleted file mode 100644 index 5222c1576..000000000 --- a/src/main/java/org/springframework/data/r2dbc/core/UpdatedRowsFetchSpec.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2018-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 reactor.core.publisher.Mono; - -/** - * Contract for fetching the number of affected rows. - * - * @author Mark Paluch - * @deprecated since 1.2, use Spring's {@link org.springframework.r2dbc.core.UpdatedRowsFetchSpec} support instead. - */ -@Deprecated -public interface UpdatedRowsFetchSpec { - - /** - * Get the number of updated rows. - * - * @return {@link Mono} emitting the number of updated rows. Never {@literal null}. - */ - Mono rowsUpdated(); -} diff --git a/src/main/java/org/springframework/data/r2dbc/dialect/BindMarker.java b/src/main/java/org/springframework/data/r2dbc/dialect/BindMarker.java deleted file mode 100644 index eaa4e4ad7..000000000 --- a/src/main/java/org/springframework/data/r2dbc/dialect/BindMarker.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.springframework.data.r2dbc.dialect; - -import io.r2dbc.spi.Statement; - -/** - * A bind marker represents a single bindable parameter within a query. Bind markers are dialect-specific and provide a - * {@link #getPlaceholder() placeholder} that is used in the actual query. - * - * @author Mark Paluch - * @see Statement#bind - * @see BindMarkers - * @see BindMarkersFactory - * @deprecated since 1.2 in favor of Spring R2DBC. Use {@link org.springframework.r2dbc.core.binding.BindMarker} - * instead. - */ -@Deprecated -public interface BindMarker extends org.springframework.r2dbc.core.binding.BindMarker { - - /** - * Returns the database-specific placeholder for a given substitution. - * - * @return the database-specific placeholder for a given substitution. - */ - String getPlaceholder(); - - /** - * Bind the given {@code value} to the {@link Statement} using the underlying binding strategy. - * - * @param bindTarget the target to bind the value to. - * @param value the actual value. Must not be {@literal null}. Use {@link #bindNull(BindTarget, Class)} for - * {@literal null} values. - * @see Statement#bind - */ - void bind(BindTarget bindTarget, Object value); - - /** - * Bind a {@literal null} value to the {@link Statement} using the underlying binding strategy. - * - * @param bindTarget the target to bind the value to. - * @param valueType value type, must not be {@literal null}. - * @see Statement#bindNull - */ - void bindNull(BindTarget bindTarget, Class valueType); -} diff --git a/src/main/java/org/springframework/data/r2dbc/dialect/BindMarkers.java b/src/main/java/org/springframework/data/r2dbc/dialect/BindMarkers.java deleted file mode 100644 index c2e3ed367..000000000 --- a/src/main/java/org/springframework/data/r2dbc/dialect/BindMarkers.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.springframework.data.r2dbc.dialect; - -/** - * Bind markers represent placeholders in SQL queries for substitution for an actual parameter. Using bind markers - * allows creating safe queries so query strings are not required to contain escaped values but rather the driver - * encodes parameter in the appropriate representation. - *

- * {@link BindMarkers} is stateful and can be only used for a single binding pass of one or more parameters. It - * maintains bind indexes/bind parameter names. - * - * @author Mark Paluch - * @see BindMarker - * @see BindMarkersFactory - * @see io.r2dbc.spi.Statement#bind - * @deprecated since 1.2 in favor of Spring R2DBC. Use {@link org.springframework.r2dbc.core.binding.BindMarkers} - * instead. - */ -@FunctionalInterface -@Deprecated -public interface BindMarkers extends org.springframework.r2dbc.core.binding.BindMarkers { - - /** - * Creates a new {@link BindMarker}. - * - * @return a new {@link BindMarker}. - */ - BindMarker next(); - - /** - * Creates a new {@link BindMarker} that accepts a {@code hint}. Implementations are allowed to consider/ignore/filter - * the name hint to create more expressive bind markers. - * - * @param hint an optional name hint that can be used as part of the bind marker. - * @return a new {@link BindMarker}. - */ - default BindMarker next(String hint) { - return next(); - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/dialect/BindMarkersAdapter.java b/src/main/java/org/springframework/data/r2dbc/dialect/BindMarkersAdapter.java deleted file mode 100644 index bdb50d35c..000000000 --- a/src/main/java/org/springframework/data/r2dbc/dialect/BindMarkersAdapter.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2020-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.dialect; - -import org.springframework.r2dbc.core.binding.BindMarker; -import org.springframework.r2dbc.core.binding.BindMarkers; -import org.springframework.r2dbc.core.binding.BindTarget; - -/** - * Adapter to use Spring R2DBC's {@link org.springframework.r2dbc.core.binding.BindMarkers} exposing it as - * {@link org.springframework.data.r2dbc.dialect.BindMarkers}. - * - * @author Mark Paluch - * @since 1.2 - */ -class BindMarkersAdapter implements org.springframework.data.r2dbc.dialect.BindMarkers { - - private final BindMarkers delegate; - - BindMarkersAdapter(BindMarkers delegate) { - this.delegate = delegate; - } - - @Override - public org.springframework.data.r2dbc.dialect.BindMarker next() { - return new BindMarkerAdapter(delegate.next()); - } - - @Override - public org.springframework.data.r2dbc.dialect.BindMarker next(String hint) { - return new BindMarkerAdapter(delegate.next()); - } - - static class BindMarkerAdapter implements org.springframework.data.r2dbc.dialect.BindMarker { - - private final BindMarker delegate; - - BindMarkerAdapter(BindMarker delegate) { - this.delegate = delegate; - } - - @Override - public String getPlaceholder() { - return delegate.getPlaceholder(); - } - - @Override - public void bind(org.springframework.data.r2dbc.dialect.BindTarget bindTarget, Object value) { - delegate.bind(bindTarget, value); - } - - @Override - public void bindNull(org.springframework.data.r2dbc.dialect.BindTarget bindTarget, Class valueType) { - delegate.bindNull(bindTarget, valueType); - } - - @Override - public void bind(BindTarget bindTarget, Object value) { - delegate.bind(bindTarget, value); - } - - @Override - public void bindNull(BindTarget bindTarget, Class valueType) { - delegate.bindNull(bindTarget, valueType); - } - - @Override - public String toString() { - return delegate.toString(); - } - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/dialect/BindMarkersFactory.java b/src/main/java/org/springframework/data/r2dbc/dialect/BindMarkersFactory.java deleted file mode 100644 index 719f880b9..000000000 --- a/src/main/java/org/springframework/data/r2dbc/dialect/BindMarkersFactory.java +++ /dev/null @@ -1,165 +0,0 @@ -package org.springframework.data.r2dbc.dialect; - -import java.util.function.Function; - -import org.springframework.util.Assert; - -/** - * This class creates new {@link BindMarkers} instances to bind parameter for a specific {@link io.r2dbc.spi.Statement}. - *

- * Bind markers can be typically represented as placeholder and identifier. Placeholders are used within the query to - * execute so the underlying database system can substitute the placeholder with the actual value. Identifiers are used - * in R2DBC drivers to bind a value to a bind marker. Identifiers are typically a part of an entire bind marker when - * using indexed or named bind markers. - * - * @author Mark Paluch - * @see BindMarkers - * @see io.r2dbc.spi.Statement - * @deprecated since 1.2 in favor of Spring R2DBC. Use {@link org.springframework.r2dbc.core.binding.BindMarkersFactory} - * instead. - */ -@FunctionalInterface -@Deprecated -public interface BindMarkersFactory extends org.springframework.r2dbc.core.binding.BindMarkersFactory { - - /** - * Create a new {@link BindMarkers} instance. - * - * @return a new {@link BindMarkers} instance. - */ - BindMarkers create(); - - /** - * Return whether the {@link BindMarkersFactory} uses identifiable placeholders. - * - * @return whether the {@link BindMarkersFactory} uses identifiable placeholders. {@literal false} if multiple - * placeholders cannot be distinguished by just the {@link BindMarker#getPlaceholder() placeholder} - * identifier. - */ - default boolean identifiablePlaceholders() { - return true; - } - - /** - * Create index-based {@link BindMarkers} using indexes to bind parameters. Allow customization of the bind marker - * placeholder {@code prefix} to represent the bind marker as placeholder within the query. - * - * @param prefix bind parameter prefix that is included in {@link BindMarker#getPlaceholder()} but not the actual - * identifier. - * @param beginWith the first index to use. - * @return a {@link BindMarkersFactory} using {@code prefix} and {@code beginWith}. - * @see io.r2dbc.spi.Statement#bindNull(int, Class) - * @see io.r2dbc.spi.Statement#bind(int, Object) - */ - static BindMarkersFactory indexed(String prefix, int beginWith) { - - Assert.notNull(prefix, "Prefix must not be null!"); - - org.springframework.r2dbc.core.binding.BindMarkersFactory factory = org.springframework.r2dbc.core.binding.BindMarkersFactory - .indexed(prefix, beginWith); - - return new BindMarkersFactory() { - - @Override - public BindMarkers create() { - return new BindMarkersAdapter(factory.create()); - } - - @Override - public boolean identifiablePlaceholders() { - return factory.identifiablePlaceholders(); - } - }; - } - - /** - * Creates anonymous, index-based bind marker using a static placeholder. Instances are bound by the ordinal position - * ordered by the appearance of the placeholder. This implementation creates indexed bind markers using an anonymous - * placeholder that correlates with an index. - * - * @param placeholder parameter placeholder. - * @return a {@link BindMarkersFactory} using {@code placeholder}. - * @see io.r2dbc.spi.Statement#bindNull(int, Class) - * @see io.r2dbc.spi.Statement#bind(int, Object) - */ - static BindMarkersFactory anonymous(String placeholder) { - - Assert.hasText(placeholder, "Placeholder must not be empty!"); - org.springframework.r2dbc.core.binding.BindMarkersFactory factory = org.springframework.r2dbc.core.binding.BindMarkersFactory - .anonymous(placeholder); - - return new BindMarkersFactory() { - - @Override - public BindMarkers create() { - return new BindMarkersAdapter(factory.create()); - } - - @Override - public boolean identifiablePlaceholders() { - return factory.identifiablePlaceholders(); - } - }; - } - - /** - * Create named {@link BindMarkers} using identifiers to bind parameters. Named bind markers can support - * {@link BindMarkers#next(String) name hints}. If no {@link BindMarkers#next(String) hint} is given, named bind - * markers can use a counter or a random value source to generate unique bind markers. - *

- * Allow customization of the bind marker placeholder {@code prefix} and {@code namePrefix} to represent the bind - * marker as placeholder within the query. - * - * @param prefix bind parameter prefix that is included in {@link BindMarker#getPlaceholder()} but not the actual - * identifier. - * @param namePrefix prefix for bind marker name that is included in {@link BindMarker#getPlaceholder()} and the - * actual identifier. - * @param maxLength maximal length of parameter names when using name hints. - * @return a {@link BindMarkersFactory} using {@code prefix} and {@code beginWith}. - * @see io.r2dbc.spi.Statement#bindNull(String, Class) - * @see io.r2dbc.spi.Statement#bind(String, Object) - */ - static BindMarkersFactory named(String prefix, String namePrefix, int maxLength) { - return named(prefix, namePrefix, maxLength, Function.identity()); - } - - /** - * Create named {@link BindMarkers} using identifiers to bind parameters. Named bind markers can support - * {@link BindMarkers#next(String) name hints}. If no {@link BindMarkers#next(String) hint} is given, named bind - * markers can use a counter or a random value source to generate unique bind markers. - * - * @param prefix bind parameter prefix that is included in {@link BindMarker#getPlaceholder()} but not the actual - * identifier. - * @param namePrefix prefix for bind marker name that is included in {@link BindMarker#getPlaceholder()} and the - * actual identifier. - * @param maxLength maximal length of parameter names when using name hints. - * @param hintFilterFunction filter {@link Function} to consider database-specific limitations in bind marker/variable - * names such as ASCII chars only. - * @return a {@link BindMarkersFactory} using {@code prefix} and {@code beginWith}. - * @see io.r2dbc.spi.Statement#bindNull(String, Class) - * @see io.r2dbc.spi.Statement#bind(String, Object) - */ - static BindMarkersFactory named(String prefix, String namePrefix, int maxLength, - Function hintFilterFunction) { - - Assert.notNull(prefix, "Prefix must not be null!"); - Assert.notNull(namePrefix, "Index prefix must not be null!"); - Assert.notNull(hintFilterFunction, "Hint filter function must not be null!"); - - org.springframework.r2dbc.core.binding.BindMarkersFactory factory = org.springframework.r2dbc.core.binding.BindMarkersFactory - .named(prefix, namePrefix, maxLength, hintFilterFunction); - - return new BindMarkersFactory() { - - @Override - public BindMarkers create() { - return new BindMarkersAdapter(factory.create()); - } - - @Override - public boolean identifiablePlaceholders() { - return factory.identifiablePlaceholders(); - } - }; - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/dialect/BindTarget.java b/src/main/java/org/springframework/data/r2dbc/dialect/BindTarget.java deleted file mode 100644 index 777e36f1d..000000000 --- a/src/main/java/org/springframework/data/r2dbc/dialect/BindTarget.java +++ /dev/null @@ -1,64 +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.dialect; - -import org.springframework.data.r2dbc.core.PreparedOperation; - -/** - * Target to apply bindings to. - * - * @author Mark Paluch - * @see PreparedOperation - * @see io.r2dbc.spi.Statement#bind - * @see io.r2dbc.spi.Statement#bindNull - * @deprecated since 1.2 in favor of Spring R2DBC. Use {@link org.springframework.r2dbc.core.binding.BindTarget} - * instead. - */ -@Deprecated -public interface BindTarget extends org.springframework.r2dbc.core.binding.BindTarget { - - /** - * Bind a value. - * - * @param identifier the identifier to bind to. - * @param value the value to bind. - */ - void bind(String identifier, Object value); - - /** - * Bind a value to an index. Indexes are zero-based. - * - * @param index the index to bind to. - * @param value the value to bind. - */ - void bind(int index, Object value); - - /** - * Bind a {@literal null} value. - * - * @param identifier the identifier to bind to. - * @param type the type of {@literal null} value. - */ - void bindNull(String identifier, Class type); - - /** - * Bind a {@literal null} value. - * - * @param index the index to bind to. - * @param type the type of {@literal null} value. - */ - void bindNull(int index, Class type); -} diff --git a/src/main/java/org/springframework/data/r2dbc/dialect/Bindings.java b/src/main/java/org/springframework/data/r2dbc/dialect/Bindings.java deleted file mode 100644 index 46bf8d9a3..000000000 --- a/src/main/java/org/springframework/data/r2dbc/dialect/Bindings.java +++ /dev/null @@ -1,289 +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.dialect; - -import io.r2dbc.spi.Statement; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Spliterator; -import java.util.function.Consumer; - -import org.springframework.data.util.Streamable; -import org.springframework.lang.Nullable; -import org.springframework.r2dbc.core.binding.BindMarker; -import org.springframework.r2dbc.core.binding.BindMarkers; -import org.springframework.r2dbc.core.binding.BindTarget; -import org.springframework.util.Assert; - -/** - * Value object representing value and {@literal null} bindings for a {@link Statement} using {@link BindMarkers}. - * Bindings are typically immutable. - * - * @author Mark Paluch - * @deprecated since 1.2 in favor of Spring R2DBC. Use {@link org.springframework.r2dbc.core.binding.Bindings} instead. - */ -@Deprecated -public class Bindings implements Streamable { - - private static final Bindings EMPTY = new Bindings(); - - private final Map bindings; - - /** - * Create empty {@link Bindings}. - */ - public Bindings() { - this.bindings = Collections.emptyMap(); - } - - /** - * Create {@link Bindings} from a {@link Map}. - * - * @param bindings must not be {@literal null}. - */ - public Bindings(Collection bindings) { - - Assert.notNull(bindings, "Bindings must not be null"); - - Map mapping = new LinkedHashMap<>(bindings.size()); - bindings.forEach(it -> mapping.put(it.getBindMarker(), it)); - this.bindings = mapping; - } - - Bindings(Map bindings) { - this.bindings = bindings; - } - - /** - * Create a new, empty {@link Bindings} object. - * - * @return a new, empty {@link Bindings} object. - */ - public static Bindings empty() { - return EMPTY; - } - - protected Map getBindings() { - return this.bindings; - } - - /** - * Merge this bindings with an other {@link Bindings} object and create a new merged {@link Bindings} object. - * - * @param left the left object to merge with. - * @param right the right object to merge with. - * @return a new, merged {@link Bindings} object. - */ - public static Bindings merge(Bindings left, Bindings right) { - - Assert.notNull(left, "Left side Bindings must not be null"); - Assert.notNull(right, "Right side Bindings must not be null"); - - List result = new ArrayList<>(left.getBindings().size() + right.getBindings().size()); - - result.addAll(left.getBindings().values()); - result.addAll(right.getBindings().values()); - - return new Bindings(result); - } - - /** - * Merge this bindings with an other {@link Bindings} object and create a new merged {@link Bindings} object. - * - * @param other the object to merge with. - * @return a new, merged {@link Bindings} object. - */ - public Bindings and(Bindings other) { - return merge(this, other); - } - - /** - * Apply the bindings to a {@link BindTarget}. - * - * @param bindTarget the target to apply bindings to. - */ - public void apply(BindTarget bindTarget) { - - Assert.notNull(bindTarget, "BindTarget must not be null"); - this.bindings.forEach((marker, binding) -> binding.apply(bindTarget)); - } - - /** - * Performs the given action for each binding of this {@link Bindings} until all bindings have been processed or the - * action throws an exception. Actions are performed in the order of iteration (if an iteration order is specified). - * Exceptions thrown by the action are relayed to the - * - * @param action The action to be performed for each {@link Binding}. - */ - public void forEach(Consumer action) { - this.bindings.forEach((marker, binding) -> action.accept(binding)); - } - - /* - * (non-Javadoc) - * @see java.lang.Iterable#iterator() - */ - @Override - public Iterator iterator() { - return this.bindings.values().iterator(); - } - - /* - * (non-Javadoc) - * @see java.lang.Iterable#spliterator() - */ - @Override - public Spliterator spliterator() { - return this.bindings.values().spliterator(); - } - - /** - * Base class for value objects representing a value or a {@code NULL} binding. - */ - public abstract static class Binding { - - private final BindMarker marker; - - protected Binding(BindMarker marker) { - this.marker = marker; - } - - /** - * @return the associated {@link BindMarker}. - */ - public BindMarker getBindMarker() { - return this.marker; - } - - /** - * Return {@literal true} if there is a value present, otherwise {@literal false} for a {@code NULL} binding. - * - * @return {@literal true} if there is a value present, otherwise {@literal false} for a {@code NULL} binding. - */ - public abstract boolean hasValue(); - - /** - * Return {@literal true} if this is is a {@code NULL} binding. - * - * @return {@literal true} if this is is a {@code NULL} binding. - */ - public boolean isNull() { - return !hasValue(); - } - - /** - * Returns the value of this binding. Can be {@literal null} if this is a {@code NULL} binding. - * - * @return value of this binding. Can be {@literal null} if this is a {@code NULL} binding. - */ - @Nullable - public abstract Object getValue(); - - /** - * Applies the binding to a {@link BindTarget}. - * - * @param bindTarget the target to apply bindings to. - */ - public abstract void apply(BindTarget bindTarget); - } - - /** - * Value binding. - */ - public static class ValueBinding extends Binding { - - private final Object value; - - public ValueBinding(BindMarker marker, Object value) { - super(marker); - this.value = value; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.query.Bindings.Binding#hasValue() - */ - public boolean hasValue() { - return true; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.query.Bindings.Binding#getValue() - */ - public Object getValue() { - return this.value; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.query.Bindings.Binding#apply(io.r2dbc.spi.Statement) - */ - @Override - public void apply(BindTarget bindTarget) { - getBindMarker().bind(bindTarget, getValue()); - } - } - - /** - * {@code NULL} binding. - */ - public static class NullBinding extends Binding { - - private final Class valueType; - - public NullBinding(BindMarker marker, Class valueType) { - super(marker); - this.valueType = valueType; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.query.Bindings.Binding#hasValue() - */ - public boolean hasValue() { - return false; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.query.Bindings.Binding#getValue() - */ - @Nullable - public Object getValue() { - return null; - } - - public Class getValueType() { - return this.valueType; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.query.Bindings.Binding#apply(BindTarget) - */ - @Override - public void apply(BindTarget bindTarget) { - getBindMarker().bindNull(bindTarget, getValueType()); - } - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/dialect/MutableBindings.java b/src/main/java/org/springframework/data/r2dbc/dialect/MutableBindings.java deleted file mode 100644 index 0a6e34a1b..000000000 --- a/src/main/java/org/springframework/data/r2dbc/dialect/MutableBindings.java +++ /dev/null @@ -1,135 +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.dialect; - -import io.r2dbc.spi.Statement; - -import java.util.LinkedHashMap; - -import org.springframework.util.Assert; - -/** - * Mutable extension to {@link Bindings} for Value and {@literal null} bindings for a {@link Statement} using - * {@link BindMarkers}. - * - * @author Mark Paluch - * @deprecated since 1.2 in favor of Spring R2DBC. Use {@link org.springframework.r2dbc.core.binding.MutableBindings} - * instead. - */ -@Deprecated -public class MutableBindings extends Bindings { - - private final BindMarkers markers; - - /** - * Create new {@link MutableBindings}. - * - * @param markers must not be {@literal null}. - */ - public MutableBindings(BindMarkers markers) { - - super(new LinkedHashMap<>()); - - Assert.notNull(markers, "BindMarkers must not be null"); - - this.markers = markers; - } - - /** - * Obtain the next {@link BindMarker}. Increments {@link BindMarkers} state. - * - * @return the next {@link BindMarker}. - */ - public BindMarker nextMarker() { - return this.markers.next(); - } - - /** - * Obtain the next {@link BindMarker} with a name {@code hint}. Increments {@link BindMarkers} state. - * - * @param hint name hint. - * @return the next {@link BindMarker}. - */ - public BindMarker nextMarker(String hint) { - return this.markers.next(hint); - } - - /** - * Bind a value to {@link BindMarker}. - * - * @param marker must not be {@literal null}. - * @param value must not be {@literal null}. - * @return {@code this} {@link MutableBindings}. - */ - public MutableBindings bind(BindMarker marker, Object value) { - - Assert.notNull(marker, "BindMarker must not be null"); - Assert.notNull(value, "Value must not be null"); - - getBindings().put(marker, new ValueBinding(marker, value)); - - return this; - } - - /** - * Bind a value and return the related {@link BindMarker}. Increments {@link BindMarkers} state. - * - * @param value must not be {@literal null}. - * @return {@code this} {@link MutableBindings}. - */ - public BindMarker bind(Object value) { - - Assert.notNull(value, "Value must not be null"); - - BindMarker marker = nextMarker(); - getBindings().put(marker, new ValueBinding(marker, value)); - - return marker; - } - - /** - * Bind a {@code NULL} value to {@link BindMarker}. - * - * @param marker must not be {@literal null}. - * @param valueType must not be {@literal null}. - * @return {@code this} {@link MutableBindings}. - */ - public MutableBindings bindNull(BindMarker marker, Class valueType) { - - Assert.notNull(marker, "BindMarker must not be null"); - Assert.notNull(valueType, "Value type must not be null"); - - getBindings().put(marker, new NullBinding(marker, valueType)); - - return this; - } - - /** - * Bind a {@code NULL} value and return the related {@link BindMarker}. Increments {@link BindMarkers} state. - * - * @param valueType must not be {@literal null}. - * @return {@code this} {@link MutableBindings}. - */ - public BindMarker bindNull(Class valueType) { - - Assert.notNull(valueType, "Value type must not be null"); - - BindMarker marker = nextMarker(); - getBindings().put(marker, new NullBinding(marker, valueType)); - - return marker; - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/mapping/SettableValue.java b/src/main/java/org/springframework/data/r2dbc/mapping/SettableValue.java deleted file mode 100644 index 45dba48a6..000000000 --- a/src/main/java/org/springframework/data/r2dbc/mapping/SettableValue.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2018-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.mapping; - -import org.springframework.lang.Nullable; -import org.springframework.r2dbc.core.Parameter; -import org.springframework.util.Assert; - -/** - * A database value that can be set in a statement. - * - * @author Mark Paluch - * @see OutboundRow - * @deprecated since 1.2, use Spring R2DBC's {@link Parameter} directly. - */ -@Deprecated -public class SettableValue { - - private final Parameter parameter; - - private SettableValue(Parameter parameter) { - this.parameter = parameter; - } - - /** - * Creates a new {@link SettableValue} from {@code value}. - * - * @param value must not be {@literal null}. - * @return the {@link SettableValue} value for {@code value}. - */ - public static SettableValue from(Object value) { - - Assert.notNull(value, "Value must not be null"); - - return new SettableValue(Parameter.from(value)); - } - - /** - * Creates a new {@link SettableValue} from {@code value} and {@code type}. - * - * @param value can be {@literal null}. - * @param type must not be {@literal null}. - * @return the {@link SettableValue} value for {@code value}. - */ - public static SettableValue fromOrEmpty(@Nullable Object value, Class type) { - return new SettableValue(Parameter.fromOrEmpty(value, type)); - } - - /** - * Creates a new empty {@link SettableValue} for {@code type}. - * - * @return the empty {@link SettableValue} value for {@code type}. - */ - public static SettableValue empty(Class type) { - - Assert.notNull(type, "Type must not be null"); - - return new SettableValue(Parameter.empty(type)); - } - - /** - * Factory method to create a {@link SettableValue} from {@link Parameter}. Retains empty/type information. - * - * @param parameter the parameter to create a {@link SettableValue} from. - * @return a new {@link SettableValue} from {@link Parameter}. - * @since 1.4 - */ - public static SettableValue fromParameter(Parameter parameter) { - - Assert.notNull(parameter, "Parameter must not be null"); - - return parameter.isEmpty() ? SettableValue.empty(parameter.getType()) - : SettableValue.fromOrEmpty(parameter.getValue(), parameter.getType()); - } - - /** - * Returns the column value. Can be {@literal null}. - * - * @return the column value. Can be {@literal null}. - * @see #hasValue() - */ - @Nullable - public Object getValue() { - return this.parameter.getValue(); - } - - /** - * Returns the column value type. Must be also present if the {@code value} is {@literal null}. - * - * @return the column value type - */ - public Class getType() { - return this.parameter.getType(); - } - - /** - * Returns whether this {@link SettableValue} has a value. - * - * @return whether this {@link SettableValue} has a value. {@literal false} if {@link #getValue()} is {@literal null}. - */ - public boolean hasValue() { - return this.parameter.hasValue(); - } - - /** - * Returns whether this {@link SettableValue} has a empty. - * - * @return whether this {@link SettableValue} is empty. {@literal true} if {@link #getValue()} is {@literal null}. - */ - public boolean isEmpty() { - return this.parameter.isEmpty(); - } - - @Override - public boolean equals(Object o) { - if (this == o) - return true; - if (!(o instanceof SettableValue)) - return false; - SettableValue value1 = (SettableValue) o; - return this.parameter.equals(value1.parameter); - } - - @Override - public int hashCode() { - return this.parameter.hashCode(); - } - - @Override - public String toString() { - return this.parameter.toString(); - } - - /** - * @return the {@link Parameter} representing this settable value. - * @since 1.2 - */ - public Parameter toParameter() { - return isEmpty() ? Parameter.empty(getType()) : Parameter.fromOrEmpty(getValue(), getType()); - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/query/Criteria.java b/src/main/java/org/springframework/data/r2dbc/query/Criteria.java deleted file mode 100644 index c00809321..000000000 --- a/src/main/java/org/springframework/data/r2dbc/query/Criteria.java +++ /dev/null @@ -1,705 +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.query; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import org.springframework.dao.InvalidDataAccessApiUsageException; -import org.springframework.data.relational.core.query.CriteriaDefinition; -import org.springframework.data.relational.core.sql.SqlIdentifier; -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; - -/** - * Central class for creating queries. It follows a fluent API style so that you can easily chain together multiple - * criteria. Static import of the {@code Criteria.property(…)} method will improve readability as in - * {@code where(property(…).is(…)}. - *

- * The Criteria API supports composition with a {@link #empty() NULL object} and a {@link #from(List) static factory - * method}. Example usage: - * - *

- * Criteria.from(Criteria.where("name").is("Foo"), Criteria.from(Criteria.where("age").greaterThan(42)));
- * 
- * - * rendering: - * - *
- * WHERE name = 'Foo' AND age > 42
- * 
- * - * @author Mark Paluch - * @author Oliver Drotbohm - * @deprecated since 1.1, use {@link org.springframework.data.relational.core.query.Criteria} instead. - */ -@Deprecated -public class Criteria implements CriteriaDefinition { - - private static final Criteria EMPTY = new Criteria(SqlIdentifier.EMPTY, Comparator.INITIAL, null); - - private final @Nullable Criteria previous; - private final Combinator combinator; - private final List group; - - private final @Nullable SqlIdentifier column; - private final @Nullable Comparator comparator; - private final @Nullable Object value; - private final boolean ignoreCase; - - private Criteria(SqlIdentifier column, Comparator comparator, @Nullable Object value) { - this(null, Combinator.INITIAL, Collections.emptyList(), column, comparator, value, false); - } - - private Criteria(@Nullable Criteria previous, Combinator combinator, List group, - @Nullable SqlIdentifier column, @Nullable Comparator comparator, @Nullable Object value) { - this(previous, combinator, group, column, comparator, value, false); - } - - private Criteria(@Nullable Criteria previous, Combinator combinator, List group, - @Nullable SqlIdentifier column, @Nullable Comparator comparator, @Nullable Object value, boolean ignoreCase) { - - this.previous = previous; - this.combinator = previous != null && previous.isEmpty() ? Combinator.INITIAL : combinator; - this.group = group; - this.column = column; - this.comparator = comparator; - this.value = value; - this.ignoreCase = ignoreCase; - } - - private Criteria(@Nullable Criteria previous, Combinator combinator, List group) { - - this.previous = previous; - this.combinator = previous != null && previous.isEmpty() ? Combinator.INITIAL : combinator; - this.group = group; - this.column = null; - this.comparator = null; - this.value = null; - this.ignoreCase = false; - } - - /** - * Static factory method to create an empty Criteria. - * - * @return an empty {@link Criteria}. - * @since 1.1 - */ - public static Criteria empty() { - return EMPTY; - } - - /** - * Create a new {@link Criteria} and combine it as group with {@code AND} using the provided {@link List Criterias}. - * - * @return new {@link Criteria}. - * @since 1.1 - */ - public static Criteria from(Criteria... criteria) { - - Assert.notNull(criteria, "Criteria must not be null"); - Assert.noNullElements(criteria, "Criteria must not contain null elements"); - - return from(Arrays.asList(criteria)); - } - - /** - * Create a new {@link Criteria} and combine it as group with {@code AND} using the provided {@link List Criterias}. - * - * @return new {@link Criteria}. - * @since 1.1 - */ - public static Criteria from(List criteria) { - - Assert.notNull(criteria, "Criteria must not be null"); - Assert.noNullElements(criteria, "Criteria must not contain null elements"); - - if (criteria.isEmpty()) { - return EMPTY; - } - - if (criteria.size() == 1) { - return criteria.get(0); - } - - return EMPTY.and(criteria); - } - - /** - * Static factory method to create a Criteria using the provided {@code column} name. - * - * @param column Must not be {@literal null} or empty. - * @return a new {@link CriteriaStep} object to complete the first {@link Criteria}. - */ - public static CriteriaStep where(String column) { - - Assert.hasText(column, "Column name must not be null or empty!"); - - return new DefaultCriteriaStep(SqlIdentifier.unquoted(column)); - } - - /** - * Create a new {@link Criteria} and combine it with {@code AND} using the provided {@code column} name. - * - * @param column Must not be {@literal null} or empty. - * @return a new {@link CriteriaStep} object to complete the next {@link Criteria}. - */ - public CriteriaStep and(String column) { - - Assert.hasText(column, "Column name must not be null or empty!"); - - SqlIdentifier identifier = SqlIdentifier.unquoted(column); - return new DefaultCriteriaStep(identifier) { - @Override - protected Criteria createCriteria(Comparator comparator, Object value) { - return new Criteria(Criteria.this, Combinator.AND, Collections.emptyList(), identifier, comparator, value); - } - }; - } - - /** - * Create a new {@link Criteria} and combine it as group with {@code AND} using the provided {@link Criteria} group. - * - * @param criteria criteria object. - * @return a new {@link Criteria} object. - * @since 1.1 - */ - public Criteria and(Criteria criteria) { - - Assert.notNull(criteria, "Criteria must not be null!"); - - return and(Collections.singletonList(criteria)); - } - - /** - * Create a new {@link Criteria} and combine it as group with {@code AND} using the provided {@link Criteria} group. - * - * @param criteria criteria objects. - * @return a new {@link Criteria} object. - * @since 1.1 - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - public Criteria and(List criteria) { - - Assert.notNull(criteria, "Criteria must not be null!"); - - return new Criteria(Criteria.this, Combinator.AND, (List) criteria); - } - - /** - * Create a new {@link Criteria} and combine it with {@code OR} using the provided {@code column} name. - * - * @param column Must not be {@literal null} or empty. - * @return a new {@link CriteriaStep} object to complete the next {@link Criteria}. - */ - public CriteriaStep or(String column) { - - Assert.hasText(column, "Column name must not be null or empty!"); - - SqlIdentifier identifier = SqlIdentifier.unquoted(column); - return new DefaultCriteriaStep(identifier) { - @Override - protected Criteria createCriteria(Comparator comparator, Object value) { - return new Criteria(Criteria.this, Combinator.OR, Collections.emptyList(), identifier, comparator, value); - } - }; - } - - /** - * Create a new {@link Criteria} and combine it as group with {@code OR} using the provided {@link Criteria} group. - * - * @param criteria criteria object. - * @return a new {@link Criteria} object. - * @since 1.1 - */ - public Criteria or(Criteria criteria) { - - Assert.notNull(criteria, "Criteria must not be null!"); - - return or(Collections.singletonList(criteria)); - } - - /** - * Create a new {@link Criteria} and combine it as group with {@code OR} using the provided {@link Criteria} group. - * - * @param criteria criteria object. - * @return a new {@link Criteria} object. - * @since 1.1 - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - public Criteria or(List criteria) { - - Assert.notNull(criteria, "Criteria must not be null!"); - - return new Criteria(Criteria.this, Combinator.OR, (List) criteria); - } - - /** - * Creates a new {@link Criteria} with the given "ignore case" flag. - * - * @param ignoreCase {@literal true} if comparison should be done in case-insensitive way - * @return a new {@link Criteria} object - */ - public Criteria ignoreCase(boolean ignoreCase) { - if (this.ignoreCase != ignoreCase) { - return new Criteria(previous, combinator, group, column, comparator, value, ignoreCase); - } - return this; - } - - /** - * @return the previous {@link Criteria} object. Can be {@literal null} if there is no previous {@link Criteria}. - * @see #hasPrevious() - */ - @Nullable - public Criteria getPrevious() { - return previous; - } - - /** - * @return {@literal true} if this {@link Criteria} has a previous one. - */ - public boolean hasPrevious() { - return previous != null; - } - - /** - * @return {@literal true} if this {@link Criteria} is empty. - * @since 1.1 - */ - public boolean isEmpty() { - - if (!doIsEmpty()) { - return false; - } - - Criteria parent = this.previous; - - while (parent != null) { - - if (!parent.doIsEmpty()) { - return false; - } - - parent = parent.previous; - } - - return true; - } - - private boolean doIsEmpty() { - - if (this.comparator == Comparator.INITIAL) { - return true; - } - - if (this.column != null) { - return false; - } - - for (CriteriaDefinition criteria : group) { - - if (!criteria.isEmpty()) { - return false; - } - } - - return true; - } - - /** - * @return {@literal true} if this {@link Criteria} is empty. - */ - @Override - public boolean isGroup() { - return !this.group.isEmpty(); - } - - /** - * @return {@link Combinator} to combine this criteria with a previous one. - */ - @Override - public Combinator getCombinator() { - return combinator; - } - - @Override - public List getGroup() { - return group; - } - - /** - * @return the column/property name. - */ - @Nullable - @Override - public SqlIdentifier getColumn() { - return column; - } - - /** - * @return {@link Comparator}. - */ - @Nullable - @Override - public Comparator getComparator() { - return comparator; - } - - /** - * @return the comparison value. Can be {@literal null}. - */ - @Nullable - @Override - public Object getValue() { - return value; - } - - /** - * Checks whether comparison should be done in case-insensitive way. - * - * @return {@literal true} if comparison should be done in case-insensitive way - */ - @Override - public boolean isIgnoreCase() { - return ignoreCase; - } - - /** - * Interface declaring terminal builder methods to build a {@link Criteria}. - */ - public interface CriteriaStep { - - /** - * Creates a {@link Criteria} using equality. - * - * @param value must not be {@literal null}. - */ - Criteria is(Object value); - - /** - * Creates a {@link Criteria} using equality (is not). - * - * @param value must not be {@literal null}. - */ - Criteria not(Object value); - - /** - * Creates a {@link Criteria} using {@code IN}. - * - * @param values must not be {@literal null}. - */ - Criteria in(Object... values); - - /** - * Creates a {@link Criteria} using {@code IN}. - * - * @param values must not be {@literal null}. - */ - Criteria in(Collection values); - - /** - * Creates a {@link Criteria} using {@code NOT IN}. - * - * @param values must not be {@literal null}. - */ - Criteria notIn(Object... values); - - /** - * Creates a {@link Criteria} using {@code NOT IN}. - * - * @param values must not be {@literal null}. - */ - Criteria notIn(Collection values); - - /** - * Creates a {@link Criteria} using less-than ({@literal <}). - * - * @param value must not be {@literal null}. - */ - Criteria lessThan(Object value); - - /** - * Creates a {@link Criteria} using less-than or equal to ({@literal <=}). - * - * @param value must not be {@literal null}. - */ - Criteria lessThanOrEquals(Object value); - - /** - * Creates a {@link Criteria} using greater-than({@literal >}). - * - * @param value must not be {@literal null}. - */ - Criteria greaterThan(Object value); - - /** - * Creates a {@link Criteria} using greater-than or equal to ({@literal >=}). - * - * @param value must not be {@literal null}. - */ - Criteria greaterThanOrEquals(Object value); - - /** - * Creates a {@link Criteria} using {@code LIKE}. - * - * @param value must not be {@literal null}. - */ - Criteria like(Object value); - - /** - * Creates a {@link Criteria} using {@code NOT LIKE}. - * - * @param value must not be {@literal null} - * @return a new {@link Criteria} object - */ - Criteria notLike(Object value); - - /** - * Creates a {@link Criteria} using {@code IS NULL}. - */ - Criteria isNull(); - - /** - * Creates a {@link Criteria} using {@code IS NOT NULL}. - */ - Criteria isNotNull(); - - /** - * Creates a {@link Criteria} using {@code IS TRUE}. - * - * @return a new {@link Criteria} object - */ - Criteria isTrue(); - - /** - * Creates a {@link Criteria} using {@code IS FALSE}. - * - * @return a new {@link Criteria} object - */ - Criteria isFalse(); - } - - /** - * Default {@link CriteriaStep} implementation. - */ - static class DefaultCriteriaStep implements CriteriaStep { - - private final SqlIdentifier property; - - DefaultCriteriaStep(SqlIdentifier property) { - this.property = property; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.query.Criteria.CriteriaStep#is(java.lang.Object) - */ - @Override - public Criteria is(Object value) { - - Assert.notNull(value, "Value must not be null!"); - - return createCriteria(Comparator.EQ, value); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.query.Criteria.CriteriaStep#not(java.lang.Object) - */ - @Override - public Criteria not(Object value) { - - Assert.notNull(value, "Value must not be null!"); - - return createCriteria(Comparator.NEQ, value); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.query.Criteria.CriteriaStep#in(java.lang.Object[]) - */ - @Override - public Criteria in(Object... values) { - - Assert.notNull(values, "Values must not be null!"); - Assert.noNullElements(values, "Values must not contain a null value!"); - - if (values.length > 1 && values[1] instanceof Collection) { - throw new InvalidDataAccessApiUsageException( - "You can only pass in one argument of type " + values[1].getClass().getName()); - } - - return createCriteria(Comparator.IN, Arrays.asList(values)); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.query.Criteria.CriteriaStep#in(java.util.Collection) - */ - @Override - public Criteria in(Collection values) { - - Assert.notNull(values, "Values must not be null!"); - Assert.noNullElements(values.toArray(), "Values must not contain a null value!"); - - return createCriteria(Comparator.IN, values); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.query.Criteria.CriteriaStep#notIn(java.lang.Object[]) - */ - @Override - public Criteria notIn(Object... values) { - - Assert.notNull(values, "Values must not be null!"); - Assert.noNullElements(values, "Values must not contain a null value!"); - - if (values.length > 1 && values[1] instanceof Collection) { - throw new InvalidDataAccessApiUsageException( - "You can only pass in one argument of type " + values[1].getClass().getName()); - } - - return createCriteria(Comparator.NOT_IN, Arrays.asList(values)); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.query.Criteria.CriteriaStep#notIn(java.util.Collection) - */ - @Override - public Criteria notIn(Collection values) { - - Assert.notNull(values, "Values must not be null!"); - Assert.noNullElements(values.toArray(), "Values must not contain a null value!"); - - return createCriteria(Comparator.NOT_IN, values); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.query.Criteria.CriteriaStep#lessThan(java.lang.Object) - */ - @Override - public Criteria lessThan(Object value) { - - Assert.notNull(value, "Value must not be null!"); - - return createCriteria(Comparator.LT, value); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.query.Criteria.CriteriaStep#lessThanOrEquals(java.lang.Object) - */ - @Override - public Criteria lessThanOrEquals(Object value) { - - Assert.notNull(value, "Value must not be null!"); - - return createCriteria(Comparator.LTE, value); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.query.Criteria.CriteriaStep#greaterThan(java.lang.Object) - */ - @Override - public Criteria greaterThan(Object value) { - - Assert.notNull(value, "Value must not be null!"); - - return createCriteria(Comparator.GT, value); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.query.Criteria.CriteriaStep#greaterThanOrEquals(java.lang.Object) - */ - @Override - public Criteria greaterThanOrEquals(Object value) { - - Assert.notNull(value, "Value must not be null!"); - - return createCriteria(Comparator.GTE, value); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.query.Criteria.CriteriaStep#like(java.lang.Object) - */ - @Override - public Criteria like(Object value) { - - Assert.notNull(value, "Value must not be null!"); - - return createCriteria(Comparator.LIKE, value); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.query.Criteria.CriteriaStep#notLike(java.lang.Object) - */ - @Override - public Criteria notLike(Object value) { - Assert.notNull(value, "Value must not be null!"); - return createCriteria(Comparator.NOT_LIKE, value); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.query.Criteria.CriteriaStep#isNull() - */ - @Override - public Criteria isNull() { - return createCriteria(Comparator.IS_NULL, null); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.query.Criteria.CriteriaStep#isNotNull() - */ - @Override - public Criteria isNotNull() { - return createCriteria(Comparator.IS_NOT_NULL, null); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.query.Criteria.CriteriaStep#isTrue() - */ - @Override - public Criteria isTrue() { - return createCriteria(Comparator.IS_TRUE, null); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.function.query.Criteria.CriteriaStep#isFalse() - */ - @Override - public Criteria isFalse() { - return createCriteria(Comparator.IS_FALSE, null); - } - - protected Criteria createCriteria(Comparator comparator, Object value) { - return new Criteria(this.property, comparator, value); - } - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/query/QueryMapper.java b/src/main/java/org/springframework/data/r2dbc/query/QueryMapper.java index ad3e3f548..908c0d97b 100644 --- a/src/main/java/org/springframework/data/r2dbc/query/QueryMapper.java +++ b/src/main/java/org/springframework/data/r2dbc/query/QueryMapper.java @@ -30,10 +30,10 @@ import org.springframework.data.mapping.PropertyReferenceException; import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.r2dbc.convert.R2dbcConverter; import org.springframework.data.r2dbc.dialect.R2dbcDialect; -import org.springframework.data.r2dbc.mapping.SettableValue; import org.springframework.data.relational.core.dialect.Escaper; import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; import org.springframework.data.relational.core.mapping.RelationalPersistentProperty; +import org.springframework.data.relational.core.query.Criteria; import org.springframework.data.relational.core.query.CriteriaDefinition; import org.springframework.data.relational.core.query.CriteriaDefinition.Comparator; import org.springframework.data.relational.core.query.ValueFunction; @@ -347,13 +347,7 @@ public class QueryMapper { Object mappedValue; Class typeHint; - if (criteria.getValue() instanceof SettableValue) { - - SettableValue settableValue = (SettableValue) criteria.getValue(); - - mappedValue = convertValue(settableValue.getValue(), propertyField.getTypeHint()); - typeHint = getTypeHint(mappedValue, actualType.getType(), settableValue); - } else if (criteria.getValue() instanceof Parameter) { + if (criteria.getValue() instanceof Parameter) { Parameter parameter = (Parameter) criteria.getValue(); @@ -384,21 +378,6 @@ public class QueryMapper { return Escaper.DEFAULT; } - /** - * Potentially convert the {@link SettableValue}. - * - * @param value - * @return - */ - public SettableValue getBindValue(SettableValue value) { - - if (value.isEmpty()) { - return SettableValue.empty(converter.getTargetType(value.getType())); - } - - return SettableValue.from(convertValue(value.getValue(), ClassTypeInformation.OBJECT)); - } - /** * Potentially convert the {@link Parameter}. * @@ -587,19 +566,6 @@ public class QueryMapper { return propertyType; } - Class getTypeHint(@Nullable Object mappedValue, Class propertyType, SettableValue settableValue) { - - if (mappedValue == null || propertyType.equals(Object.class)) { - return settableValue.getType(); - } - - if (mappedValue.getClass().equals(settableValue.getValue().getClass())) { - return settableValue.getType(); - } - - return propertyType; - } - Class getTypeHint(@Nullable Object mappedValue, Class propertyType, Parameter parameter) { if (mappedValue == null || propertyType.equals(Object.class)) { diff --git a/src/main/java/org/springframework/data/r2dbc/query/Update.java b/src/main/java/org/springframework/data/r2dbc/query/Update.java deleted file mode 100644 index f7e3505cf..000000000 --- a/src/main/java/org/springframework/data/r2dbc/query/Update.java +++ /dev/null @@ -1,99 +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.query; - -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.Map; - -import org.springframework.data.relational.core.sql.SqlIdentifier; -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; - -/** - * Class to easily construct SQL update assignments. - * - * @author Mark Paluch - * @author Oliver Drotbohm - * @deprecated since 1.1, use {@link org.springframework.data.relational.core.query.Update} instead. - */ -@Deprecated -public class Update { - - private static final Update EMPTY = new Update(Collections.emptyMap()); - - private final Map columnsToUpdate; - - private Update(Map columnsToUpdate) { - this.columnsToUpdate = columnsToUpdate; - } - - /** - * Static factory method to create an {@link Update} using the provided column. - * - * @param column must not be {@literal null}. - * @param value can be {@literal null}. - * @return - */ - public static Update update(String column, @Nullable Object value) { - return EMPTY.set(column, value); - } - - /** - * Update a column by assigning a value. - * - * @param column must not be {@literal null}. - * @param value can be {@literal null}. - * @return - */ - public Update set(String column, @Nullable Object value) { - - Assert.hasText(column, "Column for update must not be null or blank"); - - return addMultiFieldOperation(SqlIdentifier.unquoted(column), value); - } - - /** - * Update a column by assigning a value. - * - * @param column must not be {@literal null}. - * @param value can be {@literal null}. - * @return - * @since 1.1 - */ - public Update set(SqlIdentifier column, @Nullable Object value) { - return addMultiFieldOperation(column, value); - } - - /** - * Returns all assignments. - * - * @return - */ - public Map getAssignments() { - return Collections.unmodifiableMap(this.columnsToUpdate); - } - - private Update addMultiFieldOperation(SqlIdentifier key, @Nullable Object value) { - - Assert.notNull(key, "Column for update must not be null"); - - Map updates = new LinkedHashMap<>(this.columnsToUpdate); - updates.put(key, value); - - return new Update(updates); - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/query/UpdateMapper.java b/src/main/java/org/springframework/data/r2dbc/query/UpdateMapper.java index 855ca4ee8..032aa772a 100644 --- a/src/main/java/org/springframework/data/r2dbc/query/UpdateMapper.java +++ b/src/main/java/org/springframework/data/r2dbc/query/UpdateMapper.java @@ -20,14 +20,10 @@ import java.util.List; import java.util.Map; import org.springframework.data.r2dbc.convert.R2dbcConverter; -import org.springframework.r2dbc.core.Parameter; -import org.springframework.r2dbc.core.binding.BindMarkers; -import org.springframework.r2dbc.core.binding.Bindings; -import org.springframework.r2dbc.core.binding.MutableBindings; import org.springframework.data.r2dbc.dialect.R2dbcDialect; -import org.springframework.data.r2dbc.mapping.SettableValue; import org.springframework.data.relational.core.dialect.Escaper; import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; +import org.springframework.data.relational.core.query.Update; import org.springframework.data.relational.core.query.ValueFunction; import org.springframework.data.relational.core.sql.AssignValue; import org.springframework.data.relational.core.sql.Assignment; @@ -38,7 +34,11 @@ import org.springframework.data.relational.core.sql.SqlIdentifier; import org.springframework.data.relational.core.sql.Table; import org.springframework.data.util.TypeInformation; import org.springframework.lang.Nullable; +import org.springframework.r2dbc.core.Parameter; import org.springframework.r2dbc.core.binding.BindMarker; +import org.springframework.r2dbc.core.binding.BindMarkers; +import org.springframework.r2dbc.core.binding.Bindings; +import org.springframework.r2dbc.core.binding.MutableBindings; import org.springframework.util.Assert; /** @@ -58,24 +58,6 @@ public class UpdateMapper extends QueryMapper { super(dialect, converter); } - /** - * Map a {@link Update} object to {@link BoundAssignments} and consider value/{@code NULL} {@link Bindings}. - * - * @param markers bind markers object, must not be {@literal null}. - * @param update update definition to map, must not be {@literal null}. - * @param table must not be {@literal null}. - * @param entity related {@link RelationalPersistentEntity}, can be {@literal null}. - * @return the mapped {@link BoundAssignments}. - * @deprecated since 1.1, use - * {@link #getMappedObject(BindMarkers, org.springframework.data.relational.core.query.Update, Table, RelationalPersistentEntity)} - * instead. - */ - @Deprecated - public BoundAssignments getMappedObject(BindMarkers markers, Update update, Table table, - @Nullable RelationalPersistentEntity entity) { - return getMappedObject(markers, update.getAssignments(), table, entity); - } - /** * Map a {@link org.springframework.data.relational.core.query.Update} object to {@link BoundAssignments} and consider * value/{@code NULL} {@link Bindings}. @@ -87,8 +69,7 @@ public class UpdateMapper extends QueryMapper { * @return the mapped {@link BoundAssignments}. * @since 1.1 */ - public BoundAssignments getMappedObject(BindMarkers markers, - org.springframework.data.relational.core.query.Update update, Table table, + public BoundAssignments getMappedObject(BindMarkers markers, Update update, Table table, @Nullable RelationalPersistentEntity entity) { return getMappedObject(markers, update.getAssignments(), table, entity); } @@ -130,14 +111,7 @@ public class UpdateMapper extends QueryMapper { Object mappedValue; Class typeHint; - if (value instanceof SettableValue) { - - SettableValue settableValue = (SettableValue) value; - - mappedValue = convertValue(settableValue.getValue(), propertyField.getTypeHint()); - typeHint = getTypeHint(mappedValue, actualType.getType(), settableValue); - - } else if (value instanceof Parameter) { + if (value instanceof Parameter) { Parameter parameter = (Parameter) value; diff --git a/src/main/java/org/springframework/data/r2dbc/repository/config/EnableR2dbcRepositories.java b/src/main/java/org/springframework/data/r2dbc/repository/config/EnableR2dbcRepositories.java index 808d9b93e..d6491fbb5 100644 --- a/src/main/java/org/springframework/data/r2dbc/repository/config/EnableR2dbcRepositories.java +++ b/src/main/java/org/springframework/data/r2dbc/repository/config/EnableR2dbcRepositories.java @@ -116,22 +116,9 @@ public @interface EnableR2dbcRepositories { */ Class repositoryBaseClass() default DefaultRepositoryBaseClass.class; - /** - * Configures the name of the {@link org.springframework.data.r2dbc.core.DatabaseClient} bean to be used with the - * repositories detected. - * - * @return - * @see #entityOperationsRef() - * @deprecated since 1.2, in favor of {@link #entityOperationsRef()}. - */ - @Deprecated - String databaseClientRef() default ""; - /** * Configures the name of the {@link org.springframework.data.r2dbc.core.R2dbcEntityOperations} bean to be used with - * the repositories detected. Used as alternative to {@link #databaseClientRef()} to configure an access strategy when - * using repositories with different database systems/dialects. If this attribute is set, then - * {@link #databaseClientRef()} is ignored. + * the repositories detected. * * @return * @since 1.1.3 diff --git a/src/main/java/org/springframework/data/r2dbc/repository/config/R2dbcRepositoryConfigurationExtension.java b/src/main/java/org/springframework/data/r2dbc/repository/config/R2dbcRepositoryConfigurationExtension.java index d00250fe1..485fe4998 100644 --- a/src/main/java/org/springframework/data/r2dbc/repository/config/R2dbcRepositoryConfigurationExtension.java +++ b/src/main/java/org/springframework/data/r2dbc/repository/config/R2dbcRepositoryConfigurationExtension.java @@ -29,7 +29,6 @@ import org.springframework.data.repository.config.RepositoryConfigurationExtensi import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport; import org.springframework.data.repository.config.XmlRepositoryConfigurationSource; import org.springframework.data.repository.core.RepositoryMetadata; -import org.springframework.util.StringUtils; /** * Reactive {@link RepositoryConfigurationExtension} for R2DBC. @@ -98,13 +97,7 @@ public class R2dbcRepositoryConfigurationExtension extends RepositoryConfigurati AnnotationAttributes attributes = config.getAttributes(); - String databaseClientRef = attributes.getString("databaseClientRef"); - if (StringUtils.hasText(databaseClientRef)) { - builder.addPropertyReference("databaseClient", attributes.getString("databaseClientRef")); - builder.addPropertyReference("dataAccessStrategy", "reactiveDataAccessStrategy"); - } else { - builder.addPropertyReference("entityOperations", attributes.getString("entityOperationsRef")); - } + builder.addPropertyReference("entityOperations", attributes.getString("entityOperationsRef")); } /* diff --git a/src/main/java/org/springframework/data/r2dbc/repository/query/ExpressionEvaluatingParameterBinder.java b/src/main/java/org/springframework/data/r2dbc/repository/query/ExpressionEvaluatingParameterBinder.java index f89532664..d67ea8e5b 100644 --- a/src/main/java/org/springframework/data/r2dbc/repository/query/ExpressionEvaluatingParameterBinder.java +++ b/src/main/java/org/springframework/data/r2dbc/repository/query/ExpressionEvaluatingParameterBinder.java @@ -128,8 +128,6 @@ class ExpressionEvaluatingParameterBinder { return dataAccessStrategy.getBindValue(parameter); } - - private org.springframework.r2dbc.core.Parameter getBindValue(org.springframework.r2dbc.core.Parameter bindValue) { return dataAccessStrategy.getBindValue(bindValue); } diff --git a/src/main/java/org/springframework/data/r2dbc/repository/query/StringBasedR2dbcQuery.java b/src/main/java/org/springframework/data/r2dbc/repository/query/StringBasedR2dbcQuery.java index 7548326c3..eeb6d4cea 100644 --- a/src/main/java/org/springframework/data/r2dbc/repository/query/StringBasedR2dbcQuery.java +++ b/src/main/java/org/springframework/data/r2dbc/repository/query/StringBasedR2dbcQuery.java @@ -28,7 +28,6 @@ import org.springframework.data.r2dbc.convert.R2dbcConverter; import org.springframework.data.r2dbc.core.R2dbcEntityOperations; import org.springframework.data.r2dbc.core.ReactiveDataAccessStrategy; import org.springframework.data.r2dbc.dialect.BindTargetBinder; -import org.springframework.data.r2dbc.mapping.SettableValue; import org.springframework.data.r2dbc.repository.Query; import org.springframework.data.relational.repository.query.RelationalParameterAccessor; import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider; @@ -202,12 +201,12 @@ public class StringBasedR2dbcQuery extends AbstractR2dbcQuery { if (recordedBindings.byName.containsKey(name)) { remainderByName.remove(name); - return SettableValue.fromParameter(recordedBindings.byName.get(name)); + return recordedBindings.byName.get(name); } if (recordedBindings.byIndex.containsKey(index)) { remainderByIndex.remove(index); - return SettableValue.fromParameter(recordedBindings.byIndex.get(index)); + return recordedBindings.byIndex.get(index); } return null; @@ -253,11 +252,6 @@ public class StringBasedR2dbcQuery extends AbstractR2dbcQuery { @NotNull private Parameter toParameter(Object value) { - - if (value instanceof SettableValue) { - return ((SettableValue) value).toParameter(); - } - return value instanceof Parameter ? (Parameter) value : Parameter.from(value); } diff --git a/src/main/java/org/springframework/data/r2dbc/repository/support/BindSpecAdapter.java b/src/main/java/org/springframework/data/r2dbc/repository/support/BindSpecAdapter.java deleted file mode 100644 index 658fa96b5..000000000 --- a/src/main/java/org/springframework/data/r2dbc/repository/support/BindSpecAdapter.java +++ /dev/null @@ -1,103 +0,0 @@ -package org.springframework.data.r2dbc.repository.support; - -import io.r2dbc.spi.Result; -import io.r2dbc.spi.Statement; - -import org.reactivestreams.Publisher; -import org.springframework.data.r2dbc.core.DatabaseClient.BindSpec; - -/** - * Adapter for {@link BindSpec} to be used with {@link org.springframework.data.r2dbc.dialect.BindMarker} binding. - * Binding parameters updates the {@link BindSpec} - * - * @param type of the bind specification. - * @author Mark Paluch - */ -class BindSpecAdapter> implements Statement { - - private S bindSpec; - - private BindSpecAdapter(S bindSpec) { - this.bindSpec = bindSpec; - } - - /** - * Create a new {@link BindSpecAdapter} for the given {@link BindSpec}. - * - * @param bindSpec the bind specification. - * @param type of the bind spec to retain the type through {@link #getBoundOperation()}. - * @return {@link BindSpecAdapter} for the {@link BindSpec}. - */ - public static > BindSpecAdapter create(S bindSpec) { - return new BindSpecAdapter<>(bindSpec); - } - - /* - * (non-Javadoc) - * @see io.r2dbc.spi.Statement#add() - */ - @Override - public BindSpecAdapter add() { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * @see io.r2dbc.spi.Statement#execute() - */ - @Override - public Publisher execute() { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * @see io.r2dbc.spi.Statement#bind(java.lang.Object, java.lang.Object) - */ - @Override - public BindSpecAdapter bind(String identifier, Object value) { - - this.bindSpec = bindSpec.bind(identifier, value); - return this; - } - - /* - * (non-Javadoc) - * @see io.r2dbc.spi.Statement#bind(int, java.lang.Object) - */ - @Override - public BindSpecAdapter bind(int index, Object value) { - - this.bindSpec = bindSpec.bind(index, value); - return this; - } - - /* - * (non-Javadoc) - * @see io.r2dbc.spi.Statement#bindNull(java.lang.Object, java.lang.Class) - */ - @Override - public BindSpecAdapter bindNull(String identifier, Class type) { - - this.bindSpec = bindSpec.bindNull(identifier, type); - return this; - } - - /* - * (non-Javadoc) - * @see io.r2dbc.spi.Statement#bindNull(int, java.lang.Class) - */ - @Override - public BindSpecAdapter bindNull(int index, Class type) { - - this.bindSpec = bindSpec.bindNull(index, type); - return this; - } - - /** - * @return the bound (final) bind specification. - */ - public S getBoundOperation() { - return bindSpec; - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/repository/support/SimpleR2dbcRepository.java b/src/main/java/org/springframework/data/r2dbc/repository/support/SimpleR2dbcRepository.java index 670277e50..f203c7f3e 100644 --- a/src/main/java/org/springframework/data/r2dbc/repository/support/SimpleR2dbcRepository.java +++ b/src/main/java/org/springframework/data/r2dbc/repository/support/SimpleR2dbcRepository.java @@ -105,29 +105,6 @@ public class SimpleR2dbcRepository implements R2dbcRepository { this.exampleMapper = new RelationalExampleMapper(converter.getMappingContext()); } - /** - * Create a new {@link SimpleR2dbcRepository}. - * - * @param entity - * @param databaseClient - * @param converter - * @param accessStrategy - * @deprecated since 1.2. - */ - @Deprecated - public SimpleR2dbcRepository(RelationalEntityInformation entity, - org.springframework.data.r2dbc.core.DatabaseClient databaseClient, R2dbcConverter converter, - ReactiveDataAccessStrategy accessStrategy) { - - this.entity = entity; - this.entityOperations = new R2dbcEntityTemplate(databaseClient, accessStrategy); - this.idProperty = Lazy.of(() -> converter // - .getMappingContext() // - .getRequiredPersistentEntity(this.entity.getJavaType()) // - .getRequiredIdProperty()); - this.exampleMapper = new RelationalExampleMapper(converter.getMappingContext()); - } - // ------------------------------------------------------------------------- // Methods from ReactiveCrudRepository // ------------------------------------------------------------------------- diff --git a/src/main/java/org/springframework/data/r2dbc/support/AbstractFallbackR2dbcExceptionTranslator.java b/src/main/java/org/springframework/data/r2dbc/support/AbstractFallbackR2dbcExceptionTranslator.java deleted file mode 100644 index 3a7cfb75d..000000000 --- a/src/main/java/org/springframework/data/r2dbc/support/AbstractFallbackR2dbcExceptionTranslator.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2018-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.support; - -import io.r2dbc.spi.R2dbcException; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.dao.DataAccessException; -import org.springframework.data.r2dbc.UncategorizedR2dbcException; -import org.springframework.lang.NonNull; -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; - -/** - * Base class for {@link R2dbcExceptionTranslator} implementations that allow for fallback to some other - * {@link R2dbcExceptionTranslator}. - * - * @author Mark Paluch - * @deprecated since 1.2. Use Spring R2DBC's - * {@link org.springframework.r2dbc.connection.ConnectionFactoryUtils#convertR2dbcException(String, String, R2dbcException)} - * instead. - */ -@Deprecated -public abstract class AbstractFallbackR2dbcExceptionTranslator implements R2dbcExceptionTranslator { - - /** Logger available to subclasses */ - protected final Log logger = LogFactory.getLog(getClass()); - - @Nullable private R2dbcExceptionTranslator fallbackTranslator; - - /** - * Override the default SQL state fallback translator (typically a {@link R2dbcExceptionTranslator}). - */ - public void setFallbackTranslator(@Nullable R2dbcExceptionTranslator fallback) { - this.fallbackTranslator = fallback; - } - - /** - * Return the fallback exception translator, if any. - */ - @Nullable - public R2dbcExceptionTranslator getFallbackTranslator() { - return this.fallbackTranslator; - } - - /** - * Pre-checks the arguments, calls {@link #doTranslate}, and invokes the {@link #getFallbackTranslator() fallback - * translator} if necessary. - */ - @Override - @NonNull - public DataAccessException translate(String task, @Nullable String sql, R2dbcException ex) { - - Assert.notNull(ex, "Cannot translate a null R2dbcException"); - - DataAccessException dae = doTranslate(task, sql, ex); - if (dae != null) { - // Specific exception match found. - return dae; - } - - // Looking for a fallback... - R2dbcExceptionTranslator fallback = getFallbackTranslator(); - if (fallback != null) { - dae = fallback.translate(task, sql, ex); - if (dae != null) { - // Fallback exception match found. - return dae; - } - } - - // We couldn't identify it more precisely. - return new UncategorizedR2dbcException(task, sql, ex); - } - - /** - * Template method for actually translating the given exception. - *

- * The passed-in arguments will have been pre-checked. Furthermore, this method is allowed to return {@literal null} - * to indicate that no exception match has been found and that fallback translation should kick in. - * - * @param task readable text describing the task being attempted. - * @param sql SQL query or update that caused the problem (if known). - * @param ex the offending {@link R2dbcException}. - * @return the DataAccessException, wrapping the {@link R2dbcException}; or {@literal null} if no exception match - * found. - */ - @Nullable - protected abstract DataAccessException doTranslate(String task, @Nullable String sql, R2dbcException ex); - - /** - * Build a message {@code String} for the given {@link R2dbcException}. - *

- * To be called by translator subclasses when creating an instance of a generic - * {@link org.springframework.dao.DataAccessException} class. - * - * @param task readable text describing the task being attempted. - * @param sql the SQL statement that caused the problem. - * @param ex the offending {@link R2dbcException}. - * @return the message {@code String} to use. - */ - protected String buildMessage(String task, @Nullable String sql, R2dbcException ex) { - - return task + "; " + // - (sql != null // - ? "SQL [" + sql + "]; " // - : "" // - ) + ex.getMessage(); - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/support/R2dbcExceptionSubclassTranslator.java b/src/main/java/org/springframework/data/r2dbc/support/R2dbcExceptionSubclassTranslator.java deleted file mode 100644 index e6a3a180e..000000000 --- a/src/main/java/org/springframework/data/r2dbc/support/R2dbcExceptionSubclassTranslator.java +++ /dev/null @@ -1,95 +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.support; - -import io.r2dbc.spi.R2dbcBadGrammarException; -import io.r2dbc.spi.R2dbcDataIntegrityViolationException; -import io.r2dbc.spi.R2dbcException; -import io.r2dbc.spi.R2dbcNonTransientException; -import io.r2dbc.spi.R2dbcNonTransientResourceException; -import io.r2dbc.spi.R2dbcPermissionDeniedException; -import io.r2dbc.spi.R2dbcRollbackException; -import io.r2dbc.spi.R2dbcTimeoutException; -import io.r2dbc.spi.R2dbcTransientException; -import io.r2dbc.spi.R2dbcTransientResourceException; - -import org.springframework.dao.ConcurrencyFailureException; -import org.springframework.dao.DataAccessException; -import org.springframework.dao.DataAccessResourceFailureException; -import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.dao.PermissionDeniedDataAccessException; -import org.springframework.dao.QueryTimeoutException; -import org.springframework.dao.TransientDataAccessResourceException; -import org.springframework.data.r2dbc.BadSqlGrammarException; -import org.springframework.lang.Nullable; - -/** - * {@link R2dbcExceptionTranslator} implementation which analyzes the specific {@link R2dbcException} subclass thrown by - * the R2DBC driver. - *

- * Falls back to a standard {@link SqlStateR2dbcExceptionTranslator}. - * - * @author Mark Paluch - * @deprecated since 1.2. Use Spring R2DBC's - * {@link org.springframework.r2dbc.connection.ConnectionFactoryUtils#convertR2dbcException(String, String, R2dbcException)} - * instead. - */ -@Deprecated -public class R2dbcExceptionSubclassTranslator extends AbstractFallbackR2dbcExceptionTranslator { - - public R2dbcExceptionSubclassTranslator() { - setFallbackTranslator(new SqlStateR2dbcExceptionTranslator()); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.r2dbc.support.AbstractFallbackR2dbcExceptionTranslator#doTranslate(java.lang.String, java.lang.String, io.r2dbc.spi.R2dbcException) - */ - @Override - @Nullable - protected DataAccessException doTranslate(String task, @Nullable String sql, R2dbcException ex) { - - if (ex instanceof R2dbcTransientException) { - if (ex instanceof R2dbcTransientResourceException) { - return new TransientDataAccessResourceException(buildMessage(task, sql, ex), ex); - } - if (ex instanceof R2dbcRollbackException) { - return new ConcurrencyFailureException(buildMessage(task, sql, ex), ex); - } - if (ex instanceof R2dbcTimeoutException) { - return new QueryTimeoutException(buildMessage(task, sql, ex), ex); - } - } - - if (ex instanceof R2dbcNonTransientException) { - if (ex instanceof R2dbcNonTransientResourceException) { - return new DataAccessResourceFailureException(buildMessage(task, sql, ex), ex); - } - if (ex instanceof R2dbcDataIntegrityViolationException) { - return new DataIntegrityViolationException(buildMessage(task, sql, ex), ex); - } - if (ex instanceof R2dbcPermissionDeniedException) { - return new PermissionDeniedDataAccessException(buildMessage(task, sql, ex), ex); - } - if (ex instanceof R2dbcBadGrammarException) { - return new BadSqlGrammarException(task, (sql != null ? sql : ""), ex); - } - } - - // Fallback to Spring's own R2DBC state translation... - return null; - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/support/R2dbcExceptionTranslator.java b/src/main/java/org/springframework/data/r2dbc/support/R2dbcExceptionTranslator.java deleted file mode 100644 index c175c3d8b..000000000 --- a/src/main/java/org/springframework/data/r2dbc/support/R2dbcExceptionTranslator.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2018-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.support; - -import io.r2dbc.spi.R2dbcException; - -import org.springframework.dao.DataAccessException; -import org.springframework.lang.Nullable; - -/** - * Strategy interface for translating between {@link io.r2dbc.spi.R2dbcException R2dbcExceptions} and Spring's data - * access strategy-agnostic {@link DataAccessException} hierarchy. - *

- * Implementations can be generic (for example, using {@link io.r2dbc.spi.R2dbcException#getSqlState() SQLState} codes - * for R2DBC) or wholly proprietary (for example, using Oracle error codes) for greater precision. - * - * @author Mark Paluch - * @see org.springframework.dao.DataAccessException - * @see SqlStateR2dbcExceptionTranslator - * @see SqlErrorCodeR2dbcExceptionTranslator - * @deprecated since 1.2. Use Spring R2DBC's - * {@link org.springframework.r2dbc.connection.ConnectionFactoryUtils#convertR2dbcException(String, String, R2dbcException)} - * instead. - */ -@FunctionalInterface -@Deprecated -public interface R2dbcExceptionTranslator { - - /** - * Translate the given {@link R2dbcException} into a generic {@link DataAccessException}. - *

- * The returned DataAccessException is supposed to contain the original {@link R2dbcException} as root cause. However, - * client code may not generally rely on this due to DataAccessExceptions possibly being caused by other resource APIs - * as well. That said, a {@code getRootCause() instanceof R2dbcException} check (and subsequent cast) is considered - * reliable when expecting R2DBC-based access to have happened. - * - * @param task readable text describing the task being attempted. - * @param sql SQL query or update that caused the problem (if known). - * @param ex the offending {@link R2dbcException}. - * @return the DataAccessException wrapping the {@code R2dbcException}, or {@literal null} if no translation could be - * applied (in a custom translator; the default translators always throw an - * {@link org.springframework.data.r2dbc.UncategorizedR2dbcException} in such a case). - * @see org.springframework.dao.DataAccessException#getRootCause() - */ - @Nullable - DataAccessException translate(String task, @Nullable String sql, R2dbcException ex); - -} diff --git a/src/main/java/org/springframework/data/r2dbc/support/SqlErrorCodeR2dbcExceptionTranslator.java b/src/main/java/org/springframework/data/r2dbc/support/SqlErrorCodeR2dbcExceptionTranslator.java deleted file mode 100644 index 4a631bcac..000000000 --- a/src/main/java/org/springframework/data/r2dbc/support/SqlErrorCodeR2dbcExceptionTranslator.java +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright 2018-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.support; - -import io.r2dbc.spi.ConnectionFactory; -import io.r2dbc.spi.R2dbcException; - -import java.sql.SQLException; -import java.util.Arrays; - -import org.springframework.dao.CannotAcquireLockException; -import org.springframework.dao.CannotSerializeTransactionException; -import org.springframework.dao.DataAccessException; -import org.springframework.dao.DataAccessResourceFailureException; -import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.dao.DeadlockLoserDataAccessException; -import org.springframework.dao.DuplicateKeyException; -import org.springframework.dao.PermissionDeniedDataAccessException; -import org.springframework.dao.TransientDataAccessResourceException; -import org.springframework.data.r2dbc.BadSqlGrammarException; -import org.springframework.data.r2dbc.InvalidResultAccessException; -import org.springframework.jdbc.support.SQLErrorCodes; -import org.springframework.jdbc.support.SQLErrorCodesFactory; -import org.springframework.jdbc.support.SQLExceptionTranslator; -import org.springframework.lang.Nullable; - -/** - * Implementation of {@link R2dbcExceptionTranslator} that analyzes vendor-specific error codes. More precise than an - * implementation based on SQL state, but heavily vendor-specific. - *

- * This class applies the following matching rules: - *

    - *
  • Try custom translation implemented by any subclass. Note that this class is concrete and is typically used - * itself, in which case this rule doesn't apply. - *
  • Apply error code matching. Error codes are obtained from the SQLErrorCodesFactory by default. This factory loads - * a "sql-error-codes.xml" file from the class path, defining error code mappings for database names from database - * meta-data. - *
  • Fallback to a fallback translator. {@link SqlStateR2dbcExceptionTranslator} is the default fallback translator, - * analyzing the exception's SQL state only. - *
- *

- * The configuration file named "sql-error-codes.xml" is by default read from the - * {@code org.springframework.jdbc.support} package. It can be overridden through a file of the same name in the root of - * the class path (e.g. in the "/WEB-INF/classes" directory), as long as the Spring JDBC package is loaded from the same - * ClassLoader. - * - * @author Mark Paluch - * @see SQLErrorCodesFactory - * @see SqlStateR2dbcExceptionTranslator - * @deprecated since 1.2. Use Spring R2DBC's - * {@link org.springframework.r2dbc.connection.ConnectionFactoryUtils#convertR2dbcException(String, String, R2dbcException)} - * instead. - */ -@Deprecated -public class SqlErrorCodeR2dbcExceptionTranslator extends AbstractFallbackR2dbcExceptionTranslator { - - /** Error codes used by this translator */ - @Nullable private SQLErrorCodes sqlErrorCodes; - - /** - * Creates a new {@link SqlErrorCodeR2dbcExceptionTranslator}. The {@link SQLErrorCodes} or - * {@link io.r2dbc.spi.ConnectionFactory} property must be set. - */ - public SqlErrorCodeR2dbcExceptionTranslator() {} - - /** - * Create a SQL error code translator for the given DataSource. Invoking this constructor will cause a Connection to - * be obtained from the DataSource to get the meta-data. - * - * @param connectionFactory {@link ConnectionFactory} to use to find meta-data and establish which error codes are - * usable. - * @see SQLErrorCodesFactory - */ - public SqlErrorCodeR2dbcExceptionTranslator(ConnectionFactory connectionFactory) { - this(); - setConnectionFactory(connectionFactory); - } - - /** - * Create a SQL error code translator for the given database product name. Invoking this constructor will avoid - * obtaining a Connection from the DataSource to get the meta-data. - * - * @param dbName the database product name that identifies the error codes entry - * @see SQLErrorCodesFactory - * @see java.sql.DatabaseMetaData#getDatabaseProductName() - */ - public SqlErrorCodeR2dbcExceptionTranslator(String dbName) { - this(); - setDatabaseProductName(dbName); - } - - /** - * Create a SQLErrorCode translator given these error codes. Does not require a database meta-data lookup to be - * performed using a connection. - * - * @param sec error codes - */ - public SqlErrorCodeR2dbcExceptionTranslator(@Nullable SQLErrorCodes sec) { - this(); - this.sqlErrorCodes = sec; - } - - /** - * Set the DataSource for this translator. - *

- * Setting this property will cause a Connection to be obtained from the DataSource to get the meta-data. - * - * @param connectionFactory {@link ConnectionFactory} to use to find meta-data and establish which error codes are - * usable. - * @see SQLErrorCodesFactory#getErrorCodes(String) - * @see io.r2dbc.spi.ConnectionFactoryMetadata#getName() - */ - public void setConnectionFactory(ConnectionFactory connectionFactory) { - this.sqlErrorCodes = SQLErrorCodesFactory.getInstance().getErrorCodes(connectionFactory.getMetadata().getName()); - } - - /** - * Set the database product name for this translator. - *

- * Setting this property will avoid obtaining a Connection from the DataSource to get the meta-data. - * - * @param dbName the database product name that identifies the error codes entry. - * @see SQLErrorCodesFactory#getErrorCodes(String) - * @see io.r2dbc.spi.ConnectionFactoryMetadata#getName() - */ - public void setDatabaseProductName(String dbName) { - this.sqlErrorCodes = SQLErrorCodesFactory.getInstance().getErrorCodes(dbName); - } - - /** - * Set custom error codes to be used for translation. - * - * @param sec custom error codes to use. - */ - public void setSqlErrorCodes(@Nullable SQLErrorCodes sec) { - this.sqlErrorCodes = sec; - } - - /** - * Return the error codes used by this translator. Usually determined via a DataSource. - * - * @see #setConnectionFactory - */ - @Nullable - public SQLErrorCodes getSqlErrorCodes() { - return this.sqlErrorCodes; - } - - @Override - @Nullable - protected DataAccessException doTranslate(String task, @Nullable String sql, R2dbcException ex) { - - R2dbcException translated = ex; - - // First, try custom translation from overridden method. - DataAccessException dex = customTranslate(task, sql, translated); - if (dex != null) { - return dex; - } - - // Next, try the custom SQLExceptionTranslator, if available. - if (this.sqlErrorCodes != null) { - SQLExceptionTranslator customTranslator = this.sqlErrorCodes.getCustomSqlExceptionTranslator(); - if (customTranslator != null) { - DataAccessException customDex = customTranslator.translate(task, sql, - new SQLException(ex.getMessage(), ex.getSqlState(), ex)); - if (customDex != null) { - return customDex; - } - } - } - - // Check SQLErrorCodes with corresponding error code, if available. - if (this.sqlErrorCodes != null) { - String errorCode; - if (this.sqlErrorCodes.isUseSqlStateForTranslation()) { - errorCode = translated.getSqlState(); - } else { - // Try to find R2dbcException with actual error code, looping through the causes. - R2dbcException current = translated; - while (current.getErrorCode() == 0 && current.getCause() instanceof R2dbcException) { - current = (R2dbcException) current.getCause(); - } - errorCode = Integer.toString(current.getErrorCode()); - } - - if (errorCode != null) { - // Look for grouped error codes. - if (Arrays.binarySearch(this.sqlErrorCodes.getBadSqlGrammarCodes(), errorCode) >= 0) { - logTranslation(task, sql, translated); - return new BadSqlGrammarException(task, (sql != null ? sql : ""), translated); - } else if (Arrays.binarySearch(this.sqlErrorCodes.getInvalidResultSetAccessCodes(), errorCode) >= 0) { - logTranslation(task, sql, translated); - return new InvalidResultAccessException(task, (sql != null ? sql : ""), translated); - } else if (Arrays.binarySearch(this.sqlErrorCodes.getDuplicateKeyCodes(), errorCode) >= 0) { - logTranslation(task, sql, translated); - return new DuplicateKeyException(buildMessage(task, sql, translated), translated); - } else if (Arrays.binarySearch(this.sqlErrorCodes.getDataIntegrityViolationCodes(), errorCode) >= 0) { - logTranslation(task, sql, translated); - return new DataIntegrityViolationException(buildMessage(task, sql, translated), translated); - } else if (Arrays.binarySearch(this.sqlErrorCodes.getPermissionDeniedCodes(), errorCode) >= 0) { - logTranslation(task, sql, translated); - return new PermissionDeniedDataAccessException(buildMessage(task, sql, translated), translated); - } else if (Arrays.binarySearch(this.sqlErrorCodes.getDataAccessResourceFailureCodes(), errorCode) >= 0) { - logTranslation(task, sql, translated); - return new DataAccessResourceFailureException(buildMessage(task, sql, translated), translated); - } else if (Arrays.binarySearch(this.sqlErrorCodes.getTransientDataAccessResourceCodes(), errorCode) >= 0) { - logTranslation(task, sql, translated); - return new TransientDataAccessResourceException(buildMessage(task, sql, translated), translated); - } else if (Arrays.binarySearch(this.sqlErrorCodes.getCannotAcquireLockCodes(), errorCode) >= 0) { - logTranslation(task, sql, translated); - return new CannotAcquireLockException(buildMessage(task, sql, translated), translated); - } else if (Arrays.binarySearch(this.sqlErrorCodes.getDeadlockLoserCodes(), errorCode) >= 0) { - logTranslation(task, sql, translated); - return new DeadlockLoserDataAccessException(buildMessage(task, sql, translated), translated); - } else if (Arrays.binarySearch(this.sqlErrorCodes.getCannotSerializeTransactionCodes(), errorCode) >= 0) { - logTranslation(task, sql, translated); - return new CannotSerializeTransactionException(buildMessage(task, sql, translated), translated); - } - } - } - - // We couldn't identify it more precisely - let's hand it over to the SQLState fallback translator. - if (logger.isDebugEnabled()) { - String codes; - if (this.sqlErrorCodes != null && this.sqlErrorCodes.isUseSqlStateForTranslation()) { - codes = "SQL state '" + translated.getSqlState() + "', error code '" + translated.getErrorCode(); - } else { - codes = "Error code '" + translated.getErrorCode() + "'"; - } - logger.debug("Unable to translate R2dbcException with " + codes + ", will now try the fallback translator"); - } - - return null; - } - - /** - * Subclasses can override this method to attempt a custom mapping from {@link R2dbcException} to - * {@link DataAccessException}. - * - * @param task readable text describing the task being attempted - * @param sql SQL query or update that caused the problem. May be {@literal null}. - * @param ex the offending {@link R2dbcException}. - * @return null if no custom translation was possible, otherwise a {@link DataAccessException} resulting from custom - * translation. This exception should include the {@link R2dbcException} parameter as a nested root cause. - * This implementation always returns null, meaning that the translator always falls back to the default error - * codes. - */ - @Nullable - protected DataAccessException customTranslate(String task, @Nullable String sql, R2dbcException ex) { - return null; - } - - private void logTranslation(String task, @Nullable String sql, R2dbcException exception) { - - if (logger.isDebugEnabled()) { - - String intro = "Translating"; - logger.debug(intro + " R2dbcException with SQL state '" + exception.getSqlState() + "', error code '" - + exception.getErrorCode() + "', message [" + exception.getMessage() + "]" - + (sql != null ? "; SQL was [" + sql + "]" : "") + " for task [" + task + "]"); - } - } -} diff --git a/src/main/java/org/springframework/data/r2dbc/support/SqlStateR2dbcExceptionTranslator.java b/src/main/java/org/springframework/data/r2dbc/support/SqlStateR2dbcExceptionTranslator.java deleted file mode 100644 index 5597640e3..000000000 --- a/src/main/java/org/springframework/data/r2dbc/support/SqlStateR2dbcExceptionTranslator.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2018-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.support; - -import io.r2dbc.spi.R2dbcException; - -import java.util.HashSet; -import java.util.Set; - -import org.springframework.dao.ConcurrencyFailureException; -import org.springframework.dao.DataAccessException; -import org.springframework.dao.DataAccessResourceFailureException; -import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.dao.TransientDataAccessResourceException; -import org.springframework.data.r2dbc.BadSqlGrammarException; -import org.springframework.lang.Nullable; - -/** - * {@link R2dbcExceptionTranslator} implementation that analyzes the SQL state in the {@link R2dbcException} based on - * the first two digits (the SQL state "class"). Detects standard SQL state values and well-known vendor-specific SQL - * states. - *

- * Not able to diagnose all problems, but is portable between databases and does not require special initialization (no - * database vendor detection, etc.). For more precise translation, consider - * {@link SqlErrorCodeR2dbcExceptionTranslator}. - * - * @author Mark Paluch - * @see io.r2dbc.spi.R2dbcException#getSqlState() - * @see SqlErrorCodeR2dbcExceptionTranslator - * @deprecated since 1.2. Use Spring R2DBC's - * {@link org.springframework.r2dbc.connection.ConnectionFactoryUtils#convertR2dbcException(String, String, R2dbcException)} - * instead. - */ -@Deprecated -public class SqlStateR2dbcExceptionTranslator extends AbstractFallbackR2dbcExceptionTranslator { - - private static final Set BAD_SQL_GRAMMAR_CODES = new HashSet<>(8); - private static final Set DATA_INTEGRITY_VIOLATION_CODES = new HashSet<>(8); - private static final Set DATA_ACCESS_RESOURCE_FAILURE_CODES = new HashSet<>(8); - private static final Set TRANSIENT_DATA_ACCESS_RESOURCE_CODES = new HashSet<>(8); - private static final Set CONCURRENCY_FAILURE_CODES = new HashSet<>(4); - - static { - BAD_SQL_GRAMMAR_CODES.add("07"); // Dynamic SQL error - BAD_SQL_GRAMMAR_CODES.add("21"); // Cardinality violation - BAD_SQL_GRAMMAR_CODES.add("2A"); // Syntax error direct SQL - BAD_SQL_GRAMMAR_CODES.add("37"); // Syntax error dynamic SQL - BAD_SQL_GRAMMAR_CODES.add("42"); // General SQL syntax error - BAD_SQL_GRAMMAR_CODES.add("65"); // Oracle: unknown identifier - - DATA_INTEGRITY_VIOLATION_CODES.add("01"); // Data truncation - DATA_INTEGRITY_VIOLATION_CODES.add("02"); // No data found - DATA_INTEGRITY_VIOLATION_CODES.add("22"); // Value out of range - DATA_INTEGRITY_VIOLATION_CODES.add("23"); // Integrity constraint violation - DATA_INTEGRITY_VIOLATION_CODES.add("27"); // Triggered data change violation - DATA_INTEGRITY_VIOLATION_CODES.add("44"); // With check violation - - DATA_ACCESS_RESOURCE_FAILURE_CODES.add("08"); // Connection exception - DATA_ACCESS_RESOURCE_FAILURE_CODES.add("53"); // PostgreSQL: insufficient resources (e.g. disk full) - DATA_ACCESS_RESOURCE_FAILURE_CODES.add("54"); // PostgreSQL: program limit exceeded (e.g. statement too complex) - DATA_ACCESS_RESOURCE_FAILURE_CODES.add("57"); // DB2: out-of-memory exception / database not started - DATA_ACCESS_RESOURCE_FAILURE_CODES.add("58"); // DB2: unexpected system error - - TRANSIENT_DATA_ACCESS_RESOURCE_CODES.add("JW"); // Sybase: internal I/O error - TRANSIENT_DATA_ACCESS_RESOURCE_CODES.add("JZ"); // Sybase: unexpected I/O error - TRANSIENT_DATA_ACCESS_RESOURCE_CODES.add("S1"); // DB2: communication failure - - CONCURRENCY_FAILURE_CODES.add("40"); // Transaction rollback - CONCURRENCY_FAILURE_CODES.add("61"); // Oracle: deadlock - } - - @Override - @Nullable - protected DataAccessException doTranslate(String task, @Nullable String sql, R2dbcException ex) { - - // First, the getSQLState check... - String sqlState = getSqlState(ex); - if (sqlState != null && sqlState.length() >= 2) { - - String classCode = sqlState.substring(0, 2); - - if (logger.isDebugEnabled()) { - logger.debug("Extracted SQL state class '" + classCode + "' from value '" + sqlState + "'"); - } - - if (BAD_SQL_GRAMMAR_CODES.contains(classCode)) { - return new BadSqlGrammarException(task, (sql != null ? sql : ""), ex); - } else if (DATA_INTEGRITY_VIOLATION_CODES.contains(classCode)) { - return new DataIntegrityViolationException(buildMessage(task, sql, ex), ex); - } else if (DATA_ACCESS_RESOURCE_FAILURE_CODES.contains(classCode)) { - return new DataAccessResourceFailureException(buildMessage(task, sql, ex), ex); - } else if (TRANSIENT_DATA_ACCESS_RESOURCE_CODES.contains(classCode)) { - return new TransientDataAccessResourceException(buildMessage(task, sql, ex), ex); - } else if (CONCURRENCY_FAILURE_CODES.contains(classCode)) { - return new ConcurrencyFailureException(buildMessage(task, sql, ex), ex); - } - } - - // Couldn't resolve anything proper - resort to UncategorizedR2dbcException. - return null; - } - - /** - * Gets the SQL state code from the supplied {@link R2dbcException exception}. - *

- * Some R2DBC drivers nest the actual exception from a batched update, so we might need to dig down into the nested - * exception. - * - * @param ex the exception from which the {@link R2dbcException#getSqlState() SQL state} is to be extracted. - * @return the SQL state code. - */ - @Nullable - private String getSqlState(R2dbcException ex) { - - String sqlState = ex.getSqlState(); - - if (sqlState == null) { - - for (Throwable throwable : ex.getSuppressed()) { - - if (!(throwable instanceof R2dbcException)) { - continue; - } - - R2dbcException r2dbcException = (R2dbcException) throwable; - if (r2dbcException.getSqlState() != null) { - sqlState = r2dbcException.getSqlState(); - break; - } - } - } - - return sqlState; - } -} diff --git a/src/main/kotlin/org/springframework/data/r2dbc/core/CriteriaStepExtensions.kt b/src/main/kotlin/org/springframework/data/r2dbc/core/CriteriaStepExtensions.kt deleted file mode 100644 index 376d3759e..000000000 --- a/src/main/kotlin/org/springframework/data/r2dbc/core/CriteriaStepExtensions.kt +++ /dev/null @@ -1,49 +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 org.springframework.data.r2dbc.query.Criteria - -/** - * Extension for [Criteria.CriteriaStep. is] providing a - * `eq(value)` variant. - * - * @author Jonas Bark - */ -@Deprecated("Deprecated in favor of Spring Data Relational's Criteria") -infix fun Criteria.CriteriaStep.isEquals(value: Any): Criteria = - `is`(value) - -/** - * Extension for [Criteria.CriteriaStep. in] providing a - * `isIn(value)` variant. - * - * @author Jonas Bark - */ -@Deprecated("Deprecated in favor of Spring Data Relational's Criteria") -fun Criteria.CriteriaStep.isIn(vararg value: Any): Criteria = - `in`(value) - -/** - * Extension for [Criteria.CriteriaStep. in] providing a - * `isIn(value)` variant. - * - * @author Jonas Bark - */ -@Deprecated("Deprecated in favor of Spring Data Relational's Criteria") -fun Criteria.CriteriaStep.isIn(values: Collection): Criteria = - `in`(values) - diff --git a/src/main/kotlin/org/springframework/data/r2dbc/core/DatabaseClientExtensions.kt b/src/main/kotlin/org/springframework/data/r2dbc/core/DatabaseClientExtensions.kt deleted file mode 100644 index 9ffe413bc..000000000 --- a/src/main/kotlin/org/springframework/data/r2dbc/core/DatabaseClientExtensions.kt +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright 2018-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 kotlinx.coroutines.reactive.awaitFirstOrNull -import org.springframework.data.r2dbc.mapping.SettableValue - -/** - * Coroutines variant of [DatabaseClient.GenericExecuteSpec.then]. - * - * @author Sebastien Deleuze - */ -@Deprecated("Deprecated in favor of Spring R2DBC's DatabaseClient") -suspend fun DatabaseClient.GenericExecuteSpec.await() { - then().awaitFirstOrNull() -} - -/** - * Extension for [DatabaseClient.BindSpec.bind] providing a variant leveraging reified type parameters - * - * @author Mark Paluch - * @author Ibanga Enoobong Ime - */ -@Suppress("EXTENSION_SHADOWED_BY_MEMBER") -@Deprecated("Deprecated in favor of Spring R2DBC's DatabaseClient") -inline fun DatabaseClient.TypedExecuteSpec<*>.bind(index: Int, value: T?) = bind(index, SettableValue.fromOrEmpty(value, T::class.java)) - -/** - * Extension for [DatabaseClient.BindSpec.bind] providing a variant leveraging reified type parameters - * - * @author Mark Paluch - * @author Ibanga Enoobong Ime - */ -@Suppress("EXTENSION_SHADOWED_BY_MEMBER") -@Deprecated("Deprecated in favor of Spring R2DBC's DatabaseClient") -inline fun DatabaseClient.GenericExecuteSpec.bind(index: Int, value: T?) = bind(index, SettableValue.fromOrEmpty(value, T::class.java)) - -/** - * Extension for [DatabaseClient.BindSpec.bind] providing a variant leveraging reified type parameters - * - * @author Mark Paluch - * @author Ibanga Enoobong Ime - */ -@Suppress("EXTENSION_SHADOWED_BY_MEMBER") -@Deprecated("Deprecated in favor of Spring R2DBC's DatabaseClient") -inline fun DatabaseClient.TypedExecuteSpec<*>.bind(name: String, value: T?) = bind(name, SettableValue.fromOrEmpty(value, T::class.java)) - -/** - * Extension for [DatabaseClient.BindSpec.bind] providing a variant leveraging reified type parameters - * - * @author Mark Paluch - * @author Ibanga Enoobong Ime - */ -@Suppress("EXTENSION_SHADOWED_BY_MEMBER") -@Deprecated("Deprecated in favor of Spring R2DBC's DatabaseClient") -inline fun DatabaseClient.GenericExecuteSpec.bind(name: String, value: T?) = bind(name, SettableValue.fromOrEmpty(value, T::class.java)) - -/** - * Extension for [DatabaseClient.GenericExecuteSpec. as] providing a - * `asType()` variant. - * - * @author Sebastien Deleuze - */ -@Deprecated("Deprecated in favor of Spring R2DBC's DatabaseClient") -inline fun DatabaseClient.GenericExecuteSpec.asType(): DatabaseClient.TypedExecuteSpec = - `as`(T::class.java) - -/** - * Extension for [DatabaseClient.GenericSelectSpec.as] providing a - * `asType()` variant. - * - * @author Sebastien Deleuze - */ -@Deprecated("Deprecated in favor of Spring R2DBC's DatabaseClient") -inline fun DatabaseClient.GenericSelectSpec.asType(): DatabaseClient.TypedSelectSpec = - `as`(T::class.java) - -/** - * Coroutines variant of [DatabaseClient.TypedExecuteSpec.then]. - * - * @author Sebastien Deleuze - */ -@Deprecated("Deprecated in favor of Spring R2DBC's DatabaseClient") -suspend fun DatabaseClient.TypedExecuteSpec.await() { - then().awaitFirstOrNull() -} - -/** - * Extension for [DatabaseClient.TypedExecuteSpec. as] providing a - * `asType()` variant. - * - * @author Sebastien Deleuze - */ -@Deprecated("Deprecated in favor of Spring R2DBC's DatabaseClient") -inline fun DatabaseClient.TypedExecuteSpec.asType(): DatabaseClient.TypedExecuteSpec = - `as`(T::class.java) - -/** - * Coroutines variant of [DatabaseClient.InsertSpec.then]. - * - * @author Sebastien Deleuze - */ -@Deprecated("Deprecated in favor of Spring R2DBC's DatabaseClient") -suspend fun DatabaseClient.InsertSpec.await() { - then().awaitFirstOrNull() -} - -/** - * Extension for [DatabaseClient.InsertIntoSpec.into] providing a - * `into()` variant. - * - * @author Sebastien Deleuze - */ -@Deprecated("Deprecated in favor of Spring R2DBC's DatabaseClient") -inline fun DatabaseClient.InsertIntoSpec.into(): DatabaseClient.TypedInsertSpec = - into(T::class.java) - -/** - * Extension for [DatabaseClient.GenericInsertSpec.value] providing a variant leveraging reified type parameters - * - * @author Mark Paluch - */ -@Suppress("EXTENSION_SHADOWED_BY_MEMBER") -@Deprecated("Deprecated in favor of Spring R2DBC's DatabaseClient") -inline fun DatabaseClient.GenericInsertSpec<*>.value(name: String, value: T?) = value(name, SettableValue.fromOrEmpty(value, T::class.java)) - - -/** - * Extension for [DatabaseClient.SelectFromSpec.from] providing a - * `from()` variant. - * - * @author Jonas Bark - */ -@Deprecated("Deprecated in favor of Spring R2DBC's DatabaseClient") -inline fun DatabaseClient.SelectFromSpec.from(): DatabaseClient.TypedSelectSpec = - from(T::class.java) - -/** - * Extension for [DatabaseClient.UpdateTableSpec.table] providing a - * `table()` variant. - * - * @author Mark Paluch - */ -@Deprecated("Deprecated in favor of Spring R2DBC's DatabaseClient") -inline fun DatabaseClient.UpdateTableSpec.table(): DatabaseClient.TypedUpdateSpec = - table(T::class.java) - -/** - * Extension for [DatabaseClient.SelectFromSpec.from] providing a - * `from()` variant. - * - * @author Jonas Bark - */ -@Deprecated("Deprecated in favor of Spring R2DBC's DatabaseClient") -inline fun DatabaseClient.DeleteFromSpec.from(): DatabaseClient.TypedDeleteSpec = - from(T::class.java) diff --git a/src/main/kotlin/org/springframework/data/r2dbc/core/RowsFetchSpecExtensions.kt b/src/main/kotlin/org/springframework/data/r2dbc/core/RowsFetchSpecExtensions.kt deleted file mode 100644 index b43c9ec05..000000000 --- a/src/main/kotlin/org/springframework/data/r2dbc/core/RowsFetchSpecExtensions.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2018-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 kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.reactive.asFlow -import kotlinx.coroutines.reactive.awaitFirstOrNull -import org.springframework.dao.EmptyResultDataAccessException - -/** - * Non-nullable Coroutines variant of [RowsFetchSpec.one]. - * - * @author Sebastien Deleuze - */ -suspend fun RowsFetchSpec.awaitOne(): T { - return one().awaitFirstOrNull() ?: throw EmptyResultDataAccessException(1) -} - -/** - * Nullable Coroutines variant of [RowsFetchSpec.one]. - * - * @author Sebastien Deleuze - */ -suspend fun RowsFetchSpec.awaitOneOrNull(): T? = - one().awaitFirstOrNull() - -/** - * Non-nullable Coroutines variant of [RowsFetchSpec.first]. - * - * @author Sebastien Deleuze - */ -suspend fun RowsFetchSpec.awaitFirst(): T { - return first().awaitFirstOrNull() ?: throw EmptyResultDataAccessException(1) -} - -/** - * Nullable Coroutines variant of [RowsFetchSpec.first]. - * - * @author Sebastien Deleuze - */ -suspend fun RowsFetchSpec.awaitFirstOrNull(): T? = - first().awaitFirstOrNull() - -/** - * Coroutines [Flow] variant of [RowsFetchSpec.all]. - * - * @author Sebastien Deleuze - */ -fun RowsFetchSpec.flow(): Flow = all().asFlow() diff --git a/src/main/kotlin/org/springframework/data/r2dbc/core/UpdatedRowsFetchSpecExtensions.kt b/src/main/kotlin/org/springframework/data/r2dbc/core/UpdatedRowsFetchSpecExtensions.kt deleted file mode 100644 index 616895634..000000000 --- a/src/main/kotlin/org/springframework/data/r2dbc/core/UpdatedRowsFetchSpecExtensions.kt +++ /dev/null @@ -1,26 +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 kotlinx.coroutines.reactive.awaitSingle - -/** - * Coroutines variant of [UpdatedRowsFetchSpec.rowsUpdated]. - * - * @author Fred Montariol - */ -suspend fun UpdatedRowsFetchSpec.awaitRowsUpdated(): Int = - rowsUpdated().awaitSingle() diff --git a/src/test/java/org/springframework/data/r2dbc/connectionfactory/DelegatingConnectionFactoryUnitTests.java b/src/test/java/org/springframework/data/r2dbc/connectionfactory/DelegatingConnectionFactoryUnitTests.java deleted file mode 100644 index 66eeeabe2..000000000 --- a/src/test/java/org/springframework/data/r2dbc/connectionfactory/DelegatingConnectionFactoryUnitTests.java +++ /dev/null @@ -1,60 +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.connectionfactory; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import io.r2dbc.spi.Connection; -import io.r2dbc.spi.ConnectionFactory; -import reactor.core.publisher.Mono; - -import org.junit.jupiter.api.Test; - -/** - * Unit tests for {@link DelegatingConnectionFactory}. - * - * @author Mark Paluch - */ -public class DelegatingConnectionFactoryUnitTests { - - ConnectionFactory delegate = mock(ConnectionFactory.class); - Connection connectionMock = mock(Connection.class); - - DelegatingConnectionFactory connectionFactory = new ExampleConnectionFactory(delegate); - - @Test // gh-107 - public void shouldDelegateGetConnection() { - - Mono connectionMono = Mono.just(connectionMock); - when(delegate.create()).thenReturn((Mono) connectionMono); - - assertThat(connectionFactory.create()).isSameAs(connectionMono); - } - - @Test // gh-107 - public void shouldDelegateUnwrapWithoutImplementing() { - assertThat(connectionFactory.unwrap()).isSameAs(delegate); - } - - static class ExampleConnectionFactory extends DelegatingConnectionFactory { - - ExampleConnectionFactory(ConnectionFactory targetConnectionFactory) { - super(targetConnectionFactory); - } - } - -} diff --git a/src/test/java/org/springframework/data/r2dbc/connectionfactory/SingleConnectionConnectionFactoryUnitTests.java b/src/test/java/org/springframework/data/r2dbc/connectionfactory/SingleConnectionConnectionFactoryUnitTests.java deleted file mode 100644 index 74c725c02..000000000 --- a/src/test/java/org/springframework/data/r2dbc/connectionfactory/SingleConnectionConnectionFactoryUnitTests.java +++ /dev/null @@ -1,121 +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.connectionfactory; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import io.r2dbc.h2.H2Connection; -import io.r2dbc.spi.Connection; -import io.r2dbc.spi.ConnectionFactoryMetadata; -import io.r2dbc.spi.IsolationLevel; -import io.r2dbc.spi.R2dbcNonTransientResourceException; -import io.r2dbc.spi.Wrapped; -import reactor.core.publisher.Mono; -import reactor.test.StepVerifier; - -import org.junit.jupiter.api.Test; - -/** - * Unit tests for {@link SingleConnectionConnectionFactory}. - * - * @author Mark Paluch - */ -class SingleConnectionConnectionFactoryUnitTests { - - @Test // gh-204 - void shouldAllocateSameConnection() { - - SingleConnectionConnectionFactory factory = new SingleConnectionConnectionFactory("r2dbc:h2:mem:///foo", false); - - Mono cf1 = factory.create(); - Mono cf2 = factory.create(); - - Connection c1 = cf1.block(); - Connection c2 = cf2.block(); - - assertThat(c1).isSameAs(c2); - factory.destroy(); - } - - @Test // gh-204 - void shouldApplyAutoCommit() { - - SingleConnectionConnectionFactory factory = new SingleConnectionConnectionFactory("r2dbc:h2:mem:///foo", false); - factory.setAutoCommit(false); - - factory.create().as(StepVerifier::create).consumeNextWith(actual -> { - assertThat(actual.isAutoCommit()).isFalse(); - }).verifyComplete(); - - factory.setAutoCommit(true); - - factory.create().as(StepVerifier::create).consumeNextWith(actual -> { - assertThat(actual.isAutoCommit()).isTrue(); - }).verifyComplete(); - - factory.destroy(); - } - - @Test // gh-204 - void shouldSuppressClose() { - - SingleConnectionConnectionFactory factory = new SingleConnectionConnectionFactory("r2dbc:h2:mem:///foo", true); - - Connection connection = factory.create().block(); - - StepVerifier.create(connection.close()).verifyComplete(); - assertThat(connection).isInstanceOf(Wrapped.class); - assertThat(((Wrapped) connection).unwrap()).isInstanceOf(H2Connection.class); - - StepVerifier.create(connection.setTransactionIsolationLevel(IsolationLevel.READ_COMMITTED)) // - .verifyComplete(); - factory.destroy(); - } - - @Test // gh-204 - void shouldNotSuppressClose() { - - SingleConnectionConnectionFactory factory = new SingleConnectionConnectionFactory("r2dbc:h2:mem:///foo", false); - - Connection connection = factory.create().block(); - - StepVerifier.create(connection.close()).verifyComplete(); - - StepVerifier.create(connection.setTransactionIsolationLevel(IsolationLevel.READ_COMMITTED)) - .verifyError(R2dbcNonTransientResourceException.class); - factory.destroy(); - } - - @Test // gh-204 - void releaseConnectionShouldCloseUnrelatedConnection() { - - Connection connectionMock = mock(Connection.class); - Connection otherConnection = mock(Connection.class); - ConnectionFactoryMetadata metadata = mock(ConnectionFactoryMetadata.class); - when(otherConnection.close()).thenReturn(Mono.empty()); - - SingleConnectionConnectionFactory factory = new SingleConnectionConnectionFactory(connectionMock, metadata, false); - - factory.create().as(StepVerifier::create).expectNextCount(1).verifyComplete(); - - ConnectionFactoryUtils.releaseConnection(otherConnection, factory) // - .as(StepVerifier::create) // - .verifyComplete(); - - verify(otherConnection).close(); - } -} diff --git a/src/test/java/org/springframework/data/r2dbc/connectionfactory/TransactionAwareConnectionFactoryProxyUnitTests.java b/src/test/java/org/springframework/data/r2dbc/connectionfactory/TransactionAwareConnectionFactoryProxyUnitTests.java deleted file mode 100644 index 9af860650..000000000 --- a/src/test/java/org/springframework/data/r2dbc/connectionfactory/TransactionAwareConnectionFactoryProxyUnitTests.java +++ /dev/null @@ -1,163 +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.connectionfactory; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import io.r2dbc.spi.Connection; -import io.r2dbc.spi.ConnectionFactory; -import reactor.core.publisher.Mono; -import reactor.test.StepVerifier; - -import java.util.concurrent.atomic.AtomicReference; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import org.springframework.transaction.reactive.TransactionalOperator; - -/** - * Unit tests for {@link TransactionAwareConnectionFactoryProxy}. - * - * @author Mark Paluch - * @author Christoph Strobl - */ -public class TransactionAwareConnectionFactoryProxyUnitTests { - - ConnectionFactory connectionFactoryMock = mock(ConnectionFactory.class); - Connection connectionMock1 = mock(Connection.class); - Connection connectionMock2 = mock(Connection.class); - Connection connectionMock3 = mock(Connection.class); - - private R2dbcTransactionManager tm; - - @BeforeEach - public void before() { - - when(connectionFactoryMock.create()).thenReturn((Mono) Mono.just(connectionMock1), - (Mono) Mono.just(connectionMock2), (Mono) Mono.just(connectionMock3)); - tm = new R2dbcTransactionManager(connectionFactoryMock); - } - - @Test // gh-107 - public void createShouldProxyConnection() { - - new TransactionAwareConnectionFactoryProxy(connectionFactoryMock).create() // - .as(StepVerifier::create) // - .consumeNextWith(connection -> { - assertThat(connection).isInstanceOf(ConnectionProxy.class); - }).verifyComplete(); - } - - @Test // gh-107 - public void unwrapShouldReturnTargetConnection() { - - new TransactionAwareConnectionFactoryProxy(connectionFactoryMock).create() // - .map(ConnectionProxy.class::cast).as(StepVerifier::create) // - .consumeNextWith(proxy -> { - assertThat(proxy.unwrap()).isEqualTo(connectionMock1); - }).verifyComplete(); - } - - @Test // gh-107 - public void unwrapShouldReturnTargetConnectionEvenWhenClosed() { - - when(connectionMock1.close()).thenReturn(Mono.empty()); - - new TransactionAwareConnectionFactoryProxy(connectionFactoryMock).create() // - .map(ConnectionProxy.class::cast).flatMap(it -> Mono.from(it.close()).then(Mono.just(it))) - .as(StepVerifier::create) // - .consumeNextWith(proxy -> { - assertThat(proxy.unwrap()).isEqualTo(connectionMock1); - }).verifyComplete(); - } - - @Test // gh-107 - public void getTargetConnectionShouldReturnTargetConnection() { - - new TransactionAwareConnectionFactoryProxy(connectionFactoryMock).create() // - .map(ConnectionProxy.class::cast).as(StepVerifier::create) // - .consumeNextWith(proxy -> { - assertThat(proxy.getTargetConnection()).isEqualTo(connectionMock1); - }).verifyComplete(); - } - - @Test // gh-107 - public void getTargetConnectionShouldThrowsErrorEvenWhenClosed() { - - when(connectionMock1.close()).thenReturn(Mono.empty()); - - new TransactionAwareConnectionFactoryProxy(connectionFactoryMock).create() // - .map(ConnectionProxy.class::cast).flatMap(it -> Mono.from(it.close()).then(Mono.just(it))) - .as(StepVerifier::create) // - .consumeNextWith(proxy -> { - assertThatExceptionOfType(IllegalStateException.class).isThrownBy(() -> proxy.getTargetConnection()); - }).verifyComplete(); - } - - @Test // gh-107 - public void hashCodeShouldReturnProxyHash() { - - new TransactionAwareConnectionFactoryProxy(connectionFactoryMock).create() // - .map(ConnectionProxy.class::cast).as(StepVerifier::create) // - .consumeNextWith(proxy -> { - assertThat(proxy.hashCode()).isEqualTo(System.identityHashCode(proxy)); - }).verifyComplete(); - } - - @Test // gh-107 - public void equalsShouldCompareCorrectly() { - - new TransactionAwareConnectionFactoryProxy(connectionFactoryMock).create() // - .map(ConnectionProxy.class::cast).as(StepVerifier::create) // - .consumeNextWith(proxy -> { - assertThat(proxy.equals(proxy)).isTrue(); - assertThat(proxy.equals(connectionMock1)).isFalse(); - }).verifyComplete(); - } - - @Test // gh-107 - public void shouldEmitBoundConnection() { - - when(connectionMock1.beginTransaction()).thenReturn(Mono.empty()); - when(connectionMock1.commitTransaction()).thenReturn(Mono.empty()); - when(connectionMock1.close()).thenReturn(Mono.empty()); - - TransactionalOperator rxtx = TransactionalOperator.create(tm); - AtomicReference transactionalConnection = new AtomicReference<>(); - - TransactionAwareConnectionFactoryProxy proxyCf = new TransactionAwareConnectionFactoryProxy(connectionFactoryMock); - - ConnectionFactoryUtils.getConnection(connectionFactoryMock) // - .doOnNext(transactionalConnection::set).flatMap(it -> { - - return proxyCf.create().doOnNext(connectionFromProxy -> { - - ConnectionProxy connectionProxy = (ConnectionProxy) connectionFromProxy; - assertThat(connectionProxy.getTargetConnection()).isSameAs(it); - assertThat(connectionProxy.unwrap()).isSameAs(it); - }); - }).as(rxtx::transactional) // - .flatMapMany(Connection::close) // - .as(StepVerifier::create) // - .verifyComplete(); - - verifyNoInteractions(connectionMock2); - verifyNoInteractions(connectionMock3); - verify(connectionFactoryMock, times(1)).create(); - } -} diff --git a/src/test/java/org/springframework/data/r2dbc/connectionfactory/init/AbstractDatabaseInitializationTests.java b/src/test/java/org/springframework/data/r2dbc/connectionfactory/init/AbstractDatabaseInitializationTests.java deleted file mode 100644 index 853a8f367..000000000 --- a/src/test/java/org/springframework/data/r2dbc/connectionfactory/init/AbstractDatabaseInitializationTests.java +++ /dev/null @@ -1,134 +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.connectionfactory.init; - -import io.r2dbc.spi.ConnectionFactory; -import reactor.test.StepVerifier; - -import org.junit.jupiter.api.Test; - -import org.springframework.core.io.ClassRelativeResourceLoader; -import org.springframework.core.io.Resource; -import org.springframework.data.r2dbc.core.DatabaseClient; - -/** - * Abstract test support for {@link DatabasePopulator}. - * - * @author Mark Paluch - */ -abstract class AbstractDatabaseInitializationTests { - - private final ClassRelativeResourceLoader resourceLoader = new ClassRelativeResourceLoader(getClass()); - ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator(); - - @Test - void scriptWithSingleLineCommentsAndFailedDrop() { - - databasePopulator.addScript(resource("db-schema-failed-drop-comments.sql")); - databasePopulator.addScript(resource("db-test-data.sql")); - databasePopulator.setIgnoreFailedDrops(true); - - runPopulator(); - - assertUsersDatabaseCreated("Heisenberg"); - } - - private void runPopulator() { - DatabasePopulatorUtils.execute(databasePopulator, getConnectionFactory()) // - .as(StepVerifier::create) // - .verifyComplete(); - } - - @Test - void scriptWithStandardEscapedLiteral() { - - databasePopulator.addScript(defaultSchema()); - databasePopulator.addScript(resource("db-test-data-escaped-literal.sql")); - - runPopulator(); - - assertUsersDatabaseCreated("'Heisenberg'"); - } - - @Test - void scriptWithMySqlEscapedLiteral() { - - databasePopulator.addScript(defaultSchema()); - databasePopulator.addScript(resource("db-test-data-mysql-escaped-literal.sql")); - - runPopulator(); - - assertUsersDatabaseCreated("\\$Heisenberg\\$"); - } - - @Test - void scriptWithMultipleStatements() { - - databasePopulator.addScript(defaultSchema()); - databasePopulator.addScript(resource("db-test-data-multiple.sql")); - - runPopulator(); - - assertUsersDatabaseCreated("Heisenberg", "Jesse"); - } - - @Test - void scriptWithMultipleStatementsAndLongSeparator() { - - databasePopulator.addScript(defaultSchema()); - databasePopulator.addScript(resource("db-test-data-endings.sql")); - databasePopulator.setSeparator("@@"); - - runPopulator(); - - assertUsersDatabaseCreated("Heisenberg", "Jesse"); - } - - abstract ConnectionFactory getConnectionFactory(); - - Resource resource(String path) { - return resourceLoader.getResource(path); - } - - Resource defaultSchema() { - return resource("db-schema.sql"); - } - - Resource usersSchema() { - return resource("users-schema.sql"); - } - - void assertUsersDatabaseCreated(String... lastNames) { - assertUsersDatabaseCreated(getConnectionFactory(), lastNames); - } - - void assertUsersDatabaseCreated(ConnectionFactory connectionFactory, String... lastNames) { - - DatabaseClient client = DatabaseClient.create(connectionFactory); - - for (String lastName : lastNames) { - - client.execute("select count(0) from users where last_name = :name") // - .bind("name", lastName) // - .map((row, metadata) -> row.get(0)) // - .first() // - .map(it -> ((Number) it).intValue()) // - .as(StepVerifier::create) // - .expectNext(1).as("Did not find user with last name [" + lastName + "].") // - .verifyComplete(); - } - } -} diff --git a/src/test/java/org/springframework/data/r2dbc/connectionfactory/init/CompositeDatabasePopulatorTests.java b/src/test/java/org/springframework/data/r2dbc/connectionfactory/init/CompositeDatabasePopulatorTests.java deleted file mode 100644 index 1f84fb786..000000000 --- a/src/test/java/org/springframework/data/r2dbc/connectionfactory/init/CompositeDatabasePopulatorTests.java +++ /dev/null @@ -1,112 +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.connectionfactory.init; - -import static org.mockito.Mockito.*; - -import io.r2dbc.spi.Connection; -import reactor.core.publisher.Mono; -import reactor.test.StepVerifier; - -import java.util.LinkedHashSet; -import java.util.Set; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -/** - * Unit tests for {@link CompositeDatabasePopulator}. - * - * @author Mark Paluch - */ -class CompositeDatabasePopulatorTests { - - private final Connection mockedConnection = mock(Connection.class); - - private final DatabasePopulator mockedDatabasePopulator1 = mock(DatabasePopulator.class); - - private final DatabasePopulator mockedDatabasePopulator2 = mock(DatabasePopulator.class); - - @BeforeEach - void before() { - - when(mockedDatabasePopulator1.populate(mockedConnection)).thenReturn(Mono.empty()); - when(mockedDatabasePopulator2.populate(mockedConnection)).thenReturn(Mono.empty()); - } - - @Test - void addPopulators() { - - CompositeDatabasePopulator populator = new CompositeDatabasePopulator(); - populator.addPopulators(mockedDatabasePopulator1, mockedDatabasePopulator2); - - populator.populate(mockedConnection).as(StepVerifier::create).verifyComplete(); - - verify(mockedDatabasePopulator1, times(1)).populate(mockedConnection); - verify(mockedDatabasePopulator2, times(1)).populate(mockedConnection); - } - - @Test - void setPopulatorsWithMultiple() { - - CompositeDatabasePopulator populator = new CompositeDatabasePopulator(); - populator.setPopulators(mockedDatabasePopulator1, mockedDatabasePopulator2); // multiple - - populator.populate(mockedConnection).as(StepVerifier::create).verifyComplete(); - - verify(mockedDatabasePopulator1, times(1)).populate(mockedConnection); - verify(mockedDatabasePopulator2, times(1)).populate(mockedConnection); - } - - @Test - void setPopulatorsForOverride() { - - CompositeDatabasePopulator populator = new CompositeDatabasePopulator(); - populator.setPopulators(mockedDatabasePopulator1); - populator.setPopulators(mockedDatabasePopulator2); // override - - populator.populate(mockedConnection).as(StepVerifier::create).verifyComplete(); - - verify(mockedDatabasePopulator1, times(0)).populate(mockedConnection); - verify(mockedDatabasePopulator2, times(1)).populate(mockedConnection); - } - - @Test - void constructWithVarargs() { - - CompositeDatabasePopulator populator = new CompositeDatabasePopulator(mockedDatabasePopulator1, - mockedDatabasePopulator2); - - populator.populate(mockedConnection).as(StepVerifier::create).verifyComplete(); - - verify(mockedDatabasePopulator1, times(1)).populate(mockedConnection); - verify(mockedDatabasePopulator2, times(1)).populate(mockedConnection); - } - - @Test - void constructWithCollection() { - - Set populators = new LinkedHashSet<>(); - populators.add(mockedDatabasePopulator1); - populators.add(mockedDatabasePopulator2); - - CompositeDatabasePopulator populator = new CompositeDatabasePopulator(populators); - populator.populate(mockedConnection).as(StepVerifier::create).verifyComplete(); - - verify(mockedDatabasePopulator1, times(1)).populate(mockedConnection); - verify(mockedDatabasePopulator2, times(1)).populate(mockedConnection); - } -} diff --git a/src/test/java/org/springframework/data/r2dbc/connectionfactory/init/ConnectionFactoryInitializerUnitTests.java b/src/test/java/org/springframework/data/r2dbc/connectionfactory/init/ConnectionFactoryInitializerUnitTests.java deleted file mode 100644 index c5c36d5b5..000000000 --- a/src/test/java/org/springframework/data/r2dbc/connectionfactory/init/ConnectionFactoryInitializerUnitTests.java +++ /dev/null @@ -1,70 +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.connectionfactory.init; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import io.r2dbc.spi.test.MockConnection; -import io.r2dbc.spi.test.MockConnectionFactory; -import reactor.core.publisher.Mono; - -import java.util.concurrent.atomic.AtomicBoolean; - -import org.junit.jupiter.api.Test; - -/** - * Unit tests for {@link ConnectionFactoryInitializer}. - * - * @author Mark Paluch - */ -class ConnectionFactoryInitializerUnitTests { - - private final AtomicBoolean called = new AtomicBoolean(); - private final DatabasePopulator populator = mock(DatabasePopulator.class); - private final MockConnection connection = MockConnection.builder().build(); - private final MockConnectionFactory connectionFactory = MockConnectionFactory.builder().connection(connection) - .build(); - - @Test // gh-216 - void shouldInitializeConnectionFactory() { - - when(populator.populate(any())).thenReturn(Mono. empty().doOnSubscribe(subscription -> called.set(true))); - - ConnectionFactoryInitializer initializer = new ConnectionFactoryInitializer(); - initializer.setConnectionFactory(connectionFactory); - initializer.setDatabasePopulator(populator); - - initializer.afterPropertiesSet(); - - assertThat(called).isTrue(); - } - - @Test // gh-216 - void shouldCleanConnectionFactory() { - - when(populator.populate(any())).thenReturn(Mono. empty().doOnSubscribe(subscription -> called.set(true))); - - ConnectionFactoryInitializer initializer = new ConnectionFactoryInitializer(); - initializer.setConnectionFactory(connectionFactory); - initializer.setDatabaseCleaner(populator); - - initializer.afterPropertiesSet(); - initializer.destroy(); - - assertThat(called).isTrue(); - } -} diff --git a/src/test/java/org/springframework/data/r2dbc/connectionfactory/init/H2DatabasePopulatorIntegrationTests.java b/src/test/java/org/springframework/data/r2dbc/connectionfactory/init/H2DatabasePopulatorIntegrationTests.java deleted file mode 100644 index 94ceb7656..000000000 --- a/src/test/java/org/springframework/data/r2dbc/connectionfactory/init/H2DatabasePopulatorIntegrationTests.java +++ /dev/null @@ -1,57 +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.connectionfactory.init; - -import io.r2dbc.spi.ConnectionFactories; -import io.r2dbc.spi.ConnectionFactory; -import reactor.test.StepVerifier; - -import java.util.UUID; - -import org.junit.jupiter.api.Test; - -/** - * Integration tests for {@link DatabasePopulator} using H2. - * - * @author Mark Paluch - */ -class H2DatabasePopulatorIntegrationTests extends AbstractDatabaseInitializationTests { - - private final UUID databaseName = UUID.randomUUID(); - - private final ConnectionFactory connectionFactory = ConnectionFactories - .get("r2dbc:h2:mem:///" + databaseName + "?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE"); - - @Override - ConnectionFactory getConnectionFactory() { - return this.connectionFactory; - } - - @Test - void shouldRunScript() { - - databasePopulator.addScript(usersSchema()); - databasePopulator.addScript(resource("db-test-data-h2.sql")); - // Set statement separator to double newline so that ";" is not - // considered a statement separator within the source code of the - // aliased function 'REVERSE'. - databasePopulator.setSeparator("\n\n"); - - DatabasePopulatorUtils.execute(databasePopulator, connectionFactory).as(StepVerifier::create).verifyComplete(); - - assertUsersDatabaseCreated(connectionFactory, "White"); - } -} diff --git a/src/test/java/org/springframework/data/r2dbc/connectionfactory/init/ResourceDatabasePopulatorUnitTests.java b/src/test/java/org/springframework/data/r2dbc/connectionfactory/init/ResourceDatabasePopulatorUnitTests.java deleted file mode 100644 index 1d64ba647..000000000 --- a/src/test/java/org/springframework/data/r2dbc/connectionfactory/init/ResourceDatabasePopulatorUnitTests.java +++ /dev/null @@ -1,110 +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.connectionfactory.init; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import org.junit.jupiter.api.Test; - -import org.springframework.core.io.Resource; - -/** - * Unit tests for {@link ResourceDatabasePopulator}. - * - * @author Mark Paluch - */ -class ResourceDatabasePopulatorUnitTests { - - private static final Resource script1 = mock(Resource.class); - private static final Resource script2 = mock(Resource.class); - private static final Resource script3 = mock(Resource.class); - - @Test - void constructWithNullResource() { - assertThatIllegalArgumentException().isThrownBy(() -> new ResourceDatabasePopulator((Resource) null)); - } - - @Test - void constructWithNullResourceArray() { - assertThatIllegalArgumentException().isThrownBy(() -> new ResourceDatabasePopulator((Resource[]) null)); - } - - @Test - void constructWithResource() { - - ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator(script1); - assertThat(databasePopulator.scripts.size()).isEqualTo(1); - } - - @Test - void constructWithMultipleResources() { - - ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator(script1, script2); - assertThat(databasePopulator.scripts.size()).isEqualTo(2); - } - - @Test - void constructWithMultipleResourcesAndThenAddScript() { - - ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator(script1, script2); - assertThat(databasePopulator.scripts.size()).isEqualTo(2); - - databasePopulator.addScript(script3); - assertThat(databasePopulator.scripts.size()).isEqualTo(3); - } - - @Test - void addScriptsWithNullResource() { - - ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator(); - assertThatIllegalArgumentException().isThrownBy(() -> databasePopulator.addScripts((Resource) null)); - } - - @Test - void addScriptsWithNullResourceArray() { - - ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator(); - assertThatIllegalArgumentException().isThrownBy(() -> databasePopulator.addScripts((Resource[]) null)); - } - - @Test - void setScriptsWithNullResource() { - - ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator(); - assertThatIllegalArgumentException().isThrownBy(() -> databasePopulator.setScripts((Resource) null)); - } - - @Test - void setScriptsWithNullResourceArray() { - - ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator(); - assertThatIllegalArgumentException().isThrownBy(() -> databasePopulator.setScripts((Resource[]) null)); - } - - @Test - void setScriptsAndThenAddScript() { - - ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator(); - assertThat(databasePopulator.scripts.size()).isEqualTo(0); - - databasePopulator.setScripts(script1, script2); - assertThat(databasePopulator.scripts.size()).isEqualTo(2); - - databasePopulator.addScript(script3); - assertThat(databasePopulator.scripts.size()).isEqualTo(3); - } -} diff --git a/src/test/java/org/springframework/data/r2dbc/connectionfactory/init/ScriptUtilsUnitTests.java b/src/test/java/org/springframework/data/r2dbc/connectionfactory/init/ScriptUtilsUnitTests.java deleted file mode 100644 index 1846be737..000000000 --- a/src/test/java/org/springframework/data/r2dbc/connectionfactory/init/ScriptUtilsUnitTests.java +++ /dev/null @@ -1,205 +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.connectionfactory.init; - -import static org.assertj.core.api.Assertions.*; - -import java.util.ArrayList; -import java.util.List; - -import org.assertj.core.util.Strings; -import org.junit.jupiter.api.Test; - -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.buffer.DefaultDataBufferFactory; -import org.springframework.core.io.support.EncodedResource; - -/** - * Unit tests for {@link ScriptUtils}. - * - * @author Mark Paluch - */ -class ScriptUtilsUnitTests { - - @Test - void splitSqlScriptDelimitedWithSemicolon() { - - String rawStatement1 = "insert into customer (id, name)\nvalues (1, 'Rod ; Johnson'), (2, 'Adrian \n Collier')"; - String cleanedStatement1 = "insert into customer (id, name) values (1, 'Rod ; Johnson'), (2, 'Adrian \n Collier')"; - String rawStatement2 = "insert into orders(id, order_date, customer_id)\nvalues (1, '2008-01-02', 2)"; - String cleanedStatement2 = "insert into orders(id, order_date, customer_id) values (1, '2008-01-02', 2)"; - String rawStatement3 = "insert into orders(id, order_date, customer_id) values (1, '2008-01-02', 2)"; - String cleanedStatement3 = "insert into orders(id, order_date, customer_id) values (1, '2008-01-02', 2)"; - - String script = Strings.join(rawStatement1, rawStatement2, rawStatement3).with(";"); - - List statements = new ArrayList<>(); - ScriptUtils.splitSqlScript(script, ";", statements); - - assertThat(statements).hasSize(3).containsSequence(cleanedStatement1, cleanedStatement2, cleanedStatement3); - } - - @Test - void splitSqlScriptDelimitedWithNewLine() { - - String statement1 = "insert into customer (id, name) values (1, 'Rod ; Johnson'), (2, 'Adrian \n Collier')"; - String statement2 = "insert into orders(id, order_date, customer_id) values (1, '2008-01-02', 2)"; - String statement3 = "insert into orders(id, order_date, customer_id) values (1, '2008-01-02', 2)"; - - String script = Strings.join(statement1, statement2, statement3).with("\n"); - - List statements = new ArrayList<>(); - ScriptUtils.splitSqlScript(script, "\n", statements); - - assertThat(statements).hasSize(3).containsSequence(statement1, statement2, statement3); - } - - @Test - void splitSqlScriptDelimitedWithNewLineButDefaultDelimiterSpecified() { - - String statement1 = "do something"; - String statement2 = "do something else"; - - char delim = '\n'; - String script = statement1 + delim + statement2 + delim; - - List statements = new ArrayList<>(); - - ScriptUtils.splitSqlScript(script, ScriptUtils.DEFAULT_STATEMENT_SEPARATOR, statements); - - assertThat(statements).hasSize(1).contains(script.replace('\n', ' ')); - } - - @Test - void splitScriptWithSingleQuotesNestedInsideDoubleQuotes() { - - String statement1 = "select '1' as \"Dogbert's owner's\" from dual"; - String statement2 = "select '2' as \"Dilbert's\" from dual"; - - char delim = ';'; - String script = statement1 + delim + statement2 + delim; - - List statements = new ArrayList<>(); - ScriptUtils.splitSqlScript(script, ';', statements); - - assertThat(statements).hasSize(2).containsSequence(statement1, statement2); - } - - @Test - void readAndSplitScriptWithMultipleNewlinesAsSeparator() { - - String script = readScript("db-test-data-multi-newline.sql"); - List statements = new ArrayList<>(); - ScriptUtils.splitSqlScript(script, "\n\n", statements); - - String statement1 = "insert into users (last_name) values ('Walter')"; - String statement2 = "insert into users (last_name) values ('Jesse')"; - - assertThat(statements.size()).as("wrong number of statements").isEqualTo(2); - assertThat(statements.get(0)).as("statement 1 not split correctly").isEqualTo(statement1); - assertThat(statements.get(1)).as("statement 2 not split correctly").isEqualTo(statement2); - } - - @Test - void readAndSplitScriptContainingComments() { - String script = readScript("test-data-with-comments.sql"); - splitScriptContainingComments(script); - } - - @Test - void readAndSplitScriptContainingCommentsWithWindowsLineEnding() { - String script = readScript("test-data-with-comments.sql").replaceAll("\n", "\r\n"); - splitScriptContainingComments(script); - } - - private void splitScriptContainingComments(String script) { - - List statements = new ArrayList<>(); - ScriptUtils.splitSqlScript(script, ';', statements); - - String statement1 = "insert into customer (id, name) values (1, 'Rod; Johnson'), (2, 'Adrian Collier')"; - String statement2 = "insert into orders(id, order_date, customer_id) values (1, '2008-01-02', 2)"; - String statement3 = "insert into orders(id, order_date, customer_id) values (1, '2008-01-02', 2)"; - String statement4 = "INSERT INTO persons( person_id , name) VALUES( 1 , 'Name' )"; - - assertThat(statements).hasSize(4).containsSequence(statement1, statement2, statement3, statement4); - } - - @Test - void readAndSplitScriptContainingCommentsWithLeadingTabs() { - - String script = readScript("test-data-with-comments-and-leading-tabs.sql"); - List statements = new ArrayList<>(); - ScriptUtils.splitSqlScript(script, ';', statements); - - String statement1 = "insert into customer (id, name) values (1, 'Walter White')"; - String statement2 = "insert into orders(id, order_date, customer_id) values (1, '2013-06-08', 1)"; - String statement3 = "insert into orders(id, order_date, customer_id) values (2, '2013-06-08', 1)"; - - assertThat(statements).hasSize(3).containsSequence(statement1, statement2, statement3); - } - - @Test - void readAndSplitScriptContainingMultiLineComments() { - - String script = readScript("test-data-with-multi-line-comments.sql"); - List statements = new ArrayList<>(); - ScriptUtils.splitSqlScript(script, ';', statements); - - String statement1 = "INSERT INTO users(first_name, last_name) VALUES('Walter', 'White')"; - String statement2 = "INSERT INTO users(first_name, last_name) VALUES( 'Jesse' , 'Pinkman' )"; - - assertThat(statements).hasSize(2).containsSequence(statement1, statement2); - } - - @Test - void readAndSplitScriptContainingMultiLineNestedComments() { - - String script = readScript("test-data-with-multi-line-nested-comments.sql"); - List statements = new ArrayList<>(); - ScriptUtils.splitSqlScript(script, ';', statements); - - String statement1 = "INSERT INTO users(first_name, last_name) VALUES('Walter', 'White')"; - String statement2 = "INSERT INTO users(first_name, last_name) VALUES( 'Jesse' , 'Pinkman' )"; - - assertThat(statements).hasSize(2).containsSequence(statement1, statement2); - } - - @Test - void containsDelimiters() { - - assertThat(ScriptUtils.containsSqlScriptDelimiters("select 1\n select ';'", ";")).isFalse(); - assertThat(ScriptUtils.containsSqlScriptDelimiters("select 1; select 2", ";")).isTrue(); - - assertThat(ScriptUtils.containsSqlScriptDelimiters("select 1; select '\\n\n';", "\n")).isFalse(); - assertThat(ScriptUtils.containsSqlScriptDelimiters("select 1\n select 2", "\n")).isTrue(); - - assertThat(ScriptUtils.containsSqlScriptDelimiters("select 1\n select 2", "\n\n")).isFalse(); - assertThat(ScriptUtils.containsSqlScriptDelimiters("select 1\n\n select 2", "\n\n")).isTrue(); - - // MySQL style escapes '\\' - assertThat( - ScriptUtils.containsSqlScriptDelimiters("insert into users(first_name, last_name)\nvalues('a\\\\', 'b;')", ";")) - .isFalse(); - assertThat(ScriptUtils.containsSqlScriptDelimiters( - "insert into users(first_name, last_name)\nvalues('Charles', 'd\\'Artagnan'); select 1;", ";")).isTrue(); - } - - private String readScript(String path) { - EncodedResource resource = new EncodedResource(new ClassPathResource(path, getClass())); - return ScriptUtils.readScript(resource, new DefaultDataBufferFactory()).block(); - } -} diff --git a/src/test/java/org/springframework/data/r2dbc/connectionfactory/lookup/AbstractRoutingConnectionFactoryUnitTests.java b/src/test/java/org/springframework/data/r2dbc/connectionfactory/lookup/AbstractRoutingConnectionFactoryUnitTests.java deleted file mode 100644 index 17d5775c2..000000000 --- a/src/test/java/org/springframework/data/r2dbc/connectionfactory/lookup/AbstractRoutingConnectionFactoryUnitTests.java +++ /dev/null @@ -1,190 +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.connectionfactory.lookup; - -import static java.util.Collections.*; -import static org.assertj.core.api.Assertions.*; - -import io.r2dbc.spi.ConnectionFactory; -import reactor.core.publisher.Mono; -import reactor.test.StepVerifier; -import reactor.util.context.Context; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -/** - * Unit tests for {@link AbstractRoutingConnectionFactory}. - * - * @author Mark Paluch - * @author Jens Schauder - */ -@ExtendWith(MockitoExtension.class) -class AbstractRoutingConnectionFactoryUnitTests { - - private static final String ROUTING_KEY = "routingKey"; - - @Mock ConnectionFactory defaultConnectionFactory; - @Mock ConnectionFactory routedConnectionFactory; - - private DummyRoutingConnectionFactory connectionFactory; - - @BeforeEach - void before() { - - connectionFactory = new DummyRoutingConnectionFactory(); - connectionFactory.setDefaultTargetConnectionFactory(defaultConnectionFactory); - } - - @Test // gh-98 - void shouldDetermineRoutedFactory() { - - connectionFactory.setTargetConnectionFactories(singletonMap("key", routedConnectionFactory)); - connectionFactory.setConnectionFactoryLookup(new MapConnectionFactoryLookup()); - connectionFactory.afterPropertiesSet(); - - connectionFactory.determineTargetConnectionFactory() // - .subscriberContext(Context.of(ROUTING_KEY, "key")) // - .as(StepVerifier::create) // - .expectNext(routedConnectionFactory) // - .verifyComplete(); - } - - @Test // gh-98 - void shouldFallbackToDefaultConnectionFactory() { - - connectionFactory.setTargetConnectionFactories(singletonMap("key", routedConnectionFactory)); - connectionFactory.afterPropertiesSet(); - - connectionFactory.determineTargetConnectionFactory() // - .as(StepVerifier::create) // - .expectNext(defaultConnectionFactory) // - .verifyComplete(); - } - - @Test // gh-98 - void initializationShouldFailUnsupportedLookupKey() { - - connectionFactory.setTargetConnectionFactories(singletonMap("key", new Object())); - - assertThatThrownBy(() -> connectionFactory.afterPropertiesSet()).isInstanceOf(IllegalArgumentException.class); - } - - @Test // gh-98 - void initializationShouldFailUnresolvableKey() { - - connectionFactory.setTargetConnectionFactories(singletonMap("key", "value")); - connectionFactory.setConnectionFactoryLookup(new MapConnectionFactoryLookup()); - - assertThatThrownBy(() -> connectionFactory.afterPropertiesSet()) // - .isInstanceOf(ConnectionFactoryLookupFailureException.class) // - .hasMessageContaining("No ConnectionFactory with name 'value' registered"); - } - - @Test // gh-98 - void unresolvableConnectionFactoryRetrievalShouldFail() { - - connectionFactory.setLenientFallback(false); - connectionFactory.setConnectionFactoryLookup(new MapConnectionFactoryLookup()); - connectionFactory.setTargetConnectionFactories(singletonMap("key", routedConnectionFactory)); - connectionFactory.afterPropertiesSet(); - - connectionFactory.determineTargetConnectionFactory() // - .subscriberContext(Context.of(ROUTING_KEY, "unknown")) // - .as(StepVerifier::create) // - .verifyError(IllegalStateException.class); - } - - @Test // gh-98 - void connectionFactoryRetrievalWithUnknownLookupKeyShouldReturnDefaultConnectionFactory() { - - connectionFactory.setTargetConnectionFactories(singletonMap("key", routedConnectionFactory)); - connectionFactory.setDefaultTargetConnectionFactory(defaultConnectionFactory); - connectionFactory.afterPropertiesSet(); - - connectionFactory.determineTargetConnectionFactory() // - .subscriberContext(Context.of(ROUTING_KEY, "unknown")) // - .as(StepVerifier::create) // - .expectNext(defaultConnectionFactory) // - .verifyComplete(); - } - - @Test // gh-98 - void connectionFactoryRetrievalWithoutLookupKeyShouldReturnDefaultConnectionFactory() { - - connectionFactory.setTargetConnectionFactories(singletonMap("key", routedConnectionFactory)); - connectionFactory.setDefaultTargetConnectionFactory(defaultConnectionFactory); - connectionFactory.setLenientFallback(false); - connectionFactory.afterPropertiesSet(); - - connectionFactory.determineTargetConnectionFactory() // - .as(StepVerifier::create) // - .expectNext(defaultConnectionFactory) // - .verifyComplete(); - } - - @Test // gh-98 - void shouldLookupFromMap() { - - MapConnectionFactoryLookup lookup = new MapConnectionFactoryLookup("lookup-key", routedConnectionFactory); - - connectionFactory.setConnectionFactoryLookup(lookup); - connectionFactory.setTargetConnectionFactories(singletonMap("my-key", "lookup-key")); - connectionFactory.afterPropertiesSet(); - - connectionFactory.determineTargetConnectionFactory() // - .subscriberContext(Context.of(ROUTING_KEY, "my-key")) // - .as(StepVerifier::create) // - .expectNext(routedConnectionFactory) // - .verifyComplete(); - } - - @Test // gh-98 - void shouldAllowModificationsAfterInitialization() { - - MapConnectionFactoryLookup lookup = new MapConnectionFactoryLookup(); - - connectionFactory.setConnectionFactoryLookup(lookup); - connectionFactory.setTargetConnectionFactories(lookup.getConnectionFactories()); - connectionFactory.afterPropertiesSet(); - - connectionFactory.determineTargetConnectionFactory() // - .subscriberContext(Context.of(ROUTING_KEY, "lookup-key")) // - .as(StepVerifier::create) // - .expectNext(defaultConnectionFactory) // - .verifyComplete(); - - lookup.addConnectionFactory("lookup-key", routedConnectionFactory); - connectionFactory.afterPropertiesSet(); - - connectionFactory.determineTargetConnectionFactory() // - .subscriberContext(Context.of(ROUTING_KEY, "lookup-key")) // - .as(StepVerifier::create) // - .expectNext(routedConnectionFactory) // - .verifyComplete(); - } - - static class DummyRoutingConnectionFactory extends AbstractRoutingConnectionFactory { - - @Override - protected Mono determineCurrentLookupKey() { - return Mono.subscriberContext().filter(it -> it.hasKey(ROUTING_KEY)).map(it -> it.get(ROUTING_KEY)); - } - } -} diff --git a/src/test/java/org/springframework/data/r2dbc/connectionfactory/lookup/BeanFactoryConnectionFactoryLookupUnitTests.java b/src/test/java/org/springframework/data/r2dbc/connectionfactory/lookup/BeanFactoryConnectionFactoryLookupUnitTests.java deleted file mode 100644 index 1c12944f4..000000000 --- a/src/test/java/org/springframework/data/r2dbc/connectionfactory/lookup/BeanFactoryConnectionFactoryLookupUnitTests.java +++ /dev/null @@ -1,81 +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.connectionfactory.lookup; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import io.r2dbc.spi.ConnectionFactory; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanNotOfRequiredTypeException; - -/** - * Unit tests for {@link BeanFactoryConnectionFactoryLookup}. - * - * @author Mark Paluch - */ -@ExtendWith(MockitoExtension.class) -class BeanFactoryConnectionFactoryLookupUnitTests { - - private static final String CONNECTION_FACTORY_BEAN_NAME = "connectionFactory"; - - @Mock BeanFactory beanFactory; - - @Test // gh-98 - void shouldLookupConnectionFactory() { - - DummyConnectionFactory expectedConnectionFactory = new DummyConnectionFactory(); - when(beanFactory.getBean(CONNECTION_FACTORY_BEAN_NAME, ConnectionFactory.class)) - .thenReturn(expectedConnectionFactory); - - BeanFactoryConnectionFactoryLookup lookup = new BeanFactoryConnectionFactoryLookup(); - lookup.setBeanFactory(beanFactory); - - ConnectionFactory connectionFactory = lookup.getConnectionFactory(CONNECTION_FACTORY_BEAN_NAME); - - assertThat(connectionFactory).isNotNull(); - assertThat(connectionFactory).isSameAs(expectedConnectionFactory); - } - - @Test // gh-98 - void shouldLookupWhereBeanFactoryYieldsNonConnectionFactoryType() { - - BeanFactory beanFactory = mock(BeanFactory.class); - - when(beanFactory.getBean(CONNECTION_FACTORY_BEAN_NAME, ConnectionFactory.class)).thenThrow( - new BeanNotOfRequiredTypeException(CONNECTION_FACTORY_BEAN_NAME, ConnectionFactory.class, String.class)); - - BeanFactoryConnectionFactoryLookup lookup = new BeanFactoryConnectionFactoryLookup(beanFactory); - - assertThatExceptionOfType(ConnectionFactoryLookupFailureException.class) - .isThrownBy(() -> lookup.getConnectionFactory(CONNECTION_FACTORY_BEAN_NAME)); - } - - @Test // gh-98 - void shouldLookupWhereBeanFactoryHasNotBeenSupplied() { - - BeanFactoryConnectionFactoryLookup lookup = new BeanFactoryConnectionFactoryLookup(); - - assertThatThrownBy(() -> lookup.getConnectionFactory(CONNECTION_FACTORY_BEAN_NAME)) - .isInstanceOf(IllegalStateException.class); - } -} diff --git a/src/test/java/org/springframework/data/r2dbc/connectionfactory/lookup/DummyConnectionFactory.java b/src/test/java/org/springframework/data/r2dbc/connectionfactory/lookup/DummyConnectionFactory.java deleted file mode 100644 index 0eecad8f2..000000000 --- a/src/test/java/org/springframework/data/r2dbc/connectionfactory/lookup/DummyConnectionFactory.java +++ /dev/null @@ -1,42 +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.connectionfactory.lookup; - -import io.r2dbc.spi.Connection; -import io.r2dbc.spi.ConnectionFactory; -import io.r2dbc.spi.ConnectionFactoryMetadata; - -import org.reactivestreams.Publisher; - -/** - * Stub, do-nothing {@link ConnectionFactory} implementation. - *

- * All methods throw {@link UnsupportedOperationException}. - * - * @author Mark Paluch - */ -class DummyConnectionFactory implements ConnectionFactory { - - @Override - public Publisher create() { - throw new UnsupportedOperationException(); - } - - @Override - public ConnectionFactoryMetadata getMetadata() { - throw new UnsupportedOperationException(); - } -} diff --git a/src/test/java/org/springframework/data/r2dbc/connectionfactory/lookup/MapConnectionFactoryLookupUnitTests.java b/src/test/java/org/springframework/data/r2dbc/connectionfactory/lookup/MapConnectionFactoryLookupUnitTests.java deleted file mode 100644 index 2f67fccbc..000000000 --- a/src/test/java/org/springframework/data/r2dbc/connectionfactory/lookup/MapConnectionFactoryLookupUnitTests.java +++ /dev/null @@ -1,102 +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.connectionfactory.lookup; - -import static org.assertj.core.api.Assertions.*; - -import io.r2dbc.spi.ConnectionFactory; - -import java.util.HashMap; -import java.util.Map; - -import org.junit.jupiter.api.Test; - -/** - * Unit tests for {@link MapConnectionFactoryLookup}. - * - * @author Mark Paluch - */ -public class MapConnectionFactoryLookupUnitTests { - - private static final String CONNECTION_FACTORY_NAME = "connectionFactory"; - - @Test // gh-98 - public void getConnectionFactorysReturnsUnmodifiableMap() { - - MapConnectionFactoryLookup lookup = new MapConnectionFactoryLookup(); - Map connectionFactories = lookup.getConnectionFactories(); - - assertThatThrownBy(() -> connectionFactories.put("", new DummyConnectionFactory())) - .isInstanceOf(UnsupportedOperationException.class); - } - - @Test // gh-98 - public void shouldLookupConnectionFactory() { - - Map connectionFactories = new HashMap<>(); - DummyConnectionFactory expectedConnectionFactory = new DummyConnectionFactory(); - - connectionFactories.put(CONNECTION_FACTORY_NAME, expectedConnectionFactory); - MapConnectionFactoryLookup lookup = new MapConnectionFactoryLookup(); - - lookup.setConnectionFactories(connectionFactories); - - ConnectionFactory connectionFactory = lookup.getConnectionFactory(CONNECTION_FACTORY_NAME); - - assertThat(connectionFactory).isNotNull(); - assertThat(connectionFactory).isSameAs(expectedConnectionFactory); - } - - @Test // gh-98 - public void addingConnectionFactoryPermitsOverride() { - - Map connectionFactories = new HashMap<>(); - DummyConnectionFactory overriddenConnectionFactory = new DummyConnectionFactory(); - DummyConnectionFactory expectedConnectionFactory = new DummyConnectionFactory(); - connectionFactories.put(CONNECTION_FACTORY_NAME, overriddenConnectionFactory); - - MapConnectionFactoryLookup lookup = new MapConnectionFactoryLookup(); - - lookup.setConnectionFactories(connectionFactories); - lookup.addConnectionFactory(CONNECTION_FACTORY_NAME, expectedConnectionFactory); - - ConnectionFactory connectionFactory = lookup.getConnectionFactory(CONNECTION_FACTORY_NAME); - - assertThat(connectionFactory).isNotNull(); - assertThat(connectionFactory).isSameAs(expectedConnectionFactory); - } - - @Test // gh-98 - @SuppressWarnings("unchecked") - public void getConnectionFactoryWhereSuppliedMapHasNonConnectionFactoryTypeUnderSpecifiedKey() { - - Map connectionFactories = new HashMap<>(); - connectionFactories.put(CONNECTION_FACTORY_NAME, new Object()); - MapConnectionFactoryLookup lookup = new MapConnectionFactoryLookup(connectionFactories); - - assertThatThrownBy(() -> lookup.getConnectionFactory(CONNECTION_FACTORY_NAME)) - .isInstanceOf(ClassCastException.class); - } - - @Test // gh-98 - public void getConnectionFactoryWhereSuppliedMapHasNoEntryForSpecifiedKey() { - - MapConnectionFactoryLookup lookup = new MapConnectionFactoryLookup(); - - assertThatThrownBy(() -> lookup.getConnectionFactory(CONNECTION_FACTORY_NAME)) - .isInstanceOf(ConnectionFactoryLookupFailureException.class); - } -} diff --git a/src/test/java/org/springframework/data/r2dbc/core/AbstractDatabaseClientIntegrationTests.java b/src/test/java/org/springframework/data/r2dbc/core/AbstractDatabaseClientIntegrationTests.java deleted file mode 100644 index 2778d0023..000000000 --- a/src/test/java/org/springframework/data/r2dbc/core/AbstractDatabaseClientIntegrationTests.java +++ /dev/null @@ -1,527 +0,0 @@ -/* - * Copyright 2018-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 static org.springframework.data.domain.Sort.Order.*; -import static org.springframework.data.r2dbc.query.Criteria.*; - -import io.r2dbc.spi.ConnectionFactory; -import lombok.Data; -import reactor.test.StepVerifier; - -import javax.sql.DataSource; - -import org.assertj.core.api.Condition; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import org.springframework.dao.DataAccessException; -import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.data.annotation.Id; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Sort; -import org.springframework.data.r2dbc.testing.R2dbcIntegrationTestSupport; -import org.springframework.data.relational.core.mapping.Table; -import org.springframework.data.relational.core.query.Criteria; -import org.springframework.data.relational.core.query.Update; -import org.springframework.jdbc.core.JdbcTemplate; - -/** - * Integration tests for {@link DatabaseClient}. - * - * @author Mark Paluch - * @author Mingyuan Wu - */ -public abstract class AbstractDatabaseClientIntegrationTests extends R2dbcIntegrationTestSupport { - - private ConnectionFactory connectionFactory; - - private JdbcTemplate jdbc; - - @BeforeEach - public void before() { - - connectionFactory = createConnectionFactory(); - - jdbc = createJdbcTemplate(createDataSource()); - - try { - jdbc.execute("DROP TABLE legoset"); - } catch (DataAccessException e) {} - jdbc.execute(getCreateTableStatement()); - } - - /** - * Creates a {@link DataSource} to be used in this test. - * - * @return the {@link DataSource} to be used in this test. - */ - protected abstract DataSource createDataSource(); - - /** - * Creates a {@link ConnectionFactory} to be used in this test. - * - * @return the {@link ConnectionFactory} to be used in this test. - */ - protected abstract ConnectionFactory createConnectionFactory(); - - /** - * Returns the the CREATE TABLE statement for table {@code legoset} with the following three columns: - *

    - *
  • id integer (primary key), not null
  • - *
  • name varchar(255), nullable
  • - *
  • manual integer, nullable
  • - *
- * - * @return the CREATE TABLE statement for table {@code legoset} with three columns. - */ - protected abstract String getCreateTableStatement(); - - /** - * Get a parameterized {@code INSERT INTO legoset} statement setting id, name, and manual values. - */ - protected String getInsertIntoLegosetStatement() { - return "INSERT INTO legoset (id, name, manual) VALUES(:id, :name, :manual)"; - } - - @Test // gh-2 - public void executeInsert() { - - DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); - - databaseClient.execute(getInsertIntoLegosetStatement()) // - .bind("id", 42055) // - .bind("name", "SCHAUFELRADBAGGER") // - .bindNull("manual", Integer.class) // - .fetch().rowsUpdated() // - .as(StepVerifier::create) // - .expectNext(1) // - .verifyComplete(); - - assertThat(jdbc.queryForMap("SELECT id, name, manual FROM legoset")).hasEntrySatisfying("id", numberOf(42055)); - } - - @Test // gh-2 - public void shouldTranslateDuplicateKeyException() { - - DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); - - executeInsert(); - - databaseClient.execute(getInsertIntoLegosetStatement()) // - .bind("id", 42055) // - .bind("name", "SCHAUFELRADBAGGER") // - .bindNull("manual", Integer.class) // - .fetch().rowsUpdated() // - .as(StepVerifier::create) // - .expectErrorSatisfies(exception -> assertThat(exception) // - .isInstanceOf(DataIntegrityViolationException.class) // - .hasMessageContaining("execute; SQL [INSERT INTO legoset")) // - .verify(); - } - - @Test // gh-2 - public void executeSelect() { - - jdbc.execute("INSERT INTO legoset (id, name, manual) VALUES(42055, 'SCHAUFELRADBAGGER', 12)"); - - DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); - - databaseClient.execute("SELECT id, name, manual FROM legoset") // - .as(LegoSet.class) // - .fetch().all() // - .as(StepVerifier::create) // - .consumeNextWith(actual -> { - - assertThat(actual.getId()).isEqualTo(42055); - assertThat(actual.getName()).isEqualTo("SCHAUFELRADBAGGER"); - assertThat(actual.getManual()).isEqualTo(12); - }).verifyComplete(); - } - - @Test // gh-2 - public void executeSelectNamedParameters() { - - DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); - - databaseClient.execute("SELECT id, name, manual FROM legoset WHERE name = :name or name = :name") // - .bind("name", "unknown").as(LegoSet.class) // - .fetch().all() // - .as(StepVerifier::create) // - .verifyComplete(); - } - - @Test // gh-2 - public void insert() { - - DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); - - databaseClient.insert().into("legoset")// - .value("id", 42055) // - .value("name", "SCHAUFELRADBAGGER") // - .nullValue("manual", Integer.class) // - .fetch() // - .rowsUpdated() // - .as(StepVerifier::create) // - .expectNext(1) // - .verifyComplete(); - - assertThat(jdbc.queryForMap("SELECT id, name, manual FROM legoset")).hasEntrySatisfying("id", numberOf(42055)); - } - - @Test // gh-2 - public void insertWithoutResult() { - - DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); - - databaseClient.insert().into("legoset")// - .value("id", 42055) // - .value("name", "SCHAUFELRADBAGGER") // - .nullValue("manual", Integer.class) // - .then() // - .as(StepVerifier::create) // - .verifyComplete(); - - assertThat(jdbc.queryForMap("SELECT id, name, manual FROM legoset")).hasEntrySatisfying("id", numberOf(42055)); - } - - @Test // gh-2 - public void insertTypedObject() { - - LegoSet legoSet = new LegoSet(); - legoSet.setId(42055); - legoSet.setName("SCHAUFELRADBAGGER"); - legoSet.setManual(12); - - DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); - - databaseClient.insert().into(LegoSet.class)// - .using(legoSet) // - .fetch() // - .rowsUpdated() // - .as(StepVerifier::create) // - .expectNext(1) // - .verifyComplete(); - - assertThat(jdbc.queryForMap("SELECT id, name, manual FROM legoset")).hasEntrySatisfying("id", numberOf(42055)); - } - - @Test // gh-2 - public void insertTypedObjectWithBinary() { - - LegoSet legoSet = new LegoSet(); - legoSet.setId(42055); - legoSet.setName("SCHAUFELRADBAGGER"); - legoSet.setManual(12); - legoSet.setCert(new byte[] { 1, 2, 3, 4, 5 }); - - DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); - - databaseClient.insert().into(LegoSet.class)// - .using(legoSet) // - .fetch() // - .rowsUpdated() // - .then() // - .as(StepVerifier::create) // - .verifyComplete(); - - databaseClient.select().from(LegoSet.class) // - .matching(where("name").is("SCHAUFELRADBAGGER")) // - .fetch() // - .first() // - .as(StepVerifier::create) // - .assertNext(actual -> { - - assertThat(actual.getCert()).isEqualTo(new byte[] { 1, 2, 3, 4, 5 }); - }).verifyComplete(); - } - - @Test // gh-64 - public void update() { - - jdbc.execute("INSERT INTO legoset (id, name, manual) VALUES(42055, 'SCHAUFELRADBAGGER', 12)"); - - DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); - - databaseClient.update().table("legoset")// - .using(Update.update("name", "Lego")) // - .matching(Criteria.where("id").is(42055)) // - .fetch() // - .rowsUpdated() // - .as(StepVerifier::create) // - .expectNext(1) // - .verifyComplete(); - - assertThat(jdbc.queryForMap("SELECT name, manual FROM legoset")).containsEntry("name", "Lego"); - } - - @Test // gh-64 - public void updateWithoutResult() { - - jdbc.execute("INSERT INTO legoset (id, name, manual) VALUES(42055, 'SCHAUFELRADBAGGER', 12)"); - - DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); - - databaseClient.update().table("legoset")// - .using(Update.update("name", "Lego")) // - .then() // - .as(StepVerifier::create) // - .verifyComplete(); - - assertThat(jdbc.queryForMap("SELECT name, manual FROM legoset")).containsEntry("name", "Lego"); - } - - @Test // gh-64 - public void updateTypedObject() { - - jdbc.execute("INSERT INTO legoset (id, name, manual) VALUES(42055, 'SCHAUFELRADBAGGER', 12)"); - - LegoSet legoSet = new LegoSet(); - legoSet.setId(42055); - legoSet.setName("Lego"); - legoSet.setManual(null); - - DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); - - databaseClient.update() // - .table(LegoSet.class) // - .using(legoSet) // - .fetch() // - .rowsUpdated() // - .as(StepVerifier::create) // - .expectNext(1) // - .verifyComplete(); - - assertThat(jdbc.queryForMap("SELECT name, manual FROM legoset")).containsEntry("name", "Lego"); - } - - @Test // gh-64 - public void deleteUntyped() { - - jdbc.execute("INSERT INTO legoset (id, name, manual) VALUES(42055, 'SCHAUFELRADBAGGER', 12)"); - jdbc.execute("INSERT INTO legoset (id, name, manual) VALUES(42064, 'FORSCHUNGSSCHIFF', 13)"); - - DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); - - databaseClient.delete() // - .from("legoset") // - .matching(where("id").is(42055)) // - .fetch() // - .rowsUpdated() // - .as(StepVerifier::create) // - .expectNext(1).verifyComplete(); - - assertThat(jdbc.queryForList("SELECT id AS count FROM legoset")).hasSize(1); - } - - @Test // gh-64 - public void deleteTyped() { - - jdbc.execute("INSERT INTO legoset (id, name, manual) VALUES(42055, 'SCHAUFELRADBAGGER', 12)"); - jdbc.execute("INSERT INTO legoset (id, name, manual) VALUES(42064, 'FORSCHUNGSSCHIFF', 13)"); - - DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); - - databaseClient.delete() // - .from(LegoSet.class) // - .matching(where("id").is(42055)) // - .then() // - .as(StepVerifier::create) // - .verifyComplete(); - - assertThat(jdbc.queryForList("SELECT id AS count FROM legoset")).hasSize(1); - } - - @Test // gh-2 - public void selectAsMap() { - - jdbc.execute("INSERT INTO legoset (id, name, manual) VALUES(42055, 'SCHAUFELRADBAGGER', 12)"); - - DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); - - databaseClient.select().from(LegoSet.class) // - .project("id", "name", "manual") // - .orderBy(Sort.by("id")) // - .fetch() // - .all() // - .as(StepVerifier::create) // - .assertNext(actual -> { - assertThat(actual.getId()).isEqualTo(42055); - assertThat(actual.getName()).isEqualTo("SCHAUFELRADBAGGER"); - assertThat(actual.getManual()).isEqualTo(12); - }).verifyComplete(); - } - - @Test // gh-8 - public void selectExtracting() { - - jdbc.execute("INSERT INTO legoset (id, name, manual) VALUES(42055, 'SCHAUFELRADBAGGER', 12)"); - - DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); - - databaseClient.select().from("legoset") // - .project("id", "name", "manual") // - .orderBy(Sort.by("id")) // - .map((r) -> r.get("id", Integer.class)) // - .all() // - .as(StepVerifier::create) // - .expectNext(42055) // - .verifyComplete(); - } - - @Test // gh-109 - public void selectSimpleTypeProjection() { - - jdbc.execute("INSERT INTO legoset (id, name, manual) VALUES(42055, 'SCHAUFELRADBAGGER', 12)"); - - DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); - - databaseClient.execute("SELECT COUNT(*) FROM legoset") // - .as(Long.class) // - .fetch() // - .all() // - .as(StepVerifier::create) // - .expectNext(1L) // - .verifyComplete(); - - databaseClient.execute("SELECT name FROM legoset") // - .as(String.class) // - .fetch() // - .one() // - .as(StepVerifier::create) // - .expectNext("SCHAUFELRADBAGGER") // - .verifyComplete(); - } - - @Test // gh-8 - public void selectWithCriteria() { - - jdbc.execute("INSERT INTO legoset (id, name, manual) VALUES(42055, 'SCHAUFELRADBAGGER', 12)"); - - DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); - - databaseClient.select().from("legoset") // - .project("id", "name", "manual") // - .orderBy(Sort.by("id")) // - .matching(where("id").greaterThanOrEquals(42055).and("id").lessThanOrEquals(42055)) - .map((r) -> r.get("id", Integer.class)) // - .all() // - .as(StepVerifier::create) // - .expectNext(42055) // - .verifyComplete(); - } - - @Test // gh-64 - public void selectWithCriteriaIn() { - - jdbc.execute("INSERT INTO legoset (id, name, manual) VALUES(42055, 'SCHAUFELRADBAGGER', 12)"); - jdbc.execute("INSERT INTO legoset (id, name, manual) VALUES(42064, 'FORSCHUNGSSCHIFF', 13)"); - jdbc.execute("INSERT INTO legoset (id, name, manual) VALUES(42068, 'FLUGHAFEN-LÖSCHFAHRZEUG', 13)"); - - DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); - - databaseClient.select().from(LegoSet.class) // - .orderBy(Sort.by("id")) // - .matching(where("id").in(42055, 42064)) // - .map((r, md) -> r.get("id", Integer.class)) // - .all() // - .as(StepVerifier::create) // - .expectNext(42055) // - .expectNext(42064) // - .verifyComplete(); - } - - @Test // gh-2 - public void selectOrderByIdDesc() { - - jdbc.execute("INSERT INTO legoset (id, name, manual) VALUES(42055, 'SCHAUFELRADBAGGER', 12)"); - jdbc.execute("INSERT INTO legoset (id, name, manual) VALUES(42064, 'FORSCHUNGSSCHIFF', 13)"); - jdbc.execute("INSERT INTO legoset (id, name, manual) VALUES(42068, 'FLUGHAFEN-LÖSCHFAHRZEUG', 13)"); - - DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); - - databaseClient.select().from(LegoSet.class) // - .orderBy(Sort.by(desc("id"))) // - .fetch().all() // - .map(LegoSet::getId) // - .as(StepVerifier::create) // - .expectNext(42068, 42064, 42055) // - .verifyComplete(); - } - - @Test // gh-2 - public void selectOrderPaged() { - - jdbc.execute("INSERT INTO legoset (id, name, manual) VALUES(42055, 'SCHAUFELRADBAGGER', 12)"); - jdbc.execute("INSERT INTO legoset (id, name, manual) VALUES(42064, 'FORSCHUNGSSCHIFF', 13)"); - jdbc.execute("INSERT INTO legoset (id, name, manual) VALUES(42068, 'FLUGHAFEN-LÖSCHFAHRZEUG', 13)"); - - DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); - - databaseClient.select().from(LegoSet.class) // - .orderBy(Sort.by(desc("id"))) // - .page(PageRequest.of(2, 1)) // - .fetch().all() // - .map(LegoSet::getId) // - .as(StepVerifier::create) // - .expectNext(42055) // - .verifyComplete(); - - databaseClient.select().from(LegoSet.class) // - .page(PageRequest.of(2, 1, Sort.by(Sort.Direction.ASC, "id"))) // - .fetch().all() // - .map(LegoSet::getId) // - .as(StepVerifier::create) // - .expectNext(42068) // - .verifyComplete(); - } - - @Test // gh-2 - public void selectTypedLater() { - - jdbc.execute("INSERT INTO legoset (id, name, manual) VALUES(42055, 'SCHAUFELRADBAGGER', 12)"); - jdbc.execute("INSERT INTO legoset (id, name, manual) VALUES(42064, 'FORSCHUNGSSCHIFF', 13)"); - jdbc.execute("INSERT INTO legoset (id, name, manual) VALUES(42068, 'FLUGHAFEN-LÖSCHFAHRZEUG', 13)"); - - DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); - - databaseClient.select().from("legoset") // - .orderBy(Sort.by(desc("id"))) // - .as(LegoSet.class) // - .fetch().all() // - .map(LegoSet::getId) // - .as(StepVerifier::create) // - .expectNext(42068, 42064, 42055) // - .verifyComplete(); - } - - private Condition numberOf(int expected) { - return new Condition<>(it -> { - return it instanceof Number && ((Number) it).intValue() == expected; - }, "Number %d", expected); - } - - @Data - @Table("legoset") - static class LegoSet { - - @Id int id; - String name; - Integer manual; - byte[] cert; - } -} diff --git a/src/test/java/org/springframework/data/r2dbc/core/AbstractTransactionalDatabaseClientIntegrationTests.java b/src/test/java/org/springframework/data/r2dbc/core/AbstractTransactionalDatabaseClientIntegrationTests.java deleted file mode 100644 index 24c6feb8f..000000000 --- a/src/test/java/org/springframework/data/r2dbc/core/AbstractTransactionalDatabaseClientIntegrationTests.java +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Copyright 2018-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 reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import reactor.test.StepVerifier; - -import javax.sql.DataSource; - -import org.assertj.core.api.Condition; -import org.junit.After; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.support.GenericApplicationContext; -import org.springframework.dao.DataAccessException; -import org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration; -import org.springframework.data.r2dbc.testing.R2dbcIntegrationTestSupport; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.r2dbc.connection.R2dbcTransactionManager; -import org.springframework.r2dbc.core.DatabaseClient; -import org.springframework.transaction.ReactiveTransactionManager; -import org.springframework.transaction.annotation.EnableTransactionManagement; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.transaction.reactive.TransactionalOperator; -import org.springframework.transaction.support.DefaultTransactionDefinition; - -/** - * Abstract base class for transactional integration tests for {@link DatabaseClient}. - * - * @author Mark Paluch - * @author Christoph Strobl - */ -public abstract class AbstractTransactionalDatabaseClientIntegrationTests extends R2dbcIntegrationTestSupport { - - private ConnectionFactory connectionFactory; - - private JdbcTemplate jdbc; - - AnnotationConfigApplicationContext context; - TransactionalService service; - - DatabaseClient databaseClient; - R2dbcTransactionManager transactionManager; - TransactionalOperator rxtx; - - @BeforeEach - public void before() { - - connectionFactory = createConnectionFactory(); - - context = new AnnotationConfigApplicationContext(); - context.registerBean("theConnectionFactory", ConnectionFactory.class, () -> connectionFactory); - context.register(Config.class, TransactionalService.class); - context.refresh(); - - service = context.getBean(TransactionalService.class); - - jdbc = createJdbcTemplate(createDataSource()); - try { - jdbc.execute("DROP TABLE legoset"); - } catch (DataAccessException e) {} - jdbc.execute(getCreateTableStatement()); - jdbc.execute("DELETE FROM legoset"); - - databaseClient = DatabaseClient.create(connectionFactory); - transactionManager = new R2dbcTransactionManager(connectionFactory); - rxtx = TransactionalOperator.create(transactionManager); - } - - @After - public void tearDown() { - context.close(); - } - - /** - * Creates a {@link DataSource} to be used in this test. - * - * @return the {@link DataSource} to be used in this test. - */ - protected abstract DataSource createDataSource(); - - /** - * Creates a {@link ConnectionFactory} to be used in this test. - * - * @return the {@link ConnectionFactory} to be used in this test. - */ - protected abstract ConnectionFactory createConnectionFactory(); - - /** - * Returns the the CREATE TABLE statement for table {@code legoset} with the following three columns: - *
    - *
  • id integer (primary key), not null
  • - *
  • name varchar(255), nullable
  • - *
  • manual integer, nullable
  • - *
- * - * @return the CREATE TABLE statement for table {@code legoset} with three columns. - */ - protected abstract String getCreateTableStatement(); - - /** - * Get a parameterized {@code INSERT INTO legoset} statement setting id, name, and manual values. - */ - protected String getInsertIntoLegosetStatement() { - return "INSERT INTO legoset (id, name, manual) VALUES(:id, :name, :manual)"; - } - - /** - * Some Databases require special treatment to convince them to start a transaction. Some even start a transaction but - * store its id async so that it might show up a little late. - * - * @param client the client to use - * @return an empty {@link Mono} by default. - */ - protected Mono prepareForTransaction(DatabaseClient client) { - return Mono.empty(); - } - - /** - * Get a statement that returns the current transactionId. - */ - protected abstract String getCurrentTransactionIdStatement(); - - @Test // gh-2 - public void executeInsertInManagedTransaction() { - - Flux integerFlux = databaseClient // - .sql(getInsertIntoLegosetStatement()) // - .bind(0, 42055) // - .bind(1, "SCHAUFELRADBAGGER") // - .bindNull(2, Integer.class) // - .fetch().rowsUpdated().flux().as(rxtx::transactional); - - integerFlux.as(StepVerifier::create) // - .expectNext(1) // - .verifyComplete(); - - assertThat(jdbc.queryForMap("SELECT id, name, manual FROM legoset")).hasEntrySatisfying("id", numberOf(42055)); - } - - @Test // gh-2 - public void executeInsertInAutoCommitTransaction() { - - Flux integerFlux = databaseClient.sql(getInsertIntoLegosetStatement()) // - .bind(0, 42055) // - .bind(1, "SCHAUFELRADBAGGER") // - .bindNull(2, Integer.class) // - .fetch().rowsUpdated().flux().as(rxtx::transactional); - - integerFlux.as(StepVerifier::create) // - .expectNext(1) // - .verifyComplete(); - - assertThat(jdbc.queryForMap("SELECT id, name, manual FROM legoset")).hasEntrySatisfying("id", numberOf(42055)); - } - - @Test // gh-2 - public void shouldRollbackTransaction() { - - Mono integerFlux = databaseClient.sql(getInsertIntoLegosetStatement()) // - .bind(0, 42055) // - .bind(1, "SCHAUFELRADBAGGER") // - .bindNull(2, Integer.class) // - .fetch().rowsUpdated() // - .then(Mono.error(new IllegalStateException("failed"))).as(rxtx::transactional); - - integerFlux.as(StepVerifier::create) // - .expectError(IllegalStateException.class) // - .verify(); - - Integer count = jdbc.queryForObject("SELECT COUNT(*) FROM legoset", Integer.class); - assertThat(count).isEqualTo(0); - } - - @Test // gh-2, gh-75, gh-107 - public void emitTransactionIds() { - - Flux txId = databaseClient.sql(getCurrentTransactionIdStatement()) // - .map((row, md) -> row.get(0)) // - .all(); - - Flux transactionIds = prepareForTransaction(databaseClient).thenMany(txId.concatWith(txId)) // - .as(rxtx::transactional); - - transactionIds.collectList().as(StepVerifier::create) // - .consumeNextWith(actual -> { - - assertThat(actual).hasSize(2); - assertThat(actual.get(0)).isEqualTo(actual.get(1)); - }) // - .verifyComplete(); - } - - @Test // gh-107 - public void shouldRollbackTransactionUsingTransactionalOperator() { - - DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); - - TransactionalOperator transactionalOperator = TransactionalOperator - .create(new R2dbcTransactionManager(connectionFactory), new DefaultTransactionDefinition()); - - Flux integerFlux = databaseClient.sql(getInsertIntoLegosetStatement()) // - .bind(0, 42055) // - .bind(1, "SCHAUFELRADBAGGER") // - .bindNull(2, Integer.class) // - .fetch().rowsUpdated() // - .thenMany(Mono.fromSupplier(() -> { - throw new IllegalStateException("failed"); - })); - - integerFlux.as(transactionalOperator::transactional) // - .as(StepVerifier::create) // - .expectError(IllegalStateException.class) // - .verify(); - - Integer count = jdbc.queryForObject("SELECT COUNT(*) FROM legoset", Integer.class); - assertThat(count).isEqualTo(0); - } - - @Test // gh-107 - public void emitTransactionIdsUsingManagedTransactions() { - - service.emitTransactionIds(prepareForTransaction(service.getDatabaseClient()), getCurrentTransactionIdStatement()) - .collectList().as(StepVerifier::create) // - .consumeNextWith(actual -> { - - assertThat(actual).hasSize(2); - assertThat(actual.get(0)).isEqualTo(actual.get(1)); - }) // - .verifyComplete(); - } - - @Test // gh-107 - public void shouldRollbackTransactionUsingManagedTransactions() { - - service.shouldRollbackTransactionUsingTransactionalOperator(getInsertIntoLegosetStatement()) - .as(StepVerifier::create) // - .expectError(IllegalStateException.class) // - .verify(); - - Integer count = jdbc.queryForObject("SELECT COUNT(*) FROM legoset", Integer.class); - assertThat(count).isEqualTo(0); - } - - private Condition numberOf(int expected) { - return new Condition<>(it -> { - return it instanceof Number && ((Number) it).intValue() == expected; - }, "Number %d", expected); - } - - @Configuration - @EnableTransactionManagement - static class Config extends AbstractR2dbcConfiguration { - - @Autowired GenericApplicationContext context; - - @Override - public ConnectionFactory connectionFactory() { - return lookup(); - } - - ConnectionFactory lookup() { - return context.getBean("theConnectionFactory", ConnectionFactory.class); - } - - @Bean - ReactiveTransactionManager txMgr(ConnectionFactory connectionFactory) { - return new R2dbcTransactionManager(connectionFactory); - } - } - - static class TransactionalService { - - private final DatabaseClient databaseClient; - - public TransactionalService(DatabaseClient databaseClient) { - this.databaseClient = databaseClient; - } - - @Transactional - public Flux emitTransactionIds(Mono prepareTransaction, String idStatement) { - - Flux txId = databaseClient.sql(idStatement) // - .map((row, md) -> row.get(0)) // - .all(); - - return prepareTransaction.thenMany(txId.concatWith(txId)); - } - - @Transactional - public Flux shouldRollbackTransactionUsingTransactionalOperator(String insertStatement) { - - return databaseClient.sql(insertStatement) // - .bind(0, 42055) // - .bind(1, "SCHAUFELRADBAGGER") // - .bindNull(2, Integer.class) // - .fetch().rowsUpdated() // - .thenMany(Mono.fromSupplier(() -> { - throw new IllegalStateException("failed"); - })); - } - - public DatabaseClient getDatabaseClient() { - return databaseClient; - } - } -} diff --git a/src/test/java/org/springframework/data/r2dbc/core/DefaultDatabaseClientUnitTests.java b/src/test/java/org/springframework/data/r2dbc/core/DefaultDatabaseClientUnitTests.java deleted file mode 100644 index a6f445f5e..000000000 --- a/src/test/java/org/springframework/data/r2dbc/core/DefaultDatabaseClientUnitTests.java +++ /dev/null @@ -1,575 +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 static org.mockito.Mockito.*; -import static org.springframework.data.r2dbc.query.Criteria.*; - -import io.r2dbc.spi.Connection; -import io.r2dbc.spi.ConnectionFactory; -import io.r2dbc.spi.Result; -import io.r2dbc.spi.Statement; -import io.r2dbc.spi.test.MockColumnMetadata; -import io.r2dbc.spi.test.MockResult; -import io.r2dbc.spi.test.MockRow; -import io.r2dbc.spi.test.MockRowMetadata; -import reactor.core.CoreSubscriber; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import reactor.test.StepVerifier; - -import java.util.Arrays; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InOrder; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.jupiter.MockitoExtension; -import org.mockito.junit.jupiter.MockitoSettings; -import org.mockito.quality.Strictness; -import org.reactivestreams.Publisher; -import org.reactivestreams.Subscription; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.data.annotation.Id; -import org.springframework.data.projection.SpelAwareProxyProjectionFactory; -import org.springframework.data.r2dbc.dialect.PostgresDialect; -import org.springframework.data.r2dbc.mapping.SettableValue; -import org.springframework.lang.Nullable; - -/** - * Unit tests for {@link DefaultDatabaseClient}. - * - * @author Mark Paluch - * @author Ferdinand Jacobs - * @author Jens Schauder - * @author Zsombor Gegesy - */ -@ExtendWith(MockitoExtension.class) -@MockitoSettings(strictness = Strictness.LENIENT) -public class DefaultDatabaseClientUnitTests { - - @Mock Connection connection; - private DatabaseClient.Builder databaseClientBuilder; - - @BeforeEach - void before() { - - ConnectionFactory connectionFactory = Mockito.mock(ConnectionFactory.class); - - when(connectionFactory.create()).thenReturn((Publisher) Mono.just(connection)); - when(connection.close()).thenReturn(Mono.empty()); - - databaseClientBuilder = DatabaseClient.builder() // - .connectionFactory(connectionFactory) // - .dataAccessStrategy(new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)); - } - - @Test // gh-48 - void shouldCloseConnectionOnlyOnce() { - - DefaultDatabaseClient databaseClient = (DefaultDatabaseClient) databaseClientBuilder.build(); - - Flux flux = databaseClient.inConnectionMany(it -> Flux.empty()); - - flux.subscribe(new CoreSubscriber() { - Subscription subscription; - - @Override - public void onSubscribe(Subscription s) { - s.request(1); - subscription = s; - } - - @Override - public void onNext(Object o) {} - - @Override - public void onError(Throwable t) {} - - @Override - public void onComplete() { - subscription.cancel(); - } - }); - - verify(connection, times(1)).close(); - } - - @Test // gh-128 - void executeShouldBindNullValues() { - - Statement statement = mockStatementFor("SELECT * FROM table WHERE key = $1"); - - DatabaseClient databaseClient = databaseClientBuilder.build(); - - databaseClient.execute("SELECT * FROM table WHERE key = $1") // - .bindNull(0, String.class) // - .then() // - .as(StepVerifier::create) // - .verifyComplete(); - - verify(statement).bindNull(0, String.class); - - databaseClient.execute("SELECT * FROM table WHERE key = $1") // - .bindNull("$1", String.class) // - .then() // - .as(StepVerifier::create) // - .verifyComplete(); - - verify(statement).bindNull("$1", String.class); - } - - @Test // gh-162 - void executeShouldBindSettableValues() { - - Statement statement = mockStatementFor("SELECT * FROM table WHERE key = $1"); - - DatabaseClient databaseClient = databaseClientBuilder.build(); - - databaseClient.execute("SELECT * FROM table WHERE key = $1") // - .bind(0, SettableValue.empty(String.class)) // - .then() // - .as(StepVerifier::create) // - .verifyComplete(); - - verify(statement).bindNull(0, String.class); - - databaseClient.execute("SELECT * FROM table WHERE key = $1") // - .bind("$1", SettableValue.empty(String.class)) // - .then() // - .as(StepVerifier::create) // - .verifyComplete(); - - verify(statement).bindNull("$1", String.class); - } - - @Test // gh-128 - void executeShouldBindNamedNullValues() { - - Statement statement = mockStatementFor("SELECT * FROM table WHERE key = $1"); - DatabaseClient databaseClient = databaseClientBuilder.build(); - - databaseClient.execute("SELECT * FROM table WHERE key = :key") // - .bindNull("key", String.class) // - .then() // - .as(StepVerifier::create) // - .verifyComplete(); - - verify(statement).bindNull(0, String.class); - } - - @Test // gh-178 - void executeShouldBindNamedValuesFromIndexes() { - - Statement statement = mockStatementFor("SELECT id, name, manual FROM legoset WHERE name IN ($1, $2, $3)"); - - DatabaseClient databaseClient = databaseClientBuilder.build(); - - databaseClient.execute("SELECT id, name, manual FROM legoset WHERE name IN (:name)") // - .bind(0, Arrays.asList("unknown", "dunno", "other")) // - .then() // - .as(StepVerifier::create) // - .verifyComplete(); - - verify(statement).bind(0, "unknown"); - verify(statement).bind(1, "dunno"); - verify(statement).bind(2, "other"); - verify(statement).execute(); - verifyNoMoreInteractions(statement); - } - - @Test // gh-128, gh-162 - void executeShouldBindValues() { - - Statement statement = mockStatementFor("SELECT * FROM table WHERE key = $1"); - - DatabaseClient databaseClient = databaseClientBuilder.build(); - - databaseClient.execute("SELECT * FROM table WHERE key = $1") // - .bind(0, SettableValue.from("foo")) // - .then() // - .as(StepVerifier::create) // - .verifyComplete(); - - verify(statement).bind(0, "foo"); - - databaseClient.execute("SELECT * FROM table WHERE key = $1") // - .bind("$1", "foo") // - .then() // - .as(StepVerifier::create) // - .verifyComplete(); - - verify(statement).bind("$1", "foo"); - } - - @Test // gh-162 - void insertShouldAcceptNullValues() { - - Statement statement = mockStatementFor("INSERT INTO foo (first, second) VALUES ($1, $2)"); - DatabaseClient databaseClient = databaseClientBuilder.build(); - - databaseClient.insert().into("foo") // - .value("first", "foo") // - .nullValue("second", Integer.class) // - .then() // - .as(StepVerifier::create) // - .verifyComplete(); - - verify(statement).bind(0, "foo"); - verify(statement).bindNull(1, Integer.class); - } - - @Test // gh-162 - void insertShouldAcceptSettableValue() { - - Statement statement = mockStatementFor("INSERT INTO foo (first, second) VALUES ($1, $2)"); - DatabaseClient databaseClient = databaseClientBuilder.build(); - - databaseClient.insert().into("foo") // - .value("first", SettableValue.from("foo")) // - .value("second", SettableValue.empty(Integer.class)) // - .then() // - .as(StepVerifier::create) // - .verifyComplete(); - - verify(statement).bind(0, "foo"); - verify(statement).bindNull(1, Integer.class); - } - - @Test // gh-390 - void insertShouldWorkWithoutValues() { - - Statement statement = mockStatementFor("INSERT INTO id_only VALUES (DEFAULT)"); - DatabaseClient databaseClient = databaseClientBuilder.build(); - - databaseClient.insert().into("id_only") // - .then() // - .as(StepVerifier::create) // - .verifyComplete(); - - verify(statement).returnGeneratedValues(); - verify(statement).execute(); - verifyNoMoreInteractions(statement); - } - - @Test // gh-128 - void executeShouldBindNamedValuesByIndex() { - - Statement statement = mockStatementFor("SELECT * FROM table WHERE key = $1"); - DatabaseClient databaseClient = databaseClientBuilder.build(); - - databaseClient.execute("SELECT * FROM table WHERE key = :key") // - .bind("key", "foo") // - .then() // - .as(StepVerifier::create) // - .verifyComplete(); - - verify(statement).bind(0, "foo"); - } - - @Test // gh-177 - void deleteNotInShouldRenderCorrectQuery() { - - Statement statement = mockStatementFor("DELETE FROM tab WHERE tab.pole = $1 AND tab.id NOT IN ($2, $3)"); - DatabaseClient databaseClient = databaseClientBuilder.build(); - - databaseClient.delete().from("tab").matching(where("pole").is("foo").and("id").notIn(1, 2)) // - .then() // - .as(StepVerifier::create) // - .verifyComplete(); - - verify(statement).bind(0, "foo"); - verify(statement).bind(1, 1); - verify(statement).bind(2, 2); - } - - @Test // gh-243 - void rowsUpdatedShouldEmitSingleValue() { - - Result result = mock(Result.class); - when(result.getRowsUpdated()).thenReturn(Mono.empty(), Mono.just(2), Flux.just(1, 2, 3)); - mockStatementFor("DROP TABLE tab;", result); - - DatabaseClient databaseClient = databaseClientBuilder.build(); - - databaseClient.execute("DROP TABLE tab;") // - .fetch() // - .rowsUpdated() // - .as(StepVerifier::create) // - .expectNextCount(1) // - .verifyComplete(); - - databaseClient.execute("DROP TABLE tab;") // - .fetch() // - .rowsUpdated() // - .as(StepVerifier::create) // - .expectNextCount(1) // - .verifyComplete(); - - databaseClient.execute("DROP TABLE tab;") // - .fetch() // - .rowsUpdated() // - .as(StepVerifier::create) // - .expectNextCount(1) // - .verifyComplete(); - } - - @Test // gh-250 - void shouldThrowExceptionForSingleColumnObjectUpdate() { - - DatabaseClient databaseClient = databaseClientBuilder.build(); - - assertThatIllegalArgumentException().isThrownBy(() -> databaseClient.update() // - .table(IdOnly.class) // - .using(new IdOnly()) // - .then()).withMessageContaining("UPDATE contains no assignments"); - } - - @Test // gh-260 - void shouldProjectGenericExecuteAs() { - - MockResult result = mockSingleColumnResult(MockRow.builder().identified(0, Object.class, "Walter")); - mockStatement(result); - - DatabaseClient databaseClient = databaseClientBuilder // - .projectionFactory(new SpelAwareProxyProjectionFactory()) // - .build(); - - databaseClient.execute("SELECT * FROM person") // - .as(Projection.class) // - .fetch() // - .one() // - .as(StepVerifier::create) // - .consumeNextWith(actual -> { - - assertThat(actual.getName()).isEqualTo("Walter"); - assertThat(actual.getGreeting()).isEqualTo("Hello Walter"); - - }) // - .verifyComplete(); - } - - @Test // gh-260 - void shouldProjectGenericSelectAs() { - - MockResult result = mockSingleColumnResult(MockRow.builder().identified(0, Object.class, "Walter")); - mockStatement(result); - - DatabaseClient databaseClient = databaseClientBuilder // - .projectionFactory(new SpelAwareProxyProjectionFactory()) // - .build(); - - databaseClient.select().from("person") // - .project("*") // - .as(Projection.class) // - .fetch() // - .one() // - .as(StepVerifier::create) // - .consumeNextWith(actual -> { - - assertThat(actual.getName()).isEqualTo("Walter"); - assertThat(actual.getGreeting()).isEqualTo("Hello Walter"); - - }) // - .verifyComplete(); - } - - @Test // gh-260 - void shouldProjectTypedSelectAs() { - - MockResult result = mockSingleColumnResult(MockRow.builder().identified("name", Object.class, "Walter")); - mockStatement(result); - - DatabaseClient databaseClient = databaseClientBuilder // - .projectionFactory(new SpelAwareProxyProjectionFactory()) // - .build(); - - databaseClient.select().from(Person.class) // - .as(Projection.class) // - .one() // - .as(StepVerifier::create) // - .consumeNextWith(actual -> { - - assertThat(actual.getName()).isEqualTo("Walter"); - assertThat(actual.getGreeting()).isEqualTo("Hello Walter"); - - }) // - .verifyComplete(); - } - - @Test // gh-189 - void shouldApplyExecuteFunction() { - - Statement statement = mockStatement(); - MockResult result = mockSingleColumnResult(MockRow.builder().identified(0, Object.class, "Walter")); - - DatabaseClient databaseClient = databaseClientBuilder // - .executeFunction(it -> Mono.just(result)) // - .build(); - - databaseClient.execute("SELECT") // - .fetch().all() // - .as(StepVerifier::create) // - .expectNextCount(1).verifyComplete(); - - verifyNoInteractions(statement); - } - - @Test // gh-189 - void shouldApplyStatementFilterFunctions() { - - MockRowMetadata metadata = MockRowMetadata.builder() - .columnMetadata(MockColumnMetadata.builder().name("name").build()).build(); - MockResult result = MockResult.builder().rowMetadata(metadata).build(); - - Statement statement = mockStatement(result); - - DatabaseClient databaseClient = databaseClientBuilder.build(); - - databaseClient.execute("SELECT") // - .filter((s, next) -> next.execute(s.returnGeneratedValues("foo"))) // - .filter((s, next) -> next.execute(s.returnGeneratedValues("bar"))) // - .fetch().all() // - .as(StepVerifier::create) // - .verifyComplete(); - - InOrder inOrder = inOrder(statement); - inOrder.verify(statement).returnGeneratedValues("foo"); - inOrder.verify(statement).returnGeneratedValues("bar"); - inOrder.verify(statement).execute(); - inOrder.verifyNoMoreInteractions(); - } - - @Test // gh-189 - void shouldApplyStatementFilterFunctionsToTypedExecute() { - - MockRowMetadata metadata = MockRowMetadata.builder() - .columnMetadata(MockColumnMetadata.builder().name("name").build()).build(); - MockResult result = MockResult.builder().rowMetadata(metadata).build(); - - Statement statement = mockStatement(result); - - DatabaseClient databaseClient = databaseClientBuilder.build(); - - databaseClient.execute("SELECT") // - .filter((s, next) -> next.execute(s.returnGeneratedValues("foo"))) // - .as(Person.class) // - .fetch().all() // - .as(StepVerifier::create) // - .verifyComplete(); - - InOrder inOrder = inOrder(statement); - inOrder.verify(statement).returnGeneratedValues("foo"); - inOrder.verify(statement).execute(); - inOrder.verifyNoMoreInteractions(); - } - - @Test // gh-189 - void shouldApplySimpleStatementFilterFunctions() { - - MockResult result = mockSingleColumnEmptyResult(); - - Statement statement = mockStatement(result); - - DatabaseClient databaseClient = databaseClientBuilder.build(); - - databaseClient.execute("SELECT") // - .filter(s -> s.returnGeneratedValues("foo")) // - .filter(s -> s.returnGeneratedValues("bar")) // - .fetch().all() // - .as(StepVerifier::create) // - .verifyComplete(); - - InOrder inOrder = inOrder(statement); - inOrder.verify(statement).returnGeneratedValues("foo"); - inOrder.verify(statement).returnGeneratedValues("bar"); - inOrder.verify(statement).execute(); - inOrder.verifyNoMoreInteractions(); - } - - private Statement mockStatement() { - return mockStatementFor(null, null); - } - - private Statement mockStatement(Result result) { - return mockStatementFor(null, result); - } - - private Statement mockStatementFor(String sql) { - return mockStatementFor(sql, null); - } - - private Statement mockStatementFor(@Nullable String sql, @Nullable Result result) { - - Statement statement = mock(Statement.class); - when(connection.createStatement(sql == null ? anyString() : eq(sql))).thenReturn(statement); - when(statement.returnGeneratedValues(anyString())).thenReturn(statement); - when(statement.returnGeneratedValues()).thenReturn(statement); - - doReturn(result == null ? Mono.empty() : Flux.just(result)).when(statement).execute(); - - return statement; - } - - private MockResult mockSingleColumnEmptyResult() { - return mockSingleColumnResult(null); - } - - /** - * Mocks a {@link Result} with a single column "name" and a single row if a non null row is provided. - */ - private MockResult mockSingleColumnResult(@Nullable MockRow.Builder row) { - - MockRowMetadata metadata = MockRowMetadata.builder() - .columnMetadata(MockColumnMetadata.builder().name("name").build()).build(); - - MockResult.Builder resultBuilder = MockResult.builder().rowMetadata(metadata); - if (row != null) { - resultBuilder = resultBuilder.row(row.build()); - } - return resultBuilder.build(); - } - - static class Person { - - String name; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - } - - interface Projection { - - String getName(); - - @Value("#{'Hello ' + target.name}") - String getGreeting(); - } - - static class IdOnly { - - @Id String id; - } -} diff --git a/src/test/java/org/springframework/data/r2dbc/core/H2DatabaseClientIntegrationTests.java b/src/test/java/org/springframework/data/r2dbc/core/H2DatabaseClientIntegrationTests.java deleted file mode 100644 index a422cb889..000000000 --- a/src/test/java/org/springframework/data/r2dbc/core/H2DatabaseClientIntegrationTests.java +++ /dev/null @@ -1,48 +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 javax.sql.DataSource; - -import org.springframework.data.r2dbc.testing.H2TestSupport; - -/** - * Integration tests for {@link DatabaseClient} against H2. - * - * @author Mark Paluch - */ -public class H2DatabaseClientIntegrationTests extends AbstractDatabaseClientIntegrationTests { - - @Override - protected DataSource createDataSource() { - return H2TestSupport.createDataSource(); - } - - @Override - protected ConnectionFactory createConnectionFactory() { - return H2TestSupport.createConnectionFactory(); - } - - @Override - protected String getCreateTableStatement() { - return H2TestSupport.CREATE_TABLE_LEGOSET; - } - - @Override - public void shouldTranslateDuplicateKeyException() {} -} diff --git a/src/test/java/org/springframework/data/r2dbc/core/MariaDbDatabaseClientIntegrationTests.java b/src/test/java/org/springframework/data/r2dbc/core/MariaDbDatabaseClientIntegrationTests.java deleted file mode 100644 index 96e62dba2..000000000 --- a/src/test/java/org/springframework/data/r2dbc/core/MariaDbDatabaseClientIntegrationTests.java +++ /dev/null @@ -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.MariaDbTestSupport; -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 MariaDB. - * - * @author Mark Paluch - * @author Mingyuan Wu - */ -public class MariaDbDatabaseClientIntegrationTests extends AbstractDatabaseClientIntegrationTests { - - @RegisterExtension public static final ExternalDatabase database = MariaDbTestSupport.database(); - - @Override - protected DataSource createDataSource() { - return MariaDbTestSupport.createDataSource(database); - } - - @Override - protected ConnectionFactory createConnectionFactory() { - return MariaDbTestSupport.createConnectionFactory(database); - } - - @Override - protected String getCreateTableStatement() { - return MariaDbTestSupport.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 { - INSTANCE; - - @Override - public String convert(UUID uuid) { - return uuid.toString(); - } - } - - @ReadingConverter - enum StringToUuidConverter implements Converter { - INSTANCE; - - @Override - public UUID convert(String value) { - return UUID.fromString(value); - } - } - -} diff --git a/src/test/java/org/springframework/data/r2dbc/core/MariaDbTransactionalDatabaseClientIntegrationTests.java b/src/test/java/org/springframework/data/r2dbc/core/MariaDbTransactionalDatabaseClientIntegrationTests.java deleted file mode 100644 index 058c59f3c..000000000 --- a/src/test/java/org/springframework/data/r2dbc/core/MariaDbTransactionalDatabaseClientIntegrationTests.java +++ /dev/null @@ -1,78 +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.MariaDbTestSupport; -import org.springframework.r2dbc.core.DatabaseClient; - -/** - * Transactional integration tests for {@link DatabaseClient} against MariaDb. - * - * @author Mark Paluch - */ -public class MariaDbTransactionalDatabaseClientIntegrationTests - extends AbstractTransactionalDatabaseClientIntegrationTests { - - @RegisterExtension public static final ExternalDatabase database = MariaDbTestSupport.database(); - - @Override - protected DataSource createDataSource() { - return MariaDbTestSupport.createDataSource(database); - } - - @Override - protected ConnectionFactory createConnectionFactory() { - return MariaDbTestSupport.createConnectionFactory(database); - } - - @Override - protected String getCreateTableStatement() { - return MariaDbTestSupport.CREATE_TABLE_LEGOSET; - } - - @Override - protected Mono prepareForTransaction(DatabaseClient client) { - - /* - * We have to execute a sql statement first. - * Otherwise Mariadb don't have a transaction id. - * And we need to delay emitting the result so that Mariadb has time to write the transaction id, which is done in - * batches every now and then. - */ - 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()"; - } -} diff --git a/src/test/java/org/springframework/data/r2dbc/core/MySqlDatabaseClientIntegrationTests.java b/src/test/java/org/springframework/data/r2dbc/core/MySqlDatabaseClientIntegrationTests.java deleted file mode 100644 index 8662160b2..000000000 --- a/src/test/java/org/springframework/data/r2dbc/core/MySqlDatabaseClientIntegrationTests.java +++ /dev/null @@ -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 { - INSTANCE; - - @Override - public String convert(UUID uuid) { - return uuid.toString(); - } - } - - @ReadingConverter - enum StringToUuidConverter implements Converter { - INSTANCE; - - @Override - public UUID convert(String value) { - return UUID.fromString(value); - } - } - -} diff --git a/src/test/java/org/springframework/data/r2dbc/core/MySqlTransactionalDatabaseClientIntegrationTests.java b/src/test/java/org/springframework/data/r2dbc/core/MySqlTransactionalDatabaseClientIntegrationTests.java deleted file mode 100644 index b26b48f30..000000000 --- a/src/test/java/org/springframework/data/r2dbc/core/MySqlTransactionalDatabaseClientIntegrationTests.java +++ /dev/null @@ -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 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()"; - } -} diff --git a/src/test/java/org/springframework/data/r2dbc/core/NamedParameterUtilsUnitTests.java b/src/test/java/org/springframework/data/r2dbc/core/NamedParameterUtilsUnitTests.java deleted file mode 100644 index 7b3b71d5b..000000000 --- a/src/test/java/org/springframework/data/r2dbc/core/NamedParameterUtilsUnitTests.java +++ /dev/null @@ -1,468 +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 static org.mockito.Mockito.*; - -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; - -import org.junit.jupiter.api.Test; - -import org.springframework.data.r2dbc.dialect.BindTarget; -import org.springframework.data.r2dbc.dialect.PostgresDialect; -import org.springframework.data.r2dbc.dialect.SqlServerDialect; -import org.springframework.data.r2dbc.mapping.SettableValue; -import org.springframework.r2dbc.core.binding.BindMarkersFactory; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; - -/** - * Unit tests for {@link NamedParameterUtils}. - * - * @author Mark Paluch - * @author Jens Schauder - */ -class NamedParameterUtilsUnitTests { - - private final BindMarkersFactory BIND_MARKERS = PostgresDialect.INSTANCE.getBindMarkersFactory(); - - @Test // gh-23 - void shouldParseSql() { - - String sql = "xxx :a yyyy :b :c :a zzzzz"; - ParsedSql psql = NamedParameterUtils.parseSqlStatement(sql); - assertThat(psql.getParameterNames()).containsExactly("a", "b", "c", "a"); - assertThat(psql.getTotalParameterCount()).isEqualTo(4); - assertThat(psql.getNamedParameterCount()).isEqualTo(3); - - String sql2 = "xxx &a yyyy ? zzzzz"; - ParsedSql psql2 = NamedParameterUtils.parseSqlStatement(sql2); - assertThat(psql2.getParameterNames()).containsExactly("a"); - assertThat(psql2.getTotalParameterCount()).isEqualTo(1); - assertThat(psql2.getNamedParameterCount()).isEqualTo(1); - - String sql3 = "xxx &ä+:ö" + '\t' + ":ü%10 yyyy ? zzzzz"; - ParsedSql psql3 = NamedParameterUtils.parseSqlStatement(sql3); - assertThat(psql3.getParameterNames()).containsExactly("ä", "ö", "ü"); - } - - @Test // gh-23 - void substituteNamedParameters() { - - MapBindParameterSource namedParams = new MapBindParameterSource(new HashMap<>()); - namedParams.addValue("a", "a").addValue("b", "b").addValue("c", "c"); - - PreparedOperation operation = NamedParameterUtils.substituteNamedParameters("xxx :a :b :c", - PostgresDialect.INSTANCE.getBindMarkersFactory(), namedParams); - - assertThat(operation.toQuery()).isEqualTo("xxx $1 $2 $3"); - - PreparedOperation operation2 = NamedParameterUtils.substituteNamedParameters("xxx :a :b :c", - SqlServerDialect.INSTANCE.getBindMarkersFactory(), namedParams); - - assertThat(operation2.toQuery()).isEqualTo("xxx @P0_a @P1_b @P2_c"); - } - - @Test // gh-23 - void substituteObjectArray() { - - MapBindParameterSource namedParams = new MapBindParameterSource(new HashMap<>()); - namedParams.addValue("a", - Arrays.asList(new Object[] { "Walter", "Heisenberg" }, new Object[] { "Walt Jr.", "Flynn" })); - - PreparedOperation operation = NamedParameterUtils.substituteNamedParameters("xxx :a", BIND_MARKERS, namedParams); - - assertThat(operation.toQuery()).isEqualTo("xxx ($1, $2), ($3, $4)"); - } - - @Test // gh-23, gh-105 - void shouldBindObjectArray() { - - MapBindParameterSource namedParams = new MapBindParameterSource(new HashMap<>()); - namedParams.addValue("a", - Arrays.asList(new Object[] { "Walter", "Heisenberg" }, new Object[] { "Walt Jr.", "Flynn" })); - - BindTarget bindTarget = mock(BindTarget.class); - - PreparedOperation operation = NamedParameterUtils.substituteNamedParameters("xxx :a", BIND_MARKERS, namedParams); - operation.bindTo(bindTarget); - - verify(bindTarget).bind(0, "Walter"); - verify(bindTarget).bind(1, "Heisenberg"); - verify(bindTarget).bind(2, "Walt Jr."); - verify(bindTarget).bind(3, "Flynn"); - } - - @Test // gh-23 - void parseSqlContainingComments() { - - String sql1 = "/*+ HINT */ xxx /* comment ? */ :a yyyy :b :c :a zzzzz -- :xx XX\n"; - - ParsedSql psql1 = NamedParameterUtils.parseSqlStatement(sql1); - assertThat(expand(psql1)).isEqualTo("/*+ HINT */ xxx /* comment ? */ $1 yyyy $2 $3 $1 zzzzz -- :xx XX\n"); - - MapBindParameterSource paramMap = new MapBindParameterSource(new HashMap<>()); - paramMap.addValue("a", "a"); - paramMap.addValue("b", "b"); - paramMap.addValue("c", "c"); - - String sql2 = "/*+ HINT */ xxx /* comment ? */ :a yyyy :b :c :a zzzzz -- :xx XX"; - ParsedSql psql2 = NamedParameterUtils.parseSqlStatement(sql2); - assertThat(expand(psql2)).isEqualTo("/*+ HINT */ xxx /* comment ? */ $1 yyyy $2 $3 $1 zzzzz -- :xx XX"); - } - - @Test // gh-23 - void parseSqlStatementWithPostgresCasting() { - - String expectedSql = "select 'first name' from artists where id = $1 and birth_date=$2::timestamp"; - String sql = "select 'first name' from artists where id = :id and birth_date=:birthDate::timestamp"; - - ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql); - PreparedOperation operation = NamedParameterUtils.substituteNamedParameters(parsedSql, BIND_MARKERS, - new MapBindParameterSource()); - - assertThat(operation.toQuery()).isEqualTo(expectedSql); - } - - @Test // gh-23 - void parseSqlStatementWithPostgresContainedOperator() { - - String expectedSql = "select 'first name' from artists where info->'stat'->'albums' = ?? $1 and '[\"1\",\"2\",\"3\"]'::jsonb ?? '4'"; - String sql = "select 'first name' from artists where info->'stat'->'albums' = ?? :album and '[\"1\",\"2\",\"3\"]'::jsonb ?? '4'"; - - ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql); - - assertThat(parsedSql.getTotalParameterCount()).isEqualTo(1); - assertThat(expand(parsedSql)).isEqualTo(expectedSql); - } - - @Test // gh-23 - void parseSqlStatementWithPostgresAnyArrayStringsExistsOperator() { - - String expectedSql = "select '[\"3\", \"11\"]'::jsonb ?| '{1,3,11,12,17}'::text[]"; - String sql = "select '[\"3\", \"11\"]'::jsonb ?| '{1,3,11,12,17}'::text[]"; - - ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql); - - assertThat(parsedSql.getTotalParameterCount()).isEqualTo(0); - assertThat(expand(parsedSql)).isEqualTo(expectedSql); - } - - @Test // gh-23 - void parseSqlStatementWithPostgresAllArrayStringsExistsOperator() { - - String expectedSql = "select '[\"3\", \"11\"]'::jsonb ?& '{1,3,11,12,17}'::text[] AND $1 = 'Back in Black'"; - String sql = "select '[\"3\", \"11\"]'::jsonb ?& '{1,3,11,12,17}'::text[] AND :album = 'Back in Black'"; - - ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql); - assertThat(parsedSql.getTotalParameterCount()).isEqualTo(1); - assertThat(expand(parsedSql)).isEqualTo(expectedSql); - } - - @Test // gh-23 - void parseSqlStatementWithEscapedColon() { - - String expectedSql = "select '0\\:0' as a, foo from bar where baz < DATE($1 23:59:59) and baz = $2"; - String sql = "select '0\\:0' as a, foo from bar where baz < DATE(:p1 23\\:59\\:59) and baz = :p2"; - - ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql); - - assertThat(parsedSql.getParameterNames()).containsExactly("p1", "p2"); - assertThat(expand(parsedSql)).isEqualTo(expectedSql); - } - - @Test // gh-23 - void parseSqlStatementWithBracketDelimitedParameterNames() { - - String expectedSql = "select foo from bar where baz = b$1$2z"; - String sql = "select foo from bar where baz = b:{p1}:{p2}z"; - - ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql); - assertThat(parsedSql.getParameterNames()).containsExactly("p1", "p2"); - assertThat(expand(parsedSql)).isEqualTo(expectedSql); - } - - @Test // gh-23 - void parseSqlStatementWithEmptyBracketsOrBracketsInQuotes() { - - String expectedSql = "select foo from bar where baz = b:{}z"; - String sql = "select foo from bar where baz = b:{}z"; - - ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql); - - assertThat(parsedSql.getParameterNames()).isEmpty(); - assertThat(expand(parsedSql)).isEqualTo(expectedSql); - - String expectedSql2 = "select foo from bar where baz = 'b:{p1}z'"; - String sql2 = "select foo from bar where baz = 'b:{p1}z'"; - - ParsedSql parsedSql2 = NamedParameterUtils.parseSqlStatement(sql2); - assertThat(parsedSql2.getParameterNames()).isEmpty(); - assertThat(expand(parsedSql2)).isEqualTo(expectedSql2); - } - - @Test // gh-23 - void parseSqlStatementWithSingleLetterInBrackets() { - - String expectedSql = "select foo from bar where baz = b$1z"; - String sql = "select foo from bar where baz = b:{p}z"; - - ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql); - assertThat(parsedSql.getParameterNames()).containsExactly("p"); - assertThat(expand(parsedSql)).isEqualTo(expectedSql); - } - - @Test // gh-23 - void parseSqlStatementWithLogicalAnd() { - - String expectedSql = "xxx & yyyy"; - - ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(expectedSql); - - assertThat(expand(parsedSql)).isEqualTo(expectedSql); - } - - @Test // gh-23 - void substituteNamedParametersWithLogicalAnd() { - - String expectedSql = "xxx & yyyy"; - - assertThat(expand(expectedSql)).isEqualTo(expectedSql); - } - - @Test // gh-23 - void variableAssignmentOperator() { - - String expectedSql = "x := 1"; - - assertThat(expand(expectedSql)).isEqualTo(expectedSql); - } - - @Test // gh-23 - void parseSqlStatementWithQuotedSingleQuote() { - - String sql = "SELECT ':foo'':doo', :xxx FROM DUAL"; - - ParsedSql psql = NamedParameterUtils.parseSqlStatement(sql); - - assertThat(psql.getTotalParameterCount()).isEqualTo(1); - assertThat(psql.getParameterNames()).containsExactly("xxx"); - } - - @Test // gh-23 - void parseSqlStatementWithQuotesAndCommentBefore() { - - String sql = "SELECT /*:doo*/':foo', :xxx FROM DUAL"; - - ParsedSql psql = NamedParameterUtils.parseSqlStatement(sql); - - assertThat(psql.getTotalParameterCount()).isEqualTo(1); - assertThat(psql.getParameterNames()).containsExactly("xxx"); - } - - @Test // gh-23 - void parseSqlStatementWithQuotesAndCommentAfter() { - - String sql2 = "SELECT ':foo'/*:doo*/, :xxx FROM DUAL"; - - ParsedSql psql2 = NamedParameterUtils.parseSqlStatement(sql2); - - assertThat(psql2.getTotalParameterCount()).isEqualTo(1); - assertThat(psql2.getParameterNames()).containsExactly("xxx"); - } - - @Test // gh-138 - void shouldAllowParsingMultipleUseOfParameter() { - - String sql = "SELECT * FROM person where name = :id or lastname = :id"; - - ParsedSql parsed = NamedParameterUtils.parseSqlStatement(sql); - - assertThat(parsed.getTotalParameterCount()).isEqualTo(2); - assertThat(parsed.getNamedParameterCount()).isEqualTo(1); - assertThat(parsed.getParameterNames()).containsExactly("id", "id"); - } - - @Test // gh-138 - void multipleEqualParameterReferencesBindsValueOnce() { - - String sql = "SELECT * FROM person where name = :id or lastname = :id"; - - BindMarkersFactory factory = BindMarkersFactory.indexed("$", 0); - - PreparedOperation operation = NamedParameterUtils.substituteNamedParameters(sql, factory, - new MapBindParameterSource(Collections.singletonMap("id", SettableValue.from("foo")))); - - assertThat(operation.toQuery()).isEqualTo("SELECT * FROM person where name = $0 or lastname = $0"); - - operation.bindTo(new BindTarget() { - @Override - public void bind(String identifier, Object value) { - throw new UnsupportedOperationException(); - } - - @Override - public void bind(int index, Object value) { - assertThat(index).isEqualTo(0); - assertThat(value).isEqualTo("foo"); - } - - @Override - public void bindNull(String identifier, Class type) { - throw new UnsupportedOperationException(); - } - - @Override - public void bindNull(int index, Class type) { - throw new UnsupportedOperationException(); - } - }); - } - - @Test // gh-310 - void multipleEqualCollectionParameterReferencesBindsValueOnce() { - - String sql = "SELECT * FROM person where name IN (:ids) or lastname IN (:ids)"; - - BindMarkersFactory factory = BindMarkersFactory.indexed("$", 0); - - MultiValueMap bindings = new LinkedMultiValueMap<>(); - - PreparedOperation operation = NamedParameterUtils.substituteNamedParameters(sql, factory, - new MapBindParameterSource( - Collections.singletonMap("ids", SettableValue.from(Arrays.asList("foo", "bar", "baz"))))); - - assertThat(operation.toQuery()) - .isEqualTo("SELECT * FROM person where name IN ($0, $1, $2) or lastname IN ($0, $1, $2)"); - - operation.bindTo(new BindTarget() { - @Override - public void bind(String identifier, Object value) { - throw new UnsupportedOperationException(); - } - - @Override - public void bind(int index, Object value) { - assertThat(index).isIn(0, 1, 2); - assertThat(value).isIn("foo", "bar", "baz"); - - bindings.add(index, value); - } - - @Override - public void bindNull(String identifier, Class type) { - throw new UnsupportedOperationException(); - } - - @Override - public void bindNull(int index, Class type) { - throw new UnsupportedOperationException(); - } - }); - - assertThat(bindings).containsEntry(0, Collections.singletonList("foo")) // - .containsEntry(1, Collections.singletonList("bar")) // - .containsEntry(2, Collections.singletonList("baz")); - } - - @Test // gh-138 - void multipleEqualParameterReferencesForAnonymousMarkersBindsValueMultipleTimes() { - - String sql = "SELECT * FROM person where name = :id or lastname = :id"; - - BindMarkersFactory factory = BindMarkersFactory.anonymous("?"); - - PreparedOperation operation = NamedParameterUtils.substituteNamedParameters(sql, factory, - new MapBindParameterSource(Collections.singletonMap("id", SettableValue.from("foo")))); - - assertThat(operation.toQuery()).isEqualTo("SELECT * FROM person where name = ? or lastname = ?"); - - Map bindValues = new LinkedHashMap<>(); - - operation.bindTo(new BindTarget() { - @Override - public void bind(String identifier, Object value) { - throw new UnsupportedOperationException(); - } - - @Override - public void bind(int index, Object value) { - bindValues.put(index, value); - } - - @Override - public void bindNull(String identifier, Class type) { - throw new UnsupportedOperationException(); - } - - @Override - public void bindNull(int index, Class type) { - throw new UnsupportedOperationException(); - } - }); - - assertThat(bindValues).hasSize(2).containsEntry(0, "foo").containsEntry(1, "foo"); - } - - @Test // gh-138 - void multipleEqualParameterReferencesBindsNullOnce() { - - String sql = "SELECT * FROM person where name = :id or lastname = :id"; - - BindMarkersFactory factory = BindMarkersFactory.indexed("$", 0); - - PreparedOperation operation = NamedParameterUtils.substituteNamedParameters(sql, factory, - new MapBindParameterSource(Collections.singletonMap("id", SettableValue.empty(String.class)))); - - assertThat(operation.toQuery()).isEqualTo("SELECT * FROM person where name = $0 or lastname = $0"); - - operation.bindTo(new BindTarget() { - @Override - public void bind(String identifier, Object value) { - throw new UnsupportedOperationException(); - } - - @Override - public void bind(int index, Object value) { - throw new UnsupportedOperationException(); - } - - @Override - public void bindNull(String identifier, Class type) { - throw new UnsupportedOperationException(); - } - - @Override - public void bindNull(int index, Class type) { - assertThat(index).isEqualTo(0); - assertThat(type).isEqualTo(String.class); - } - }); - } - - private String expand(ParsedSql sql) { - return NamedParameterUtils.substituteNamedParameters(sql, BIND_MARKERS, new MapBindParameterSource()).toQuery(); - } - - private String expand(String sql) { - return NamedParameterUtils.substituteNamedParameters(sql, BIND_MARKERS, new MapBindParameterSource()).toQuery(); - } -} diff --git a/src/test/java/org/springframework/data/r2dbc/core/OracleDatabaseClientIntegrationTests.java b/src/test/java/org/springframework/data/r2dbc/core/OracleDatabaseClientIntegrationTests.java deleted file mode 100644 index 4f30a1c07..000000000 --- a/src/test/java/org/springframework/data/r2dbc/core/OracleDatabaseClientIntegrationTests.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2018-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 javax.sql.DataSource; - -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.extension.RegisterExtension; - -import org.springframework.data.r2dbc.testing.EnabledOnClass; -import org.springframework.data.r2dbc.testing.ExternalDatabase; -import org.springframework.data.r2dbc.testing.OracleTestSupport; - -/** - * Integration tests for {@link DatabaseClient} against Oracle. - * - * @author Mark Paluch - */ -@EnabledOnClass("oracle.r2dbc.impl.OracleConnectionFactoryProviderImpl") -public class OracleDatabaseClientIntegrationTests extends AbstractDatabaseClientIntegrationTests { - - @RegisterExtension public static final ExternalDatabase database = OracleTestSupport.database(); - - @Override - protected DataSource createDataSource() { - return OracleTestSupport.createDataSource(database); - } - - @Override - protected ConnectionFactory createConnectionFactory() { - return OracleTestSupport.createConnectionFactory(database); - } - - @Override - protected String getCreateTableStatement() { - return OracleTestSupport.CREATE_TABLE_LEGOSET; - } - - @Override - @Disabled("https://github.com/oracle/oracle-r2dbc/issues/9") - public void executeSelectNamedParameters() {} -} diff --git a/src/test/java/org/springframework/data/r2dbc/core/PostgresDatabaseClientIntegrationTests.java b/src/test/java/org/springframework/data/r2dbc/core/PostgresDatabaseClientIntegrationTests.java deleted file mode 100644 index abe0a987a..000000000 --- a/src/test/java/org/springframework/data/r2dbc/core/PostgresDatabaseClientIntegrationTests.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2018-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 javax.sql.DataSource; - -import org.junit.jupiter.api.extension.RegisterExtension; - -import org.springframework.data.r2dbc.testing.ExternalDatabase; -import org.springframework.data.r2dbc.testing.PostgresTestSupport; - -/** - * Integration tests for {@link DatabaseClient} against PostgreSQL. - * - * @author Mark Paluch - */ -public class PostgresDatabaseClientIntegrationTests extends AbstractDatabaseClientIntegrationTests { - - @RegisterExtension public static final ExternalDatabase database = PostgresTestSupport.database(); - - @Override - protected DataSource createDataSource() { - return PostgresTestSupport.createDataSource(database); - } - - @Override - protected ConnectionFactory createConnectionFactory() { - return PostgresTestSupport.createConnectionFactory(database); - } - - @Override - protected String getCreateTableStatement() { - return PostgresTestSupport.CREATE_TABLE_LEGOSET; - } - -} diff --git a/src/test/java/org/springframework/data/r2dbc/core/PostgresIntegrationTests.java b/src/test/java/org/springframework/data/r2dbc/core/PostgresIntegrationTests.java index 8a8b79cfa..5a011b2a1 100644 --- a/src/test/java/org/springframework/data/r2dbc/core/PostgresIntegrationTests.java +++ b/src/test/java/org/springframework/data/r2dbc/core/PostgresIntegrationTests.java @@ -36,10 +36,8 @@ import lombok.Data; import reactor.test.StepVerifier; import java.time.Duration; -import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.function.Consumer; import javax.sql.DataSource; @@ -57,6 +55,7 @@ import org.springframework.data.r2dbc.testing.R2dbcIntegrationTestSupport; import org.springframework.data.relational.core.mapping.Table; import org.springframework.data.relational.core.query.Query; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.r2dbc.core.DatabaseClient; /** * Integration tests for PostgreSQL-specific features such as array support. @@ -84,62 +83,6 @@ public class PostgresIntegrationTests extends R2dbcIntegrationTestSupport { + "collection_array INT[][])"); } - @Test // gh-30 - void shouldReadAndWritePrimitiveSingleDimensionArrays() { - - EntityWithArrays withArrays = new EntityWithArrays(null, null, new int[] { 1, 2, 3 }, null, null); - - insert(withArrays); - selectAndAssert(actual -> { - assertThat(actual.primitiveArray).containsExactly(1, 2, 3); - }); - } - - @Test // gh-30 - void shouldReadAndWriteBoxedSingleDimensionArrays() { - - EntityWithArrays withArrays = new EntityWithArrays(null, new Integer[] { 1, 2, 3 }, null, null, null); - - insert(withArrays); - - selectAndAssert(actual -> { - - assertThat(actual.boxedArray).containsExactly(1, 2, 3); - - }); - } - - @Test // gh-30 - void shouldReadAndWriteConvertedDimensionArrays() { - - EntityWithArrays withArrays = new EntityWithArrays(null, null, null, null, Arrays.asList(5, 6, 7)); - - insert(withArrays); - - selectAndAssert(actual -> { - assertThat(actual.collectionArray).containsExactly(5, 6, 7); - }); - } - - @Test // gh-30 - void shouldReadAndWriteMultiDimensionArrays() { - - EntityWithArrays withArrays = new EntityWithArrays(null, null, null, new int[][] { { 1, 2, 3 }, { 4, 5, 6 } }, - null); - - insert(withArrays); - - selectAndAssert(actual -> { - - assertThat(actual.multidimensionalArray).hasDimensions(2, 3); - assertThat(actual.multidimensionalArray[0]).containsExactly(1, 2, 3); - assertThat(actual.multidimensionalArray[1]).containsExactly(4, 5, 6); - }); - - client.update().table(EntityWithArrays.class).using(withArrays).then() // - .as(StepVerifier::create).verifyComplete(); - } - @Test // gh-411 void shouldWriteAndReadEnumValuesUsingDriverInternals() { @@ -270,25 +213,6 @@ public class PostgresIntegrationTests extends R2dbcIntegrationTestSupport { }).verifyComplete(); } - private void insert(EntityWithArrays object) { - - client.insert() // - .into(EntityWithArrays.class) // - .using(object) // - .then() // - .as(StepVerifier::create) // - .verifyComplete(); - } - - private void selectAndAssert(Consumer assertion) { - - client.select() // - .from(EntityWithArrays.class).fetch() // - .first() // - .as(StepVerifier::create) // - .consumeNextWith(assertion).verifyComplete(); - } - @Data @AllArgsConstructor static class EntityWithEnum { diff --git a/src/test/java/org/springframework/data/r2dbc/core/PostgresTransactionalDatabaseClientIntegrationTests.java b/src/test/java/org/springframework/data/r2dbc/core/PostgresTransactionalDatabaseClientIntegrationTests.java deleted file mode 100644 index f653ae544..000000000 --- a/src/test/java/org/springframework/data/r2dbc/core/PostgresTransactionalDatabaseClientIntegrationTests.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.springframework.data.r2dbc.core; - -import io.r2dbc.spi.ConnectionFactory; - -import javax.sql.DataSource; - -import org.junit.jupiter.api.extension.RegisterExtension; - -import org.springframework.data.r2dbc.testing.ExternalDatabase; -import org.springframework.data.r2dbc.testing.PostgresTestSupport; - -/** - * Transactional integration tests for {@link DatabaseClient} against PostgreSQL. - * - * @author Mark Paluch - */ -public class PostgresTransactionalDatabaseClientIntegrationTests - extends AbstractTransactionalDatabaseClientIntegrationTests { - - @RegisterExtension public static final ExternalDatabase database = PostgresTestSupport.database(); - - @Override - protected DataSource createDataSource() { - return PostgresTestSupport.createDataSource(database); - } - - @Override - protected ConnectionFactory createConnectionFactory() { - return PostgresTestSupport.createConnectionFactory(database); - } - - @Override - protected String getCreateTableStatement() { - return PostgresTestSupport.CREATE_TABLE_LEGOSET; - } - - @Override - protected String getCurrentTransactionIdStatement() { - return "SELECT txid_current();"; - } -} diff --git a/src/test/java/org/springframework/data/r2dbc/core/ReactiveDataAccessStrategyTests.java b/src/test/java/org/springframework/data/r2dbc/core/ReactiveDataAccessStrategyTests.java index 9270f0526..b083ee8a1 100644 --- a/src/test/java/org/springframework/data/r2dbc/core/ReactiveDataAccessStrategyTests.java +++ b/src/test/java/org/springframework/data/r2dbc/core/ReactiveDataAccessStrategyTests.java @@ -15,8 +15,8 @@ */ package org.springframework.data.r2dbc.core; -import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; +import static org.springframework.data.r2dbc.testing.Assertions.*; import java.util.Arrays; import java.util.UUID; @@ -26,12 +26,12 @@ import org.junit.jupiter.api.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.relational.core.query.Criteria; import org.springframework.data.relational.core.query.Update; +import org.springframework.r2dbc.core.Parameter; import org.springframework.r2dbc.core.PreparedOperation; +import org.springframework.r2dbc.core.binding.BindTarget; /** * Unit tests for {@link ReactiveDataAccessStrategy}. @@ -46,20 +46,19 @@ public class ReactiveDataAccessStrategyTests { Arrays.asList(UuidToStringConverter.INSTANCE, StringToUuidConverter.INSTANCE)); @Test // gh-305 - public void shouldConvertSettableValue() { + public void shouldConvertParameter() { 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")); + assertThat(strategy.getBindValue(Parameter.from(value))).isEqualTo(Parameter.from(value.toString())); + assertThat(strategy.getBindValue(Parameter.from(Condition.New))).isEqualTo(Parameter.from("New")); } @Test // gh-305 - public void shouldConvertEmptySettableValue() { + public void shouldConvertEmptyParameter() { - assertThat(strategy.getBindValue(SettableValue.empty(UUID.class))).isEqualTo(SettableValue.empty(String.class)); - assertThat(strategy.getBindValue(SettableValue.empty(Condition.class))) - .isEqualTo(SettableValue.empty(String.class)); + assertThat(strategy.getBindValue(Parameter.empty(UUID.class))).isEqualTo(Parameter.empty(String.class)); + assertThat(strategy.getBindValue(Parameter.empty(Condition.class))).isEqualTo(Parameter.empty(String.class)); } @Test // gh-305 diff --git a/src/test/java/org/springframework/data/r2dbc/core/ReactiveDeleteOperationUnitTests.java b/src/test/java/org/springframework/data/r2dbc/core/ReactiveDeleteOperationUnitTests.java index d199f57a6..518f1f599 100644 --- a/src/test/java/org/springframework/data/r2dbc/core/ReactiveDeleteOperationUnitTests.java +++ b/src/test/java/org/springframework/data/r2dbc/core/ReactiveDeleteOperationUnitTests.java @@ -29,6 +29,7 @@ import org.springframework.data.annotation.Id; import org.springframework.data.r2dbc.dialect.PostgresDialect; import org.springframework.data.r2dbc.testing.StatementRecorder; import org.springframework.data.relational.core.mapping.Column; +import org.springframework.r2dbc.core.DatabaseClient; import org.springframework.r2dbc.core.Parameter; /** @@ -47,8 +48,8 @@ public class ReactiveDeleteOperationUnitTests { recorder = StatementRecorder.newInstance(); client = DatabaseClient.builder().connectionFactory(recorder) - .dataAccessStrategy(new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)).build(); - entityTemplate = new R2dbcEntityTemplate(client); + .bindMarkers(PostgresDialect.INSTANCE.getBindMarkersFactory()).build(); + entityTemplate = new R2dbcEntityTemplate(client, new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)); } @Test // gh-410 diff --git a/src/test/java/org/springframework/data/r2dbc/core/ReactiveInsertOperationUnitTests.java b/src/test/java/org/springframework/data/r2dbc/core/ReactiveInsertOperationUnitTests.java index 7de954a11..a8d402d5d 100644 --- a/src/test/java/org/springframework/data/r2dbc/core/ReactiveInsertOperationUnitTests.java +++ b/src/test/java/org/springframework/data/r2dbc/core/ReactiveInsertOperationUnitTests.java @@ -30,6 +30,7 @@ import org.springframework.data.annotation.Id; import org.springframework.data.r2dbc.dialect.PostgresDialect; import org.springframework.data.r2dbc.testing.StatementRecorder; import org.springframework.data.relational.core.mapping.Column; +import org.springframework.r2dbc.core.DatabaseClient; import org.springframework.r2dbc.core.Parameter; /** @@ -48,8 +49,8 @@ public class ReactiveInsertOperationUnitTests { recorder = StatementRecorder.newInstance(); client = DatabaseClient.builder().connectionFactory(recorder) - .dataAccessStrategy(new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)).build(); - entityTemplate = new R2dbcEntityTemplate(client); + .bindMarkers(PostgresDialect.INSTANCE.getBindMarkersFactory()).build(); + entityTemplate = new R2dbcEntityTemplate(client, new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)); } @Test // gh-220 diff --git a/src/test/java/org/springframework/data/r2dbc/core/ReactiveSelectOperationUnitTests.java b/src/test/java/org/springframework/data/r2dbc/core/ReactiveSelectOperationUnitTests.java index c6f9132f9..19aaf28bd 100644 --- a/src/test/java/org/springframework/data/r2dbc/core/ReactiveSelectOperationUnitTests.java +++ b/src/test/java/org/springframework/data/r2dbc/core/ReactiveSelectOperationUnitTests.java @@ -32,6 +32,7 @@ import org.springframework.data.annotation.Id; import org.springframework.data.r2dbc.dialect.PostgresDialect; import org.springframework.data.r2dbc.testing.StatementRecorder; import org.springframework.data.relational.core.mapping.Column; +import org.springframework.r2dbc.core.DatabaseClient; /** * Unit test for {@link ReactiveSelectOperation}. @@ -49,8 +50,8 @@ public class ReactiveSelectOperationUnitTests { recorder = StatementRecorder.newInstance(); client = DatabaseClient.builder().connectionFactory(recorder) - .dataAccessStrategy(new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)).build(); - entityTemplate = new R2dbcEntityTemplate(client); + .bindMarkers(PostgresDialect.INSTANCE.getBindMarkersFactory()).build(); + entityTemplate = new R2dbcEntityTemplate(client, new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)); } @Test // gh-220 diff --git a/src/test/java/org/springframework/data/r2dbc/core/ReactiveUpdateOperationUnitTests.java b/src/test/java/org/springframework/data/r2dbc/core/ReactiveUpdateOperationUnitTests.java index 89bc948e7..2aef24e3f 100644 --- a/src/test/java/org/springframework/data/r2dbc/core/ReactiveUpdateOperationUnitTests.java +++ b/src/test/java/org/springframework/data/r2dbc/core/ReactiveUpdateOperationUnitTests.java @@ -16,7 +16,7 @@ package org.springframework.data.r2dbc.core; import static org.assertj.core.api.Assertions.*; -import static org.springframework.data.r2dbc.query.Criteria.*; +import static org.springframework.data.relational.core.query.Criteria.*; import static org.springframework.data.relational.core.query.Query.*; import io.r2dbc.spi.test.MockResult; @@ -30,6 +30,7 @@ import org.springframework.data.r2dbc.dialect.PostgresDialect; import org.springframework.data.r2dbc.testing.StatementRecorder; import org.springframework.data.relational.core.mapping.Column; import org.springframework.data.relational.core.query.Update; +import org.springframework.r2dbc.core.DatabaseClient; import org.springframework.r2dbc.core.Parameter; /** @@ -48,8 +49,8 @@ public class ReactiveUpdateOperationUnitTests { recorder = StatementRecorder.newInstance(); client = DatabaseClient.builder().connectionFactory(recorder) - .dataAccessStrategy(new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)).build(); - entityTemplate = new R2dbcEntityTemplate(client); + .bindMarkers(PostgresDialect.INSTANCE.getBindMarkersFactory()).build(); + entityTemplate = new R2dbcEntityTemplate(client, new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)); } @Test // gh-410 diff --git a/src/test/java/org/springframework/data/r2dbc/core/SqlServerDatabaseClientIntegrationTests.java b/src/test/java/org/springframework/data/r2dbc/core/SqlServerDatabaseClientIntegrationTests.java deleted file mode 100644 index e9d1609f9..000000000 --- a/src/test/java/org/springframework/data/r2dbc/core/SqlServerDatabaseClientIntegrationTests.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2018-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 javax.sql.DataSource; - -import org.junit.jupiter.api.extension.RegisterExtension; - -import org.springframework.data.r2dbc.testing.ExternalDatabase; -import org.springframework.data.r2dbc.testing.SqlServerTestSupport; - -/** - * Integration tests for {@link DatabaseClient} against Microsoft SQL Server. - * - * @author Mark Paluch - */ -public class SqlServerDatabaseClientIntegrationTests extends AbstractDatabaseClientIntegrationTests { - - @RegisterExtension public static final ExternalDatabase database = SqlServerTestSupport.database(); - - @Override - protected DataSource createDataSource() { - return SqlServerTestSupport.createDataSource(database); - } - - @Override - protected ConnectionFactory createConnectionFactory() { - return SqlServerTestSupport.createConnectionFactory(database); - } - - @Override - protected String getCreateTableStatement() { - return SqlServerTestSupport.CREATE_TABLE_LEGOSET; - } -} diff --git a/src/test/java/org/springframework/data/r2dbc/core/SqlServerTransactionalDatabaseClientIntegrationTests.java b/src/test/java/org/springframework/data/r2dbc/core/SqlServerTransactionalDatabaseClientIntegrationTests.java deleted file mode 100644 index a2c363020..000000000 --- a/src/test/java/org/springframework/data/r2dbc/core/SqlServerTransactionalDatabaseClientIntegrationTests.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.springframework.data.r2dbc.core; - -import io.r2dbc.spi.ConnectionFactory; - -import javax.sql.DataSource; - -import org.junit.jupiter.api.extension.RegisterExtension; - -import org.springframework.data.r2dbc.testing.ExternalDatabase; -import org.springframework.data.r2dbc.testing.SqlServerTestSupport; - -/** - * Transactional integration tests for {@link DatabaseClient} against Microsoft SQL Server. - * - * @author Mark Paluch - */ -public class SqlServerTransactionalDatabaseClientIntegrationTests - extends AbstractTransactionalDatabaseClientIntegrationTests { - - @RegisterExtension public static final ExternalDatabase database = SqlServerTestSupport.database(); - - @Override - protected DataSource createDataSource() { - return SqlServerTestSupport.createDataSource(database); - } - - @Override - protected ConnectionFactory createConnectionFactory() { - return SqlServerTestSupport.createConnectionFactory(database); - } - - @Override - protected String getCreateTableStatement() { - return SqlServerTestSupport.CREATE_TABLE_LEGOSET; - } - - @Override - protected String getInsertIntoLegosetStatement() { - return SqlServerTestSupport.INSERT_INTO_LEGOSET; - } - - @Override - protected String getCurrentTransactionIdStatement() { - return "SELECT CURRENT_TRANSACTION_ID();"; - } -} diff --git a/src/test/java/org/springframework/data/r2dbc/core/StatementMapperUnitTests.java b/src/test/java/org/springframework/data/r2dbc/core/StatementMapperUnitTests.java index 302802947..76c55364c 100644 --- a/src/test/java/org/springframework/data/r2dbc/core/StatementMapperUnitTests.java +++ b/src/test/java/org/springframework/data/r2dbc/core/StatementMapperUnitTests.java @@ -23,11 +23,11 @@ import org.junit.jupiter.api.Test; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.data.r2dbc.core.StatementMapper.UpdateSpec; -import org.springframework.data.r2dbc.dialect.BindTarget; import org.springframework.data.r2dbc.dialect.PostgresDialect; import org.springframework.data.relational.core.query.Criteria; import org.springframework.data.relational.core.query.Update; import org.springframework.r2dbc.core.PreparedOperation; +import org.springframework.r2dbc.core.binding.BindTarget; /** * Unit tests for {@link DefaultStatementMapper}. diff --git a/src/test/java/org/springframework/data/r2dbc/dialect/BindingsUnitTests.java b/src/test/java/org/springframework/data/r2dbc/dialect/BindingsUnitTests.java deleted file mode 100644 index 822a54122..000000000 --- a/src/test/java/org/springframework/data/r2dbc/dialect/BindingsUnitTests.java +++ /dev/null @@ -1,150 +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.dialect; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -import org.junit.jupiter.api.Test; - -/** - * Unit tests for {@link Bindings}. - * - * @author Mark Paluch - */ -class BindingsUnitTests { - - private final BindMarkersFactory markersFactory = BindMarkersFactory.indexed("$", 1); - private final BindTarget bindTarget = mock(BindTarget.class); - - @Test // gh-64 - void shouldCreateBindings() { - - MutableBindings bindings = new MutableBindings(markersFactory.create()); - - bindings.bind(bindings.nextMarker(), "foo"); - bindings.bindNull(bindings.nextMarker(), String.class); - - assertThat(bindings.stream()).hasSize(2); - } - - @Test // gh-64 - void shouldApplyValueBinding() { - - MutableBindings bindings = new MutableBindings(markersFactory.create()); - - bindings.bind(bindings.nextMarker(), "foo"); - bindings.apply(bindTarget); - - verify(bindTarget).bind(0, "foo"); - } - - @Test // gh-64 - void shouldApplySimpleValueBinding() { - - MutableBindings bindings = new MutableBindings(markersFactory.create()); - - BindMarker marker = bindings.bind("foo"); - bindings.apply(bindTarget); - - assertThat(marker.getPlaceholder()).isEqualTo("$1"); - verify(bindTarget).bind(0, "foo"); - } - - @Test // gh-64 - void shouldApplyNullBinding() { - - MutableBindings bindings = new MutableBindings(markersFactory.create()); - - bindings.bindNull(bindings.nextMarker(), String.class); - - bindings.apply(bindTarget); - - verify(bindTarget).bindNull(0, String.class); - } - - @Test // gh-64 - void shouldApplySimpleNullBinding() { - - MutableBindings bindings = new MutableBindings(markersFactory.create()); - - BindMarker marker = bindings.bindNull(String.class); - bindings.apply(bindTarget); - - assertThat(marker.getPlaceholder()).isEqualTo("$1"); - verify(bindTarget).bindNull(0, String.class); - } - - @Test // gh-64 - void shouldConsumeBindings() { - - MutableBindings bindings = new MutableBindings(markersFactory.create()); - - bindings.bind(bindings.nextMarker(), "foo"); - bindings.bindNull(bindings.nextMarker(), String.class); - - AtomicInteger counter = new AtomicInteger(); - - bindings.forEach(binding -> { - - if (binding.hasValue()) { - counter.incrementAndGet(); - assertThat(binding.getValue()).isEqualTo("foo"); - assertThat(binding.getBindMarker().getPlaceholder()).isEqualTo("$1"); - } - - if (binding.isNull()) { - counter.incrementAndGet(); - - assertThat(((Bindings.NullBinding) binding).getValueType()).isEqualTo(String.class); - assertThat(binding.getBindMarker().getPlaceholder()).isEqualTo("$2"); - } - }); - - assertThat(counter).hasValue(2); - } - - @Test // gh-64 - void shouldMergeBindings() { - - BindMarkers markers = markersFactory.create(); - - BindMarker shared = markers.next(); - BindMarker leftMarker = markers.next(); - List left = new ArrayList<>(); - left.add(new Bindings.NullBinding(shared, String.class)); - left.add(new Bindings.ValueBinding(leftMarker, "left")); - - BindMarker rightMarker = markers.next(); - List right = new ArrayList<>(); - left.add(new Bindings.ValueBinding(shared, "override")); - left.add(new Bindings.ValueBinding(rightMarker, "right")); - - Bindings merged = Bindings.merge(new Bindings(left), new Bindings(right)); - - assertThat(merged).hasSize(3); - - merged.apply(bindTarget); - verify(bindTarget).bind(0, "override"); - verify(bindTarget).bind(1, "left"); - verify(bindTarget).bind(2, "right"); - } - -} diff --git a/src/test/java/org/springframework/data/r2dbc/dialect/DialectResolverUnitTests.java b/src/test/java/org/springframework/data/r2dbc/dialect/DialectResolverUnitTests.java index 278ef51bb..bcf15d676 100644 --- a/src/test/java/org/springframework/data/r2dbc/dialect/DialectResolverUnitTests.java +++ b/src/test/java/org/springframework/data/r2dbc/dialect/DialectResolverUnitTests.java @@ -24,6 +24,7 @@ import org.springframework.data.relational.core.dialect.LimitClause; import org.springframework.data.relational.core.dialect.LockClause; import org.springframework.data.relational.core.sql.LockOptions; import org.springframework.data.relational.core.sql.render.SelectRenderContext; +import org.springframework.r2dbc.core.binding.BindMarkersFactory; /** * Unit tests for {@link DialectResolver}. diff --git a/src/test/java/org/springframework/data/r2dbc/mapping/SettableValueUnitTests.java b/src/test/java/org/springframework/data/r2dbc/mapping/SettableValueUnitTests.java deleted file mode 100644 index ec797b98e..000000000 --- a/src/test/java/org/springframework/data/r2dbc/mapping/SettableValueUnitTests.java +++ /dev/null @@ -1,56 +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.mapping; - -import static org.assertj.core.api.Assertions.*; - -import org.junit.jupiter.api.Test; - -/** - * Unit tests for {@link SettableValue}. - * - * @author Mark Paluch - */ -class SettableValueUnitTests { - - @Test // gh-59 - void shouldCreateSettableValue() { - - SettableValue value = SettableValue.from("foo"); - - assertThat(value.isEmpty()).isFalse(); - assertThat(value.hasValue()).isTrue(); - assertThat(value).isEqualTo(SettableValue.from("foo")); - } - - @Test // gh-59 - void shouldCreateEmpty() { - - SettableValue value = SettableValue.empty(Object.class); - - assertThat(value.isEmpty()).isTrue(); - assertThat(value.hasValue()).isFalse(); - assertThat(value).isEqualTo(SettableValue.empty(Object.class)); - assertThat(value).isNotEqualTo(SettableValue.empty(String.class)); - } - - @Test // gh-59 - void shouldCreatePotentiallyEmpty() { - - assertThat(SettableValue.fromOrEmpty("foo", Object.class).isEmpty()).isFalse(); - assertThat(SettableValue.fromOrEmpty(null, Object.class).isEmpty()).isTrue(); - } -} diff --git a/src/test/java/org/springframework/data/r2dbc/query/QueryMapperUnitTests.java b/src/test/java/org/springframework/data/r2dbc/query/QueryMapperUnitTests.java index dca6f465f..c582c921d 100644 --- a/src/test/java/org/springframework/data/r2dbc/query/QueryMapperUnitTests.java +++ b/src/test/java/org/springframework/data/r2dbc/query/QueryMapperUnitTests.java @@ -26,16 +26,16 @@ import org.junit.jupiter.api.Test; import org.springframework.data.domain.Sort; import org.springframework.data.r2dbc.convert.MappingR2dbcConverter; import org.springframework.data.r2dbc.convert.R2dbcConverter; -import org.springframework.data.r2dbc.dialect.BindMarkersFactory; -import org.springframework.data.r2dbc.dialect.BindTarget; import org.springframework.data.r2dbc.dialect.PostgresDialect; import org.springframework.data.r2dbc.mapping.R2dbcMappingContext; -import org.springframework.data.r2dbc.mapping.SettableValue; import org.springframework.data.relational.core.mapping.Column; import org.springframework.data.relational.core.query.Criteria; import org.springframework.data.relational.core.sql.Expression; import org.springframework.data.relational.core.sql.Functions; import org.springframework.data.relational.core.sql.Table; +import org.springframework.r2dbc.core.Parameter; +import org.springframework.r2dbc.core.binding.BindMarkersFactory; +import org.springframework.r2dbc.core.binding.BindTarget; /** * Unit tests for {@link QueryMapper}. @@ -229,7 +229,7 @@ class QueryMapperUnitTests { @Test // gh-64 void shouldMapSimpleNullableCriteria() { - Criteria criteria = Criteria.where("name").is(SettableValue.empty(Integer.class)); + Criteria criteria = Criteria.where("name").is(Parameter.empty(Integer.class)); BoundCondition bindings = map(criteria); diff --git a/src/test/java/org/springframework/data/r2dbc/query/UpdateMapperUnitTests.java b/src/test/java/org/springframework/data/r2dbc/query/UpdateMapperUnitTests.java index d13e7e2f1..7e33189df 100644 --- a/src/test/java/org/springframework/data/r2dbc/query/UpdateMapperUnitTests.java +++ b/src/test/java/org/springframework/data/r2dbc/query/UpdateMapperUnitTests.java @@ -25,11 +25,8 @@ import org.junit.jupiter.api.Test; import org.springframework.data.r2dbc.convert.MappingR2dbcConverter; import org.springframework.data.r2dbc.convert.R2dbcConverter; -import org.springframework.data.r2dbc.dialect.BindMarkersFactory; -import org.springframework.data.r2dbc.dialect.BindTarget; import org.springframework.data.r2dbc.dialect.PostgresDialect; import org.springframework.data.r2dbc.mapping.R2dbcMappingContext; -import org.springframework.data.r2dbc.mapping.SettableValue; import org.springframework.data.relational.core.mapping.Column; import org.springframework.data.relational.core.query.Update; import org.springframework.data.relational.core.sql.AssignValue; @@ -37,6 +34,9 @@ import org.springframework.data.relational.core.sql.Expression; import org.springframework.data.relational.core.sql.SQL; import org.springframework.data.relational.core.sql.SqlIdentifier; import org.springframework.data.relational.core.sql.Table; +import org.springframework.r2dbc.core.Parameter; +import org.springframework.r2dbc.core.binding.BindMarkersFactory; +import org.springframework.r2dbc.core.binding.BindTarget; /** * Unit tests for {@link UpdateMapper}. @@ -66,7 +66,7 @@ public class UpdateMapperUnitTests { @Test // gh-64 void shouldUpdateToSettableValue() { - Update update = Update.update("alternative", SettableValue.empty(String.class)); + Update update = Update.update("alternative", Parameter.empty(String.class)); BoundAssignments mapped = map(update); diff --git a/src/test/java/org/springframework/data/r2dbc/repository/AbstractR2dbcRepositoryIntegrationTests.java b/src/test/java/org/springframework/data/r2dbc/repository/AbstractR2dbcRepositoryIntegrationTests.java index f5bae172c..2cc6b6948 100644 --- a/src/test/java/org/springframework/data/r2dbc/repository/AbstractR2dbcRepositoryIntegrationTests.java +++ b/src/test/java/org/springframework/data/r2dbc/repository/AbstractR2dbcRepositoryIntegrationTests.java @@ -43,13 +43,13 @@ import org.springframework.data.annotation.Id; import org.springframework.data.annotation.PersistenceConstructor; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; -import org.springframework.data.r2dbc.connectionfactory.R2dbcTransactionManager; import org.springframework.data.r2dbc.repository.support.R2dbcRepositoryFactory; import org.springframework.data.r2dbc.testing.R2dbcIntegrationTestSupport; import org.springframework.data.relational.core.mapping.Table; import org.springframework.data.repository.NoRepositoryBean; import org.springframework.data.repository.reactive.ReactiveCrudRepository; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.r2dbc.connection.R2dbcTransactionManager; import org.springframework.transaction.reactive.TransactionalOperator; /** diff --git a/src/test/java/org/springframework/data/r2dbc/support/R2dbcExceptionSubclassTranslatorUnitTests.java b/src/test/java/org/springframework/data/r2dbc/support/R2dbcExceptionSubclassTranslatorUnitTests.java deleted file mode 100644 index 541b8086e..000000000 --- a/src/test/java/org/springframework/data/r2dbc/support/R2dbcExceptionSubclassTranslatorUnitTests.java +++ /dev/null @@ -1,144 +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.support; - -import static org.assertj.core.api.Assertions.*; - -import io.r2dbc.spi.R2dbcBadGrammarException; -import io.r2dbc.spi.R2dbcDataIntegrityViolationException; -import io.r2dbc.spi.R2dbcException; -import io.r2dbc.spi.R2dbcNonTransientResourceException; -import io.r2dbc.spi.R2dbcPermissionDeniedException; -import io.r2dbc.spi.R2dbcRollbackException; -import io.r2dbc.spi.R2dbcTimeoutException; -import io.r2dbc.spi.R2dbcTransientResourceException; - -import org.junit.jupiter.api.Test; -import org.springframework.dao.ConcurrencyFailureException; -import org.springframework.dao.DataAccessResourceFailureException; -import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.dao.PermissionDeniedDataAccessException; -import org.springframework.dao.QueryTimeoutException; -import org.springframework.dao.TransientDataAccessResourceException; -import org.springframework.data.r2dbc.BadSqlGrammarException; -import org.springframework.data.r2dbc.UncategorizedR2dbcException; - -/** - * Unit tests for {@link R2dbcExceptionSubclassTranslator}. - * - * @author Mark Paluch - */ -class R2dbcExceptionSubclassTranslatorUnitTests { - - private final R2dbcExceptionSubclassTranslator translator = new R2dbcExceptionSubclassTranslator(); - - @Test // gh-57 - void shouldTranslateTransientResourceException() { - - Exception exception = translator.translate("", "", new R2dbcTransientResourceException("")); - - assertThat(exception) - .isInstanceOf(TransientDataAccessResourceException.class); - } - - @Test // gh-57 - void shouldTranslateRollbackException() { - - Exception exception = translator.translate("", "", new R2dbcRollbackException()); - - assertThat(exception).isInstanceOf(ConcurrencyFailureException.class); - } - - @Test // gh-57 - void shouldTranslateTimeoutException() { - - Exception exception = translator.translate("", "", new R2dbcTimeoutException()); - - assertThat(exception).isInstanceOf(QueryTimeoutException.class); - } - - @Test // gh-57 - void shouldNotTranslateUnknownExceptions() { - - Exception exception = translator.translate("", "", new MyTransientExceptions()); - - assertThat(exception).isInstanceOf(UncategorizedR2dbcException.class); - } - - @Test // gh-57 - void shouldTranslateNonTransientResourceException() { - - Exception exception = translator.translate("", "", new R2dbcNonTransientResourceException()); - - assertThat(exception).isInstanceOf(DataAccessResourceFailureException.class); - } - - @Test // gh-57 - void shouldTranslateIntegrityViolationException() { - - Exception exception = translator.translate("", "", new R2dbcDataIntegrityViolationException()); - - assertThat(exception).isInstanceOf(DataIntegrityViolationException.class); - } - - @Test // gh-57 - void shouldTranslatePermissionDeniedException() { - - Exception exception = translator.translate("", "", new R2dbcPermissionDeniedException()); - - assertThat(exception).isInstanceOf(PermissionDeniedDataAccessException.class); - } - - @Test // gh-57 - void shouldTranslateBadSqlGrammarException() { - - Exception exception = translator.translate("", "", new R2dbcBadGrammarException()); - - assertThat(exception).isInstanceOf(BadSqlGrammarException.class); - } - - @Test // gh-57 - void messageGeneration() { - - Exception exception = translator.translate("TASK", "SOME-SQL", new R2dbcTransientResourceException("MESSAGE")); - - assertThat(exception) // - .isInstanceOf(TransientDataAccessResourceException.class) // - .hasMessage("TASK; SQL [SOME-SQL]; MESSAGE; nested exception is io.r2dbc.spi.R2dbcTransientResourceException: MESSAGE"); - } - - @Test // gh-57 - void messageGenerationNullSQL() { - - Exception exception = translator.translate("TASK", null, new R2dbcTransientResourceException("MESSAGE")); - - assertThat(exception) // - .isInstanceOf(TransientDataAccessResourceException.class) // - .hasMessage("TASK; MESSAGE; nested exception is io.r2dbc.spi.R2dbcTransientResourceException: MESSAGE"); - } - - @Test // gh-57 - void messageGenerationNullMessage() { - - Exception exception = translator.translate("TASK", "SOME-SQL", new R2dbcTransientResourceException()); - - assertThat(exception) // - .isInstanceOf(TransientDataAccessResourceException.class) // - .hasMessage("TASK; SQL [SOME-SQL]; null; nested exception is io.r2dbc.spi.R2dbcTransientResourceException"); - } - - private static class MyTransientExceptions extends R2dbcException {} -} diff --git a/src/test/java/org/springframework/data/r2dbc/support/SqlErrorCodeR2dbcExceptionTranslatorUnitTests.java b/src/test/java/org/springframework/data/r2dbc/support/SqlErrorCodeR2dbcExceptionTranslatorUnitTests.java deleted file mode 100644 index 71f63184d..000000000 --- a/src/test/java/org/springframework/data/r2dbc/support/SqlErrorCodeR2dbcExceptionTranslatorUnitTests.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright 2018-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.support; - -import static org.assertj.core.api.Assertions.*; - -import io.r2dbc.spi.R2dbcException; - -import org.junit.jupiter.api.Test; -import org.springframework.dao.CannotAcquireLockException; -import org.springframework.dao.CannotSerializeTransactionException; -import org.springframework.dao.DataAccessException; -import org.springframework.dao.DataAccessResourceFailureException; -import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.dao.DeadlockLoserDataAccessException; -import org.springframework.dao.DuplicateKeyException; -import org.springframework.data.r2dbc.BadSqlGrammarException; -import org.springframework.data.r2dbc.InvalidResultAccessException; -import org.springframework.data.r2dbc.UncategorizedR2dbcException; -import org.springframework.jdbc.support.SQLErrorCodes; - -/** - * Unit tests for {@link SqlErrorCodeR2dbcExceptionTranslator}. - * - * @author Mark Paluch - */ -class SqlErrorCodeR2dbcExceptionTranslatorUnitTests { - - private static final SQLErrorCodes ERROR_CODES = new SQLErrorCodes(); - static { - ERROR_CODES.setBadSqlGrammarCodes("1", "2"); - ERROR_CODES.setInvalidResultSetAccessCodes("3", "4"); - ERROR_CODES.setDuplicateKeyCodes("10"); - ERROR_CODES.setDataAccessResourceFailureCodes("5"); - ERROR_CODES.setDataIntegrityViolationCodes("6"); - ERROR_CODES.setCannotAcquireLockCodes("7"); - ERROR_CODES.setDeadlockLoserCodes("8"); - ERROR_CODES.setCannotSerializeTransactionCodes("9"); - } - - @Test - void shouldTranslateToBadGrammarException() { - - R2dbcExceptionTranslator sut = new SqlErrorCodeR2dbcExceptionTranslator(ERROR_CODES); - - R2dbcException cause = new MyR2dbcException("", "", 1); - BadSqlGrammarException exception = (BadSqlGrammarException) sut.translate("task", "SQL", cause); - - assertThat(exception.getSql()).isEqualTo("SQL"); - assertThat(exception.getR2dbcException()).isEqualTo(cause); - } - - @Test - void shouldTranslateToResultException() { - - R2dbcExceptionTranslator sut = new SqlErrorCodeR2dbcExceptionTranslator(ERROR_CODES); - - R2dbcException cause = new MyR2dbcException("", "", 4); - InvalidResultAccessException exception = (InvalidResultAccessException) sut.translate("task", "SQL", cause); - - assertThat(exception.getSql()).isEqualTo("SQL"); - assertThat(exception.getR2dbcException()).isEqualTo(cause); - } - - @Test - void shouldFallbackToUncategorized() { - - R2dbcExceptionTranslator sut = new SqlErrorCodeR2dbcExceptionTranslator(ERROR_CODES); - - // Test fallback. We assume that no database will ever return this error code, - // but 07xxx will be bad grammar picked up by the fallback SQLState translator - R2dbcException cause = new MyR2dbcException("", "07xxx", 666666666); - UncategorizedR2dbcException exception = (UncategorizedR2dbcException) sut.translate("task", "SQL2", cause); - - assertThat(exception.getSql()).isEqualTo("SQL2"); - assertThat(exception.getR2dbcException()).isEqualTo(cause); - } - - @Test - void shouldTranslateDataIntegrityViolationException() { - - R2dbcExceptionTranslator sut = new SqlErrorCodeR2dbcExceptionTranslator(ERROR_CODES); - - R2dbcException cause = new MyR2dbcException("", "", 10); - DataAccessException exception = sut.translate("task", "SQL", cause); - - assertThat(exception).isInstanceOf(DataIntegrityViolationException.class); - } - - @Test - void errorCodeTranslation() { - - R2dbcExceptionTranslator sut = new SqlErrorCodeR2dbcExceptionTranslator(ERROR_CODES); - - checkTranslation(sut, 5, DataAccessResourceFailureException.class); - checkTranslation(sut, 6, DataIntegrityViolationException.class); - checkTranslation(sut, 7, CannotAcquireLockException.class); - checkTranslation(sut, 8, DeadlockLoserDataAccessException.class); - checkTranslation(sut, 9, CannotSerializeTransactionException.class); - checkTranslation(sut, 10, DuplicateKeyException.class); - } - - private static void checkTranslation(R2dbcExceptionTranslator sext, int errorCode, Class exClass) { - - R2dbcException cause = new MyR2dbcException("", "", errorCode); - DataAccessException exception = sext.translate("", "", cause); - - assertThat(exception).isInstanceOf(exClass).hasCause(cause); - } - - @Test - void shouldApplyCustomTranslation() { - - String TASK = "TASK"; - String SQL = "SQL SELECT *"; - DataAccessException custom = new DataAccessException("") {}; - - R2dbcException cause = new MyR2dbcException("", "", 1); - R2dbcException intVioEx = new MyR2dbcException("", "", 6); - - SqlErrorCodeR2dbcExceptionTranslator translator = new SqlErrorCodeR2dbcExceptionTranslator() { - @Override - protected DataAccessException customTranslate(String task, String sql, R2dbcException sqlex) { - - assertThat(task).isEqualTo(TASK); - assertThat(sql).isEqualTo(SQL); - return (sqlex == cause) ? custom : null; - } - }; - translator.setSqlErrorCodes(ERROR_CODES); - - // Shouldn't custom translate this - assertThat(translator.translate(TASK, SQL, cause)).isEqualTo(custom); - - DataIntegrityViolationException diex = (DataIntegrityViolationException) translator.translate(TASK, SQL, intVioEx); - assertThat(diex).hasCause(intVioEx); - } - - static class MyR2dbcException extends R2dbcException { - - MyR2dbcException(String reason, String sqlState, int errorCode) { - super(reason, sqlState, errorCode); - } - } -} diff --git a/src/test/java/org/springframework/data/r2dbc/support/SqlStateR2dbcExceptionTranslatorUnitTests.java b/src/test/java/org/springframework/data/r2dbc/support/SqlStateR2dbcExceptionTranslatorUnitTests.java deleted file mode 100644 index ce843487d..000000000 --- a/src/test/java/org/springframework/data/r2dbc/support/SqlStateR2dbcExceptionTranslatorUnitTests.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2018-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.support; - -import static org.assertj.core.api.Assertions.*; - -import io.r2dbc.spi.R2dbcException; - -import org.junit.jupiter.api.Test; -import org.springframework.dao.ConcurrencyFailureException; -import org.springframework.dao.DataAccessException; -import org.springframework.dao.DataAccessResourceFailureException; -import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.dao.TransientDataAccessResourceException; -import org.springframework.data.r2dbc.BadSqlGrammarException; -import org.springframework.data.r2dbc.UncategorizedR2dbcException; - -/** - * Unit tests for {@link SqlStateR2dbcExceptionTranslator}. - * - * @author Mark Paluch - */ -class SqlStateR2dbcExceptionTranslatorUnitTests { - - private static final String REASON = "The game is afoot!"; - private static final String TASK = "Counting sheep... yawn."; - private static final String SQL = "select count(0) from t_sheep where over_fence = ... yawn... 1"; - - @Test - void testTranslateNullException() { - assertThatIllegalArgumentException() - .isThrownBy(() -> new SqlStateR2dbcExceptionTranslator().translate("", "", null)); - } - - @Test - void testTranslateBadSqlGrammar() { - doTest("07", BadSqlGrammarException.class); - } - - @Test - void testTranslateDataIntegrityViolation() { - doTest("23", DataIntegrityViolationException.class); - } - - @Test - void testTranslateDataAccessResourceFailure() { - doTest("53", DataAccessResourceFailureException.class); - } - - @Test - void testTranslateTransientDataAccessResourceFailure() { - doTest("S1", TransientDataAccessResourceException.class); - } - - @Test - void testTranslateConcurrencyFailure() { - doTest("40", ConcurrencyFailureException.class); - } - - @Test - void testTranslateUncategorized() { - doTest("00000000", UncategorizedR2dbcException.class); - } - - private static void doTest(String sqlState, Class dataAccessExceptionType) { - - R2dbcException ex = new R2dbcException(REASON, sqlState) {}; - SqlStateR2dbcExceptionTranslator translator = new SqlStateR2dbcExceptionTranslator(); - DataAccessException dax = translator.translate(TASK, SQL, ex); - - assertThat(dax).isNotNull().isInstanceOf(dataAccessExceptionType).hasCause(ex); - } -} diff --git a/src/test/kotlin/org/springframework/data/r2dbc/core/CriteriaStepExtensionsTests.kt b/src/test/kotlin/org/springframework/data/r2dbc/core/CriteriaStepExtensionsTests.kt deleted file mode 100644 index ffbbfdef3..000000000 --- a/src/test/kotlin/org/springframework/data/r2dbc/core/CriteriaStepExtensionsTests.kt +++ /dev/null @@ -1,76 +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.mockk.every -import io.mockk.mockk -import io.mockk.verify -import org.assertj.core.api.Assertions.assertThat -import org.junit.Test -import org.springframework.data.r2dbc.query.Criteria - -/** - * Unit tests for [Criteria.CriteriaStep] extensions. - * - * @author Jonas Bark - */ -class CriteriaStepExtensionsTests { - - @Test // gh-122 - fun eqIsCriteriaStep() { - - val spec = mockk() - val criteria = mockk() - - every { spec.`is`("test") } returns criteria - - assertThat(spec isEquals "test").isEqualTo(criteria) - - verify { - spec.`is`("test") - } - } - - @Test // gh-122 - fun inVarargCriteriaStep() { - - val spec = mockk() - val criteria = mockk() - - every { spec.`in`(any() as Array) } returns criteria - - assertThat(spec.isIn("test")).isEqualTo(criteria) - - verify { - spec.`in`(arrayOf("test")) - } - } - - @Test // gh-122 - fun inListCriteriaStep() { - - val spec = mockk() - val criteria = mockk() - - every { spec.`in`(listOf("test")) } returns criteria - - assertThat(spec.isIn(listOf("test"))).isEqualTo(criteria) - - verify { - spec.`in`(listOf("test")) - } - } -} diff --git a/src/test/kotlin/org/springframework/data/r2dbc/core/DatabaseClientExtensionsTests.kt b/src/test/kotlin/org/springframework/data/r2dbc/core/DatabaseClientExtensionsTests.kt deleted file mode 100644 index 43a8be6e7..000000000 --- a/src/test/kotlin/org/springframework/data/r2dbc/core/DatabaseClientExtensionsTests.kt +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright 2018-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.mockk.every -import io.mockk.mockk -import io.mockk.verify -import kotlinx.coroutines.runBlocking -import org.assertj.core.api.Assertions.assertThat -import org.junit.Test -import org.springframework.data.r2dbc.mapping.SettableValue -import reactor.core.publisher.Mono - -/** - * Unit tests for [DatabaseClient] extensions. - * - * @author Sebastien Deleuze - * @author Jonas Bark - * @author Mark Paluch - */ -class DatabaseClientExtensionsTests { - - @Test // gh-162 - fun bindByIndexShouldBindValue() { - - val spec = mockk() - every { spec.bind(eq(0), any()) } returns spec - - runBlocking { - spec.bind(0, "foo") - } - - verify { - spec.bind(0, SettableValue.fromOrEmpty("foo", String::class.java)) - } - } - - @Test // gh-209 - fun typedExecuteSpecBindByIndexShouldBindValue() { - - val spec = mockk>() - every { spec.bind(eq(0), any()) } returns spec - - runBlocking { - spec.bind(0, "foo") - } - - verify { - spec.bind(0, SettableValue.fromOrEmpty("foo", String::class.java)) - } - } - - @Test // gh-162 - fun bindByIndexShouldBindNull() { - - val spec = mockk() - every { spec.bind(eq(0), any()) } returns spec - - runBlocking { - spec.bind(0, null) - } - - verify { - spec.bind(0, SettableValue.empty(String::class.java)) - } - } - - @Test // gh-209 - fun typedExecuteSpecBindByIndexShouldBindNull() { - - val spec = mockk>() - every { spec.bind(eq(0), any()) } returns spec - - runBlocking { - spec.bind(0, null) - } - - verify { - spec.bind(0, SettableValue.empty(String::class.java)) - } - } - - @Test // gh-162 - fun bindByNameShouldBindValue() { - - val spec = mockk() - every { spec.bind(eq("field"), any()) } returns spec - - runBlocking { - spec.bind("field", "foo") - } - - verify { - spec.bind("field", SettableValue.fromOrEmpty("foo", String::class.java)) - } - } - - @Test // gh-162, gh-209 - fun typedExecuteSpecBindByNameShouldBindValue() { - - val spec = mockk>() - every { spec.bind(eq("field"), any()) } returns spec - - runBlocking { - spec.bind("field", "foo") - } - - verify { - spec.bind("field", SettableValue.fromOrEmpty("foo", String::class.java)) - } - } - - @Test // gh-162 - fun bindByNameShouldBindNull() { - - val spec = mockk() - every { spec.bind(eq("field"), any()) } returns spec - - runBlocking { - spec.bind("field", null) - } - - verify { - spec.bind("field", SettableValue.empty(String::class.java)) - } - } - - @Test // gh-63 - fun genericExecuteSpecAwait() { - - val spec = mockk() - every { spec.then() } returns Mono.empty() - - runBlocking { - spec.await() - } - - verify { - spec.then() - } - } - - @Test // gh-63 - fun genericExecuteSpecAsType() { - - val genericSpec = mockk() - val typedSpec: DatabaseClient.TypedExecuteSpec = mockk() - every { genericSpec.`as`(String::class.java) } returns typedSpec - - runBlocking { - assertThat(genericSpec.asType()).isEqualTo(typedSpec) - } - - verify { - genericSpec.`as`(String::class.java) - } - } - - @Test // gh-63 - fun genericSelectSpecAsType() { - - val genericSpec = mockk() - val typedSpec: DatabaseClient.TypedSelectSpec = mockk() - every { genericSpec.`as`(String::class.java) } returns typedSpec - - runBlocking { - assertThat(genericSpec.asType()).isEqualTo(typedSpec) - } - - verify { - genericSpec.`as`(String::class.java) - } - } - - @Test // gh-63 - fun typedExecuteSpecAwait() { - - val spec = mockk>() - every { spec.then() } returns Mono.empty() - - runBlocking { - spec.await() - } - - verify { - spec.then() - } - } - - @Test // gh-63 - fun typedExecuteSpecAsType() { - - val spec: DatabaseClient.TypedExecuteSpec = mockk() - every { spec.`as`(String::class.java) } returns spec - - runBlocking { - assertThat(spec.asType()).isEqualTo(spec) - } - - verify { - spec.`as`(String::class.java) - } - } - - @Test // gh-63 - fun insertSpecAwait() { - - val spec = mockk>() - every { spec.then() } returns Mono.empty() - - runBlocking { - spec.await() - } - - verify { - spec.then() - } - } - - @Test // gh-63 - fun insertIntoSpecInto() { - - val spec = mockk() - val typedSpec: DatabaseClient.TypedInsertSpec = mockk() - every { spec.into(String::class.java) } returns typedSpec - - runBlocking { - assertThat(spec.into()).isEqualTo(typedSpec) - } - - verify { - spec.into(String::class.java) - } - } - - @Test // gh-162 - fun insertValueShouldBindValue() { - - val spec = mockk>() - every { spec.value(eq("field"), any()) } returns spec - - runBlocking { - spec.value("field", "foo") - } - - verify { - spec.value("field", SettableValue.fromOrEmpty("foo", String::class.java)) - } - } - - @Test // gh-162 - fun insertValueShouldBindNull() { - - val spec = mockk>() - every { spec.value(eq("field"), any()) } returns spec - - runBlocking { - spec.value("field", null) - } - - verify { - spec.value("field", SettableValue.empty(String::class.java)) - } - } - - @Test // gh-122 - fun selectFromSpecFrom() { - - val spec = mockk() - val typedSpec: DatabaseClient.TypedSelectSpec = mockk() - every { spec.from(String::class.java) } returns typedSpec - - assertThat(spec.from()).isEqualTo(typedSpec) - - verify { - spec.from(String::class.java) - } - } - - @Test // gh-122 - fun updateTableSpecTable() { - - val spec = mockk() - val typedSpec: DatabaseClient.TypedUpdateSpec = mockk() - every { spec.table(String::class.java) } returns typedSpec - - assertThat(spec.table()).isEqualTo(typedSpec) - - verify { - spec.table(String::class.java) - } - } - - @Test // gh-122 - fun deleteFromSpecFrom() { - - val spec = mockk() - val typedSpec: DatabaseClient.TypedDeleteSpec = mockk() - every { spec.from(String::class.java) } returns typedSpec - - assertThat(spec.from()).isEqualTo(typedSpec) - - verify { - spec.from(String::class.java) - } - } -} diff --git a/src/test/kotlin/org/springframework/data/r2dbc/core/RowsFetchSpecExtensionsTests.kt b/src/test/kotlin/org/springframework/data/r2dbc/core/RowsFetchSpecExtensionsTests.kt deleted file mode 100644 index ed8c876bc..000000000 --- a/src/test/kotlin/org/springframework/data/r2dbc/core/RowsFetchSpecExtensionsTests.kt +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright 2018-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.mockk.every -import io.mockk.mockk -import io.mockk.verify -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.toList -import kotlinx.coroutines.runBlocking -import org.assertj.core.api.Assertions.assertThat -import org.assertj.core.api.Assertions.assertThatExceptionOfType -import org.junit.Test -import org.springframework.dao.EmptyResultDataAccessException -import reactor.core.publisher.Flux -import reactor.core.publisher.Mono - -/** - * Unit tests for [RowsFetchSpec] extensions. - * - * @author Sebastien Deleuze - * @author Mark Paluch - */ -class RowsFetchSpecExtensionsTests { - - @Test // gh-63 - fun awaitOneWithValue() { - - val spec = mockk>() - every { spec.one() } returns Mono.just("foo") - - runBlocking { - assertThat(spec.awaitOne()).isEqualTo("foo") - } - - verify { - spec.one() - } - } - - @Test // gh-63, gh-103 - fun awaitOneWithNull() { - - val spec = mockk>() - every { spec.one() } returns Mono.empty() - - assertThatExceptionOfType(EmptyResultDataAccessException::class.java).isThrownBy { - runBlocking { spec.awaitOne() } - } - - verify { - spec.one() - } - } - - @Test // gh-63 - fun awaitOneOrNullWithValue() { - - val spec = mockk>() - every { spec.one() } returns Mono.just("foo") - - runBlocking { - assertThat(spec.awaitOneOrNull()).isEqualTo("foo") - } - - verify { - spec.one() - } - } - - @Test // gh-63 - fun awaitOneOrNullWithNull() { - - val spec = mockk>() - every { spec.one() } returns Mono.empty() - - runBlocking { - assertThat(spec.awaitOneOrNull()).isNull() - } - - verify { - spec.one() - } - } - - @Test // gh-63 - fun awaitFirstWithValue() { - - val spec = mockk>() - every { spec.first() } returns Mono.just("foo") - - runBlocking { - assertThat(spec.awaitFirst()).isEqualTo("foo") - } - - verify { - spec.first() - } - } - - @Test // gh-63, gh-103 - fun awaitFirstWithNull() { - - val spec = mockk>() - every { spec.first() } returns Mono.empty() - - assertThatExceptionOfType(EmptyResultDataAccessException::class.java).isThrownBy { - runBlocking { spec.awaitFirst() } - } - - verify { - spec.first() - } - } - - @Test // gh-63 - fun awaitFirstOrNullWithValue() { - - val spec = mockk>() - every { spec.first() } returns Mono.just("foo") - - runBlocking { - assertThat(spec.awaitFirstOrNull()).isEqualTo("foo") - } - - verify { - spec.first() - } - } - - @Test // gh-63 - fun awaitFirstOrNullWithNull() { - - val spec = mockk>() - every { spec.first() } returns Mono.empty() - - runBlocking { - assertThat(spec.awaitFirstOrNull()).isNull() - } - - verify { - spec.first() - } - } - - @Test // gh-91 - @ExperimentalCoroutinesApi - fun allAsFlow() { - - val spec = mockk>() - every { spec.all() } returns Flux.just("foo", "bar", "baz") - - runBlocking { - assertThat(spec.flow().toList()).contains("foo", "bar", "baz") - } - - verify { - spec.all() - } - } -} diff --git a/src/test/kotlin/org/springframework/data/r2dbc/core/UpdatedRowsFetchSpecExtensionsTests.kt b/src/test/kotlin/org/springframework/data/r2dbc/core/UpdatedRowsFetchSpecExtensionsTests.kt deleted file mode 100644 index 77e237ce3..000000000 --- a/src/test/kotlin/org/springframework/data/r2dbc/core/UpdatedRowsFetchSpecExtensionsTests.kt +++ /dev/null @@ -1,47 +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.mockk.every -import io.mockk.mockk -import io.mockk.verify -import kotlinx.coroutines.runBlocking -import org.assertj.core.api.Assertions.assertThat -import org.junit.Test -import reactor.core.publisher.Mono - -/** - * Unit tests for [UpdatedRowsFetchSpec] extensions. - * - * @author Fred Montariol - */ -class UpdatedRowsFetchSpecExtensionsTests { - - @Test // gh-212 - fun awaitRowsUpdatedWithValue() { - - val spec = mockk() - every { spec.rowsUpdated() } returns Mono.just(42) - - runBlocking { - assertThat(spec.awaitRowsUpdated()).isEqualTo(42) - } - - verify { - spec.rowsUpdated() - } - } -} diff --git a/src/test/kotlin/org/springframework/data/r2dbc/repository/CoroutineRepositoryUnitTests.kt b/src/test/kotlin/org/springframework/data/r2dbc/repository/CoroutineRepositoryUnitTests.kt index d42e922cd..0126c8f72 100644 --- a/src/test/kotlin/org/springframework/data/r2dbc/repository/CoroutineRepositoryUnitTests.kt +++ b/src/test/kotlin/org/springframework/data/r2dbc/repository/CoroutineRepositoryUnitTests.kt @@ -24,13 +24,13 @@ import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.springframework.data.annotation.Id -import org.springframework.data.r2dbc.core.DatabaseClient import org.springframework.data.r2dbc.core.DefaultReactiveDataAccessStrategy import org.springframework.data.r2dbc.core.R2dbcEntityTemplate import org.springframework.data.r2dbc.dialect.PostgresDialect import org.springframework.data.r2dbc.repository.support.R2dbcRepositoryFactory import org.springframework.data.r2dbc.testing.StatementRecorder import org.springframework.data.repository.kotlin.CoroutineCrudRepository +import org.springframework.r2dbc.core.DatabaseClient /** * Unit tests for [CoroutineCrudRepository]. @@ -48,8 +48,11 @@ class CoroutineRepositoryUnitTests { fun before() { recorder = StatementRecorder.newInstance() client = DatabaseClient.builder().connectionFactory(recorder) - .dataAccessStrategy(DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)).build() - entityTemplate = R2dbcEntityTemplate(client) + .bindMarkers(PostgresDialect.INSTANCE.bindMarkersFactory).build() + entityTemplate = R2dbcEntityTemplate( + client, + DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE) + ) repositoryFactory = R2dbcRepositoryFactory(entityTemplate) }