Skip to content

Commit bab4c7e

Browse files
committed
spring-projects#282 - Add support of 'BETWEEN' operator
1 parent 21e35b2 commit bab4c7e

File tree

2 files changed

+56
-24
lines changed

2 files changed

+56
-24
lines changed

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

+32-19
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package org.springframework.data.r2dbc.repository.query;
1717

18+
import org.jetbrains.annotations.NotNull;
1819
import org.springframework.data.mapping.PropertyPath;
1920
import org.springframework.data.mapping.context.MappingContext;
2021
import org.springframework.data.r2dbc.repository.query.ParameterMetadataProvider.ParameterMetadata;
@@ -56,31 +57,43 @@ class ConditionFactory {
5657
public Condition createCondition(Part part) {
5758
Part.Type type = part.getType();
5859
switch (type) {
59-
case SIMPLE_PROPERTY: {
60-
PropertyPath propertyPath = part.getProperty();
61-
@SuppressWarnings("unchecked")
62-
RelationalPersistentEntity<?> persistentEntity
63-
= mappingContext.getRequiredPersistentEntity(propertyPath.getOwningType());
64-
RelationalPersistentProperty persistentProperty
65-
= persistentEntity.getRequiredPersistentProperty(propertyPath.getSegment());
66-
67-
Table table = SQL.table(persistentEntity.getTableName());
68-
Column column = SQL.column(persistentProperty.getColumnName(), table);
60+
case BETWEEN: {
61+
Expression pathExpression = createPropertyPathExpression(part.getProperty());
62+
BindMarker firstBindMarker = createBindMarker(parameterMetadataProvider.next(part));
63+
BindMarker secondBindMarker = createBindMarker(parameterMetadataProvider.next(part));
6964

65+
// TODO: why do not we have BETWEEN condition?
66+
return Conditions.isGreaterOrEqualTo(pathExpression, firstBindMarker)
67+
.and(Conditions.isLessOrEqualTo(pathExpression, secondBindMarker));
68+
}
69+
case SIMPLE_PROPERTY: {
70+
Expression pathExpression = createPropertyPathExpression(part.getProperty());
7071
ParameterMetadata parameterMetadata = parameterMetadataProvider.next(part);
7172
if (parameterMetadata.isIsNullParameter()) {
72-
return IsNull.create(column);
73-
}
74-
75-
BindMarker bindMarker;
76-
if (parameterMetadata.getName() != null) {
77-
bindMarker = SQL.bindMarker(parameterMetadata.getName());
78-
} else {
79-
bindMarker = SQL.bindMarker();
73+
return Conditions.isNull(pathExpression);
8074
}
81-
return Conditions.isEqual(column, bindMarker);
75+
return Conditions.isEqual(pathExpression, createBindMarker(parameterMetadata));
8276
}
8377
}
8478
throw new UnsupportedOperationException("Creating conditions for type " + type + " is unsupported");
8579
}
80+
81+
@NotNull
82+
private Expression createPropertyPathExpression(PropertyPath propertyPath) {
83+
@SuppressWarnings("unchecked")
84+
RelationalPersistentEntity<?> persistentEntity
85+
= mappingContext.getRequiredPersistentEntity(propertyPath.getOwningType());
86+
RelationalPersistentProperty persistentProperty
87+
= persistentEntity.getRequiredPersistentProperty(propertyPath.getSegment());
88+
Table table = SQL.table(persistentEntity.getTableName());
89+
return SQL.column(persistentProperty.getColumnName(), table);
90+
}
91+
92+
@NotNull
93+
private BindMarker createBindMarker(ParameterMetadata parameterMetadata) {
94+
if (parameterMetadata.getName() != null) {
95+
return SQL.bindMarker(parameterMetadata.getName());
96+
}
97+
return SQL.bindMarker();
98+
}
8699
}

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

+24-5
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import reactor.core.publisher.Mono;
4242

4343
import java.lang.reflect.Method;
44+
import java.util.Date;
4445

4546
import static org.assertj.core.api.Assertions.assertThat;
4647
import static org.mockito.Mockito.*;
@@ -51,7 +52,10 @@
5152
@RunWith(MockitoJUnitRunner.class)
5253
public class PartTreeR2dbcQueryIntegrationTests {
5354
private static final String TABLE = "users";
54-
private static final String ALL_FIELDS = TABLE + ".id, " + TABLE + ".first_name, " + TABLE + ".last_name";
55+
private static final String ALL_FIELDS = TABLE + ".id, "
56+
+ TABLE + ".first_name, "
57+
+ TABLE + ".last_name, "
58+
+ TABLE + ".date_of_birth";
5559

5660
@Mock
5761
private ConnectionFactory connectionFactory;
@@ -112,7 +116,7 @@ public void createsQueryWithLimitForExistsProjection() throws Exception {
112116

113117
@Test
114118
public void createsQueryToFindAllEntitiesByTwoStringAttributes() throws Exception {
115-
R2dbcQueryMethod queryMethod = getQueryMethod("findByLastNameAndFirstName", String.class, String.class);
119+
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByLastNameAndFirstName", String.class, String.class);
116120
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
117121
dataAccessStrategy);
118122
BindableQuery bindableQuery = r2dbcQuery.createQuery(getAccessor(queryMethod, new Object[]{"Doe", "John"}));
@@ -123,7 +127,7 @@ public void createsQueryToFindAllEntitiesByTwoStringAttributes() throws Exceptio
123127

124128
@Test
125129
public void createsQueryToFindAllEntitiesByOneOfTwoStringAttributes() throws Exception {
126-
R2dbcQueryMethod queryMethod = getQueryMethod("findByLastNameOrFirstName", String.class, String.class);
130+
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByLastNameOrFirstName", String.class, String.class);
127131
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
128132
dataAccessStrategy);
129133
BindableQuery bindableQuery = r2dbcQuery.createQuery(getAccessor(queryMethod, new Object[]{"Doe", "John"}));
@@ -132,6 +136,18 @@ public void createsQueryToFindAllEntitiesByOneOfTwoStringAttributes() throws Exc
132136
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
133137
}
134138

139+
@Test
140+
public void createsQueryToFindAllEntitiesByDateAttributeBetween() throws Exception {
141+
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByDateOfBirthBetween", Date.class, Date.class);
142+
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
143+
dataAccessStrategy);
144+
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[]{null, new Date()});
145+
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
146+
String expectedSql = "SELECT " + ALL_FIELDS + " FROM " + TABLE
147+
+ " WHERE " + TABLE + ".date_of_birth >= ? AND " + TABLE + ".date_of_birth <= ?";
148+
assertThat(bindableQuery.get()).isEqualTo(expectedSql);
149+
}
150+
135151
private R2dbcQueryMethod getQueryMethod(String methodName, Class<?>... parameterTypes) throws Exception {
136152
Method method = UserRepository.class.getMethod(methodName, parameterTypes);
137153
return new R2dbcQueryMethod(method, new DefaultRepositoryMetadata(UserRepository.class),
@@ -145,11 +161,13 @@ private RelationalParametersParameterAccessor getAccessor(R2dbcQueryMethod query
145161
private interface UserRepository extends Repository<User, Long> {
146162
Flux<User> findAllByFirstName(String firstName);
147163

148-
Flux<User> findByLastNameAndFirstName(String lastName, String firstName);
164+
Flux<User> findAllByLastNameAndFirstName(String lastName, String firstName);
149165

150-
Flux<User> findByLastNameOrFirstName(String lastName, String firstName);
166+
Flux<User> findAllByLastNameOrFirstName(String lastName, String firstName);
151167

152168
Mono<Boolean> existsByFirstName(String firstName);
169+
170+
Flux<User> findAllByDateOfBirthBetween(Date from, Date to);
153171
}
154172

155173
@Table("users")
@@ -159,5 +177,6 @@ private static class User {
159177
private Long id;
160178
private String firstName;
161179
private String lastName;
180+
private Date dateOfBirth;
162181
}
163182
}

0 commit comments

Comments
 (0)