Skip to content

Commit 0d415df

Browse files
committed
spring-projects#282 - Limit query in case of 'exists' projection
1 parent 3871f0b commit 0d415df

File tree

2 files changed

+30
-8
lines changed

2 files changed

+30
-8
lines changed

Diff for: src/main/java/org/springframework/data/r2dbc/repository/query/R2dbcQueryCreator.java

+17-8
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
import org.springframework.data.r2dbc.convert.R2dbcConverter;
55
import org.springframework.data.r2dbc.core.DatabaseClient;
66
import org.springframework.data.r2dbc.core.ReactiveDataAccessStrategy;
7-
import org.springframework.data.relational.core.sql.Column;
87
import org.springframework.data.relational.core.sql.Condition;
8+
import org.springframework.data.relational.core.sql.Expression;
99
import org.springframework.data.relational.core.sql.SelectBuilder.SelectFromAndJoin;
1010
import org.springframework.data.relational.core.sql.StatementBuilder;
1111
import org.springframework.data.relational.core.sql.Table;
12+
import org.springframework.data.relational.core.sql.render.RenderContext;
1213
import org.springframework.data.relational.core.sql.render.SqlRenderer;
1314
import org.springframework.data.relational.repository.query.RelationalEntityMetadata;
1415
import org.springframework.data.repository.query.parser.AbstractQueryCreator;
@@ -34,9 +35,9 @@ public class R2dbcQueryCreator extends AbstractQueryCreator<BindableQuery, Condi
3435
* Creates new instance of this class with the given {@link PartTree}, {@link ReactiveDataAccessStrategy},
3536
* {@link RelationalEntityMetadata} and {@link ParameterMetadataProvider}.
3637
*
37-
* @param tree part tree (must not be {@literal null})
38-
* @param dataAccessStrategy data access strategy (must not be {@literal null})
39-
* @param entityMetadata relational entity metadata (must not be {@literal null})
38+
* @param tree part tree (must not be {@literal null})
39+
* @param dataAccessStrategy data access strategy (must not be {@literal null})
40+
* @param entityMetadata relational entity metadata (must not be {@literal null})
4041
* @param parameterMetadataProvider parameter metadata provider (must not be {@literal null})
4142
*/
4243
public R2dbcQueryCreator(PartTree tree,
@@ -76,15 +77,15 @@ protected Condition or(Condition condition, Condition s1) {
7677
* Creates {@link BindableQuery} applying the given {@link Condition} and {@link Sort} definition.
7778
*
7879
* @param condition condition to be applied to query
79-
* @param sort sort option to be applied to query (must not be {@literal null})
80+
* @param sort sort option to be applied to query (must not be {@literal null})
8081
* @return new instance of {@link BindableQuery}
8182
*/
8283
@Override
8384
protected BindableQuery complete(Condition condition, Sort sort) {
8485
Table fromTable = Table.create(entityMetadata.getTableName());
85-
List<Column> columns = fromTable.columns(dataAccessStrategy.getAllColumns(entityMetadata.getJavaType()));
86+
List<? extends Expression> selectExpressions = getSelectionExpressions(fromTable);
87+
SelectFromAndJoin selectBuilder = StatementBuilder.select(selectExpressions).from(fromTable);
8688

87-
SelectFromAndJoin selectBuilder = StatementBuilder.select(columns).from(fromTable);
8889
if (tree.isExistsProjection()) {
8990
selectBuilder.limit(1);
9091
}
@@ -93,7 +94,8 @@ protected BindableQuery complete(Condition condition, Sort sort) {
9394
selectBuilder.where(condition);
9495
}
9596

96-
SqlRenderer sqlRenderer = SqlRenderer.create();
97+
RenderContext renderContext = dataAccessStrategy.getStatementMapper().getRenderContext();
98+
SqlRenderer sqlRenderer = renderContext == null ? SqlRenderer.create() : SqlRenderer.create(renderContext);
9799
String sql = sqlRenderer.render(selectBuilder.build());
98100

99101
return new BindableQuery() {
@@ -108,4 +110,11 @@ public String get() {
108110
}
109111
};
110112
}
113+
114+
private List<? extends Expression> getSelectionExpressions(Table fromTable) {
115+
if (tree.isExistsProjection()) {
116+
return fromTable.columns(dataAccessStrategy.getIdentifierColumns(entityMetadata.getJavaType()));
117+
}
118+
return fromTable.columns(dataAccessStrategy.getAllColumns(entityMetadata.getJavaType()));
119+
}
111120
}

Diff for: src/test/java/org/springframework/data/r2dbc/repository/query/PartTreeR2dbcQueryIntegrationTests.java

+13
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.springframework.data.repository.Repository;
2424
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
2525
import reactor.core.publisher.Flux;
26+
import reactor.core.publisher.Mono;
2627

2728
import java.lang.reflect.Method;
2829

@@ -81,6 +82,16 @@ public void createsQueryWithIsNullCondition() throws Exception {
8182
.isEqualTo("SELECT users.id, users.first_name FROM users WHERE users.first_name IS NULL");
8283
}
8384

85+
@Test
86+
public void createsQueryWithLimitForExistsProjection() throws Exception {
87+
R2dbcQueryMethod queryMethod = getQueryMethod("existsByFirstName", String.class);
88+
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
89+
dataAccessStrategy);
90+
BindableQuery query = r2dbcQuery.createQuery((getAccessor(queryMethod, new Object[]{"Matthews"})));
91+
assertThat(query.get())
92+
.isEqualTo("SELECT users.id FROM users WHERE users.first_name = ? LIMIT 1");
93+
}
94+
8495
private R2dbcQueryMethod getQueryMethod(String methodName, Class<?>... parameterTypes) throws Exception {
8596
Method method = UserRepository.class.getMethod(methodName, parameterTypes);
8697
return new R2dbcQueryMethod(method, new DefaultRepositoryMetadata(UserRepository.class),
@@ -93,6 +104,8 @@ private RelationalParametersParameterAccessor getAccessor(R2dbcQueryMethod query
93104

94105
private interface UserRepository extends Repository<User, Long> {
95106
Flux<User> findAllByFirstName(String firstName);
107+
108+
Mono<Boolean> existsByFirstName(String firstName);
96109
}
97110

98111
@Table("users")

0 commit comments

Comments
 (0)