Browse Source

DATAMONGO-1997 - Add support to return the single deleted item for a deleteBy query method.

Added support for:

@Nullable
Person deleteSingleByLastname(String lastname);

Optional<Person> deleteByBirthdate(Date birthdate);

Mono<Person> deleteSinglePersonByLastname(String lastname);

Original pull request: #826.
pull/832/head
Christoph Strobl 6 years ago committed by Mark Paluch
parent
commit
c56a13ad00
No known key found for this signature in database
GPG Key ID: 51A00FA751B91849
  1. 5
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryExecution.java
  2. 4
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ReactiveMongoQueryExecution.java
  3. 7
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java
  4. 3
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepository.java
  5. 26
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/ReactiveMongoRepositoryTests.java
  6. 42
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryExecutionUnitTests.java
  7. 15
      src/main/asciidoc/reference/mongo-repositories.adoc

5
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryExecution.java

@ -39,6 +39,7 @@ import org.springframework.data.repository.support.PageableExecutionUtils; @@ -39,6 +39,7 @@ import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.data.util.TypeInformation;
import com.mongodb.client.result.DeleteResult;
import org.springframework.util.ClassUtils;
/**
* Set of classes to contain query execution strategies. Depending (mostly) on the return type of a
@ -255,6 +256,10 @@ interface MongoQueryExecution { @@ -255,6 +256,10 @@ interface MongoQueryExecution {
return operations.findAllAndRemove(query, type, collectionName);
}
if(method.isQueryForEntity() && !ClassUtils.isPrimitiveOrWrapper(method.getReturnedObjectType())) {
return operations.findAndRemove(query, type, collectionName);
}
DeleteResult writeResult = operations.remove(query, type, collectionName);
return writeResult.wasAcknowledged() ? writeResult.getDeletedCount() : 0L;
}

4
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ReactiveMongoQueryExecution.java

@ -129,6 +129,10 @@ interface ReactiveMongoQueryExecution { @@ -129,6 +129,10 @@ interface ReactiveMongoQueryExecution {
return operations.findAllAndRemove(query, type, collection);
}
if(method.isQueryForEntity() && !ClassUtils.isPrimitiveOrWrapper(method.getReturnedObjectType())) {
return operations.findAndRemove(query, type, collection);
}
return operations.remove(query, type, collection)
.map(deleteResult -> deleteResult.wasAcknowledged() ? deleteResult.getDeletedCount() : 0L);
}

7
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java

@ -741,6 +741,13 @@ public abstract class AbstractPersonRepositoryIntegrationTests { @@ -741,6 +741,13 @@ public abstract class AbstractPersonRepositoryIntegrationTests {
assertThat(repository.deletePersonByLastname("Beauford")).isEqualTo(1L);
}
@Test // DATAMONGO-1997
public void deleteByShouldResultWrappedInOptionalCorrectly() {
assertThat(repository.deleteOptionalByLastname("Beauford")).isPresent();
assertThat(repository.deleteOptionalByLastname("dorfuaeB")).isNotPresent();
}
@Test // DATAMONGO-566
public void deleteByShouldReturnZeroInCaseNoDocumentHasBeenRemovedAndReturnTypeIsNumber() {
assertThat(repository.deletePersonByLastname("dorfuaeB")).isEqualTo(0L);

3
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepository.java

@ -264,6 +264,9 @@ public interface PersonRepository extends MongoRepository<Person, String>, Query @@ -264,6 +264,9 @@ public interface PersonRepository extends MongoRepository<Person, String>, Query
// DATAMONGO-566
Long deletePersonByLastname(String lastname);
// DATAMONGO-1997
Optional<Person> deleteOptionalByLastname(String lastname);
// DATAMONGO-566
@Query(value = "{ 'lastname' : ?0 }", delete = true)
List<Person> removeByLastnameUsingAnnotatedQuery(String lastname);

26
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/ReactiveMongoRepositoryTests.java

@ -589,6 +589,28 @@ public class ReactiveMongoRepositoryTests { @@ -589,6 +589,28 @@ public class ReactiveMongoRepositoryTests {
.verifyComplete();
}
@Test // DATAMONGO-1997
public void deleteByShouldAllowDeletedCountAsResult() {
repository.deleteCountByLastname(dave.getLastname()) //
.as(StepVerifier::create) //
.expectNext(2L) //
.verifyComplete();
}
@Test // DATAMONGO-1997
public void deleteByShouldAllowSingleDocumentRemovalCorrectly() {
repository.deleteSinglePersonByLastname(carter.getLastname()) //
.as(StepVerifier::create) //
.expectNext(carter) //
.verifyComplete();
repository.deleteSinglePersonByLastname("dorfuaeB") //
.as(StepVerifier::create) //
.verifyComplete();
}
interface ReactivePersonRepository
extends ReactiveMongoRepository<Person, String>, ReactiveQuerydslPredicateExecutor<Person> {
@ -661,6 +683,10 @@ public class ReactiveMongoRepositoryTests { @@ -661,6 +683,10 @@ public class ReactiveMongoRepositoryTests {
Mono<org.bson.Document> findDocumentById(String id);
Mono<Void> deleteByLastname(String lastname);
Mono<Long> deleteCountByLastname(String lastname);
Mono<Person> deleteSinglePersonByLastname(String lastname);
}
interface ReactiveContactRepository extends ReactiveMongoRepository<Contact, String> {}

42
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryExecutionUnitTests.java

@ -16,13 +16,13 @@ @@ -16,13 +16,13 @@
package org.springframework.data.mongodb.repository.query;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
@ -68,6 +68,7 @@ import com.mongodb.client.result.DeleteResult; @@ -68,6 +68,7 @@ import com.mongodb.client.result.DeleteResult;
* @author Mark Paluch
* @author Oliver Gierke
* @author Artyom Gabeev
* @author Christoph Strobl
* @soundtrack U Can't Touch This - MC Hammer
*/
@RunWith(MockitoJUnitRunner.class)
@ -181,6 +182,9 @@ public class MongoQueryExecutionUnitTests { @@ -181,6 +182,9 @@ public class MongoQueryExecutionUnitTests {
@Test // DATAMONGO-2351
public void acknowledgedDeleteReturnsDeletedCount() {
Method method = ReflectionUtils.findMethod(PersonRepository.class, "deleteAllByLastname", String.class);
MongoQueryMethod queryMethod = new MongoQueryMethod(method, metadata, factory, context);
when(mongoOperationsMock.remove(any(Query.class), any(Class.class), anyString()))
.thenReturn(DeleteResult.acknowledged(10));
@ -190,14 +194,48 @@ public class MongoQueryExecutionUnitTests { @@ -190,14 +194,48 @@ public class MongoQueryExecutionUnitTests {
@Test // DATAMONGO-2351
public void unacknowledgedDeleteReturnsZeroDeletedCount() {
Method method = ReflectionUtils.findMethod(PersonRepository.class, "deleteAllByLastname", String.class);
MongoQueryMethod queryMethod = new MongoQueryMethod(method, metadata, factory, context);
when(mongoOperationsMock.remove(any(Query.class), any(Class.class), anyString()))
.thenReturn(DeleteResult.unacknowledged());
assertThat(new DeleteExecution(mongoOperationsMock, queryMethod).execute(new Query())).isEqualTo(0L);
}
@Test // DATAMONGO-1997
public void deleteExecutionWithEntityReturnTypeTriggersFindAndRemove() {
Method method = ReflectionUtils.findMethod(PersonRepository.class, "deleteByLastname", String.class);
MongoQueryMethod queryMethod = new MongoQueryMethod(method, metadata, factory, context);
Person person = new Person();
when(mongoOperationsMock.findAndRemove(any(Query.class), any(Class.class), anyString())).thenReturn(person);
assertThat(new DeleteExecution(mongoOperationsMock, queryMethod).execute(new Query())).isEqualTo(person);
}
// @Test // DATAMONGO-1997
// public void deleteExecutionWrapsEmptyResultInOptionalCorrectly() {
//
// Method method = ReflectionUtils.findMethod(PersonRepository.class, "deleteByLastname", String.class);
// MongoQueryMethod queryMethod = new MongoQueryMethod(method, metadata, factory, context);
//
// Person person = new Person();
//
// when(mongoOperationsMock.findAndRemove(any(Query.class), any(Class.class), anyString())).thenReturn(null);
//
// assertThat(new DeleteExecution(mongoOperationsMock, queryMethod).execute(new Query())).isEqualTo(Optional.empty());
// }
interface PersonRepository extends Repository<Person, Long> {
GeoPage<Person> findByLocationNear(Point point, Distance distance, Pageable pageable);
Long deleteAllByLastname(String lastname);
Person deleteByLastname(String lastname);
Optional<Person> deletePersonByLastname(String lastname);
}
}

15
src/main/asciidoc/reference/mongo-repositories.adoc

@ -301,15 +301,22 @@ The keywords in the preceding table can be used in conjunction with `delete…By @@ -301,15 +301,22 @@ The keywords in the preceding table can be used in conjunction with `delete…By
----
public interface PersonRepository extends MongoRepository<Person, String> {
List <Person> deleteByLastname(String lastname);
List <Person> deleteByLastname(String lastname); <1>
Long deletePersonByLastname(String lastname);
Long deletePersonByLastname(String lastname); <2>
@Nullable
Person deleteSingleByLastname(String lastname); <3>
Optional<Person> deleteByBirthdate(Date birthdate); <4>
}
----
<1> Using a return type of `List` retrieves and returns all matching documents before actually deleting them.
<2> A numeric return type directly removes the matching documents, returning the total number of documents removed.
<3> A single domain type result retrieves and removes the first matching document.
<4> Same as in 3 but wrapped in an `Optional` type.
====
Using a return type of `List` retrieves and returns all matching documents before actually deleting them. A numeric return type directly removes the matching documents, returning the total number of documents removed.
[[mongodb.repositories.queries.geo-spatial]]
=== Geo-spatial Repository Queries

Loading…
Cancel
Save