Browse Source

DATAMONGO-429 - Fixed handling of nested arrays in QueryMapper.

QueryMapper now correctly transforms arrays not concreting them into BasicDBObjects anymore.
pull/2/merge
Oliver Gierke 14 years ago
parent
commit
3dfc59bfb8
  1. 57
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java
  2. 15
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java

57
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java

@ -25,10 +25,12 @@ import org.bson.types.ObjectId; @@ -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; @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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);
}
/**

15
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java

@ -32,10 +32,9 @@ import org.mockito.runners.MockitoJUnitRunner; @@ -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 { @@ -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

Loading…
Cancel
Save