Skip to content

Commit 73fe1ca

Browse files
kazuki43zooschauder
authored andcommitted
DATAJDBC-182 - Support modifying annotated queries.
Added @modify for marking queries that perform DML or DDL. Modifying queries with return type boolean or Boolean return wether the number of updated rows is greater 0. This shouldn't be used for DML statements since it will always return false. Original pull request: ##48.
1 parent ac4da66 commit 73fe1ca

File tree

5 files changed

+114
-15
lines changed

5 files changed

+114
-15
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright 2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.jdbc.repository.query;
17+
18+
import java.lang.annotation.Documented;
19+
import java.lang.annotation.ElementType;
20+
import java.lang.annotation.Retention;
21+
import java.lang.annotation.RetentionPolicy;
22+
import java.lang.annotation.Target;
23+
24+
/**
25+
* Indicates a method should be regarded as modifying query.
26+
*
27+
* @author Kazuki Shimizu
28+
*/
29+
@Retention(RetentionPolicy.RUNTIME)
30+
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
31+
@Documented
32+
public @interface Modifying {
33+
}

src/main/java/org/springframework/data/jdbc/repository/support/JdbcQueryLookupStrategy.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,17 @@ public RepositoryQuery resolveQuery(Method method, RepositoryMetadata repository
5656

5757
JdbcQueryMethod queryMethod = new JdbcQueryMethod(method, repositoryMetadata, projectionFactory);
5858
Class<?> returnedObjectType = queryMethod.getReturnedObjectType();
59-
RowMapper<?> rowMapper = context.getSimpleTypeHolder().isSimpleType(returnedObjectType)
60-
? SingleColumnRowMapper.newInstance(returnedObjectType, conversionService)
61-
: new EntityRowMapper<>( //
62-
context.getRequiredPersistentEntity(returnedObjectType), //
63-
conversionService, //
64-
context, //
65-
accessStrategy //
66-
);
67-
59+
RowMapper<?> rowMapper = null;
60+
if (!queryMethod.isModifyingQuery()) {
61+
rowMapper = context.getSimpleTypeHolder().isSimpleType(returnedObjectType)
62+
? SingleColumnRowMapper.newInstance(returnedObjectType, conversionService)
63+
: new EntityRowMapper<>( //
64+
context.getRequiredPersistentEntity(returnedObjectType), //
65+
conversionService, //
66+
context, //
67+
accessStrategy //
68+
);
69+
}
6870
return new JdbcRepositoryQuery(queryMethod, context, rowMapper);
6971
}
7072

src/main/java/org/springframework/data/jdbc/repository/support/JdbcQueryMethod.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
import java.lang.reflect.Method;
1919

2020
import org.springframework.core.annotation.AnnotatedElementUtils;
21+
import org.springframework.core.annotation.AnnotationUtils;
22+
import org.springframework.data.jdbc.repository.query.Modifying;
2123
import org.springframework.data.jdbc.repository.query.Query;
2224
import org.springframework.data.projection.ProjectionFactory;
2325
import org.springframework.data.repository.core.RepositoryMetadata;
@@ -30,6 +32,7 @@
3032
* Binds method arguments to named parameters in the SQL statement.
3133
*
3234
* @author Jens Schauder
35+
* @author Kazuki Shimizu
3336
*/
3437
public class JdbcQueryMethod extends QueryMethod {
3538

@@ -47,4 +50,15 @@ public String getAnnotatedQuery() {
4750

4851
return queryAnnotation == null ? null : queryAnnotation.value();
4952
}
53+
54+
/**
55+
* Returns whether the query method is a modifying one.
56+
*
57+
* @return if it's a modifying query, return {@code true}.
58+
*/
59+
@Override
60+
public boolean isModifyingQuery() {
61+
return AnnotationUtils.findAnnotation(method, Modifying.class) != null;
62+
}
63+
5064
}

src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryQuery.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,20 @@ public Object execute(Object[] objects) {
5555
parameters.addValue(parameterName, objects[p.getIndex()]);
5656
});
5757

58+
if (queryMethod.isModifyingQuery()) {
59+
int updatedCount = context.getTemplate().update(query, parameters);
60+
Class<?> returnedObjectType = queryMethod.getReturnedObjectType();
61+
return (returnedObjectType == boolean.class || returnedObjectType == Boolean.class) ? updatedCount != 0 : updatedCount;
62+
}
63+
5864
if (queryMethod.isCollectionQuery() || queryMethod.isStreamQuery()) {
5965
return context.getTemplate().query(query, parameters, rowMapper);
60-
} else {
66+
}
6167

62-
try {
63-
return context.getTemplate().queryForObject(query, parameters, rowMapper);
64-
} catch (EmptyResultDataAccessException e) {
65-
return null;
66-
}
68+
try {
69+
return context.getTemplate().queryForObject(query, parameters, rowMapper);
70+
} catch (EmptyResultDataAccessException e) {
71+
return null;
6772
}
6873
}
6974

src/test/java/org/springframework/data/jdbc/repository/query/QueryAnnotationHsqlIntegrationTests.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,39 @@ public void executeCustomQueryWithReturnTypeIsLocalDateTimeList() {
210210

211211
}
212212

213+
@Test // DATAJDBC-182
214+
public void executeCustomModifyingQueryWithReturnTypeIsNumber() {
215+
216+
DummyEntity entity = dummyEntity("a");
217+
repository.save(entity);
218+
219+
assertThat(repository.updateName(entity.id, "b")).isEqualTo(1);
220+
assertThat(repository.updateName(9999L, "b")).isEqualTo(0);
221+
assertThat(repository.findById(entity.id)).isPresent().map(e -> e.name).contains("b");
222+
223+
}
224+
225+
@Test // DATAJDBC-182
226+
public void executeCustomModifyingQueryWithReturnTypeIsBoolean() {
227+
228+
DummyEntity entity = dummyEntity("a");
229+
repository.save(entity);
230+
231+
assertThat(repository.deleteByName("a")).isTrue();
232+
assertThat(repository.deleteByName("b")).isFalse();
233+
assertThat(repository.findById(entity.id)).isNotPresent();
234+
235+
}
236+
237+
@Test // DATAJDBC-182
238+
public void executeCustomModifyingQueryWithReturnTypeIsVoid() {
239+
240+
repository.insert("Spring Data JDBC");
241+
242+
assertThat(repository.findByNameAsEntity("Spring Data JDBC")).isNotNull();
243+
244+
}
245+
213246
private DummyEntity dummyEntity(String name) {
214247

215248
DummyEntity entity = new DummyEntity();
@@ -265,5 +298,17 @@ private interface DummyEntityRepository extends CrudRepository<DummyEntity, Long
265298
@Query("VALUES (current_timestamp),(current_timestamp)")
266299
List<LocalDateTime> nowWithLocalDateTimeList();
267300

301+
@Modifying
302+
@Query("UPDATE DUMMYENTITY SET name = :name WHERE id = :id")
303+
int updateName(@Param("id") Long id, @Param("name") String name);
304+
305+
@Modifying
306+
@Query("DELETE FROM DUMMYENTITY WHERE name = :name")
307+
boolean deleteByName(@Param("name") String name);
308+
309+
@Modifying
310+
@Query("INSERT INTO DUMMYENTITY (name) VALUES(:name)")
311+
void insert(@Param("name") String name);
312+
268313
}
269314
}

0 commit comments

Comments
 (0)