Skip to content

Commit 0b99872

Browse files
committed
Support for binding values from a source Map
See gh-27282
1 parent b8b3e6d commit 0b99872

File tree

3 files changed

+63
-21
lines changed

3 files changed

+63
-21
lines changed

spring-r2dbc/src/main/java/org/springframework/r2dbc/core/DatabaseClient.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ interface GenericExecuteSpec {
167167
* Bind a non-{@code null} value to a parameter identified by its
168168
* {@code index}. {@code value} can be either a scalar value or {@link io.r2dbc.spi.Parameter}.
169169
* @param index zero based index to bind the parameter to
170-
* @param value either a scalar value or {@link io.r2dbc.spi.Parameter}
170+
* @param value either a scalar value or a {@link io.r2dbc.spi.Parameter}
171171
*/
172172
GenericExecuteSpec bind(int index, Object value);
173173

@@ -181,7 +181,7 @@ interface GenericExecuteSpec {
181181
/**
182182
* Bind a non-{@code null} value to a parameter identified by its {@code name}.
183183
* @param name the name of the parameter
184-
* @param value the value to bind
184+
* @param value either a scalar value or a {@link io.r2dbc.spi.Parameter}
185185
*/
186186
GenericExecuteSpec bind(String name, Object value);
187187

@@ -192,11 +192,22 @@ interface GenericExecuteSpec {
192192
*/
193193
GenericExecuteSpec bindNull(String name, Class<?> type);
194194

195+
/**
196+
* Bind the parameter values from the given source map,
197+
* registering each as a parameter with the map key as name.
198+
* @param source the source map of parameters, with keys as names and
199+
* each value either a scalar value or a {@link io.r2dbc.spi.Parameter}
200+
* @since 6.1
201+
* @see #bindProperties
202+
*/
203+
GenericExecuteSpec bindValues(Map<String, ?> source);
204+
195205
/**
196206
* Bind the bean properties or record components from the given
197207
* source object, registering each as a named parameter.
198208
* @param source the source object (a JavaBean or record)
199209
* @since 6.1
210+
* @see #mapProperties
200211
*/
201212
GenericExecuteSpec bindProperties(Object source);
202213

spring-r2dbc/src/main/java/org/springframework/r2dbc/core/DefaultDatabaseClient.java

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -249,23 +249,27 @@ class DefaultGenericExecuteSpec implements GenericExecuteSpec {
249249
}
250250

251251
@SuppressWarnings("deprecation")
252+
private Parameter resolveParameter(Object value) {
253+
if (value instanceof Parameter param) {
254+
return param;
255+
}
256+
else if (value instanceof org.springframework.r2dbc.core.Parameter param) {
257+
Object paramValue = param.getValue();
258+
return (paramValue != null ? Parameters.in(paramValue) : Parameters.in(param.getType()));
259+
}
260+
else {
261+
return Parameters.in(value);
262+
}
263+
}
264+
252265
@Override
253266
public DefaultGenericExecuteSpec bind(int index, Object value) {
254267
assertNotPreparedOperation();
255268
Assert.notNull(value, () -> String.format(
256269
"Value at index %d must not be null. Use bindNull(…) instead.", index));
257270

258271
Map<Integer, Parameter> byIndex = new LinkedHashMap<>(this.byIndex);
259-
if (value instanceof Parameter param) {
260-
byIndex.put(index, param);
261-
}
262-
else if (value instanceof org.springframework.r2dbc.core.Parameter param) {
263-
Object pv = param.getValue();
264-
byIndex.put(index, (pv != null ? Parameters.in(pv) : Parameters.in(param.getType())));
265-
}
266-
else {
267-
byIndex.put(index, Parameters.in(value));
268-
}
272+
byIndex.put(index, resolveParameter(value));
269273

270274
return new DefaultGenericExecuteSpec(byIndex, this.byName, this.sqlSupplier, this.filterFunction);
271275
}
@@ -290,15 +294,7 @@ public DefaultGenericExecuteSpec bind(String name, Object value) {
290294
"Value for parameter %s must not be null. Use bindNull(…) instead.", name));
291295

292296
Map<String, Parameter> byName = new LinkedHashMap<>(this.byName);
293-
if (value instanceof Parameter p) {
294-
byName.put(name, p);
295-
}
296-
else if (value instanceof org.springframework.r2dbc.core.Parameter p) {
297-
byName.put(name, p.hasValue() ? Parameters.in(p.getValue()) : Parameters.in(p.getType()));
298-
}
299-
else {
300-
byName.put(name, Parameters.in(value));
301-
}
297+
byName.put(name, resolveParameter(value));
302298

303299
return new DefaultGenericExecuteSpec(this.byIndex, byName, this.sqlSupplier, this.filterFunction);
304300
}
@@ -314,6 +310,17 @@ public DefaultGenericExecuteSpec bindNull(String name, Class<?> type) {
314310
return new DefaultGenericExecuteSpec(this.byIndex, byName, this.sqlSupplier, this.filterFunction);
315311
}
316312

313+
@Override
314+
public GenericExecuteSpec bindValues(Map<String, ?> source) {
315+
assertNotPreparedOperation();
316+
Assert.notNull(source, "Parameter source must not be null");
317+
318+
Map<String, Parameter> target = new LinkedHashMap<>(this.byName);
319+
source.forEach((name, value) -> target.put(name, resolveParameter(value)));
320+
321+
return new DefaultGenericExecuteSpec(this.byIndex, target, this.sqlSupplier, this.filterFunction);
322+
}
323+
317324
@Override
318325
public DefaultGenericExecuteSpec bindProperties(Object source) {
319326
assertNotPreparedOperation();

spring-r2dbc/src/test/java/org/springframework/r2dbc/core/AbstractDatabaseClientIntegrationTests.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616

1717
package org.springframework.r2dbc.core;
1818

19+
import java.util.Map;
20+
1921
import io.r2dbc.spi.ConnectionFactory;
22+
import io.r2dbc.spi.Parameters;
2023
import io.r2dbc.spi.Result;
2124
import org.junit.jupiter.api.BeforeEach;
2225
import org.junit.jupiter.api.Test;
@@ -93,6 +96,27 @@ public void executeInsert() {
9396
.verifyComplete();
9497
}
9598

99+
@Test
100+
public void executeInsertWithMap() {
101+
DatabaseClient databaseClient = DatabaseClient.create(connectionFactory);
102+
103+
databaseClient.sql("INSERT INTO legoset (id, name, manual) VALUES(:id, :name, :manual)")
104+
.bindValues(Map.of("id", 42055,
105+
"name", Parameter.from("SCHAUFELRADBAGGER"),
106+
"manual", Parameters.in(Integer.class)))
107+
.fetch().rowsUpdated()
108+
.as(StepVerifier::create)
109+
.expectNext(1L)
110+
.verifyComplete();
111+
112+
databaseClient.sql("SELECT id FROM legoset")
113+
.mapValue(Integer.class)
114+
.first()
115+
.as(StepVerifier::create)
116+
.assertNext(actual -> assertThat(actual).isEqualTo(42055))
117+
.verifyComplete();
118+
}
119+
96120
@Test
97121
public void executeInsertWithRecords() {
98122
DatabaseClient databaseClient = DatabaseClient.create(connectionFactory);

0 commit comments

Comments
 (0)