DATAMONGO-2155 - Introduce UpdateDefinition.

Original pull request: #625.
This commit is contained in:
Christoph Strobl
2018-12-04 15:05:58 +01:00
committed by Mark Paluch
parent 9f8d081ef3
commit a759dff5fd
6 changed files with 125 additions and 21 deletions

View File

@@ -24,6 +24,7 @@ import java.util.List;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.core.query.UpdateDefinition;
import org.springframework.data.util.StreamUtils;
import com.mongodb.client.model.Filters;
@@ -86,17 +87,55 @@ public class MappedDocument {
return new MappedUpdate(Update.fromDocument(document, ID_FIELD));
}
public class MappedUpdate extends Update {
/**
* An {@link UpdateDefinition} that indicates that the {@link #getUpdateObject() update object} has already been
* mapped to the specific domain type.
*
* @author Christoph Strobl
* @since 2.2
*/
public class MappedUpdate implements UpdateDefinition {
private final Update delegate;
public MappedUpdate(Update delegate) {
MappedUpdate(Update delegate) {
this.delegate = delegate;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.query.UpdateDefinition#getUpdateObject()
*/
@Override
public Document getUpdateObject() {
return delegate.getUpdateObject();
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.query.UpdateDefinition#modifies(java.lang.String)
*/
@Override
public boolean modifies(String key) {
return delegate.modifies(key);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.query.UpdateDefinition#incVersion(java.lang.String)
*/
@Override
public void incVersion(String version) {
delegate.incVersion(version);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.query.UpdateDefinition#isIsolated()
*/
@Override
public Boolean isIsolated() {
return delegate.isIsolated();
}
}
}

View File

@@ -94,6 +94,7 @@ import org.springframework.data.mongodb.core.query.Meta;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.core.query.UpdateDefinition;
import org.springframework.data.mongodb.core.validation.Validator;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.util.CloseableIterator;
@@ -1555,7 +1556,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
return doUpdate(collectionName, query, update, entityClass, false, true);
}
protected UpdateResult doUpdate(final String collectionName, final Query query, final Update update,
protected UpdateResult doUpdate(final String collectionName, final Query query, final UpdateDefinition update,
@Nullable final Class<?> entityClass, final boolean upsert, final boolean multi) {
Assert.notNull(collectionName, "CollectionName must not be null!");
@@ -1616,12 +1617,12 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
});
}
private void increaseVersionForUpdateIfNecessary(@Nullable MongoPersistentEntity<?> persistentEntity, Update update) {
private void increaseVersionForUpdateIfNecessary(@Nullable MongoPersistentEntity<?> persistentEntity, UpdateDefinition update) {
if (persistentEntity != null && persistentEntity.hasVersionProperty()) {
String versionFieldName = persistentEntity.getRequiredVersionProperty().getFieldName();
if (!update.modifies(versionFieldName)) {
update.inc(versionFieldName, 1L);
update.incVersion(versionFieldName);
}
}
}

View File

@@ -92,6 +92,7 @@ import org.springframework.data.mongodb.core.query.Meta;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.core.query.UpdateDefinition;
import org.springframework.data.mongodb.core.validation.Validator;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.util.Optionals;
@@ -1611,7 +1612,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
return doUpdate(collectionName, query, update, entityClass, false, true);
}
protected Mono<UpdateResult> doUpdate(String collectionName, Query query, @Nullable Update update,
protected Mono<UpdateResult> doUpdate(String collectionName, Query query, @Nullable UpdateDefinition update,
@Nullable Class<?> entityClass, boolean upsert, boolean multi) {
MongoPersistentEntity<?> entity = entityClass == null ? null : getPersistentEntity(entityClass);
@@ -1668,12 +1669,13 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
return result.next();
}
private void increaseVersionForUpdateIfNecessary(@Nullable MongoPersistentEntity<?> persistentEntity, Update update) {
private void increaseVersionForUpdateIfNecessary(@Nullable MongoPersistentEntity<?> persistentEntity,
UpdateDefinition update) {
if (persistentEntity != null && persistentEntity.hasVersionProperty()) {
String versionFieldName = persistentEntity.getRequiredVersionProperty().getFieldName();
if (!update.modifies(versionFieldName)) {
update.inc(versionFieldName, 1L);
update.incVersion(versionFieldName);
}
}
}

View File

@@ -48,7 +48,7 @@ import org.springframework.util.StringUtils;
* @author Mark Paluch
* @author Pavel Vodrazka
*/
public class Update {
public class Update implements UpdateDefinition {
public enum Position {
LAST, FIRST
@@ -155,6 +155,15 @@ public class Update {
return this;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.query.UpdateDefinition#incVersion()
*/
@Override
public void incVersion(String key) {
inc(key, 1L);
}
/**
* Update using the {@literal $push} update modifier
*
@@ -390,14 +399,18 @@ public class Update {
return this;
}
/**
* @return {@literal true} if update isolated is set.
* @since 2.0
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.query.UpdateDefinition#isIsolated()
*/
public Boolean isIsolated() {
return isolated;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.query.UpdateDefinition#getUpdateObject()
*/
public Document getUpdateObject() {
return new Document(modifierOps);
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.core.query;
import org.bson.Document;
/**
* Interface fixing must have operations for {@literal updates} as implemented via {@link Update}.
*
* @author Christoph Strobl
* @since 2.2
*/
public interface UpdateDefinition {
/**
* If {@literal true} prevents a write operation that affects <strong>multiple</strong> documents from yielding to
* other reads or writes once the first document is written. <br />
*
* @return {@literal true} if update isolated is set.
*/
Boolean isIsolated();
/**
* @return the actual update in its native {@link Document} format. Never {@literal null}.
*/
Document getUpdateObject();
/**
* Check if a given {@literal key} is modified by applying the update.
*
* @param key must not be {@literal null}.
* @return {@literal true} if the actual {@link UpdateDefinition} attempts to modify the given {@literal key}.
*/
boolean modifies(String key);
/**
* Bump the version of a given {@literal key} by {@code 1}.
*
* @param key must not be {@literal null}.
*/
void incVersion(String key);
}

View File

@@ -537,6 +537,8 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests {
@Test // DATAMONGO-1639
public void beforeConvertEventForUpdateSeesNextVersion() {
when(updateResult.getModifiedCount()).thenReturn(1L);
final VersionedEntity entity = new VersionedEntity();
entity.id = 1;
entity.version = 0;
@@ -553,15 +555,7 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests {
template.setApplicationContext(context);
MongoTemplate spy = Mockito.spy(template);
UpdateResult result = mock(UpdateResult.class);
doReturn(1L).when(result).getModifiedCount();
doReturn(result).when(spy).doUpdate(anyString(), any(Query.class), any(Update.class), any(Class.class),
anyBoolean(), anyBoolean());
spy.save(entity);
template.save(entity);
}
@Test // DATAMONGO-1447