diff --git a/src/main/asciidoc/reference/r2dbc-core.adoc b/src/main/asciidoc/reference/r2dbc-core.adoc index 6fdd9cb..003d4b8 100644 --- a/src/main/asciidoc/reference/r2dbc-core.adoc +++ b/src/main/asciidoc/reference/r2dbc-core.adoc @@ -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)") diff --git a/src/main/asciidoc/reference/r2dbc-sql.adoc b/src/main/asciidoc/reference/r2dbc-sql.adoc index eb824d0..8a0632f 100644 --- a/src/main/asciidoc/reference/r2dbc-sql.adoc +++ b/src/main/asciidoc/reference/r2dbc-sql.adoc @@ -6,8 +6,7 @@ The following example shows what you need to include for minimal but fully funct [source,java] ---- -Mono completion = client.execute() - .sql("CREATE TABLE person (id VARCHAR(255) PRIMARY KEY, name VARCHAR(255), age INTEGER);") +Mono completion = client.sql("CREATE TABLE person (id VARCHAR(255) PRIMARY KEY, name VARCHAR(255), age INTEGER);") .then(); ---- @@ -15,7 +14,7 @@ Mono 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` to defer the actual query creation until execution. +NOTE: `sql(…)` accepts either the SQL query string or a query `Supplier` 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 affectedRows = client.execute() - .sql("UPDATE person SET name = 'Joe'") +Mono 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> first = client.execute() - .sql("SELECT id, name FROM person") +Mono> 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 all = client.execute() - .sql("SELECT id, name FROM mytable") +Flux 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 names= client.execute() - .sql("SELECT name FROM person") +Flux 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 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)); ---- diff --git a/src/main/asciidoc/reference/r2dbc-transactions.adoc b/src/main/asciidoc/reference/r2dbc-transactions.adoc index 9379b51..e1d2cfc 100644 --- a/src/main/asciidoc/reference/r2dbc-transactions.adoc +++ b/src/main/asciidoc/reference/r2dbc-transactions.adoc @@ -18,12 +18,12 @@ TransactionalOperator operator = TransactionalOperator.create(tm); <1> DatabaseClient client = DatabaseClient.create(connectionFactory); -Mono atomicOperation = client.execute().sql("INSERT INTO person (id, name, age) VALUES(:id, :name, :age)") +Mono 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 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()) diff --git a/src/main/java/org/springframework/data/r2dbc/core/DatabaseClient.java b/src/main/java/org/springframework/data/r2dbc/core/DatabaseClient.java index 1b787e3..7205894 100644 --- a/src/main/java/org/springframework/data/r2dbc/core/DatabaseClient.java +++ b/src/main/java/org/springframework/data/r2dbc/core/DatabaseClient.java @@ -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. + *

+ * 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(NamedParameterExpander) + * @see PreparedOperation + */ + GenericExecuteSpec execute(Supplier 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 sqlSupplier); } diff --git a/src/main/java/org/springframework/data/r2dbc/core/DefaultDatabaseClient.java b/src/main/java/org/springframework/data/r2dbc/core/DefaultDatabaseClient.java index ce4923e..a1f1478 100644 --- a/src/main/java/org/springframework/data/r2dbc/core/DefaultDatabaseClient.java +++ b/src/main/java/org/springframework/data/r2dbc/core/DefaultDatabaseClient.java @@ -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 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). diff --git a/src/main/java/org/springframework/data/r2dbc/core/TransactionalDatabaseClient.java b/src/main/java/org/springframework/data/r2dbc/core/TransactionalDatabaseClient.java index f0d6a35..fd3334c 100644 --- a/src/main/java/org/springframework/data/r2dbc/core/TransactionalDatabaseClient.java +++ b/src/main/java/org/springframework/data/r2dbc/core/TransactionalDatabaseClient.java @@ -41,7 +41,7 @@ import org.springframework.util.Assert; *
  * Flux 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;
  * 
  * Mono 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") //
diff --git a/src/main/java/org/springframework/data/r2dbc/repository/query/AbstractR2dbcQuery.java b/src/main/java/org/springframework/data/r2dbc/repository/query/AbstractR2dbcQuery.java
index 3adca38..531f1b5 100644
--- a/src/main/java/org/springframework/data/r2dbc/repository/query/AbstractR2dbcQuery.java
+++ b/src/main/java/org/springframework/data/r2dbc/repository/query/AbstractR2dbcQuery.java
@@ -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();
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 70c000b..786d495 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
@@ -117,7 +117,7 @@ public class SimpleR2dbcRepository implements ReactiveCrudRepository 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 implements ReactiveCrudRepository 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 implements ReactiveCrudRepository 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 implements ReactiveCrudRepository r.get(0, Long.class)) //
 				.first() //
 				.defaultIfEmpty(0L);
diff --git a/src/test/java/org/springframework/data/r2dbc/core/AbstractDatabaseClientIntegrationTests.java b/src/test/java/org/springframework/data/r2dbc/core/AbstractDatabaseClientIntegrationTests.java
index 62b5ea2..55d8a53 100644
--- a/src/test/java/org/springframework/data/r2dbc/core/AbstractDatabaseClientIntegrationTests.java
+++ b/src/test/java/org/springframework/data/r2dbc/core/AbstractDatabaseClientIntegrationTests.java
@@ -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) //
diff --git a/src/test/java/org/springframework/data/r2dbc/core/AbstractTransactionalDatabaseClientIntegrationTests.java b/src/test/java/org/springframework/data/r2dbc/core/AbstractTransactionalDatabaseClientIntegrationTests.java
index 0c46b65..37a5f9a 100644
--- a/src/test/java/org/springframework/data/r2dbc/core/AbstractTransactionalDatabaseClientIntegrationTests.java
+++ b/src/test/java/org/springframework/data/r2dbc/core/AbstractTransactionalDatabaseClientIntegrationTests.java
@@ -145,8 +145,7 @@ public abstract class AbstractTransactionalDatabaseClientIntegrationTests extend
 		TransactionalDatabaseClient databaseClient = TransactionalDatabaseClient.create(connectionFactory);
 
 		Flux 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 integerFlux = databaseClient.execute().sql(getInsertIntoLegosetStatement()) //
+		Mono 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 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 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 txId = databaseClient.execute() //
-				.sql(getCurrentTransactionIdStatement()) //
+		Flux txId = databaseClient.execute(getCurrentTransactionIdStatement()) //
 				.map((row, md) -> row.get(0)) //
 				.all();