DATAMONGO-429 - Fixed handling of nested arrays in QueryMapper.
QueryMapper now correctly transforms arrays not concreting them into BasicDBObjects anymore.
This commit is contained in:
@@ -25,10 +25,12 @@ import org.bson.types.ObjectId;
|
||||
import org.springframework.core.convert.ConversionException;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.mongodb.BasicDBList;
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
@@ -40,6 +42,9 @@ import com.mongodb.DBObject;
|
||||
*/
|
||||
public class QueryMapper {
|
||||
|
||||
private static final List<String> DEFAULT_ID_NAMES = Arrays.asList("id", "_id");
|
||||
private static final String N_OR_PATTERN = "\\$.*or";
|
||||
|
||||
private final ConversionService conversionService;
|
||||
private final MongoConverter converter;
|
||||
|
||||
@@ -58,8 +63,8 @@ public class QueryMapper {
|
||||
* Replaces the property keys used in the given {@link DBObject} with the appropriate keys by using the
|
||||
* {@link PersistentEntity} metadata.
|
||||
*
|
||||
* @param query
|
||||
* @param entity
|
||||
* @param query must not be {@literal null}.
|
||||
* @param entity can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public DBObject getMappedObject(DBObject query, MongoPersistentEntity<?> entity) {
|
||||
@@ -67,8 +72,11 @@ public class QueryMapper {
|
||||
DBObject newDbo = new BasicDBObject();
|
||||
|
||||
for (String key : query.keySet()) {
|
||||
|
||||
MongoPersistentEntity<?> nestedEntity = getNestedEntity(entity, key);
|
||||
String newKey = key;
|
||||
Object value = query.get(key);
|
||||
|
||||
if (isIdKey(key, entity)) {
|
||||
if (value instanceof DBObject) {
|
||||
DBObject valueDbo = (DBObject) value;
|
||||
@@ -80,34 +88,51 @@ public class QueryMapper {
|
||||
}
|
||||
valueDbo.put(inKey, ids.toArray(new Object[ids.size()]));
|
||||
} else {
|
||||
value = getMappedObject((DBObject) value, entity);
|
||||
value = getMappedObject((DBObject) value, nestedEntity);
|
||||
}
|
||||
} else {
|
||||
value = convertId(value);
|
||||
}
|
||||
newKey = "_id";
|
||||
} else if (key.startsWith("$") && key.endsWith("or")) {
|
||||
} else if (key.matches(N_OR_PATTERN)) {
|
||||
// $or/$nor
|
||||
Iterable<?> conditions = (Iterable<?>) value;
|
||||
BasicBSONList newConditions = new BasicBSONList();
|
||||
Iterator<?> iter = conditions.iterator();
|
||||
while (iter.hasNext()) {
|
||||
newConditions.add(getMappedObject((DBObject) iter.next(), entity));
|
||||
newConditions.add(getMappedObject((DBObject) iter.next(), nestedEntity));
|
||||
}
|
||||
value = newConditions;
|
||||
} else if (key.equals("$ne")) {
|
||||
value = convertId(value);
|
||||
} else if (value instanceof DBObject) {
|
||||
newDbo.put(newKey, getMappedObject((DBObject) value, entity));
|
||||
continue;
|
||||
}
|
||||
|
||||
newDbo.put(newKey, converter.convertToMongoType(value));
|
||||
newDbo.put(newKey, convertSimpleOrDBObject(value, nestedEntity));
|
||||
}
|
||||
|
||||
return newDbo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retriggers mapping if the given source is a {@link DBObject} or simply invokes the
|
||||
*
|
||||
* @param source
|
||||
* @param entity
|
||||
* @return
|
||||
*/
|
||||
private Object convertSimpleOrDBObject(Object source, MongoPersistentEntity<?> entity) {
|
||||
|
||||
if (source instanceof BasicDBList) {
|
||||
return converter.convertToMongoType(source);
|
||||
}
|
||||
|
||||
if (source instanceof DBObject) {
|
||||
return getMappedObject((DBObject) source, entity);
|
||||
}
|
||||
|
||||
return converter.convertToMongoType(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given key will be considered an id key.
|
||||
*
|
||||
@@ -122,7 +147,19 @@ public class QueryMapper {
|
||||
return idProperty.getName().equals(key) || idProperty.getFieldName().equals(key);
|
||||
}
|
||||
|
||||
return Arrays.asList("id", "_id").contains(key);
|
||||
return DEFAULT_ID_NAMES.contains(key);
|
||||
}
|
||||
|
||||
private MongoPersistentEntity<?> getNestedEntity(MongoPersistentEntity<?> entity, String key) {
|
||||
|
||||
MongoPersistentProperty property = entity == null ? null : entity.getPersistentProperty(key);
|
||||
|
||||
if (property == null || !property.isEntity()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> context = converter.getMappingContext();
|
||||
return context.getPersistentEntity(property);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -32,10 +32,9 @@ import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mongodb.MongoDbFactory;
|
||||
import org.springframework.data.mongodb.core.Person;
|
||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||
import org.springframework.data.mongodb.core.convert.QueryMapper;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||
import org.springframework.data.mongodb.core.query.BasicQuery;
|
||||
import org.springframework.data.mongodb.core.query.Criteria;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
|
||||
@@ -188,6 +187,18 @@ public class QueryMapperUnitTests {
|
||||
assertThat(result.get("bar"), is(notNullValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAMONGO-429
|
||||
*/
|
||||
@Test
|
||||
public void transformsArraysCorrectly() {
|
||||
|
||||
Query query = new BasicQuery("{ 'tags' : { '$all' : [ 'green', 'orange']}}");
|
||||
|
||||
DBObject result = mapper.getMappedObject(query.getQueryObject(), null);
|
||||
assertThat(result, is(query.getQueryObject()));
|
||||
}
|
||||
|
||||
class Sample {
|
||||
|
||||
@Id
|
||||
|
||||
Reference in New Issue
Block a user