#20 - Polishing.

Rename Database.latestDialect() to defaultDialect(). Rename Dialect.returnGeneratedKeys() to Dialect.generatedKeysClause(). Simplify IndexBindMarkers. Create BindableOperation.bind(Statement, SettableValue) to reduce code duplicates. Rename BindSpecWrapper to BindSpecAdapter.

Original pull request: #24.
This commit is contained in:
Jens Schauder
2018-12-03 14:47:36 +01:00
committed by Mark Paluch
parent 68f1e0b0b3
commit 0aa623280f
15 changed files with 92 additions and 79 deletions

View File

@@ -68,7 +68,7 @@ public abstract class AbstractR2dbcConfiguration {
.orElseThrow(() -> new UnsupportedOperationException(
String.format("Cannot determine a dialect for %s using %s. Please provide a Dialect.",
connectionFactory.getMetadata().getName(), connectionFactory)))
.latestDialect();
.defaultDialect();
}
/**

View File

@@ -15,6 +15,7 @@ import org.springframework.util.Assert;
* if none was configured explicitly.
*
* @author Mark Paluch
* @author Jens Schauder
*/
public enum Database {
@@ -25,7 +26,7 @@ public enum Database {
}
@Override
public Dialect latestDialect() {
public Dialect defaultDialect() {
return PostgresDialect.INSTANCE;
}
},
@@ -37,7 +38,7 @@ public enum Database {
}
@Override
public Dialect latestDialect() {
public Dialect defaultDialect() {
return SqlServerDialect.INSTANCE;
}
},
@@ -49,7 +50,7 @@ public enum Database {
}
@Override
public Dialect latestDialect() {
public Dialect defaultDialect() {
return H2Dialect.INSTANCE;
}
};
@@ -63,7 +64,7 @@ public enum Database {
*/
public static Optional<Database> findDatabase(ConnectionFactory connectionFactory) {
Assert.notNull(connectionFactory, "ConnectionFactor must not be null!");
Assert.notNull(connectionFactory, "ConnectionFactory must not be null!");
ConnectionFactoryMetadata metadata = connectionFactory.getMetadata();
@@ -87,6 +88,6 @@ public enum Database {
*
* @return the latest {@link Dialect} for the underlying database.
*/
public abstract Dialect latestDialect();
public abstract Dialect defaultDialect();
}

View File

@@ -4,6 +4,7 @@ package org.springframework.data.r2dbc.dialect;
* Represents a dialect that is implemented by a particular database.
*
* @author Mark Paluch
* @author Jens Schauder
*/
public interface Dialect {
@@ -15,12 +16,15 @@ public interface Dialect {
BindMarkersFactory getBindMarkersFactory();
/**
* Returns the statement to include for returning generated keys. The returned query is directly appended to
* Returns the clause to include for returning generated keys. The returned query is directly appended to
* {@code INSERT} statements.
*
* @return the statement to include for returning generated keys.
* @return the clause to include for returning generated keys.
* @deprecated to be removed after upgrading to R2DBC 1.0M7 in favor of using the driver's direct support for
* retrieving generated keys.
*/
String returnGeneratedKeys();
@Deprecated
String generatedKeysClause();
/**
* Return the {@link LimitClause} used by this dialect.

View File

@@ -17,7 +17,7 @@ public class H2Dialect extends PostgresDialect {
* @see org.springframework.data.r2dbc.dialect.Dialect#returnGeneratedKeys()
*/
@Override
public String returnGeneratedKeys() {
public String generatedKeysClause() {
return "";
}
}

View File

@@ -9,6 +9,7 @@ import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
* prefix for bind markers to be represented within the query string.
*
* @author Mark Paluch
* @author Jens Schauder
*/
class IndexedBindMarkers implements BindMarkers {
@@ -28,9 +29,9 @@ class IndexedBindMarkers implements BindMarkers {
* @param beginWith the first index to use.
*/
IndexedBindMarkers(String prefix, int beginWith) {
this.counter = beginWith;
this.counter = 0;
this.prefix = prefix;
this.offset = 0 - beginWith;
this.offset = beginWith;
}
/*
@@ -42,7 +43,7 @@ class IndexedBindMarkers implements BindMarkers {
int index = COUNTER_INCREMENTER.getAndIncrement(this);
return new IndexedBindMarker(prefix + "" + index, index + offset);
return new IndexedBindMarker(prefix + "" + (index + offset), index);
}
/**

View File

@@ -16,7 +16,7 @@ public class PostgresDialect implements Dialect {
private static final LimitClause LIMIT_CLAUSE = new LimitClause() {
/*
/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.dialect.LimitClause#getClause(long, long)
*/
@@ -25,7 +25,7 @@ public class PostgresDialect implements Dialect {
return String.format("LIMIT %d OFFSET %d", limit, offset);
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.dialect.LimitClause#getClause(long)
*/
@@ -34,7 +34,7 @@ public class PostgresDialect implements Dialect {
return "LIMIT " + limit;
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.dialect.LimitClause#getClausePosition()
*/
@@ -44,7 +44,7 @@ public class PostgresDialect implements Dialect {
}
};
/*
/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.dialect.Dialect#getBindMarkersFactory()
*/
@@ -53,16 +53,16 @@ public class PostgresDialect implements Dialect {
return INDEXED;
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.dialect.Dialect#returnGeneratedKeys()
*/
@Override
public String returnGeneratedKeys() {
public String generatedKeysClause() {
return "RETURNING *";
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.dialect.Dialect#limit()
*/

View File

@@ -17,7 +17,7 @@ public class SqlServerDialect implements Dialect {
private static final LimitClause LIMIT_CLAUSE = new LimitClause() {
/*
/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.dialect.LimitClause#getClause(long)
*/
@@ -26,7 +26,7 @@ public class SqlServerDialect implements Dialect {
return "OFFSET 0 ROWS FETCH NEXT " + limit + " ROWS ONLY";
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.dialect.LimitClause#getClause(long, long)
*/
@@ -35,7 +35,7 @@ public class SqlServerDialect implements Dialect {
return String.format("OFFSET %d ROWS FETCH NEXT %d ROWS ONLY", offset, limit);
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.dialect.LimitClause#getClausePosition()
*/
@@ -45,7 +45,7 @@ public class SqlServerDialect implements Dialect {
}
};
/*
/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.dialect.Dialect#getBindMarkersFactory()
*/
@@ -54,16 +54,16 @@ public class SqlServerDialect implements Dialect {
return NAMED;
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.dialect.Dialect#returnGeneratedKeys()
*/
@Override
public String returnGeneratedKeys() {
public String generatedKeysClause() {
return "select SCOPE_IDENTITY() AS GENERATED_KEYS";
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.dialect.Dialect#limit()
*/

View File

@@ -2,6 +2,8 @@ package org.springframework.data.r2dbc.function;
import io.r2dbc.spi.Statement;
import org.springframework.data.r2dbc.function.convert.SettableValue;
/**
* Extension to {@link QueryOperation} for operations that allow parameter substitution by binding parameter values.
* {@link BindableOperation} is typically created with a {@link Set} of column names or parameter names that accept bind
@@ -33,4 +35,23 @@ public interface BindableOperation extends QueryOperation {
* @see Statement#bindNull
*/
void bindNull(Statement<?> statement, String identifier, Class<?> valueType);
/**
* Bind a {@link SettableValue} to the {@link Statement} using the underlying binding strategy. Binds either the
* {@link SettableValue#getValue()} or {@literal null}, depending on whether the value is {@literal null}.
*
* @param statement the statement to bind the value to.
* @param value the settable value
* @see Statement#bind
* @see Statement#bindNull
*/
default void bind(Statement<?> statement, SettableValue value) {
if (value.getValue() == null) {
bindNull(statement, value.getIdentifier().toString(), value.getType());
} else {
bind(statement, value.getIdentifier().toString(), value.getValue());
}
}
}

View File

@@ -818,12 +818,7 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
Statement<?> statement = it.createStatement(sql);
byName.forEach((k, v) -> {
if (v.getValue() == null) {
bindableInsert.bindNull(statement, k, v.getType());
} else {
bindableInsert.bind(statement, k, v.getValue());
}
bindableInsert.bind(statement, v);
});
return statement;
};
@@ -911,12 +906,7 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
Statement<?> statement = it.createStatement(sql);
for (SettableValue settable : insertValues) {
if (settable.getValue() == null) {
bindableInsert.bindNull(statement, settable.getIdentifier().toString(), settable.getType());
} else {
bindableInsert.bind(statement, settable.getIdentifier().toString(), settable.getValue());
}
bindableInsert.bind(statement, settable);
}
return statement;

View File

@@ -93,7 +93,7 @@ class DefaultDatabaseClientBuilder implements DatabaseClient.Builder {
Dialect dialect = Database.findDatabase(this.connectionFactory)
.orElseThrow(() -> new UnsupportedOperationException(
"Cannot determine a Dialect. Configure the dialect by providing DefaultReactiveDataAccessStrategy(Dialect)"))
.latestDialect();
.defaultDialect();
accessStrategy = new DefaultReactiveDataAccessStrategy(dialect);
}

View File

@@ -196,10 +196,10 @@ public class DefaultReactiveDataAccessStrategy implements ReactiveDataAccessStra
@Override
public BindableOperation insertAndReturnGeneratedKeys(String table, Set<String> columns) {
return new DefaultBindableInsert(dialect.getBindMarkersFactory().create(), table, columns,
dialect.returnGeneratedKeys());
dialect.generatedKeysClause());
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.function.ReactiveDataAccessStrategy#select(java.lang.String, java.util.Set, org.springframework.data.domain.Sort, org.springframework.data.domain.Pageable)
*/
@@ -283,7 +283,7 @@ public class DefaultReactiveDataAccessStrategy implements ReactiveDataAccessStra
});
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.function.ReactiveDataAccessStrategy#selectByIdIn(java.lang.String, java.util.Set, java.lang.String)
*/
@@ -303,7 +303,7 @@ public class DefaultReactiveDataAccessStrategy implements ReactiveDataAccessStra
return new DefaultBindableUpdate(dialect.getBindMarkersFactory().create(), table, columns, idColumn);
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.function.ReactiveDataAccessStrategy#deleteById(java.lang.String, java.lang.String)
*/
@@ -314,7 +314,7 @@ public class DefaultReactiveDataAccessStrategy implements ReactiveDataAccessStra
marker -> String.format("DELETE FROM %s WHERE %s = %s", table, idColumn, marker.getPlaceholder()));
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.function.ReactiveDataAccessStrategy#deleteByIdIn(java.lang.String, java.lang.String)
*/
@@ -442,7 +442,7 @@ public class DefaultReactiveDataAccessStrategy implements ReactiveDataAccessStra
idMarker.bind(statement, value);
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.function.BindIdOperation#bindIds(io.r2dbc.spi.Statement, java.lang.Iterable)
*/
@@ -503,7 +503,7 @@ public class DefaultReactiveDataAccessStrategy implements ReactiveDataAccessStra
idMarker.bind(statement, value);
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.function.BindIdOperation#bindIds(io.r2dbc.spi.Statement, java.lang.Iterable)
*/
@@ -570,7 +570,7 @@ public class DefaultReactiveDataAccessStrategy implements ReactiveDataAccessStra
bindMarker.bind(statement, value);
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.r2dbc.function.BindIdOperation#bindIds(io.r2dbc.spi.Statement, java.lang.Iterable)
*/

View File

@@ -7,41 +7,41 @@ import org.reactivestreams.Publisher;
import org.springframework.data.r2dbc.function.DatabaseClient.BindSpec;
/**
* Wrapper for {@link BindSpec} to be used with {@link org.springframework.data.r2dbc.dialect.BindMarker} binding.
* Adapter for {@link BindSpec} to be used with {@link org.springframework.data.r2dbc.dialect.BindMarker} binding.
* Binding parameters updates the {@link BindSpec}
*
* @param <S> type of the bind specification.
* @author Mark Paluch
*/
class BindSpecWrapper<S extends BindSpec<S>> implements Statement<BindSpecWrapper<S>> {
class BindSpecAdapter<S extends BindSpec<S>> implements Statement<BindSpecAdapter<S>> {
private S bindSpec;
private BindSpecWrapper(S bindSpec) {
private BindSpecAdapter(S bindSpec) {
this.bindSpec = bindSpec;
}
/**
* Create a new {@link BindSpecWrapper} for the given {@link BindSpec}.
* Create a new {@link BindSpecAdapter} for the given {@link BindSpec}.
*
* @param bindSpec the bind specification.
* @param <S> type of the bind spec to retain the type through {@link #getBoundOperation()}.
* @return {@link BindSpecWrapper} for the {@link BindSpec}.
* @return {@link BindSpecAdapter} for the {@link BindSpec}.
*/
public static <S extends BindSpec<S>> BindSpecWrapper<S> create(S bindSpec) {
return new BindSpecWrapper<>(bindSpec);
public static <S extends BindSpec<S>> BindSpecAdapter<S> create(S bindSpec) {
return new BindSpecAdapter<>(bindSpec);
}
/*
/*
* (non-Javadoc)
* @see io.r2dbc.spi.Statement#add()
*/
@Override
public BindSpecWrapper<S> add() {
public BindSpecAdapter<S> add() {
throw new UnsupportedOperationException();
}
/*
/*
* (non-Javadoc)
* @see io.r2dbc.spi.Statement#execute()
*/
@@ -50,45 +50,45 @@ class BindSpecWrapper<S extends BindSpec<S>> implements Statement<BindSpecWrappe
throw new UnsupportedOperationException();
}
/*
/*
* (non-Javadoc)
* @see io.r2dbc.spi.Statement#bind(java.lang.Object, java.lang.Object)
*/
@Override
public BindSpecWrapper<S> bind(Object identifier, Object value) {
public BindSpecAdapter<S> bind(Object identifier, Object value) {
this.bindSpec = bindSpec.bind((String) identifier, value);
return this;
}
/*
/*
* (non-Javadoc)
* @see io.r2dbc.spi.Statement#bind(int, java.lang.Object)
*/
@Override
public BindSpecWrapper<S> bind(int index, Object value) {
public BindSpecAdapter<S> 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 BindSpecWrapper<S> bindNull(Object identifier, Class<?> type) {
public BindSpecAdapter<S> bindNull(Object identifier, Class<?> type) {
this.bindSpec = bindSpec.bindNull((String) identifier, type);
return this;
}
/*
/*
* (non-Javadoc)
* @see io.r2dbc.spi.Statement#bindNull(int, java.lang.Class)
*/
@Override
public BindSpecWrapper<S> bindNull(int index, Class<?> type) {
public BindSpecAdapter<S> bindNull(int index, Class<?> type) {
this.bindSpec = bindSpec.bindNull(index, type);
return this;

View File

@@ -78,7 +78,7 @@ public class SimpleR2dbcRepository<T, ID> implements ReactiveCrudRepository<T, I
GenericExecuteSpec exec = databaseClient.execute().sql(update);
BindSpecWrapper<GenericExecuteSpec> wrapper = BindSpecWrapper.create(exec);
BindSpecAdapter<GenericExecuteSpec> wrapper = BindSpecAdapter.create(exec);
columns.forEach(bind(update, wrapper));
update.bindId(wrapper, id);
@@ -123,7 +123,7 @@ public class SimpleR2dbcRepository<T, ID> implements ReactiveCrudRepository<T, I
BindIdOperation select = accessStrategy.selectById(entity.getTableName(), columns, idColumnName);
GenericExecuteSpec sql = databaseClient.execute().sql(select);
BindSpecWrapper<GenericExecuteSpec> wrapper = BindSpecWrapper.create(sql);
BindSpecAdapter<GenericExecuteSpec> wrapper = BindSpecAdapter.create(sql);
select.bindId(wrapper, id);
return wrapper.getBoundOperation().as(entity.getJavaType()) //
@@ -152,7 +152,7 @@ public class SimpleR2dbcRepository<T, ID> implements ReactiveCrudRepository<T, I
idColumnName, 10);
GenericExecuteSpec sql = databaseClient.execute().sql(select);
BindSpecWrapper<GenericExecuteSpec> wrapper = BindSpecWrapper.create(sql);
BindSpecAdapter<GenericExecuteSpec> wrapper = BindSpecAdapter.create(sql);
select.bindId(wrapper, id);
return wrapper.getBoundOperation().as(entity.getJavaType()) //
@@ -205,7 +205,7 @@ public class SimpleR2dbcRepository<T, ID> implements ReactiveCrudRepository<T, I
String idColumnName = getIdColumnName();
BindIdOperation select = accessStrategy.selectByIdIn(entity.getTableName(), columns, idColumnName);
BindSpecWrapper<GenericExecuteSpec> wrapper = BindSpecWrapper.create(databaseClient.execute().sql(select));
BindSpecAdapter<GenericExecuteSpec> wrapper = BindSpecAdapter.create(databaseClient.execute().sql(select));
select.bindIds(wrapper, ids);
return wrapper.getBoundOperation().as(entity.getJavaType()).fetch().all();
@@ -235,7 +235,7 @@ public class SimpleR2dbcRepository<T, ID> implements ReactiveCrudRepository<T, I
Assert.notNull(id, "Id must not be null!");
BindIdOperation delete = accessStrategy.deleteById(entity.getTableName(), getIdColumnName());
BindSpecWrapper<GenericExecuteSpec> wrapper = BindSpecWrapper.create(databaseClient.execute().sql(delete));
BindSpecAdapter<GenericExecuteSpec> wrapper = BindSpecAdapter.create(databaseClient.execute().sql(delete));
delete.bindId(wrapper, id);
@@ -262,7 +262,7 @@ public class SimpleR2dbcRepository<T, ID> implements ReactiveCrudRepository<T, I
String idColumnName = getIdColumnName();
BindIdOperation delete = accessStrategy.deleteByIdIn(entity.getTableName(), idColumnName);
BindSpecWrapper<GenericExecuteSpec> wrapper = BindSpecWrapper.create(databaseClient.execute().sql(delete));
BindSpecAdapter<GenericExecuteSpec> wrapper = BindSpecAdapter.create(databaseClient.execute().sql(delete));
delete.bindIds(wrapper, ids);
return wrapper.getBoundOperation().as(entity.getJavaType()).fetch().rowsUpdated();
@@ -324,11 +324,7 @@ public class SimpleR2dbcRepository<T, ID> implements ReactiveCrudRepository<T, I
private BiConsumer<String, SettableValue> bind(BindableOperation operation, Statement<?> statement) {
return (k, v) -> {
if (v.getValue() == null) {
operation.bindNull(statement, k, v.getType());
} else {
operation.bind(statement, k, v.getValue());
}
operation.bind(statement, v);
};
}
}