#162 - Refine declaration of nullable values in DatabaseClient.
DatabaseClient.BindSpec.bind(…) (execute) and DatabaseClient.GenericInsertSpec.value(…) (insert) now consistently accept SettableValue for scalar and absent values. This change allows us to provide a Kotlin extension leveraging reified generics to provide the type of a value even if it is null to construct an appropriate SettableValue for fluent API usage.
This commit is contained in:
@@ -172,7 +172,7 @@ public abstract class AbstractDatabaseClientIntegrationTests extends R2dbcIntegr
|
||||
databaseClient.insert().into("legoset")//
|
||||
.value("id", 42055) //
|
||||
.value("name", "SCHAUFELRADBAGGER") //
|
||||
.nullValue("manual") //
|
||||
.nullValue("manual", Integer.class) //
|
||||
.fetch() //
|
||||
.rowsUpdated() //
|
||||
.as(StepVerifier::create) //
|
||||
@@ -190,7 +190,7 @@ public abstract class AbstractDatabaseClientIntegrationTests extends R2dbcIntegr
|
||||
databaseClient.insert().into("legoset")//
|
||||
.value("id", 42055) //
|
||||
.value("name", "SCHAUFELRADBAGGER") //
|
||||
.nullValue("manual") //
|
||||
.nullValue("manual", Integer.class) //
|
||||
.then() //
|
||||
.as(StepVerifier::create) //
|
||||
.verifyComplete();
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.reactivestreams.Publisher;
|
||||
import org.reactivestreams.Subscription;
|
||||
|
||||
import org.springframework.data.r2dbc.dialect.PostgresDialect;
|
||||
import org.springframework.data.r2dbc.mapping.SettableValue;
|
||||
import org.springframework.data.r2dbc.support.R2dbcExceptionTranslator;
|
||||
|
||||
/**
|
||||
@@ -118,6 +119,34 @@ public class DefaultDatabaseClientUnitTests {
|
||||
verify(statement).bindNull("$1", String.class);
|
||||
}
|
||||
|
||||
@Test // gh-162
|
||||
public void executeShouldBindSettableValues() {
|
||||
|
||||
Statement statement = mock(Statement.class);
|
||||
when(connection.createStatement("SELECT * FROM table WHERE key = $1")).thenReturn(statement);
|
||||
when(statement.execute()).thenReturn(Mono.empty());
|
||||
|
||||
DefaultDatabaseClient databaseClient = (DefaultDatabaseClient) DatabaseClient.builder()
|
||||
.connectionFactory(connectionFactory)
|
||||
.dataAccessStrategy(new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)).build();
|
||||
|
||||
databaseClient.execute("SELECT * FROM table WHERE key = $1") //
|
||||
.bind(0, SettableValue.empty(String.class)) //
|
||||
.then() //
|
||||
.as(StepVerifier::create) //
|
||||
.verifyComplete();
|
||||
|
||||
verify(statement).bindNull(0, String.class);
|
||||
|
||||
databaseClient.execute("SELECT * FROM table WHERE key = $1") //
|
||||
.bind("$1", SettableValue.empty(String.class)) //
|
||||
.then() //
|
||||
.as(StepVerifier::create) //
|
||||
.verifyComplete();
|
||||
|
||||
verify(statement).bindNull("$1", String.class);
|
||||
}
|
||||
|
||||
@Test // gh-128
|
||||
public void executeShouldBindNamedNullValues() {
|
||||
|
||||
@@ -138,7 +167,7 @@ public class DefaultDatabaseClientUnitTests {
|
||||
verify(statement).bindNull(0, String.class);
|
||||
}
|
||||
|
||||
@Test // gh-128
|
||||
@Test // gh-128, gh-162
|
||||
public void executeShouldBindValues() {
|
||||
|
||||
Statement statement = mock(Statement.class);
|
||||
@@ -150,7 +179,7 @@ public class DefaultDatabaseClientUnitTests {
|
||||
.dataAccessStrategy(new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)).build();
|
||||
|
||||
databaseClient.execute("SELECT * FROM table WHERE key = $1") //
|
||||
.bind(0, "foo") //
|
||||
.bind(0, SettableValue.from("foo")) //
|
||||
.then() //
|
||||
.as(StepVerifier::create) //
|
||||
.verifyComplete();
|
||||
@@ -166,6 +195,52 @@ public class DefaultDatabaseClientUnitTests {
|
||||
verify(statement).bind("$1", "foo");
|
||||
}
|
||||
|
||||
@Test // gh-162
|
||||
public void insertShouldAcceptNullValues() {
|
||||
|
||||
Statement statement = mock(Statement.class);
|
||||
when(connection.createStatement("INSERT INTO foo (first, second) VALUES ($1, $2)")).thenReturn(statement);
|
||||
when(statement.returnGeneratedValues()).thenReturn(statement);
|
||||
when(statement.execute()).thenReturn(Mono.empty());
|
||||
|
||||
DefaultDatabaseClient databaseClient = (DefaultDatabaseClient) DatabaseClient.builder()
|
||||
.connectionFactory(connectionFactory)
|
||||
.dataAccessStrategy(new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)).build();
|
||||
|
||||
databaseClient.insert().into("foo") //
|
||||
.value("first", "foo") //
|
||||
.nullValue("second", Integer.class) //
|
||||
.then() //
|
||||
.as(StepVerifier::create) //
|
||||
.verifyComplete();
|
||||
|
||||
verify(statement).bind(0, "foo");
|
||||
verify(statement).bindNull(1, Integer.class);
|
||||
}
|
||||
|
||||
@Test // gh-162
|
||||
public void insertShouldAcceptSettableValue() {
|
||||
|
||||
Statement statement = mock(Statement.class);
|
||||
when(connection.createStatement("INSERT INTO foo (first, second) VALUES ($1, $2)")).thenReturn(statement);
|
||||
when(statement.returnGeneratedValues()).thenReturn(statement);
|
||||
when(statement.execute()).thenReturn(Mono.empty());
|
||||
|
||||
DefaultDatabaseClient databaseClient = (DefaultDatabaseClient) DatabaseClient.builder()
|
||||
.connectionFactory(connectionFactory)
|
||||
.dataAccessStrategy(new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)).build();
|
||||
|
||||
databaseClient.insert().into("foo") //
|
||||
.value("first", SettableValue.from("foo")) //
|
||||
.value("second", SettableValue.empty(Integer.class)) //
|
||||
.then() //
|
||||
.as(StepVerifier::create) //
|
||||
.verifyComplete();
|
||||
|
||||
verify(statement).bind(0, "foo");
|
||||
verify(statement).bindNull(1, Integer.class);
|
||||
}
|
||||
|
||||
@Test // gh-128
|
||||
public void executeShouldBindNamedValuesByIndex() {
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import io.mockk.verify
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Test
|
||||
import org.springframework.data.r2dbc.mapping.SettableValue
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
/**
|
||||
@@ -32,6 +33,66 @@ import reactor.core.publisher.Mono
|
||||
*/
|
||||
class DatabaseClientExtensionsTests {
|
||||
|
||||
@Test // gh-162
|
||||
fun bindByIndexShouldBindValue() {
|
||||
|
||||
val spec = mockk<DatabaseClient.GenericExecuteSpec>()
|
||||
every { spec.bind(eq(0), any()) } returns spec
|
||||
|
||||
runBlocking {
|
||||
spec.bind<String>(0, "foo")
|
||||
}
|
||||
|
||||
verify {
|
||||
spec.bind(0, SettableValue.fromOrEmpty("foo", String::class.java))
|
||||
}
|
||||
}
|
||||
|
||||
@Test // gh-162
|
||||
fun bindByIndexShouldBindNull() {
|
||||
|
||||
val spec = mockk<DatabaseClient.GenericExecuteSpec>()
|
||||
every { spec.bind(eq(0), any()) } returns spec
|
||||
|
||||
runBlocking {
|
||||
spec.bind<String>(0, null)
|
||||
}
|
||||
|
||||
verify {
|
||||
spec.bind(0, SettableValue.empty(String::class.java))
|
||||
}
|
||||
}
|
||||
|
||||
@Test // gh-162
|
||||
fun bindByNameShouldBindValue() {
|
||||
|
||||
val spec = mockk<DatabaseClient.GenericExecuteSpec>()
|
||||
every { spec.bind(eq("field"), any()) } returns spec
|
||||
|
||||
runBlocking {
|
||||
spec.bind<String>("field", "foo")
|
||||
}
|
||||
|
||||
verify {
|
||||
spec.bind("field", SettableValue.fromOrEmpty("foo", String::class.java))
|
||||
}
|
||||
}
|
||||
|
||||
@Test // gh-162
|
||||
fun bindByNameShouldBindNull() {
|
||||
|
||||
val spec = mockk<DatabaseClient.GenericExecuteSpec>()
|
||||
every { spec.bind(eq("field"), any()) } returns spec
|
||||
|
||||
runBlocking {
|
||||
spec.bind<String>("field", null)
|
||||
}
|
||||
|
||||
verify {
|
||||
spec.bind("field", SettableValue.empty(String::class.java))
|
||||
}
|
||||
}
|
||||
|
||||
@Test // gh-63
|
||||
fun genericExecuteSpecAwait() {
|
||||
|
||||
@@ -140,6 +201,36 @@ class DatabaseClientExtensionsTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test // gh-162
|
||||
fun insertValueShouldBindValue() {
|
||||
|
||||
val spec = mockk<DatabaseClient.GenericInsertSpec<Any>>()
|
||||
every { spec.value(eq("field"), any()) } returns spec
|
||||
|
||||
runBlocking {
|
||||
spec.value<String>("field", "foo")
|
||||
}
|
||||
|
||||
verify {
|
||||
spec.value("field", SettableValue.fromOrEmpty("foo", String::class.java))
|
||||
}
|
||||
}
|
||||
|
||||
@Test // gh-162
|
||||
fun insertValueShouldBindNull() {
|
||||
|
||||
val spec = mockk<DatabaseClient.GenericInsertSpec<Any>>()
|
||||
every { spec.value(eq("field"), any()) } returns spec
|
||||
|
||||
runBlocking {
|
||||
spec.value<String>("field", null)
|
||||
}
|
||||
|
||||
verify {
|
||||
spec.value("field", SettableValue.empty(String::class.java))
|
||||
}
|
||||
}
|
||||
|
||||
@Test // gh-122
|
||||
fun selectFromSpecFrom() {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user