DATAMONGO-251 - Support geting index information on a collection or mapped class.

This commit is contained in:
Mark Pollack
2011-12-06 02:25:13 -05:00
parent ef6e08d3f4
commit e85f3d3299
8 changed files with 341 additions and 40 deletions

View File

@@ -0,0 +1,128 @@
/*
* Copyright 2011 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;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.springframework.dao.DataAccessException;
import org.springframework.data.mongodb.core.index.IndexDefinition;
import org.springframework.data.mongodb.core.index.IndexInfo;
import org.springframework.data.mongodb.core.query.Order;
import org.springframework.util.Assert;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.MongoException;
/**
* Default implementation of {@link IndexOperations}
* @author Mark Pollack
*
*/
public class DefaultIndexOperations implements IndexOperations {
private MongoTemplate mongoTemplate;
private String collectionName;
public DefaultIndexOperations(MongoTemplate mongoTemplate, String collectionName) {
Assert.notNull(collectionName, "collectionName can not be null");
this.mongoTemplate = mongoTemplate;
this.collectionName = collectionName;
}
public void ensureIndex(final IndexDefinition indexDefinition) {
mongoTemplate.execute(collectionName, new CollectionCallback<Object>() {
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException {
DBObject indexOptions = indexDefinition.getIndexOptions();
if (indexOptions != null) {
collection.ensureIndex(indexDefinition.getIndexKeys(), indexOptions);
} else {
collection.ensureIndex(indexDefinition.getIndexKeys());
}
return null;
}
});
}
public void dropIndex(final String name) {
mongoTemplate.execute(collectionName, new CollectionCallback<Object>() {
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException {
collection.dropIndex(name);
return null;
}
});
}
public void dropAllIndexes() {
dropIndex("*");
}
public void resetIndexCache() {
mongoTemplate.execute(collectionName, new CollectionCallback<Object>() {
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException {
collection.resetIndexCache();
return null;
}
});
}
public List<IndexInfo> getIndexInfo() {
return mongoTemplate.execute(collectionName, new CollectionCallback<List<IndexInfo> >() {
public List<IndexInfo> doInCollection(DBCollection collection) throws MongoException, DataAccessException {
List<DBObject> dbObjectList = collection.getIndexInfo();
return getIndexData(dbObjectList);
//return indexInfoList;
}
private List<IndexInfo> getIndexData(List<DBObject> dbObjectList) {
List<IndexInfo> indexInfoList = new ArrayList<IndexInfo>();
for (DBObject ix : dbObjectList) {
Map<String, Order> keyOrderMap = new LinkedHashMap<String, Order>();
DBObject keyDbObject = (DBObject) ix.get("key");
Iterator entries = keyDbObject.toMap().entrySet().iterator();
while (entries.hasNext()) {
Entry thisEntry = (Entry) entries.next();
String key = thisEntry.getKey().toString();
int value = (Integer) thisEntry.getValue();
if (value == 1) {
keyOrderMap.put(key, Order.ASCENDING);
} else {
keyOrderMap.put(key, Order.DESCENDING);
}
}
String name = ix.get("name").toString();
boolean unique = ix.containsField("unique") ? (Boolean)ix.get("unique") : false;
boolean dropDuplicates = ix.containsField("dropDups") ? (Boolean)ix.get("dropDups") : false;
boolean sparse = ix.containsField("sparse") ? (Boolean) ix.get("sparse") : false;
indexInfoList.add(new IndexInfo(keyOrderMap, name, unique, dropDuplicates, sparse));
}
return indexInfoList;
}
});
}
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright 2011 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;
import java.util.List;
import org.springframework.data.mongodb.core.index.IndexDefinition;
import org.springframework.data.mongodb.core.index.IndexInfo;
/**
* Index operations on a collection
*
* @author Mark Pollack
*
*/
public interface IndexOperations {
/**
* Ensure that an index for the provided {@link IndexDefinition} exists for the collection indicated by the entity
* class. If not it will be created.
*
* @param indexDefinition
* @param entityClass class that determines the collection to use
*/
void ensureIndex(IndexDefinition indexDefinition);
/**
* Drops an index from this collection
* @param name name of index to drop
*/
void dropIndex(String name);
/**
* Drops all indices from this collection
*/
void dropAllIndexes();
/**
* Clears all indices that have not yet been applied to this collection.
*/
void resetIndexCache();
/**
* Returns the index information on the collection
* @return index information on the collection
*/
List<IndexInfo> getIndexInfo();
}

View File

@@ -227,6 +227,18 @@ public interface MongoOperations {
* @param collectionName name of the collection to drop/delete.
*/
void dropCollection(String collectionName);
/**
* Returns the operations that can be performed on indexes
* @return index operations on the named collection
*/
IndexOperations indexOps(String collectionName);
/**
* Returns the operations that can be performed on indexes
* @return index operations on the named collection associated with the given entity class
*/
IndexOperations indexOps(Class<?> entityClass);
/**
* Query for a list of objects of type T from the collection used by the entity class.
@@ -353,23 +365,6 @@ public interface MongoOperations {
*/
<T> GeoResults<T> geoNear(NearQuery near, Class<T> entityClass, String collectionName);
/**
* Ensure that an index for the provided {@link IndexDefinition} exists for the collection indicated by the entity
* class. If not it will be created.
*
* @param indexDefinition
* @param entityClass class that determines the collection to use
*/
void ensureIndex(IndexDefinition indexDefinition, Class<?> entityClass);
/**
* Ensure that an index for the provided {@link IndexDefinition} exists. If not it will be created.
*
* @param index
* @param collectionName
*/
void ensureIndex(IndexDefinition indexDefinition, String collectionName);
/**
* Map the results of an ad-hoc query on the collection for the entity class to a single instance of an object of the
* specified type.

View File

@@ -436,25 +436,13 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
}
});
}
// Indexing methods
public void ensureIndex(IndexDefinition indexDefinition, Class<?> entityClass) {
ensureIndex(indexDefinition, determineCollectionName(entityClass));
public IndexOperations indexOps(String collectionName) {
return new DefaultIndexOperations(this, collectionName);
}
public void ensureIndex(final IndexDefinition indexDefinition, String collectionName) {
execute(collectionName, new CollectionCallback<Object>() {
public Object doInCollection(DBCollection collection) throws MongoException, DataAccessException {
DBObject indexOptions = indexDefinition.getIndexOptions();
if (indexOptions != null) {
collection.ensureIndex(indexDefinition.getIndexKeys(), indexOptions);
} else {
collection.ensureIndex(indexDefinition.getIndexKeys());
}
return null;
}
});
public IndexOperations indexOps(Class<?> entityClass) {
return new DefaultIndexOperations(this, determineCollectionName(entityClass));
}
// Find methods that take a Query to express the query and that return a single object.
@@ -1460,7 +1448,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
return null;
}
private String determineCollectionName(Class<?> entityClass) {
String determineCollectionName(Class<?> entityClass) {
if (entityClass == null) {
throw new InvalidDataAccessApiUsageException(

View File

@@ -0,0 +1,115 @@
/*
* Copyright 2002-2011 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.index;
import java.util.Map;
import org.springframework.data.mongodb.core.query.Order;
public class IndexInfo {
private final Map<String, Order> fieldSpec;
private String name;
private boolean unique = false;
private boolean dropDuplicates = false;
private boolean sparse = false;
public IndexInfo(Map<String, Order> fieldSpec, String name, boolean unique, boolean dropDuplicates, boolean sparse) {
super();
this.fieldSpec = fieldSpec;
this.name = name;
this.unique = unique;
this.dropDuplicates = dropDuplicates;
this.sparse = sparse;
}
public Map<String, Order> getFieldSpec() {
return fieldSpec;
}
public String getName() {
return name;
}
public boolean isUnique() {
return unique;
}
public boolean isDropDuplicates() {
return dropDuplicates;
}
public boolean isSparse() {
return sparse;
}
@Override
public String toString() {
return "IndexInfo [fieldSpec=" + fieldSpec + ", name=" + name + ", unique=" + unique + ", dropDuplicates="
+ dropDuplicates + ", sparse=" + sparse + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (dropDuplicates ? 1231 : 1237);
result = prime * result + ((fieldSpec == null) ? 0 : fieldSpec.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + (sparse ? 1231 : 1237);
result = prime * result + (unique ? 1231 : 1237);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
IndexInfo other = (IndexInfo) obj;
if (dropDuplicates != other.dropDuplicates)
return false;
if (fieldSpec == null) {
if (other.fieldSpec != null)
return false;
} else if (!fieldSpec.equals(other.fieldSpec))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (sparse != other.sparse)
return false;
if (unique != other.unique)
return false;
return true;
}
/**
* [{ "v" : 1 , "key" : { "_id" : 1} , "ns" : "database.person" , "name" : "_id_"},
{ "v" : 1 , "key" : { "age" : -1} , "ns" : "database.person" , "name" : "age_-1" , "unique" : true , "dropDups" : true}]
*/
}

View File

@@ -86,7 +86,7 @@ class IndexEnsuringQueryCreationListener implements QueryCreationListener<PartTr
}
MongoEntityInformation<?, ?> metadata = query.getQueryMethod().getEntityInformation();
operations.ensureIndex(index, metadata.getCollectionName());
operations.indexOps(metadata.getCollectionName()).ensureIndex(index);
LOG.debug(String.format("Created %s!", index));
}

View File

@@ -47,6 +47,7 @@ import org.springframework.data.mongodb.core.convert.CustomConversions;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.index.Index;
import org.springframework.data.mongodb.core.index.Index.Duplicates;
import org.springframework.data.mongodb.core.index.IndexInfo;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Order;
@@ -171,11 +172,10 @@ public class MongoTemplateTests {
p2.setAge(40);
template.insert(p2);
template.ensureIndex(new Index().on("age", Order.DESCENDING).unique(Duplicates.DROP), Person.class);
template.indexOps(Person.class).ensureIndex(new Index().on("age", Order.DESCENDING).unique(Duplicates.DROP));
DBCollection coll = template.getCollection(template.getCollectionName(Person.class));
List<DBObject> indexInfo = coll.getIndexInfo();
assertThat(indexInfo.size(), is(2));
String indexKey = null;
boolean unique = false;
@@ -190,6 +190,16 @@ public class MongoTemplateTests {
assertThat(indexKey, is("{ \"age\" : -1}"));
assertThat(unique, is(true));
assertThat(dropDupes, is(true));
List<IndexInfo> indexInfoList = template.indexOps(Person.class).getIndexInfo();
System.out.println(indexInfoList);
assertThat(indexInfoList.size(), is(2));
IndexInfo ii = indexInfoList.get(1);
assertThat(ii.isUnique(), is(true));
assertThat(ii.isDropDuplicates(), is(true));
assertThat(ii.isSparse(), is(false));
assertThat(ii.getFieldSpec().containsKey("age"), is(true));
assertThat(ii.getFieldSpec().containsValue(Order.DESCENDING), is(true));
}
@Test

View File

@@ -73,7 +73,7 @@ public class GeoSpatialTests {
applicationContext = new AnnotationConfigApplicationContext(GeoSpatialAppConfig.class);
template = applicationContext.getBean(MongoTemplate.class);
template.setWriteConcern(WriteConcern.FSYNC_SAFE);
template.ensureIndex(new GeospatialIndex("location"), Venue.class);
template.indexOps(Venue.class).ensureIndex(new GeospatialIndex("location"));
indexCreated();
addVenues();
parser = new SpelExpressionParser();