Merge branch '6.2.x'
This commit is contained in:
commit
61a517ea3b
|
@ -20,6 +20,7 @@ import java.util.List;
|
||||||
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Nested;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.springframework.core.io.ClassRelativeResourceLoader;
|
import org.springframework.core.io.ClassRelativeResourceLoader;
|
||||||
|
@ -145,14 +146,11 @@ class JdbcClientIntegrationTests {
|
||||||
assertUser(expectedId, firstName, lastName);
|
assertUser(expectedId, firstName, lastName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // gh-34768
|
|
||||||
void selectWithReusedNamedParameter() {
|
|
||||||
this.jdbcClient.sql(INSERT_WITH_JDBC_PARAMS).params("John", "John").update();
|
|
||||||
this.jdbcClient.sql(INSERT_WITH_JDBC_PARAMS).params("John", "Smith").update();
|
|
||||||
this.jdbcClient.sql(INSERT_WITH_JDBC_PARAMS).params("Smith", "Smith").update();
|
|
||||||
assertNumUsers(4);
|
|
||||||
|
|
||||||
String sql = """
|
@Nested // gh-34768
|
||||||
|
class ReusedNamedParameterTests {
|
||||||
|
|
||||||
|
private static final String QUERY1 = """
|
||||||
select * from users
|
select * from users
|
||||||
where
|
where
|
||||||
first_name in ('Bogus', :name) or
|
first_name in ('Bogus', :name) or
|
||||||
|
@ -160,22 +158,7 @@ class JdbcClientIntegrationTests {
|
||||||
order by last_name
|
order by last_name
|
||||||
""";
|
""";
|
||||||
|
|
||||||
List<User> users = this.jdbcClient.sql(sql)
|
private static final String QUERY2 = """
|
||||||
.param("name", "John")
|
|
||||||
.query(User.class)
|
|
||||||
.list();
|
|
||||||
|
|
||||||
assertThat(users).containsExactly(new User(2, "John", "John"), new User(3, "John", "Smith"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test // gh-34768
|
|
||||||
void selectWithReusedNamedParameterList() {
|
|
||||||
this.jdbcClient.sql(INSERT_WITH_JDBC_PARAMS).params("John", "John").update();
|
|
||||||
this.jdbcClient.sql(INSERT_WITH_JDBC_PARAMS).params("John", "Smith").update();
|
|
||||||
this.jdbcClient.sql(INSERT_WITH_JDBC_PARAMS).params("Smith", "Smith").update();
|
|
||||||
assertNumUsers(4);
|
|
||||||
|
|
||||||
String sql = """
|
|
||||||
select * from users
|
select * from users
|
||||||
where
|
where
|
||||||
first_name in (:names) or
|
first_name in (:names) or
|
||||||
|
@ -183,12 +166,64 @@ class JdbcClientIntegrationTests {
|
||||||
order by last_name
|
order by last_name
|
||||||
""";
|
""";
|
||||||
|
|
||||||
List<User> users = this.jdbcClient.sql(sql)
|
|
||||||
.param("names", List.of("John", "Bogus"))
|
|
||||||
.query(User.class)
|
|
||||||
.list();
|
|
||||||
|
|
||||||
assertThat(users).containsExactly(new User(2, "John", "John"), new User(3, "John", "Smith"));
|
@BeforeEach
|
||||||
|
void insertTestUsers() {
|
||||||
|
jdbcClient.sql(INSERT_WITH_JDBC_PARAMS).params("John", "John").update();
|
||||||
|
jdbcClient.sql(INSERT_WITH_JDBC_PARAMS).params("John", "Smith").update();
|
||||||
|
jdbcClient.sql(INSERT_WITH_JDBC_PARAMS).params("Smith", "Smith").update();
|
||||||
|
assertNumUsers(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void selectWithReusedNamedParameter() {
|
||||||
|
List<User> users = jdbcClient.sql(QUERY1)
|
||||||
|
.param("name", "John")
|
||||||
|
.query(User.class)
|
||||||
|
.list();
|
||||||
|
|
||||||
|
assertResults(users);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void selectWithReusedNamedParameterFromBeanProperties() {
|
||||||
|
List<User> users = jdbcClient.sql(QUERY1)
|
||||||
|
.paramSource(new Name("John"))
|
||||||
|
.query(User.class)
|
||||||
|
.list();
|
||||||
|
|
||||||
|
assertResults(users);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void selectWithReusedNamedParameterList() {
|
||||||
|
List<User> users = jdbcClient.sql(QUERY2)
|
||||||
|
.param("names", List.of("John", "Bogus"))
|
||||||
|
.query(User.class)
|
||||||
|
.list();
|
||||||
|
|
||||||
|
assertResults(users);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void selectWithReusedNamedParameterListFromBeanProperties() {
|
||||||
|
List<User> users = jdbcClient.sql(QUERY2)
|
||||||
|
.paramSource(new Names(List.of("John", "Bogus")))
|
||||||
|
.query(User.class)
|
||||||
|
.list();
|
||||||
|
|
||||||
|
assertResults(users);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void assertResults(List<User> users) {
|
||||||
|
assertThat(users).containsExactly(new User(2, "John", "John"), new User(3, "John", "Smith"));
|
||||||
|
}
|
||||||
|
|
||||||
|
record Name(String name) {}
|
||||||
|
|
||||||
|
record Names(List<String> names) {}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ import io.r2dbc.spi.ConnectionFactory;
|
||||||
import io.r2dbc.spi.Parameters;
|
import io.r2dbc.spi.Parameters;
|
||||||
import io.r2dbc.spi.Result;
|
import io.r2dbc.spi.Result;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Nested;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
@ -38,6 +39,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
* @author Mark Paluch
|
* @author Mark Paluch
|
||||||
* @author Mingyuan Wu
|
* @author Mingyuan Wu
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
* @author Sam Brannen
|
||||||
*/
|
*/
|
||||||
abstract class AbstractDatabaseClientIntegrationTests {
|
abstract class AbstractDatabaseClientIntegrationTests {
|
||||||
|
|
||||||
|
@ -121,7 +123,8 @@ abstract class AbstractDatabaseClientIntegrationTests {
|
||||||
DatabaseClient databaseClient = DatabaseClient.create(connectionFactory);
|
DatabaseClient databaseClient = DatabaseClient.create(connectionFactory);
|
||||||
|
|
||||||
databaseClient.sql("INSERT INTO legoset (id, name, manual) VALUES(:id, :name, :manual)")
|
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"),
|
"name", Parameters.in("SCHAUFELRADBAGGER"),
|
||||||
"manual", Parameters.in(Integer.class)))
|
"manual", Parameters.in(Integer.class)))
|
||||||
.fetch().rowsUpdated()
|
.fetch().rowsUpdated()
|
||||||
|
@ -199,8 +202,7 @@ abstract class AbstractDatabaseClientIntegrationTests {
|
||||||
void shouldEmitGeneratedKey() {
|
void shouldEmitGeneratedKey() {
|
||||||
DatabaseClient databaseClient = DatabaseClient.create(connectionFactory);
|
DatabaseClient databaseClient = DatabaseClient.create(connectionFactory);
|
||||||
|
|
||||||
databaseClient.sql(
|
databaseClient.sql("INSERT INTO legoset ( name, manual) VALUES(:name, :manual)")
|
||||||
"INSERT INTO legoset ( name, manual) VALUES(:name, :manual)")
|
|
||||||
.bind("name","SCHAUFELRADBAGGER")
|
.bind("name","SCHAUFELRADBAGGER")
|
||||||
.bindNull("manual", Integer.class)
|
.bindNull("manual", Integer.class)
|
||||||
.filter(statement -> statement.returnGeneratedValues("id"))
|
.filter(statement -> statement.returnGeneratedValues("id"))
|
||||||
|
@ -211,69 +213,129 @@ abstract class AbstractDatabaseClientIntegrationTests {
|
||||||
.verifyComplete();
|
.verifyComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // gh-34768
|
|
||||||
void executeInsertWithReusedNamedParameter() {
|
|
||||||
DatabaseClient databaseClient = DatabaseClient.create(connectionFactory);
|
|
||||||
|
|
||||||
Lego lego = new Lego(1, 42, "Star Wars", 42);
|
@Nested
|
||||||
|
class ReusedNamedParameterTests {
|
||||||
|
|
||||||
databaseClient.sql(() -> "INSERT INTO legoset (id, version, name, manual) VALUES(:id, :number, :name, :number)")
|
@Test // gh-34768
|
||||||
.bind("id", lego.id)
|
void executeInsertWithReusedNamedParameter() {
|
||||||
.bind("name", lego.name)
|
DatabaseClient databaseClient = DatabaseClient.create(connectionFactory);
|
||||||
.bind("number", lego.version)
|
|
||||||
.fetch().rowsUpdated()
|
Lego lego = new Lego(1, 42, "Star Wars", 42);
|
||||||
.as(StepVerifier::create)
|
|
||||||
.expectNext(1L)
|
// ":number" is reused.
|
||||||
.verifyComplete();
|
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)
|
||||||
|
.fetch().rowsUpdated()
|
||||||
|
.as(StepVerifier::create)
|
||||||
|
.expectNext(1L)
|
||||||
|
.verifyComplete();
|
||||||
|
|
||||||
|
databaseClient.sql("SELECT * FROM legoset")
|
||||||
|
.mapProperties(Lego.class)
|
||||||
|
.first()
|
||||||
|
.as(StepVerifier::create)
|
||||||
|
.assertNext(actual -> assertThat(actual).isEqualTo(lego))
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // gh-34768
|
||||||
|
void executeSelectWithReusedNamedParameterList() {
|
||||||
|
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
|
||||||
|
.bind("numbers", List.of(2, 3, lego.version, 4))
|
||||||
|
.mapProperties(Lego.class)
|
||||||
|
.first()
|
||||||
|
.as(StepVerifier::create)
|
||||||
|
.assertNext(actual -> assertThat(actual).isEqualTo(lego))
|
||||||
|
.verifyComplete();
|
||||||
|
|
||||||
|
databaseClient.sql(selectSql)
|
||||||
|
// match manual
|
||||||
|
.bind("numbers", List.of(2, 3, lego.manual, 4))
|
||||||
|
.mapProperties(Lego.class)
|
||||||
|
.first()
|
||||||
|
.as(StepVerifier::create)
|
||||||
|
.assertNext(actual -> assertThat(actual).isEqualTo(lego))
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
databaseClient.sql("SELECT * FROM legoset")
|
|
||||||
.mapProperties(Lego.class)
|
|
||||||
.first()
|
|
||||||
.as(StepVerifier::create)
|
|
||||||
.assertNext(actual -> assertThat(actual).isEqualTo(lego))
|
|
||||||
.verifyComplete();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // gh-34768
|
|
||||||
void executeSelectWithReusedNamedParameterList() {
|
|
||||||
DatabaseClient databaseClient = DatabaseClient.create(connectionFactory);
|
|
||||||
|
|
||||||
String insertSql = "INSERT INTO legoset (id, version, name, manual) VALUES(:id, :version, :name, :manual)";
|
|
||||||
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
|
|
||||||
.bind("numbers", List.of(2, 3, lego.version, 4))
|
|
||||||
.mapProperties(Lego.class)
|
|
||||||
.first()
|
|
||||||
.as(StepVerifier::create)
|
|
||||||
.assertNext(actual -> assertThat(actual).isEqualTo(lego))
|
|
||||||
.verifyComplete();
|
|
||||||
|
|
||||||
databaseClient.sql(selectSql)
|
|
||||||
// match manual
|
|
||||||
.bind("numbers", List.of(2, 3, lego.manual, 4))
|
|
||||||
.mapProperties(Lego.class)
|
|
||||||
.first()
|
|
||||||
.as(StepVerifier::create)
|
|
||||||
.assertNext(actual -> assertThat(actual).isEqualTo(lego))
|
|
||||||
.verifyComplete();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
record Lego(int id, Integer version, String name, Integer manual) {
|
|
||||||
}
|
|
||||||
|
|
||||||
record ParameterRecord(int id, String name, Integer manual) {
|
record ParameterRecord(int id, String name, Integer manual) {
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue