#89 - Accept SQL directly in DatabaseClient.execute(…) stage.
We compressed client.execute().sql(…) to client.execute(…) to not require the intermediate execute() step but rather accept the SQL to execute directly. Original pull request: #112.
This commit is contained in:
@@ -139,8 +139,7 @@ public class R2dbcApp {
|
||||
|
||||
DatabaseClient client = DatabaseClient.create(connectionFactory);
|
||||
|
||||
client.execute()
|
||||
.sql("CREATE TABLE person" +
|
||||
client.sql("CREATE TABLE person" +
|
||||
"(id VARCHAR(255) PRIMARY KEY," +
|
||||
"name VARCHAR(255)," +
|
||||
"age INT)")
|
||||
|
||||
@@ -6,8 +6,7 @@ The following example shows what you need to include for minimal but fully funct
|
||||
|
||||
[source,java]
|
||||
----
|
||||
Mono<Void> completion = client.execute()
|
||||
.sql("CREATE TABLE person (id VARCHAR(255) PRIMARY KEY, name VARCHAR(255), age INTEGER);")
|
||||
Mono<Void> completion = client.sql("CREATE TABLE person (id VARCHAR(255) PRIMARY KEY, name VARCHAR(255), age INTEGER);")
|
||||
.then();
|
||||
----
|
||||
|
||||
@@ -15,7 +14,7 @@ Mono<Void> completion = client.execute()
|
||||
It exposes intermediate, continuation, and terminal methods at each stage of the execution specification.
|
||||
The example above uses `then()` to return a completion `Publisher` that completes as soon as the query (or queries, if the SQL query contains multiple statements) completes.
|
||||
|
||||
NOTE: `execute().sql(…)` accepts either the SQL query string or a query `Supplier<String>` to defer the actual query creation until execution.
|
||||
NOTE: `sql(…)` accepts either the SQL query string or a query `Supplier<String>` to defer the actual query creation until execution.
|
||||
|
||||
[[r2dbc.datbaseclient.queries]]
|
||||
== Running Queries
|
||||
@@ -27,8 +26,7 @@ The following example shows an `UPDATE` statement that returns the number of upd
|
||||
|
||||
[source,java]
|
||||
----
|
||||
Mono<Integer> affectedRows = client.execute()
|
||||
.sql("UPDATE person SET name = 'Joe'")
|
||||
Mono<Integer> affectedRows = client.sql("UPDATE person SET name = 'Joe'")
|
||||
.fetch().rowsUpdated();
|
||||
----
|
||||
|
||||
@@ -38,8 +36,7 @@ You might have noticed the use of `fetch()` in the previous example.
|
||||
|
||||
[source,java]
|
||||
----
|
||||
Mono<Map<String, Object>> first = client.execute()
|
||||
.sql("SELECT id, name FROM person")
|
||||
Mono<Map<String, Object>> first = client.sql("SELECT id, name FROM person")
|
||||
.fetch().first();
|
||||
----
|
||||
|
||||
@@ -55,8 +52,7 @@ You can consume data with the following operators:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
Flux<Person> all = client.execute()
|
||||
.sql("SELECT id, name FROM mytable")
|
||||
Flux<Person> all = client.sql("SELECT id, name FROM mytable")
|
||||
.as(Person.class)
|
||||
.fetch().all();
|
||||
----
|
||||
@@ -73,8 +69,7 @@ The following example extracts the `id` column and emits its value:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
Flux<String> names= client.execute()
|
||||
.sql("SELECT name FROM person")
|
||||
Flux<String> names = client.sql("SELECT name FROM person")
|
||||
.map((row, rowMetadata) -> row.get("id", String.class))
|
||||
.all();
|
||||
----
|
||||
@@ -107,8 +102,7 @@ The following example shows parameter binding for a query:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
db.execute()
|
||||
.sql("INSERT INTO person (id, name, age) VALUES(:id, :name, :age)")
|
||||
db.sql("INSERT INTO person (id, name, age) VALUES(:id, :name, :age)")
|
||||
.bind("id", "joe")
|
||||
.bind("name", "Joe")
|
||||
.bind("age", 34);
|
||||
@@ -146,8 +140,7 @@ List<Object[]> tuples = new ArrayList<>();
|
||||
tuples.add(new Object[] {"John", 35});
|
||||
tuples.add(new Object[] {"Ann", 50});
|
||||
|
||||
db.execute()
|
||||
.sql("SELECT id, name, state FROM table WHERE (name, age) IN (:tuples)")
|
||||
db.sql("SELECT id, name, state FROM table WHERE (name, age) IN (:tuples)")
|
||||
.bind("tuples", tuples);
|
||||
----
|
||||
|
||||
@@ -157,7 +150,6 @@ A simpler variant using `IN` predicates:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
db.execute()
|
||||
.sql("SELECT id, name, state FROM table WHERE age IN (:ages)")
|
||||
db.sql("SELECT id, name, state FROM table WHERE age IN (:ages)")
|
||||
.bind("ages", Arrays.asList(35, 50));
|
||||
----
|
||||
|
||||
@@ -18,12 +18,12 @@ TransactionalOperator operator = TransactionalOperator.create(tm); <1>
|
||||
|
||||
DatabaseClient client = DatabaseClient.create(connectionFactory);
|
||||
|
||||
Mono<Void> atomicOperation = client.execute().sql("INSERT INTO person (id, name, age) VALUES(:id, :name, :age)")
|
||||
Mono<Void> atomicOperation = client.sql("INSERT INTO person (id, name, age) VALUES(:id, :name, :age)")
|
||||
.bind("id", "joe")
|
||||
.bind("name", "Joe")
|
||||
.bind("age", 34)
|
||||
.fetch().rowsUpdated()
|
||||
.then(client.execute().sql("INSERT INTO contacts (id, name) VALUES(:id, :name)")
|
||||
.then(client.sql("INSERT INTO contacts (id, name) VALUES(:id, :name)")
|
||||
.bind("id", "joe")
|
||||
.bind("name", "Joe")
|
||||
.fetch().rowsUpdated())
|
||||
@@ -69,12 +69,12 @@ class MyService {
|
||||
@Transactional
|
||||
public Mono<Void> insertPerson() {
|
||||
|
||||
return client.execute().sql("INSERT INTO person (id, name, age) VALUES(:id, :name, :age)")
|
||||
return client.sql("INSERT INTO person (id, name, age) VALUES(:id, :name, :age)")
|
||||
.bind("id", "joe")
|
||||
.bind("name", "Joe")
|
||||
.bind("age", 34)
|
||||
.fetch().rowsUpdated()
|
||||
.then(client.execute().sql("INSERT INTO contacts (id, name) VALUES(:id, :name)")
|
||||
.then(client.sql("INSERT INTO contacts (id, name) VALUES(:id, :name)")
|
||||
.bind("id", "joe")
|
||||
.bind("name", "Joe")
|
||||
.fetch().rowsUpdated())
|
||||
|
||||
@@ -46,8 +46,41 @@ import org.springframework.data.r2dbc.support.R2dbcExceptionTranslator;
|
||||
public interface DatabaseClient {
|
||||
|
||||
/**
|
||||
* Prepare an SQL call returning a result.
|
||||
* 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.
|
||||
*
|
||||
* @see NamedParameterExpander
|
||||
* @see DatabaseClient.Builder#namedParameters(NamedParameterExpander)
|
||||
* @param sql must not be {@literal null} or empty.
|
||||
* @return a new {@link GenericExecuteSpec}.
|
||||
* @see NamedParameterExpander
|
||||
* @see DatabaseClient.Builder#namedParameters(NamedParameterExpander)
|
||||
*/
|
||||
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.
|
||||
* <p>
|
||||
* Accepts {@link PreparedOperation} as SQL and binding {@link Supplier}.
|
||||
* </p>
|
||||
*
|
||||
* @param sqlSupplier must not be {@literal null}.
|
||||
* @return a new {@link GenericExecuteSpec}.
|
||||
* @see NamedParameterExpander
|
||||
* @see DatabaseClient.Builder#namedParameters(NamedParameterExpander)
|
||||
* @see PreparedOperation
|
||||
*/
|
||||
GenericExecuteSpec execute(Supplier<String> sqlSupplier);
|
||||
|
||||
/**
|
||||
* Prepare an SQL call returning a result.
|
||||
*
|
||||
* @deprecated will be removed with 1.0 M3. Use {@link #execute(String)} directly.
|
||||
*/
|
||||
@Deprecated
|
||||
SqlSpec execute();
|
||||
|
||||
/**
|
||||
@@ -157,7 +190,9 @@ public interface DatabaseClient {
|
||||
*
|
||||
* @see NamedParameterExpander
|
||||
* @see DatabaseClient.Builder#namedParameters(NamedParameterExpander)
|
||||
* @deprecated use {@code DatabaseClient.execute(…)} directly.
|
||||
*/
|
||||
@Deprecated
|
||||
interface SqlSpec {
|
||||
|
||||
/**
|
||||
@@ -166,6 +201,7 @@ public interface DatabaseClient {
|
||||
* @param sql must not be {@literal null} or empty.
|
||||
* @return a new {@link GenericExecuteSpec}.
|
||||
*/
|
||||
@Deprecated
|
||||
GenericExecuteSpec sql(String sql);
|
||||
|
||||
/**
|
||||
@@ -175,6 +211,7 @@ public interface DatabaseClient {
|
||||
* @return a new {@link GenericExecuteSpec}.
|
||||
* @see PreparedOperation
|
||||
*/
|
||||
@Deprecated
|
||||
GenericExecuteSpec sql(Supplier<String> sqlSupplier);
|
||||
}
|
||||
|
||||
|
||||
@@ -124,6 +124,22 @@ class DefaultDatabaseClient implements DatabaseClient, ConnectionAccessor {
|
||||
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<String> 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).
|
||||
|
||||
@@ -41,7 +41,7 @@ import org.springframework.util.Assert;
|
||||
* <pre class="code">
|
||||
* Flux<Integer> transactionalFlux = databaseClient.inTransaction(db -> {
|
||||
*
|
||||
* return db.execute().sql("INSERT INTO person (id, firstname, lastname) VALUES(:id, :firstname, :lastname)") //
|
||||
* return db.execute("INSERT INTO person (id, firstname, lastname) VALUES(:id, :firstname, :lastname)") //
|
||||
* .bind("id", 1) //
|
||||
* .bind("firstname", "Walter") //
|
||||
* .bind("lastname", "White") //
|
||||
@@ -56,7 +56,7 @@ import org.springframework.util.Assert;
|
||||
* <pre class="code">
|
||||
* Mono<Void> mono = databaseClient.beginTransaction()
|
||||
* .then(databaseClient.execute()
|
||||
* .sql("INSERT INTO person (id, firstname, lastname) VALUES(:id, :firstname, :lastname)") //
|
||||
* .execute("INSERT INTO person (id, firstname, lastname) VALUES(:id, :firstname, :lastname)") //
|
||||
* .bind("id", 1) //
|
||||
* .bind("firstname", "Walter") //
|
||||
* .bind("lastname", "White") //
|
||||
|
||||
@@ -103,7 +103,7 @@ public abstract class AbstractR2dbcQuery implements RepositoryQuery {
|
||||
BindableQuery query = createQuery(parameterAccessor);
|
||||
|
||||
ResultProcessor processor = method.getResultProcessor().withDynamicProjection(parameterAccessor);
|
||||
GenericExecuteSpec boundQuery = query.bind(databaseClient.execute().sql(query));
|
||||
GenericExecuteSpec boundQuery = query.bind(databaseClient.execute(query));
|
||||
FetchSpec<?> fetchSpec = boundQuery.as(resolveResultType(processor)).fetch();
|
||||
|
||||
String tableName = method.getEntityInformation().getTableName();
|
||||
|
||||
@@ -117,7 +117,7 @@ public class SimpleR2dbcRepository<T, ID> implements ReactiveCrudRepository<T, I
|
||||
|
||||
PreparedOperation<?> operation = mapper.getMappedObject(selectSpec);
|
||||
|
||||
return this.databaseClient.execute().sql(operation) //
|
||||
return this.databaseClient.execute(operation) //
|
||||
.as(this.entity.getJavaType()) //
|
||||
.fetch() //
|
||||
.one();
|
||||
@@ -148,7 +148,7 @@ public class SimpleR2dbcRepository<T, ID> implements ReactiveCrudRepository<T, I
|
||||
|
||||
PreparedOperation<?> operation = mapper.getMappedObject(selectSpec);
|
||||
|
||||
return this.databaseClient.execute().sql(operation) //
|
||||
return this.databaseClient.execute(operation) //
|
||||
.map((r, md) -> r) //
|
||||
.first() //
|
||||
.hasElement();
|
||||
@@ -205,7 +205,7 @@ public class SimpleR2dbcRepository<T, ID> implements ReactiveCrudRepository<T, I
|
||||
|
||||
PreparedOperation<?> operation = mapper.getMappedObject(selectSpec);
|
||||
|
||||
return this.databaseClient.execute().sql(operation).as(this.entity.getJavaType()).fetch().all();
|
||||
return this.databaseClient.execute(operation).as(this.entity.getJavaType()).fetch().all();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -221,7 +221,7 @@ public class SimpleR2dbcRepository<T, ID> implements ReactiveCrudRepository<T, I
|
||||
.from(table) //
|
||||
.build();
|
||||
|
||||
return this.databaseClient.execute().sql(SqlRenderer.toString(select)) //
|
||||
return this.databaseClient.execute(SqlRenderer.toString(select)) //
|
||||
.map((r, md) -> r.get(0, Long.class)) //
|
||||
.first() //
|
||||
.defaultIfEmpty(0L);
|
||||
|
||||
@@ -101,7 +101,7 @@ public abstract class AbstractDatabaseClientIntegrationTests extends R2dbcIntegr
|
||||
|
||||
DatabaseClient databaseClient = DatabaseClient.create(connectionFactory);
|
||||
|
||||
databaseClient.execute().sql(getInsertIntoLegosetStatement()) //
|
||||
databaseClient.execute(getInsertIntoLegosetStatement()) //
|
||||
.bind("id", 42055) //
|
||||
.bind("name", "SCHAUFELRADBAGGER") //
|
||||
.bindNull("manual", Integer.class) //
|
||||
@@ -120,7 +120,7 @@ public abstract class AbstractDatabaseClientIntegrationTests extends R2dbcIntegr
|
||||
|
||||
executeInsert();
|
||||
|
||||
databaseClient.execute().sql(getInsertIntoLegosetStatement()) //
|
||||
databaseClient.execute(getInsertIntoLegosetStatement()) //
|
||||
.bind(0, 42055) //
|
||||
.bind(1, "SCHAUFELRADBAGGER") //
|
||||
.bindNull(2, Integer.class) //
|
||||
@@ -139,7 +139,7 @@ public abstract class AbstractDatabaseClientIntegrationTests extends R2dbcIntegr
|
||||
|
||||
DatabaseClient databaseClient = DatabaseClient.create(connectionFactory);
|
||||
|
||||
databaseClient.execute().sql("SELECT id, name, manual FROM legoset") //
|
||||
databaseClient.execute("SELECT id, name, manual FROM legoset") //
|
||||
.as(LegoSet.class) //
|
||||
.fetch().all() //
|
||||
.as(StepVerifier::create) //
|
||||
|
||||
@@ -145,8 +145,7 @@ public abstract class AbstractTransactionalDatabaseClientIntegrationTests extend
|
||||
TransactionalDatabaseClient databaseClient = TransactionalDatabaseClient.create(connectionFactory);
|
||||
|
||||
Flux<Integer> integerFlux = databaseClient.inTransaction(db -> db //
|
||||
.execute() //
|
||||
.sql(getInsertIntoLegosetStatement()) //
|
||||
.execute(getInsertIntoLegosetStatement()) //
|
||||
.bind(0, 42055) //
|
||||
.bind(1, "SCHAUFELRADBAGGER") //
|
||||
.bindNull(2, Integer.class) //
|
||||
@@ -165,7 +164,7 @@ public abstract class AbstractTransactionalDatabaseClientIntegrationTests extend
|
||||
|
||||
TransactionalDatabaseClient databaseClient = TransactionalDatabaseClient.create(connectionFactory);
|
||||
|
||||
Mono<Integer> integerFlux = databaseClient.execute().sql(getInsertIntoLegosetStatement()) //
|
||||
Mono<Integer> integerFlux = databaseClient.execute(getInsertIntoLegosetStatement()) //
|
||||
.bind(0, 42055) //
|
||||
.bind(1, "SCHAUFELRADBAGGER") //
|
||||
.bindNull(2, Integer.class) //
|
||||
@@ -185,8 +184,7 @@ public abstract class AbstractTransactionalDatabaseClientIntegrationTests extend
|
||||
TransactionalDatabaseClient databaseClient = TransactionalDatabaseClient.create(connectionFactory);
|
||||
|
||||
Flux<Long> txId = databaseClient //
|
||||
.execute() //
|
||||
.sql(getCurrentTransactionIdStatement()) //
|
||||
.execute(getCurrentTransactionIdStatement()) //
|
||||
.map((r, md) -> r.get(0, Long.class)) //
|
||||
.all();
|
||||
|
||||
@@ -224,7 +222,7 @@ public abstract class AbstractTransactionalDatabaseClientIntegrationTests extend
|
||||
|
||||
Flux<Integer> integerFlux = databaseClient.inTransaction(db -> {
|
||||
|
||||
return db.execute().sql(getInsertIntoLegosetStatement()) //
|
||||
return db.execute(getInsertIntoLegosetStatement()) //
|
||||
.bind(0, 42055) //
|
||||
.bind(1, "SCHAUFELRADBAGGER") //
|
||||
.bindNull(2, Integer.class) //
|
||||
@@ -248,8 +246,7 @@ public abstract class AbstractTransactionalDatabaseClientIntegrationTests extend
|
||||
TransactionalOperator transactionalOperator = TransactionalOperator
|
||||
.create(new R2dbcTransactionManager(connectionFactory), new DefaultTransactionDefinition());
|
||||
|
||||
Flux<Object> txId = databaseClient.execute() //
|
||||
.sql(getCurrentTransactionIdStatement()) //
|
||||
Flux<Object> txId = databaseClient.execute(getCurrentTransactionIdStatement()) //
|
||||
.map((row, md) -> row.get(0)) //
|
||||
.all();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user