package cz.cuni.mff.d3s.been.objectrepository.mongo;
import java.util.Set;
import java.util.regex.Pattern;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBObject;
import cz.cuni.mff.d3s.been.core.persistence.EntityID;
import cz.cuni.mff.d3s.been.persistence.DAOException;
import cz.cuni.mff.d3s.been.persistence.QueryRedactor;
import cz.cuni.mff.d3s.been.storage.QueryExecutor;
/**
* A skeletal redactor for mongo queries. Takes care of filter construction.
* Query construction itself is left to subclasses to handle.
*
* @author darklight
*/
abstract class MongoQueryRedactor implements QueryRedactor {
private static final String NEQ_OPERATOR = "$ne";
private static final String ABOVE_OPERATOR = "$gte";
private static final String BELOW_OPERATOR = "$lt";
/**
* A projection that ensures the <code>_id</code> attribute generated by
* MongoDB is not propagated to query results
*/
private static final DBObject NO_DBID_MAPPING;
static {
NO_DBID_MAPPING = new BasicDBObject("_id", 0);
}
private final DBObject filter;
private final DBObject mapping;
private final EntityID entityID;
/**
* Creates new MongoQueryRedactor
*
* @param entityID
* target's EntityID
*/
MongoQueryRedactor(EntityID entityID) {
this.entityID = entityID;
this.filter = new BasicDBObject();
this.mapping = new BasicDBObject();
}
@Override
public void equalitySelector(String attributeName, Object value) {
filter.put(attributeName, value);
}
@Override
public void inequalitySelector(String attributeName, Object value) {
final DBObject neq = new BasicDBObject();
neq.put(NEQ_OPERATOR, value);
filter.put(attributeName, neq);
}
@Override
public void patternSelector(String attributeName, String pattern) {
filter.put(attributeName, Pattern.compile(pattern));
}
@Override
public void aboveSelector(String attributeName, Object lowBound) {
final DBObject ge = new BasicDBObject();
ge.put(ABOVE_OPERATOR, lowBound);
filter.put(attributeName, ge);
}
@Override
public void belowSelector(String attributeName, Object highBound) {
final DBObject lt = new BasicDBObject();
lt.put(BELOW_OPERATOR, highBound);
filter.put(attributeName, lt);
}
@Override
public void intervalSelector(String attributeName, Object lowBound, Object highBound) {
final DBObject between = new BasicDBObject();
between.put(ABOVE_OPERATOR, lowBound);
between.put(BELOW_OPERATOR, highBound);
filter.put(attributeName, between);
}
/**
* Return the filter to subclasses for query-specific handling
*
* @return The filter
*/
protected DBObject getFilter() {
return filter;
}
/**
* Return the attribute mapping to subclasses for query-specific handling
*
* @return The attribute mapping
*/
protected DBObject getMapping() {
mapping.putAll(NO_DBID_MAPPING);
return mapping;
}
/**
* Return the path to the objects targeted by the query.
*
* @return The Entity ID (serves as path)
*/
protected EntityID getPath() {
return entityID;
}
/**
* Factory method for {@link QueryExecutor} instances, with inferred
* {@link DB} instance
*
* @param db
* Database to use for querying
*
* @return The {@link QueryExecutor}
*
* @throws DAOException
* When a query cannot be constructed from provided information
*/
public abstract QueryExecutor createExecutor(DB db) throws DAOException;
@Override
public void map(Set<String> attributes) {
for (String attribute : attributes) {
mapping.put(attribute, 1);
}
}
}