Skip to content

Commit c68cc27

Browse files
committed
#64 - Add criteria support to DatabaseClient.
Move PreparedOperation to operation package.
1 parent 3e47f11 commit c68cc27

15 files changed

+448
-143
lines changed

src/main/java/org/springframework/data/r2dbc/function/DatabaseClient.java

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
import org.springframework.data.domain.Pageable;
3131
import org.springframework.data.domain.Sort;
32+
import org.springframework.data.r2dbc.function.operation.PreparedOperation;
3233
import org.springframework.data.r2dbc.function.query.Criteria;
3334
import org.springframework.data.r2dbc.support.R2dbcExceptionTranslator;
3435

src/main/java/org/springframework/data/r2dbc/function/DefaultDatabaseClient.java

+38-7
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
import java.util.Arrays;
3535
import java.util.Collections;
3636
import java.util.LinkedHashMap;
37-
import java.util.LinkedHashSet;
3837
import java.util.List;
3938
import java.util.Map;
4039
import java.util.concurrent.atomic.AtomicBoolean;
@@ -56,9 +55,13 @@
5655
import org.springframework.data.r2dbc.domain.SettableValue;
5756
import org.springframework.data.r2dbc.function.connectionfactory.ConnectionProxy;
5857
import org.springframework.data.r2dbc.function.convert.ColumnMapRowMapper;
58+
import org.springframework.data.r2dbc.function.operation.BindableOperation;
59+
import org.springframework.data.r2dbc.function.operation.PreparedOperation;
60+
import org.springframework.data.r2dbc.function.query.BoundCondition;
5961
import org.springframework.data.r2dbc.function.query.Criteria;
6062
import org.springframework.data.r2dbc.support.R2dbcExceptionTranslator;
6163
import org.springframework.data.relational.core.sql.Insert;
64+
import org.springframework.data.relational.core.sql.Select;
6265
import org.springframework.jdbc.core.SqlProvider;
6366
import org.springframework.lang.Nullable;
6467
import org.springframework.util.Assert;
@@ -667,15 +670,16 @@ public DefaultSelectSpecSupport page(Pageable page) {
667670
return createInstance(table, projectedFields, criteria, sort, page);
668671
}
669672

670-
<R> FetchSpec<R> execute(String sql, BiFunction<Row, RowMetadata, R> mappingFunction) {
673+
<R> FetchSpec<R> execute(PreparedOperation<?> preparedOperation, BiFunction<Row, RowMetadata, R> mappingFunction) {
671674

675+
String sql = preparedOperation.toQuery();
672676
Function<Connection, Statement> selectFunction = it -> {
673677

674678
if (logger.isDebugEnabled()) {
675679
logger.debug("Executing SQL statement [" + sql + "]");
676680
}
677681

678-
return it.createStatement(sql);
682+
return preparedOperation.bind(it.createStatement(sql));
679683
};
680684

681685
Function<Connection, Flux<Result>> resultFunction = it -> Flux.from(selectFunction.apply(it).execute());
@@ -745,9 +749,20 @@ public FetchSpec<Map<String, Object>> fetch() {
745749

746750
private <R> FetchSpec<R> exchange(BiFunction<Row, RowMetadata, R> mappingFunction) {
747751

748-
String select = dataAccessStrategy.select(table, new LinkedHashSet<>(this.projectedFields), sort, page);
752+
PreparedOperation<Select> operation = dataAccessStrategy.getStatements().select(table, this.projectedFields,
753+
(t, configurer) -> {
749754

750-
return execute(select, mappingFunction);
755+
configurer.withPageRequest(page).withSort(sort);
756+
757+
if (criteria != null) {
758+
759+
BoundCondition boundCondition = dataAccessStrategy.getMappedCriteria(criteria, t);
760+
configurer.withWhere(boundCondition.getCondition()).withBindings(boundCondition.getBindings());
761+
}
762+
763+
});
764+
765+
return execute(operation, mappingFunction);
751766
}
752767

753768
@Override
@@ -837,9 +852,25 @@ private <R> FetchSpec<R> exchange(BiFunction<Row, RowMetadata, R> mappingFunctio
837852
columns = this.projectedFields;
838853
}
839854

840-
String select = dataAccessStrategy.select(table, new LinkedHashSet<>(columns), sort, page);
855+
PreparedOperation<Select> operation = dataAccessStrategy.getStatements().select(table, columns,
856+
(table, configurer) -> {
857+
858+
Sort sortToUse;
859+
if (this.sort.isSorted()) {
860+
sortToUse = dataAccessStrategy.getMappedSort(this.sort, this.typeToRead);
861+
} else {
862+
sortToUse = this.sort;
863+
}
864+
865+
configurer.withPageRequest(page).withSort(sortToUse);
866+
867+
if (criteria != null) {
868+
BoundCondition boundCondition = dataAccessStrategy.getMappedCriteria(criteria, table, this.typeToRead);
869+
configurer.withWhere(boundCondition.getCondition()).withBindings(boundCondition.getBindings());
870+
}
871+
});
841872

842-
return execute(select, mappingFunction);
873+
return execute(operation, mappingFunction);
843874
}
844875

845876
@Override

src/main/java/org/springframework/data/r2dbc/function/DefaultReactiveDataAccessStrategy.java

+30-114
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,15 @@
1717

1818
import io.r2dbc.spi.Row;
1919
import io.r2dbc.spi.RowMetadata;
20-
import io.r2dbc.spi.Statement;
2120

2221
import java.util.ArrayList;
23-
import java.util.Collection;
2422
import java.util.Collections;
2523
import java.util.List;
26-
import java.util.OptionalLong;
27-
import java.util.Set;
2824
import java.util.function.BiFunction;
2925
import java.util.function.Function;
3026

3127
import org.springframework.dao.InvalidDataAccessResourceUsageException;
3228
import org.springframework.data.convert.CustomConversions.StoreConversions;
33-
import org.springframework.data.domain.Pageable;
3429
import org.springframework.data.domain.Sort;
3530
import org.springframework.data.domain.Sort.Order;
3631
import org.springframework.data.mapping.context.MappingContext;
@@ -44,18 +39,12 @@
4439
import org.springframework.data.r2dbc.function.convert.MappingR2dbcConverter;
4540
import org.springframework.data.r2dbc.function.convert.R2dbcConverter;
4641
import org.springframework.data.r2dbc.function.convert.R2dbcCustomConversions;
47-
import org.springframework.data.r2dbc.function.query.ConditionBindings;
42+
import org.springframework.data.r2dbc.function.query.BoundCondition;
4843
import org.springframework.data.r2dbc.function.query.Criteria;
4944
import org.springframework.data.r2dbc.function.query.CriteriaMapper;
50-
import org.springframework.data.r2dbc.support.StatementRenderUtil;
5145
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
5246
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
5347
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
54-
import org.springframework.data.relational.core.sql.Expression;
55-
import org.springframework.data.relational.core.sql.OrderByField;
56-
import org.springframework.data.relational.core.sql.Select;
57-
import org.springframework.data.relational.core.sql.SelectBuilder;
58-
import org.springframework.data.relational.core.sql.StatementBuilder;
5948
import org.springframework.data.relational.core.sql.Table;
6049
import org.springframework.data.relational.core.sql.render.NamingStrategies;
6150
import org.springframework.data.relational.core.sql.render.RenderContext;
@@ -100,14 +89,6 @@ private static R2dbcConverter createConverter(Dialect dialect) {
10089
return new MappingR2dbcConverter(context, customConversions);
10190
}
10291

103-
public R2dbcConverter getConverter() {
104-
return converter;
105-
}
106-
107-
public MappingContext<RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> getMappingContext() {
108-
return mappingContext;
109-
}
110-
11192
/**
11293
* Creates a new {@link DefaultReactiveDataAccessStrategy} given {@link Dialect} and {@link R2dbcConverter}.
11394
*
@@ -222,7 +203,7 @@ private SettableValue getArrayValue(SettableValue value, RelationalPersistentPro
222203
* @see org.springframework.data.r2dbc.function.ReactiveDataAccessStrategy#getMappedSort(java.lang.Class, org.springframework.data.domain.Sort)
223204
*/
224205
@Override
225-
public Sort getMappedSort(Class<?> typeToRead, Sort sort) {
206+
public Sort getMappedSort(Sort sort, Class<?> typeToRead) {
226207

227208
RelationalPersistentEntity<?> entity = getPersistentEntity(typeToRead);
228209
if (entity == null) {
@@ -245,105 +226,28 @@ public Sort getMappedSort(Class<?> typeToRead, Sort sort) {
245226
return Sort.by(mappedOrder);
246227
}
247228

229+
/*
230+
* (non-Javadoc)
231+
* @see org.springframework.data.r2dbc.function.ReactiveDataAccessStrategy#getMappedCriteria(org.springframework.data.r2dbc.function.query.Criteria, org.springframework.data.relational.core.sql.Table)
232+
*/
248233
@Override
249-
public PreparedOperation<Select> select(String tableName, @Nullable Class<?> entityType, Set<String> columns,
250-
Sort sort, Pageable page, Criteria criteria) {
251-
252-
Table table = Table.create(tableName);
253-
254-
Collection<? extends Expression> selectList;
255-
256-
if (columns.isEmpty()) {
257-
selectList = Collections.singletonList(table.asterisk());
258-
} else {
259-
selectList = table.columns(columns);
260-
}
261-
262-
SelectBuilder.SelectFromAndJoin selectBuilder = StatementBuilder //
263-
.select(selectList) //
264-
.from(table);//
265-
266-
ConditionBindings conditionBindings;
267-
268-
if (criteria != null) {
269-
270-
BindMarkers bindMarkers = dialect.getBindMarkersFactory().create();
271-
conditionBindings = criteriaMapper.getMappedObject(bindMarkers, criteria, table,
272-
entityType != null ? getRequiredPersistentEntity(entityType) : null);
273-
274-
selectBuilder.where(conditionBindings.getCondition());
275-
} else {
276-
conditionBindings = null;
277-
}
278-
279-
selectBuilder.orderBy(createOrderByFields(table, sort));
280-
281-
OptionalLong limit = OptionalLong.empty();
282-
OptionalLong offset = OptionalLong.empty();
283-
284-
if (page.isPaged()) {
285-
limit = OptionalLong.of(page.getPageSize());
286-
offset = OptionalLong.of(page.getOffset());
287-
}
288-
289-
Select select = selectBuilder.build();
290-
String sql = StatementRenderUtil.render(select, limit, offset, this.dialect);
291-
292-
if (conditionBindings == null) {
293-
294-
return new PreparedOperation<Select>() {
295-
@Override
296-
public Select getSource() {
297-
return select;
298-
}
299-
300-
@Override
301-
public Statement bind(Statement to) {
302-
return to;
303-
}
304-
305-
@Override
306-
public String toQuery() {
307-
return sql;
308-
}
309-
};
310-
}
311-
312-
return new PreparedOperation<Select>() {
313-
@Override
314-
public Select getSource() {
315-
return select;
316-
}
317-
318-
@Override
319-
public Statement bind(Statement to) {
320-
conditionBindings.getBindings().apply(to);
321-
return to;
322-
}
323-
324-
@Override
325-
public String toQuery() {
326-
return sql;
327-
}
328-
};
234+
public BoundCondition getMappedCriteria(Criteria criteria, Table table) {
235+
return getMappedCriteria(criteria, table, null);
329236
}
330237

331-
private Collection<? extends OrderByField> createOrderByFields(Table table, Sort sortToUse) {
332-
333-
List<OrderByField> fields = new ArrayList<>();
334-
335-
for (Sort.Order order : sortToUse) {
238+
/*
239+
* (non-Javadoc)
240+
* @see org.springframework.data.r2dbc.function.ReactiveDataAccessStrategy#getMappedCriteria(org.springframework.data.r2dbc.function.query.Criteria, org.springframework.data.relational.core.sql.Table, java.lang.Class)
241+
*/
242+
@Override
243+
public BoundCondition getMappedCriteria(Criteria criteria, Table table, @Nullable Class<?> typeToRead) {
336244

337-
OrderByField orderByField = OrderByField.from(table.column(order.getProperty()));
245+
BindMarkers bindMarkers = this.dialect.getBindMarkersFactory().create();
338246

339-
if (order.getDirection() != null) {
340-
fields.add(order.isAscending() ? orderByField.asc() : orderByField.desc());
341-
} else {
342-
fields.add(orderByField);
343-
}
344-
}
247+
RelationalPersistentEntity<?> entity = typeToRead != null ? mappingContext.getRequiredPersistentEntity(typeToRead)
248+
: null;
345249

346-
return fields;
250+
return criteriaMapper.getMappedObject(bindMarkers, criteria, table, entity);
347251
}
348252

349253
/*
@@ -382,6 +286,18 @@ public BindMarkersFactory getBindMarkersFactory() {
382286
return dialect.getBindMarkersFactory();
383287
}
384288

289+
/*
290+
* (non-Javadoc)
291+
* @see org.springframework.data.r2dbc.function.ReactiveDataAccessStrategy#getConverter()
292+
*/
293+
public R2dbcConverter getConverter() {
294+
return converter;
295+
}
296+
297+
public MappingContext<RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> getMappingContext() {
298+
return mappingContext;
299+
}
300+
385301
private RelationalPersistentEntity<?> getRequiredPersistentEntity(Class<?> typeToRead) {
386302
return mappingContext.getRequiredPersistentEntity(typeToRead);
387303
}

0 commit comments

Comments
 (0)