From dd7c713980819bbfea7b911a67b4eb2e652e3d44 Mon Sep 17 00:00:00 2001 From: Mingyuan Wu Date: Tue, 21 Apr 2020 15:12:37 +0200 Subject: [PATCH] #344 - Add support for support distinct derived query methods. We now support distinct derived queries that are useful with projections to retrieve distinct results. interface UserRepository extends Repository { Mono findDistinctByFirstName(String firstName); } interface UserProjection { String getFirstName(); } Original pull request: #346. --- .../r2dbc/core/DefaultStatementMapper.java | 8 +++- .../data/r2dbc/core/StatementMapper.java | 43 +++++++++++++------ .../repository/query/R2dbcQueryCreator.java | 4 ++ .../query/PartTreeR2dbcQueryUnitTests.java | 16 +++++++ 4 files changed, 56 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/springframework/data/r2dbc/core/DefaultStatementMapper.java b/src/main/java/org/springframework/data/r2dbc/core/DefaultStatementMapper.java index 19462459..a9a10d42 100644 --- a/src/main/java/org/springframework/data/r2dbc/core/DefaultStatementMapper.java +++ b/src/main/java/org/springframework/data/r2dbc/core/DefaultStatementMapper.java @@ -41,6 +41,7 @@ import org.springframework.util.Assert; * * @author Mark Paluch * @author Roman Chigvintsev + * @author Mingyuan Wu */ class DefaultStatementMapper implements StatementMapper { @@ -84,8 +85,11 @@ class DefaultStatementMapper implements StatementMapper { @Nullable RelationalPersistentEntity entity) { Table table = selectSpec.getTable(); - SelectBuilder.SelectFromAndJoin selectBuilder = StatementBuilder.select(getSelectList(selectSpec, entity)) - .from(table); + SelectBuilder.SelectAndFrom selectAndFrom = StatementBuilder.select(getSelectList(selectSpec, entity)); + if(selectSpec.isDistinct()){ + selectAndFrom = selectAndFrom.distinct(); + } + SelectBuilder.SelectFromAndJoin selectBuilder = selectAndFrom.from(table); BindMarkers bindMarkers = this.dialect.getBindMarkersFactory().create(); Bindings bindings = Bindings.empty(); diff --git a/src/main/java/org/springframework/data/r2dbc/core/StatementMapper.java b/src/main/java/org/springframework/data/r2dbc/core/StatementMapper.java index b3915d81..4041f398 100644 --- a/src/main/java/org/springframework/data/r2dbc/core/StatementMapper.java +++ b/src/main/java/org/springframework/data/r2dbc/core/StatementMapper.java @@ -202,9 +202,10 @@ public interface StatementMapper { private final Sort sort; private final long offset; private final int limit; + private boolean distinct = false; protected SelectSpec(Table table, List projectedFields, List selectList, - @Nullable CriteriaDefinition criteria, Sort sort, int limit, long offset) { + @Nullable CriteriaDefinition criteria, Sort sort, int limit, long offset, boolean distinct) { this.table = table; this.projectedFields = projectedFields; this.selectList = selectList; @@ -212,6 +213,7 @@ public interface StatementMapper { this.sort = sort; this.offset = offset; this.limit = limit; + this.distinct = distinct; } /** @@ -236,7 +238,7 @@ public interface StatementMapper { List projectedFields = Collections.emptyList(); List selectList = Collections.emptyList(); return new SelectSpec(Table.create(table), projectedFields, selectList, Criteria.empty(), Sort.unsorted(), -1, - -1); + -1, false); } public SelectSpec doWithTable(BiFunction function) { @@ -277,7 +279,7 @@ public interface StatementMapper { List selectList = new ArrayList<>(this.selectList); selectList.addAll(Arrays.asList(expressions)); - return new SelectSpec(this.table, projectedFields, selectList, this.criteria, this.sort, this.limit, this.offset); + return new SelectSpec(this.table, projectedFields, selectList, this.criteria, this.sort, this.limit, this.offset, this.distinct); } /** @@ -293,7 +295,7 @@ public interface StatementMapper { selectList.addAll(projectedFields); return new SelectSpec(this.table, this.projectedFields, selectList, this.criteria, this.sort, this.limit, - this.offset); + this.offset, this.distinct); } /** @@ -304,7 +306,7 @@ public interface StatementMapper { */ public SelectSpec withCriteria(CriteriaDefinition criteria) { return new SelectSpec(this.table, this.projectedFields, this.selectList, criteria, this.sort, this.limit, - this.offset); + this.offset, this.distinct); } /** @@ -317,11 +319,11 @@ public interface StatementMapper { if (sort.isSorted()) { return new SelectSpec(this.table, this.projectedFields, this.selectList, this.criteria, sort, this.limit, - this.offset); + this.offset, this.distinct); } return new SelectSpec(this.table, this.projectedFields, this.selectList, this.criteria, this.sort, this.limit, - this.offset); + this.offset, this.distinct); } /** @@ -337,33 +339,44 @@ public interface StatementMapper { Sort sort = page.getSort(); return new SelectSpec(this.table, this.projectedFields, this.selectList, this.criteria, - sort.isSorted() ? sort : this.sort, page.getPageSize(), page.getOffset()); + sort.isSorted() ? sort : this.sort, page.getPageSize(), page.getOffset(), this.distinct); } return new SelectSpec(this.table, this.projectedFields, this.selectList, this.criteria, this.sort, this.limit, - this.offset); + this.offset, this.distinct); } /** * Associate a result offset with the select and create a new {@link SelectSpec}. * - * @param page + * @param offset * @return the {@link SelectSpec}. */ public SelectSpec offset(long offset) { return new SelectSpec(this.table, this.projectedFields, this.selectList, this.criteria, this.sort, this.limit, - offset); + offset, this.distinct); } /** * Associate a result limit with the select and create a new {@link SelectSpec}. * - * @param page + * @param limit * @return the {@link SelectSpec}. */ public SelectSpec limit(int limit) { return new SelectSpec(this.table, this.projectedFields, this.selectList, this.criteria, this.sort, limit, - this.offset); + this.offset, this.distinct); + } + + /** + * Associate a result statement distinct with the select and create a new {@link SelectSpec}. + * + * @param distinct + * @return the {@link SelectSpec}. + */ + public SelectSpec distinct(boolean distinct) { + return new SelectSpec(this.table, this.projectedFields, this.selectList, this.criteria, this.sort, limit, + this.offset, distinct); } public Table getTable() { @@ -399,6 +412,10 @@ public interface StatementMapper { public int getLimit() { return this.limit; } + + public boolean isDistinct() { + return this.distinct; + } } /** diff --git a/src/main/java/org/springframework/data/r2dbc/repository/query/R2dbcQueryCreator.java b/src/main/java/org/springframework/data/r2dbc/repository/query/R2dbcQueryCreator.java index 66c95f54..6fd5fadb 100644 --- a/src/main/java/org/springframework/data/r2dbc/repository/query/R2dbcQueryCreator.java +++ b/src/main/java/org/springframework/data/r2dbc/repository/query/R2dbcQueryCreator.java @@ -123,6 +123,10 @@ public class R2dbcQueryCreator extends RelationalQueryCreator... parameterTypes) throws Exception { Method method = UserRepository.class.getMethod(methodName, parameterTypes); return new R2dbcQueryMethod(method, new DefaultRepositoryMetadata(UserRepository.class), @@ -682,6 +696,8 @@ public class PartTreeR2dbcQueryUnitTests { Flux findTop3ByFirstName(String firstName); Mono findFirstByFirstName(String firstName); + + Mono findDistinctByFirstName(String firstName); Mono deleteByFirstName(String firstName); }