|
|
|
|
@@ -23,6 +23,20 @@ import io.r2dbc.spi.Row;
|
|
|
|
|
import io.r2dbc.spi.RowMetadata;
|
|
|
|
|
import io.r2dbc.spi.Statement;
|
|
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
|
|
import org.apache.commons.logging.Log;
|
|
|
|
|
import org.apache.commons.logging.LogFactory;
|
|
|
|
|
import org.reactivestreams.Publisher;
|
|
|
|
|
import org.springframework.dao.DataAccessException;
|
|
|
|
|
import org.springframework.data.domain.Pageable;
|
|
|
|
|
import org.springframework.data.domain.Sort;
|
|
|
|
|
import org.springframework.data.r2dbc.UncategorizedR2dbcException;
|
|
|
|
|
import org.springframework.data.r2dbc.function.connectionfactory.ConnectionProxy;
|
|
|
|
|
import org.springframework.data.r2dbc.function.convert.ColumnMapRowMapper;
|
|
|
|
|
import org.springframework.data.r2dbc.function.convert.SettableValue;
|
|
|
|
|
import org.springframework.data.r2dbc.support.R2dbcExceptionTranslator;
|
|
|
|
|
import org.springframework.jdbc.core.SqlProvider;
|
|
|
|
|
import org.springframework.lang.Nullable;
|
|
|
|
|
import org.springframework.util.Assert;
|
|
|
|
|
import reactor.core.publisher.Flux;
|
|
|
|
|
import reactor.core.publisher.Mono;
|
|
|
|
|
|
|
|
|
|
@@ -43,21 +57,6 @@ 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.data.domain.Pageable;
|
|
|
|
|
import org.springframework.data.domain.Sort;
|
|
|
|
|
import org.springframework.data.r2dbc.UncategorizedR2dbcException;
|
|
|
|
|
import org.springframework.data.r2dbc.function.connectionfactory.ConnectionProxy;
|
|
|
|
|
import org.springframework.data.r2dbc.function.convert.ColumnMapRowMapper;
|
|
|
|
|
import org.springframework.data.r2dbc.function.convert.SettableValue;
|
|
|
|
|
import org.springframework.data.r2dbc.support.R2dbcExceptionTranslator;
|
|
|
|
|
import org.springframework.jdbc.core.SqlProvider;
|
|
|
|
|
import org.springframework.lang.Nullable;
|
|
|
|
|
import org.springframework.util.Assert;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Default implementation of {@link DatabaseClient}.
|
|
|
|
|
*
|
|
|
|
|
@@ -65,7 +64,9 @@ import org.springframework.util.Assert;
|
|
|
|
|
*/
|
|
|
|
|
class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
|
|
|
|
|
|
|
|
|
/** Logger available to subclasses */
|
|
|
|
|
/**
|
|
|
|
|
* Logger available to subclasses
|
|
|
|
|
*/
|
|
|
|
|
private final Log logger = LogFactory.getLog(getClass());
|
|
|
|
|
|
|
|
|
|
private final ConnectionFactory connector;
|
|
|
|
|
@@ -77,7 +78,7 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
|
|
|
|
private final DefaultDatabaseClientBuilder builder;
|
|
|
|
|
|
|
|
|
|
DefaultDatabaseClient(ConnectionFactory connector, R2dbcExceptionTranslator exceptionTranslator,
|
|
|
|
|
ReactiveDataAccessStrategy dataAccessStrategy, DefaultDatabaseClientBuilder builder) {
|
|
|
|
|
ReactiveDataAccessStrategy dataAccessStrategy, DefaultDatabaseClientBuilder builder) {
|
|
|
|
|
|
|
|
|
|
this.connector = connector;
|
|
|
|
|
this.exceptionTranslator = exceptionTranslator;
|
|
|
|
|
@@ -113,7 +114,7 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
|
|
|
|
*
|
|
|
|
|
* @param action must not be {@literal null}.
|
|
|
|
|
* @return the resulting {@link Mono}.
|
|
|
|
|
* @throws DataAccessException
|
|
|
|
|
* @throws DataAccessException when during construction of the {@link Mono} a problem occurs.
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public <T> Mono<T> inConnection(Function<Connection, Mono<T>> action) throws DataAccessException {
|
|
|
|
|
@@ -140,7 +141,7 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
|
|
|
|
*
|
|
|
|
|
* @param action must not be {@literal null}.
|
|
|
|
|
* @return the resulting {@link Flux}.
|
|
|
|
|
* @throws DataAccessException
|
|
|
|
|
* @throws DataAccessException when during construction of the {@link Mono} a problem occurs.
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public <T> Flux<T> inConnectionMany(Function<Connection, Flux<T>> action) throws DataAccessException {
|
|
|
|
|
@@ -162,7 +163,7 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
|
|
|
|
/**
|
|
|
|
|
* Obtain a {@link Connection}.
|
|
|
|
|
*
|
|
|
|
|
* @return
|
|
|
|
|
* @return a {@link Mono} able to emit a {@link Connection}.
|
|
|
|
|
*/
|
|
|
|
|
protected Mono<Connection> getConnection() {
|
|
|
|
|
return Mono.from(obtainConnectionFactory().create());
|
|
|
|
|
@@ -171,8 +172,8 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
|
|
|
|
/**
|
|
|
|
|
* Release the {@link Connection}.
|
|
|
|
|
*
|
|
|
|
|
* @param connection
|
|
|
|
|
* @return
|
|
|
|
|
* @param connection to close.
|
|
|
|
|
* @return a {@link Publisher} that completes successfully when the connection is closed.
|
|
|
|
|
*/
|
|
|
|
|
protected Publisher<Void> closeConnection(Connection connection) {
|
|
|
|
|
return connection.close();
|
|
|
|
|
@@ -196,15 +197,15 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
|
|
|
|
*/
|
|
|
|
|
protected Connection createConnectionProxy(Connection con) {
|
|
|
|
|
return (Connection) Proxy.newProxyInstance(ConnectionProxy.class.getClassLoader(),
|
|
|
|
|
new Class<?>[] { ConnectionProxy.class }, new CloseSuppressingInvocationHandler(con));
|
|
|
|
|
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}.
|
|
|
|
|
* @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) {
|
|
|
|
|
@@ -217,7 +218,7 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
|
|
|
|
* Customization hook.
|
|
|
|
|
*/
|
|
|
|
|
protected <T> DefaultTypedExecuteSpec<T> createTypedExecuteSpec(Map<Integer, SettableValue> byIndex,
|
|
|
|
|
Map<String, SettableValue> byName, Supplier<String> sqlSupplier, Class<T> typeToRead) {
|
|
|
|
|
Map<String, SettableValue> byName, Supplier<String> sqlSupplier, Class<T> typeToRead) {
|
|
|
|
|
return new DefaultTypedExecuteSpec<>(byIndex, byName, sqlSupplier, typeToRead);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -225,8 +226,8 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
|
|
|
|
* Customization hook.
|
|
|
|
|
*/
|
|
|
|
|
protected <T> DefaultTypedExecuteSpec<T> createTypedExecuteSpec(Map<Integer, SettableValue> byIndex,
|
|
|
|
|
Map<String, SettableValue> byName, Supplier<String> sqlSupplier,
|
|
|
|
|
BiFunction<Row, RowMetadata, T> mappingFunction) {
|
|
|
|
|
Map<String, SettableValue> byName, Supplier<String> sqlSupplier,
|
|
|
|
|
BiFunction<Row, RowMetadata, T> mappingFunction) {
|
|
|
|
|
return new DefaultTypedExecuteSpec<>(byIndex, byName, sqlSupplier, mappingFunction);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -234,7 +235,7 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
|
|
|
|
* Customization hook.
|
|
|
|
|
*/
|
|
|
|
|
protected ExecuteSpecSupport createGenericExecuteSpec(Map<Integer, SettableValue> byIndex,
|
|
|
|
|
Map<String, SettableValue> byName, Supplier<String> sqlSupplier) {
|
|
|
|
|
Map<String, SettableValue> byName, Supplier<String> sqlSupplier) {
|
|
|
|
|
return new DefaultGenericExecuteSpec(byIndex, byName, sqlSupplier);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -246,7 +247,7 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void doBind(Statement<?> statement, Map<String, SettableValue> byName,
|
|
|
|
|
Map<Integer, SettableValue> byIndex) {
|
|
|
|
|
Map<Integer, SettableValue> byIndex) {
|
|
|
|
|
|
|
|
|
|
byIndex.forEach((i, o) -> {
|
|
|
|
|
|
|
|
|
|
@@ -305,13 +306,6 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
|
|
|
|
this.sqlSupplier = sqlSupplier;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ExecuteSpecSupport(ExecuteSpecSupport other) {
|
|
|
|
|
|
|
|
|
|
this.byIndex = other.byIndex;
|
|
|
|
|
this.byName = other.byName;
|
|
|
|
|
this.sqlSupplier = other.sqlSupplier;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected String getSql() {
|
|
|
|
|
|
|
|
|
|
String sql = sqlSupplier.get();
|
|
|
|
|
@@ -379,7 +373,7 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected ExecuteSpecSupport createInstance(Map<Integer, SettableValue> byIndex, Map<String, SettableValue> byName,
|
|
|
|
|
Supplier<String> sqlSupplier) {
|
|
|
|
|
Supplier<String> sqlSupplier) {
|
|
|
|
|
return new ExecuteSpecSupport(byIndex, byName, sqlSupplier);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -397,7 +391,7 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
|
|
|
|
protected class DefaultGenericExecuteSpec extends ExecuteSpecSupport implements GenericExecuteSpec {
|
|
|
|
|
|
|
|
|
|
DefaultGenericExecuteSpec(Map<Integer, SettableValue> byIndex, Map<String, SettableValue> byName,
|
|
|
|
|
Supplier<String> sqlSupplier) {
|
|
|
|
|
Supplier<String> sqlSupplier) {
|
|
|
|
|
super(byIndex, byName, sqlSupplier);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -458,7 +452,7 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected ExecuteSpecSupport createInstance(Map<Integer, SettableValue> byIndex, Map<String, SettableValue> byName,
|
|
|
|
|
Supplier<String> sqlSupplier) {
|
|
|
|
|
Supplier<String> sqlSupplier) {
|
|
|
|
|
return createGenericExecuteSpec(byIndex, byName, sqlSupplier);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -473,7 +467,7 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
|
|
|
|
private final BiFunction<Row, RowMetadata, T> mappingFunction;
|
|
|
|
|
|
|
|
|
|
DefaultTypedExecuteSpec(Map<Integer, SettableValue> byIndex, Map<String, SettableValue> byName,
|
|
|
|
|
Supplier<String> sqlSupplier, Class<T> typeToRead) {
|
|
|
|
|
Supplier<String> sqlSupplier, Class<T> typeToRead) {
|
|
|
|
|
|
|
|
|
|
super(byIndex, byName, sqlSupplier);
|
|
|
|
|
|
|
|
|
|
@@ -482,9 +476,10 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DefaultTypedExecuteSpec(Map<Integer, SettableValue> byIndex, Map<String, SettableValue> byName,
|
|
|
|
|
Supplier<String> sqlSupplier, BiFunction<Row, RowMetadata, T> mappingFunction) {
|
|
|
|
|
Supplier<String> sqlSupplier, BiFunction<Row, RowMetadata, T> mappingFunction) {
|
|
|
|
|
|
|
|
|
|
super(byIndex, byName, sqlSupplier);
|
|
|
|
|
|
|
|
|
|
this.typeToRead = null;
|
|
|
|
|
this.mappingFunction = mappingFunction;
|
|
|
|
|
}
|
|
|
|
|
@@ -542,7 +537,7 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected DefaultTypedExecuteSpec<T> createInstance(Map<Integer, SettableValue> byIndex,
|
|
|
|
|
Map<String, SettableValue> byName, Supplier<String> sqlSupplier) {
|
|
|
|
|
Map<String, SettableValue> byName, Supplier<String> sqlSupplier) {
|
|
|
|
|
return createTypedExecuteSpec(byIndex, byName, sqlSupplier, typeToRead);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -629,12 +624,12 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected abstract DefaultSelectSpecSupport createInstance(String table, List<String> projectedFields, Sort sort,
|
|
|
|
|
Pageable page);
|
|
|
|
|
Pageable page);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private class DefaultGenericSelectSpec extends DefaultSelectSpecSupport implements GenericSelectSpec {
|
|
|
|
|
|
|
|
|
|
public DefaultGenericSelectSpec(String table, List<String> projectedFields, Sort sort, Pageable page) {
|
|
|
|
|
DefaultGenericSelectSpec(String table, List<String> projectedFields, Sort sort, Pageable page) {
|
|
|
|
|
super(table, projectedFields, sort, page);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -696,7 +691,7 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected DefaultGenericSelectSpec createInstance(String table, List<String> projectedFields, Sort sort,
|
|
|
|
|
Pageable page) {
|
|
|
|
|
Pageable page) {
|
|
|
|
|
return new DefaultGenericSelectSpec(table, projectedFields, sort, page);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -707,7 +702,8 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
|
private class DefaultTypedSelectSpec<T> extends DefaultSelectSpecSupport implements TypedSelectSpec<T> {
|
|
|
|
|
|
|
|
|
|
private final @Nullable Class<T> typeToRead;
|
|
|
|
|
private final @Nullable
|
|
|
|
|
Class<T> typeToRead;
|
|
|
|
|
private final BiFunction<Row, RowMetadata, T> mappingFunction;
|
|
|
|
|
|
|
|
|
|
DefaultTypedSelectSpec(Class<T> typeToRead) {
|
|
|
|
|
@@ -719,12 +715,12 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DefaultTypedSelectSpec(String table, List<String> projectedFields, Sort sort, Pageable page,
|
|
|
|
|
BiFunction<Row, RowMetadata, T> mappingFunction) {
|
|
|
|
|
BiFunction<Row, RowMetadata, T> mappingFunction) {
|
|
|
|
|
this(table, projectedFields, sort, page, null, mappingFunction);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DefaultTypedSelectSpec(String table, List<String> projectedFields, Sort sort, Pageable page, Class<T> typeToRead,
|
|
|
|
|
BiFunction<Row, RowMetadata, T> mappingFunction) {
|
|
|
|
|
BiFunction<Row, RowMetadata, T> mappingFunction) {
|
|
|
|
|
super(table, projectedFields, sort, page);
|
|
|
|
|
this.typeToRead = typeToRead;
|
|
|
|
|
this.mappingFunction = mappingFunction;
|
|
|
|
|
@@ -784,7 +780,7 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected DefaultTypedSelectSpec<T> createInstance(String table, List<String> projectedFields, Sort sort,
|
|
|
|
|
Pageable page) {
|
|
|
|
|
Pageable page) {
|
|
|
|
|
return new DefaultTypedSelectSpec<>(table, projectedFields, sort, page, typeToRead, mappingFunction);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -872,9 +868,8 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
|
|
|
|
|
|
|
|
|
Statement<?> statement = it.createStatement(sql);
|
|
|
|
|
|
|
|
|
|
byName.forEach((k, v) -> {
|
|
|
|
|
bindableInsert.bind(statement, v);
|
|
|
|
|
});
|
|
|
|
|
byName.forEach((k, v) -> bindableInsert.bind(statement, v));
|
|
|
|
|
|
|
|
|
|
return statement;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
@@ -1003,14 +998,14 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
|
|
|
|
return statement;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Function<Connection, Flux<Result>> resultFunction = it -> {
|
|
|
|
|
return Flux.from(insertFunction.apply(it).execute());
|
|
|
|
|
};
|
|
|
|
|
Function<Connection, Flux<Result>> resultFunction = it -> Flux.from(insertFunction.apply(it).execute());
|
|
|
|
|
|
|
|
|
|
return new DefaultSqlResult<>(DefaultDatabaseClient.this, //
|
|
|
|
|
sql, //
|
|
|
|
|
resultFunction, //
|
|
|
|
|
it -> resultFunction.apply(it).flatMap(Result::getRowsUpdated)
|
|
|
|
|
it -> resultFunction //
|
|
|
|
|
.apply(it) //
|
|
|
|
|
.flatMap(Result::getRowsUpdated) //
|
|
|
|
|
.collect(Collectors.summingInt(Integer::intValue)), //
|
|
|
|
|
mappingFunction);
|
|
|
|
|
}
|
|
|
|
|
@@ -1023,7 +1018,8 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
|
|
|
|
} catch (R2dbcException e) {
|
|
|
|
|
|
|
|
|
|
String sql = getSql(action);
|
|
|
|
|
return Flux.error(new UncategorizedR2dbcException("doInConnectionMany", sql, e) {});
|
|
|
|
|
return Flux.error(new UncategorizedR2dbcException("doInConnectionMany", sql, e) {
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1034,7 +1030,8 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
|
|
|
|
} catch (R2dbcException e) {
|
|
|
|
|
|
|
|
|
|
String sql = getSql(action);
|
|
|
|
|
return Mono.error(new UncategorizedR2dbcException("doInConnection", sql, e) {});
|
|
|
|
|
return Mono.error(new UncategorizedR2dbcException("doInConnection", sql, e) {
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|