DATAMONGO-2218 - Add support for replaceOne operation in BulkOperations.
Original Pull Request: #655
This commit is contained in:
@@ -31,6 +31,7 @@ import com.mongodb.bulk.BulkWriteResult;
|
||||
*
|
||||
* @author Tobias Trelle
|
||||
* @author Oliver Gierke
|
||||
* @author Minsu Kim
|
||||
* @since 1.9
|
||||
*/
|
||||
public interface BulkOperations {
|
||||
@@ -135,6 +136,15 @@ public interface BulkOperations {
|
||||
*/
|
||||
BulkOperations remove(List<Query> removes);
|
||||
|
||||
/**
|
||||
* Add a single replace operation to the bulk operation.
|
||||
*
|
||||
* @param query Update criteria.
|
||||
* @param document the document to replace, must not be {@literal null}.
|
||||
* @return the current {@link BulkOperations} instance with the replace added, will never be {@literal null}.
|
||||
*/
|
||||
BulkOperations replaceOne(Query query, Object document);
|
||||
|
||||
/**
|
||||
* Execute all bulk operations using the default write concern.
|
||||
*
|
||||
|
||||
@@ -26,7 +26,6 @@ import java.util.stream.Collectors;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.bson.conversions.Bson;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.data.mongodb.core.convert.QueryMapper;
|
||||
import org.springframework.data.mongodb.core.convert.UpdateMapper;
|
||||
@@ -38,18 +37,8 @@ import org.springframework.data.util.Pair;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.mongodb.BulkWriteException;
|
||||
import com.mongodb.WriteConcern;
|
||||
import com.mongodb.client.MongoCollection;
|
||||
import com.mongodb.client.model.BulkWriteOptions;
|
||||
import com.mongodb.client.model.DeleteManyModel;
|
||||
import com.mongodb.client.model.DeleteOneModel;
|
||||
import com.mongodb.client.model.DeleteOptions;
|
||||
import com.mongodb.client.model.InsertOneModel;
|
||||
import com.mongodb.client.model.UpdateManyModel;
|
||||
import com.mongodb.client.model.UpdateOneModel;
|
||||
import com.mongodb.client.model.UpdateOptions;
|
||||
import com.mongodb.client.model.WriteModel;
|
||||
import com.mongodb.client.model.*;
|
||||
|
||||
/**
|
||||
* Default implementation for {@link BulkOperations}.
|
||||
@@ -58,6 +47,7 @@ import com.mongodb.client.model.WriteModel;
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @author Minsu Kim
|
||||
* @since 1.9
|
||||
*/
|
||||
class DefaultBulkOperations implements BulkOperations {
|
||||
@@ -266,6 +256,32 @@ class DefaultBulkOperations implements BulkOperations {
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.BulkOperations#replaceOne(org.springframework.data.mongodb.core.query.Query, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public BulkOperations replaceOne(Query query, Object document) {
|
||||
|
||||
Assert.notNull(query, "Query must not be null!");
|
||||
Assert.notNull(document, "Document must not be null!");
|
||||
|
||||
ReplaceOptions replaceOptions = new ReplaceOptions();
|
||||
query.getCollation().map(Collation::toMongoCollation).ifPresent(replaceOptions::collation);
|
||||
Bson mappedQuery = getMappedQuery(query.getQueryObject());
|
||||
|
||||
if (document instanceof Document) {
|
||||
models.add(new ReplaceOneModel<>(mappedQuery, (Document) document, replaceOptions));
|
||||
return this;
|
||||
}
|
||||
|
||||
Document sink = new Document();
|
||||
mongoOperations.getConverter().write(document, sink);
|
||||
models.add(new ReplaceOneModel<>(mappedQuery, sink, replaceOptions));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.BulkOperations#executeBulk()
|
||||
|
||||
@@ -53,6 +53,7 @@ import com.mongodb.client.MongoCollection;
|
||||
* @author Tobias Trelle
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Minsu Kim
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration("classpath:infrastructure.xml")
|
||||
@@ -200,6 +201,31 @@ public class DefaultBulkOperationsIntegrationTests {
|
||||
testRemove(BulkMode.UNORDERED);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2218
|
||||
public void replaceOneOrdered() {
|
||||
testReplaceOne(BulkMode.ORDERED);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2218
|
||||
public void replaceOneUnordered() {
|
||||
testReplaceOne(BulkMode.UNORDERED);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2218
|
||||
public void replaceOneDoesReplace() {
|
||||
|
||||
insertSomeDocuments();
|
||||
|
||||
com.mongodb.bulk.BulkWriteResult result = createBulkOps(BulkMode.ORDERED).//
|
||||
replaceOne(where("_id", "1"), rawDoc("1", "value2")).//
|
||||
execute();
|
||||
|
||||
assertThat(result, notNullValue());
|
||||
assertThat(result.getMatchedCount(), is(1));
|
||||
assertThat(result.getModifiedCount(), is(1));
|
||||
assertThat(result.getInsertedCount(), is(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* If working on the same set of documents, only an ordered bulk operation will yield predictable results.
|
||||
*/
|
||||
@@ -278,6 +304,19 @@ public class DefaultBulkOperationsIntegrationTests {
|
||||
assertThat(createBulkOps(mode).remove(removes).execute().getDeletedCount(), is(3));
|
||||
}
|
||||
|
||||
private void testReplaceOne(BulkMode mode) {
|
||||
|
||||
BulkOperations bulkOps = createBulkOps(mode);
|
||||
|
||||
insertSomeDocuments();
|
||||
|
||||
Query query = where("_id", "1");
|
||||
Document document = rawDoc("1", "value2");
|
||||
int modifiedCount = bulkOps.replaceOne(query, document).execute().getModifiedCount();
|
||||
|
||||
assertThat(modifiedCount, is(1));
|
||||
}
|
||||
|
||||
private BulkOperations createBulkOps(BulkMode mode) {
|
||||
return createBulkOps(mode, null);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import static org.springframework.data.mongodb.core.query.Query.*;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.mongodb.client.model.*;
|
||||
import org.bson.Document;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -51,16 +52,13 @@ import org.springframework.data.mongodb.core.query.Update;
|
||||
|
||||
import com.mongodb.client.MongoCollection;
|
||||
import com.mongodb.client.MongoDatabase;
|
||||
import com.mongodb.client.model.DeleteManyModel;
|
||||
import com.mongodb.client.model.UpdateManyModel;
|
||||
import com.mongodb.client.model.UpdateOneModel;
|
||||
import com.mongodb.client.model.WriteModel;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link DefaultBulkOperations}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @author Minsu Kim
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class DefaultBulkOperationsUnitTests {
|
||||
@@ -133,6 +131,18 @@ public class DefaultBulkOperationsUnitTests {
|
||||
.isEqualTo(com.mongodb.client.model.Collation.builder().locale("de").build());
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2218
|
||||
public void replaceOneShouldUseCollationWhenPresent() {
|
||||
|
||||
ops.replaceOne(new BasicQuery("{}").collation(Collation.of("de")), new SomeDomainType()).execute();
|
||||
|
||||
verify(collection).bulkWrite(captor.capture(), any());
|
||||
|
||||
assertThat(captor.getValue().get(0)).isInstanceOf(ReplaceOneModel.class);
|
||||
assertThat(((ReplaceOneModel<Document>) captor.getValue().get(0)).getReplaceOptions().getCollation())
|
||||
.isEqualTo(com.mongodb.client.model.Collation.builder().locale("de").build());
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1678
|
||||
public void bulkUpdateShouldMapQueryAndUpdateCorrectly() {
|
||||
|
||||
@@ -156,6 +166,23 @@ public class DefaultBulkOperationsUnitTests {
|
||||
assertThat(updateModel.getFilter()).isEqualTo(new Document("first_name", "danerys"));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2218
|
||||
public void bulkReplaceOneShouldMapQueryCorrectly() {
|
||||
|
||||
SomeDomainType replacement = new SomeDomainType();
|
||||
replacement.firstName = "Minsu";
|
||||
replacement.lastName = "Kim";
|
||||
|
||||
ops.replaceOne(query(where("firstName").is("danerys")), replacement).execute();
|
||||
|
||||
verify(collection).bulkWrite(captor.capture(), any());
|
||||
|
||||
ReplaceOneModel<Document> updateModel = (ReplaceOneModel<Document>) captor.getValue().get(0);
|
||||
assertThat(updateModel.getFilter()).isEqualTo(new Document("first_name", "danerys"));
|
||||
assertThat(updateModel.getReplacement().getString("first_name")).isEqualTo("Minsu");
|
||||
assertThat(updateModel.getReplacement().getString("lastName")).isEqualTo("Kim");
|
||||
}
|
||||
|
||||
class SomeDomainType {
|
||||
|
||||
@Id String id;
|
||||
|
||||
Reference in New Issue
Block a user