DATAMONGO-2365 - Pass on index name to query hint.
Original pull request: #828.
This commit is contained in:
committed by
Mark Paluch
parent
c21b35973d
commit
0bc0fff24e
@@ -114,6 +114,7 @@ import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.mongodb.core.query.UpdateDefinition;
|
||||
import org.springframework.data.mongodb.core.query.UpdateDefinition.ArrayFilter;
|
||||
import org.springframework.data.mongodb.core.validation.Validator;
|
||||
import org.springframework.data.mongodb.util.BsonUtils;
|
||||
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
|
||||
import org.springframework.data.util.CloseableIterator;
|
||||
import org.springframework.data.util.Optionals;
|
||||
@@ -1156,7 +1157,13 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
|
||||
options.skip((int) query.getSkip());
|
||||
}
|
||||
if (StringUtils.hasText(query.getHint())) {
|
||||
options.hint(Document.parse(query.getHint()));
|
||||
|
||||
String hint = query.getHint();
|
||||
if(BsonUtils.isJsonDocument(hint)) {
|
||||
options = options.hint(BsonUtils.parse(hint, mongoDbFactory));
|
||||
} else {
|
||||
options = options.hintString(hint);
|
||||
}
|
||||
}
|
||||
|
||||
Document document = queryMapper.getMappedObject(query.getQueryObject(),
|
||||
@@ -3276,7 +3283,14 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(query.getHint())) {
|
||||
cursorToUse = cursorToUse.hint(Document.parse(query.getHint()));
|
||||
|
||||
String hint = query.getHint();
|
||||
|
||||
if(BsonUtils.isJsonDocument(hint)) {
|
||||
cursorToUse = cursorToUse.hint(BsonUtils.parse(hint, mongoDbFactory));
|
||||
} else {
|
||||
cursorToUse = cursorToUse.hintString(hint);
|
||||
}
|
||||
}
|
||||
|
||||
if (meta.hasValues()) {
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.mongodb.client.result.InsertOneResult;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.mongodb.util.BsonUtils;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.function.Tuple2;
|
||||
@@ -1279,7 +1280,13 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
options.skip((int) query.getSkip());
|
||||
}
|
||||
if (StringUtils.hasText(query.getHint())) {
|
||||
options.hint(Document.parse(query.getHint()));
|
||||
|
||||
String hint = query.getHint();
|
||||
if(BsonUtils.isJsonDocument(hint)) {
|
||||
options = options.hint(BsonUtils.parse(hint, mongoDatabaseFactory));
|
||||
} else {
|
||||
options = options.hintString(hint);
|
||||
}
|
||||
}
|
||||
|
||||
operations.forType(entityClass).getCollation(query).map(Collation::toMongoCollation) //
|
||||
@@ -3276,7 +3283,14 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(query.getHint())) {
|
||||
findPublisherToUse = findPublisherToUse.hint(Document.parse(query.getHint()));
|
||||
|
||||
String hint = query.getHint();
|
||||
|
||||
if(BsonUtils.isJsonDocument(hint)) {
|
||||
findPublisherToUse = findPublisherToUse.hint(BsonUtils.parse(hint, mongoDatabaseFactory));
|
||||
} else {
|
||||
findPublisherToUse = findPublisherToUse.hintString(hint);
|
||||
}
|
||||
}
|
||||
|
||||
if (meta.hasValues()) {
|
||||
|
||||
@@ -141,14 +141,13 @@ public class Query {
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the query to use the given hint when being executed. {@code hint} is parsed as {@link Document}.
|
||||
* Configures the query to use the given hint when being executed. The {@code hint} can either be an index name or a
|
||||
* json {@link Document} representation.
|
||||
*
|
||||
* @param hint must not be {@literal null} or empty.
|
||||
* @return
|
||||
* @see Document#parse(String)
|
||||
* @deprecated since 2.2, use {@link #withHint(Document)}
|
||||
*/
|
||||
@Deprecated
|
||||
public Query withHint(String hint) {
|
||||
|
||||
Assert.hasText(hint, "Hint must not be empty or null!");
|
||||
@@ -312,10 +311,8 @@ public class Query {
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @deprecated since 2.2. Return type to be changed to {@link Document}.
|
||||
*/
|
||||
@Nullable
|
||||
@Deprecated
|
||||
public String getHint() {
|
||||
return hint;
|
||||
}
|
||||
|
||||
@@ -25,11 +25,13 @@ import java.util.stream.StreamSupport;
|
||||
|
||||
import org.bson.BsonValue;
|
||||
import org.bson.Document;
|
||||
import org.bson.codecs.DocumentCodec;
|
||||
import org.bson.conversions.Bson;
|
||||
import org.bson.json.JsonParseException;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.mongodb.CodecRegistryProvider;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -175,6 +177,50 @@ public class BsonUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given String looks like {@link Document#parse(String) parsable} json.
|
||||
*
|
||||
* @param value can be {@literal null}.
|
||||
* @return {@literal true} if the given value looks like a json document.
|
||||
* @since 3.0
|
||||
*/
|
||||
public static boolean isJsonDocument(@Nullable String value) {
|
||||
return StringUtils.hasText(value) && (value.startsWith("{") && value.endsWith("}"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given String looks like {@link org.bson.BsonArray#parse(String) parsable} json array.
|
||||
*
|
||||
* @param value can be {@literal null}.
|
||||
* @return {@literal true} if the given value looks like a json array.
|
||||
* @since 3.0
|
||||
*/
|
||||
public static boolean isJsonArray(@Nullable String value) {
|
||||
return StringUtils.hasText(value) && (value.startsWith("[") && value.endsWith("]"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given {@literal json} to {@link Document} applying transformations as specified by a potentially given
|
||||
* {@link org.bson.codecs.Codec}.
|
||||
*
|
||||
* @param json must not be {@literal null}.
|
||||
* @param codecRegistryProvider can be {@literal null}. In that case the default {@link DocumentCodec} is used.
|
||||
* @return never {@literal null}.
|
||||
* @throws IllegalArgumentException if the required argument is {@literal null}.
|
||||
* @since 3.0
|
||||
*/
|
||||
public static Document parse(String json, @Nullable CodecRegistryProvider codecRegistryProvider) {
|
||||
|
||||
Assert.notNull(json, "Json must not be null!");
|
||||
|
||||
if (codecRegistryProvider == null) {
|
||||
return Document.parse(json);
|
||||
}
|
||||
|
||||
return Document.parse(json, codecRegistryProvider.getCodecFor(Document.class)
|
||||
.orElseGet(() -> new DocumentCodec(codecRegistryProvider.getCodecRegistry())));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String toJson(@Nullable Object value) {
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import static org.mockito.Mockito.*;
|
||||
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
|
||||
import static org.springframework.data.mongodb.test.util.Assertions.*;
|
||||
|
||||
import com.mongodb.MongoClientSettings;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigInteger;
|
||||
@@ -158,6 +159,7 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests {
|
||||
when(findIterable.iterator()).thenReturn(cursor);
|
||||
when(factory.getMongoDatabase()).thenReturn(db);
|
||||
when(factory.getExceptionTranslator()).thenReturn(exceptionTranslator);
|
||||
when(factory.getCodecRegistry()).thenReturn(MongoClientSettings.getDefaultCodecRegistry());
|
||||
when(db.getCollection(any(String.class), eq(Document.class))).thenReturn(collection);
|
||||
when(db.runCommand(any(), any(Class.class))).thenReturn(commandResultDocument);
|
||||
when(collection.find(any(org.bson.Document.class), any(Class.class))).thenReturn(findIterable);
|
||||
@@ -955,6 +957,17 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests {
|
||||
assertThat(options.getValue().getHint()).isEqualTo(queryHint);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2365
|
||||
public void countShouldApplyQueryHintAsIndexNameIfPresent() {
|
||||
|
||||
template.count(new BasicQuery("{}").withHint("idx-1"), AutogenerateableId.class);
|
||||
|
||||
ArgumentCaptor<CountOptions> options = ArgumentCaptor.forClass(CountOptions.class);
|
||||
verify(collection).countDocuments(any(), options.capture());
|
||||
|
||||
assertThat(options.getValue().getHintString()).isEqualTo("idx-1");
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-1733
|
||||
public void appliesFieldsWhenInterfaceProjectionIsClosedAndQueryDoesNotDefineFields() {
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import static org.springframework.data.mongodb.core.query.Query.*;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.mongodb.MongoClientSettings;
|
||||
import org.bson.Document;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -53,6 +54,7 @@ public class QueryCursorPreparerUnitTests {
|
||||
public void setUp() {
|
||||
|
||||
when(factory.getExceptionTranslator()).thenReturn(exceptionTranslatorMock);
|
||||
when(factory.getCodecRegistry()).thenReturn(MongoClientSettings.getDefaultCodecRegistry());
|
||||
when(cursor.batchSize(anyInt())).thenReturn(cursor);
|
||||
when(cursor.comment(anyString())).thenReturn(cursor);
|
||||
when(cursor.maxTime(anyLong(), any())).thenReturn(cursor);
|
||||
@@ -70,6 +72,15 @@ public class QueryCursorPreparerUnitTests {
|
||||
verify(cursor).hint(new Document("age", 1));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2365
|
||||
public void appliesIndexNameAsHintCorrectly() {
|
||||
|
||||
Query query = query(where("foo").is("bar")).withHint("idx-1");
|
||||
prepare(query);
|
||||
|
||||
verify(cursor).hintString("idx-1");
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2319
|
||||
public void appliesDocumentHintsCorrectly() {
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
|
||||
|
||||
import com.mongodb.MongoClientSettings;
|
||||
import lombok.Data;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
@@ -128,6 +129,7 @@ public class ReactiveMongoTemplateUnitTests {
|
||||
public void beforeEach() {
|
||||
|
||||
when(factory.getExceptionTranslator()).thenReturn(exceptionTranslator);
|
||||
when(factory.getCodecRegistry()).thenReturn(MongoClientSettings.getDefaultCodecRegistry());
|
||||
when(factory.getMongoDatabase()).thenReturn(db);
|
||||
when(db.getCollection(any())).thenReturn(collection);
|
||||
when(db.getCollection(any(), any())).thenReturn(collection);
|
||||
@@ -434,6 +436,17 @@ public class ReactiveMongoTemplateUnitTests {
|
||||
assertThat(options.getValue().getHint()).isEqualTo(queryHint);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2365
|
||||
public void countShouldApplyQueryHintAsIndexNameIfPresent() {
|
||||
|
||||
template.count(new Query().withHint("idx-1"), Person.class, "star-wars").subscribe();
|
||||
|
||||
ArgumentCaptor<CountOptions> options = ArgumentCaptor.forClass(CountOptions.class);
|
||||
verify(collection).countDocuments(any(), options.capture());
|
||||
|
||||
assertThat(options.getValue().getHintString()).isEqualTo("idx-1");
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2215
|
||||
public void updateShouldApplyArrayFilters() {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user