package org.mongodb.morphia;
import com.mongodb.MapReduceCommand.OutputType;
import com.mongodb.MapReduceOutput;
import org.mongodb.morphia.annotations.NotSaved;
import org.mongodb.morphia.annotations.Transient;
import org.mongodb.morphia.logging.Logger;
import org.mongodb.morphia.logging.MorphiaLoggerFactory;
import org.mongodb.morphia.mapping.Mapper;
import org.mongodb.morphia.mapping.MappingException;
import org.mongodb.morphia.mapping.cache.EntityCache;
import org.mongodb.morphia.query.MorphiaIterator;
import org.mongodb.morphia.query.Query;
import java.util.Iterator;
/**
* Stores the results of a map reduce operation
*
* @param <T> the type of the results
*/
@NotSaved
@SuppressWarnings("deprecation")
public class MapreduceResults<T> implements Iterable<T> {
private static final Logger LOG = MorphiaLoggerFactory.get(MapreduceResults.class);
private final Stats counts = new Stats();
private MapReduceOutput output;
private String outputCollectionName;
private OutputType outputType;
private Query<T> query;
@Transient
private Class<T> clazz;
@Transient
private Mapper mapper;
@Transient
private EntityCache cache;
private Datastore datastore;
/**
* Creates a results instance for the given output
*
* @param output the output of the operation
*/
public MapreduceResults(final MapReduceOutput output) {
this.output = output;
outputCollectionName = output.getCollectionName();
}
/**
* @return the query to use against these results
*/
public Query<T> createQuery() {
if (outputType == OutputType.INLINE) {
throw new MappingException("No collection available for inline mapreduce jobs");
}
return query.cloneQuery();
}
/**
* @return the Stats for the operation
*/
public Stats getCounts() {
return counts;
}
/**
* @return the duration of the operation
*/
public long getElapsedMillis() {
return output.getDuration();
}
/**
* @return will always return null
*/
@Deprecated
public String getError() {
LOG.warning("MapreduceResults.getError() will always return null.");
return null;
}
/**
* Creates an Iterator over the results of the operation. This method should probably not be called directly as it requires more
* context to use properly. Using {@link #iterator()} will return the proper Iterator regardless of the type of map reduce operation
* performed.
*
* @return the Iterator
* @see MapreduceType
*/
public Iterator<T> getInlineResults() {
return new MorphiaIterator<T, T>(datastore, output.results().iterator(), mapper, clazz, null, cache);
}
/**
* @return the type of the operation
* @deprecated use {@link #getOutputType()} instead
*/
@Deprecated
public MapreduceType getType() {
if (outputType == OutputType.REDUCE) {
return MapreduceType.REDUCE;
} else if (outputType == OutputType.MERGE) {
return MapreduceType.MERGE;
} else if (outputType == OutputType.INLINE) {
return MapreduceType.INLINE;
} else {
return MapreduceType.REPLACE;
}
}
@Deprecated
void setType(final MapreduceType type) {
this.outputType = type.toOutputType();
}
/**
* @return the type of the operation
* @since 1.3
*/
public OutputType getOutputType() {
return outputType;
}
/**
* Sets the output type for this mapreduce job
*
* @param outputType the output type
* @since 1.3
*/
public void setOutputType(final OutputType outputType) {
this.outputType = outputType;
}
/**
* @return will always return true
*/
@Deprecated
public boolean isOk() {
LOG.warning("MapreduceResults.isOk() will always return true.");
return true;
}
/**
* Creates an Iterator over the results of the operation.
*
* @return the Iterator
*/
@Override
public Iterator<T> iterator() {
return outputType == OutputType.INLINE ? getInlineResults() : createQuery().fetch().iterator();
}
/**
* Sets the required options when the operation type was INLINE
*
* @param datastore the Datastore to use when fetching this reference
* @param clazz the type of the results
* @param mapper the mapper to use
* @param cache the cache of entities seen so far
* @see OutputType
*/
public void setInlineRequiredOptions(final Datastore datastore, final Class<T> clazz, final Mapper mapper, final EntityCache cache) {
this.mapper = mapper;
this.datastore = datastore;
this.clazz = clazz;
this.cache = cache;
}
/**
* This class represents various statistics about a map reduce operation
*/
public class Stats {
/**
* @return the emit count of the operation
*/
public int getEmitCount() {
return output.getEmitCount();
}
/**
* @return the input count of the operation
*/
public int getInputCount() {
return output.getInputCount();
}
/**
* @return the output count of the operation
*/
public int getOutputCount() {
return output.getOutputCount();
}
}
String getOutputCollectionName() {
return outputCollectionName;
}
void setQuery(final Query<T> query) {
this.query = query;
}
}