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.
This commit is contained in:
committed by
Mark Paluch
parent
0a2ea88f3c
commit
c56a13ad00
@@ -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 {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
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> {}
|
||||
|
||||
@@ -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;
|
||||
* @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 {
|
||||
@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 {
|
||||
@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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user