|
|
|
|
@ -23,6 +23,7 @@ import io.r2dbc.spi.ConnectionFactory;
@@ -23,6 +23,7 @@ import io.r2dbc.spi.ConnectionFactory;
|
|
|
|
|
import io.r2dbc.spi.Parameters; |
|
|
|
|
import io.r2dbc.spi.Result; |
|
|
|
|
import org.junit.jupiter.api.BeforeEach; |
|
|
|
|
import org.junit.jupiter.api.Nested; |
|
|
|
|
import org.junit.jupiter.api.Test; |
|
|
|
|
import reactor.core.publisher.Flux; |
|
|
|
|
import reactor.core.publisher.Mono; |
|
|
|
|
@ -38,6 +39,7 @@ import static org.assertj.core.api.Assertions.assertThat;
@@ -38,6 +39,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|
|
|
|
* @author Mark Paluch |
|
|
|
|
* @author Mingyuan Wu |
|
|
|
|
* @author Juergen Hoeller |
|
|
|
|
* @author Sam Brannen |
|
|
|
|
*/ |
|
|
|
|
abstract class AbstractDatabaseClientIntegrationTests { |
|
|
|
|
|
|
|
|
|
@ -121,7 +123,8 @@ abstract class AbstractDatabaseClientIntegrationTests {
@@ -121,7 +123,8 @@ abstract class AbstractDatabaseClientIntegrationTests {
|
|
|
|
|
DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); |
|
|
|
|
|
|
|
|
|
databaseClient.sql("INSERT INTO legoset (id, name, manual) VALUES(:id, :name, :manual)") |
|
|
|
|
.bindValues(Map.of("id", 42055, |
|
|
|
|
.bindValues(Map.of( |
|
|
|
|
"id", 42055, |
|
|
|
|
"name", Parameters.in("SCHAUFELRADBAGGER"), |
|
|
|
|
"manual", Parameters.in(Integer.class))) |
|
|
|
|
.fetch().rowsUpdated() |
|
|
|
|
@ -199,8 +202,7 @@ abstract class AbstractDatabaseClientIntegrationTests {
@@ -199,8 +202,7 @@ abstract class AbstractDatabaseClientIntegrationTests {
|
|
|
|
|
void shouldEmitGeneratedKey() { |
|
|
|
|
DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); |
|
|
|
|
|
|
|
|
|
databaseClient.sql( |
|
|
|
|
"INSERT INTO legoset ( name, manual) VALUES(:name, :manual)") |
|
|
|
|
databaseClient.sql("INSERT INTO legoset ( name, manual) VALUES(:name, :manual)") |
|
|
|
|
.bind("name","SCHAUFELRADBAGGER") |
|
|
|
|
.bindNull("manual", Integer.class) |
|
|
|
|
.filter(statement -> statement.returnGeneratedValues("id")) |
|
|
|
|
@ -211,13 +213,18 @@ abstract class AbstractDatabaseClientIntegrationTests {
@@ -211,13 +213,18 @@ abstract class AbstractDatabaseClientIntegrationTests {
|
|
|
|
|
.verifyComplete(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Nested |
|
|
|
|
class ReusedNamedParameterTests { |
|
|
|
|
|
|
|
|
|
@Test // gh-34768
|
|
|
|
|
void executeInsertWithReusedNamedParameter() { |
|
|
|
|
DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); |
|
|
|
|
|
|
|
|
|
Lego lego = new Lego(1, 42, "Star Wars", 42); |
|
|
|
|
|
|
|
|
|
databaseClient.sql(() -> "INSERT INTO legoset (id, version, name, manual) VALUES(:id, :number, :name, :number)") |
|
|
|
|
// ":number" is reused.
|
|
|
|
|
databaseClient.sql("INSERT INTO legoset (id, version, name, manual) VALUES(:id, :number, :name, :number)") |
|
|
|
|
.bind("id", lego.id) |
|
|
|
|
.bind("name", lego.name) |
|
|
|
|
.bind("number", lego.version) |
|
|
|
|
@ -239,6 +246,7 @@ abstract class AbstractDatabaseClientIntegrationTests {
@@ -239,6 +246,7 @@ abstract class AbstractDatabaseClientIntegrationTests {
|
|
|
|
|
DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); |
|
|
|
|
|
|
|
|
|
String insertSql = "INSERT INTO legoset (id, version, name, manual) VALUES(:id, :version, :name, :manual)"; |
|
|
|
|
// ":numbers" is reused.
|
|
|
|
|
String selectSql = "SELECT * FROM legoset WHERE version IN (:numbers) OR manual IN (:numbers)"; |
|
|
|
|
Lego lego = new Lego(1, 42, "Star Wars", 99); |
|
|
|
|
|
|
|
|
|
@ -271,10 +279,64 @@ abstract class AbstractDatabaseClientIntegrationTests {
@@ -271,10 +279,64 @@ abstract class AbstractDatabaseClientIntegrationTests {
|
|
|
|
|
.verifyComplete(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test // gh-34768
|
|
|
|
|
void executeSelectWithReusedNamedParameterListFromBeanProperties() { |
|
|
|
|
DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); |
|
|
|
|
|
|
|
|
|
String insertSql = "INSERT INTO legoset (id, version, name, manual) VALUES(:id, :version, :name, :manual)"; |
|
|
|
|
// ":numbers" is reused.
|
|
|
|
|
String selectSql = "SELECT * FROM legoset WHERE version IN (:numbers) OR manual IN (:numbers)"; |
|
|
|
|
Lego lego = new Lego(1, 42, "Star Wars", 99); |
|
|
|
|
|
|
|
|
|
databaseClient.sql(insertSql) |
|
|
|
|
.bind("id", lego.id) |
|
|
|
|
.bind("version", lego.version) |
|
|
|
|
.bind("name", lego.name) |
|
|
|
|
.bind("manual", lego.manual) |
|
|
|
|
.fetch().rowsUpdated() |
|
|
|
|
.as(StepVerifier::create) |
|
|
|
|
.expectNext(1L) |
|
|
|
|
.verifyComplete(); |
|
|
|
|
|
|
|
|
|
databaseClient.sql(selectSql) |
|
|
|
|
// match version
|
|
|
|
|
.bindProperties(new LegoRequest(List.of(lego.version))) |
|
|
|
|
.mapProperties(Lego.class) |
|
|
|
|
.first() |
|
|
|
|
.as(StepVerifier::create) |
|
|
|
|
.assertNext(actual -> assertThat(actual).isEqualTo(lego)) |
|
|
|
|
.verifyComplete(); |
|
|
|
|
|
|
|
|
|
databaseClient.sql(selectSql) |
|
|
|
|
// match manual
|
|
|
|
|
.bindProperties(new LegoRequest(List.of(lego.manual))) |
|
|
|
|
.mapProperties(Lego.class) |
|
|
|
|
.first() |
|
|
|
|
.as(StepVerifier::create) |
|
|
|
|
.assertNext(actual -> assertThat(actual).isEqualTo(lego)) |
|
|
|
|
.verifyComplete(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
record Lego(int id, Integer version, String name, Integer manual) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static class LegoRequest { |
|
|
|
|
|
|
|
|
|
private final List<Integer> numbers; |
|
|
|
|
|
|
|
|
|
LegoRequest(List<Integer> numbers) { |
|
|
|
|
this.numbers = numbers; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public List<Integer> getNumbers() { |
|
|
|
|
return numbers; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
record ParameterRecord(int id, String name, Integer manual) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|