package er.neo4jadaptor.query.neo4j_by_pk;
import java.util.Collection;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.PropertyContainer;
import com.webobjects.eoaccess.EOAttribute;
import com.webobjects.eoaccess.EOEntity;
import com.webobjects.eoaccess.EORelationship;
import com.webobjects.eocontrol.EOQualifier;
import er.neo4jadaptor.query.Filter;
import er.neo4jadaptor.query.Results;
import er.neo4jadaptor.query.neo4j_by_pk.results.NodesRelatedTo;
import er.neo4jadaptor.query.neo4j_by_pk.results.NodesWithIds;
import er.neo4jadaptor.query.neo4j_eval.EvaluatingFilter;
import er.neo4jadaptor.storage.neo4j.RelationshipStore;
import er.neo4jadaptor.utils.EOUtilities;
/**
* Filters nodes being closely related to some set of nodes with known IDs. If it's known that all possible result candidates
* have relationship to one known node then it is faster to get all of that nodes and evaluate them using even reasonably
* slow technique rather than performing Lucene search which might be fast but taking around constant time therefore
* making it not the fastest for small result sets.
*
* @author Jedrzej Sobanski
*
* @param <T>
*/
public class ByPrimaryKeyFilter<T extends PropertyContainer> extends Filter<T> {
public ByPrimaryKeyFilter() {
}
@SuppressWarnings("unchecked")
@Override
public Results<T> doFilter(GraphDatabaseService db, EOEntity entity, EOQualifier qualifier) {
// check if there are any node ids specified, if yes then go to those nodes directly
ValueMap map = new ValueMap(entity, qualifier);
if (map.getAttributes().size() == 1) {
EOAttribute att = map.getMostFrequentAttribute();
EORelationship rel = EOUtilities.getRelationshipForSourceAttribute(entity, att);
Collection<?> values = map.getValuesForAttribute(att);
boolean containsNulls = values.contains(null);
if (! containsNulls) {
if (entity.primaryKeyAttributes().size() == 1 && att.equals(EOUtilities.primaryKeyAttribute(entity))) {
// it's primary key
Results<T> filter = (Results<T>) primaryKeyReference(db, (Collection<? extends Number>) values);
return new EvaluatingFilter<>(filter, entity, qualifier);
}
if (rel != null
&& ! RelationshipStore.shouldBeStoredAsRelationship(rel.entity())
&& ! RelationshipStore.shouldBeStoredAsRelationship(rel.destinationEntity()) ) {
// it's using foreign key
Results<T> filter = (Results<T>) foreignKeyReference(db, rel, (Collection<? extends Number>) values);
return new EvaluatingFilter<>(filter, entity, qualifier);
}
}
}
// responsibility chain delegation
return successor.doFilter(db, entity, qualifier);
}
private Results<Node> primaryKeyReference(GraphDatabaseService db, Collection<? extends Number> values) {
return new NodesWithIds(db, values);
}
private Results<Node> foreignKeyReference(GraphDatabaseService db, EORelationship rel, Collection<? extends Number> nodeIds) {
Results<Node> referencedNodesProvider = new NodesWithIds(db, nodeIds);
return new NodesRelatedTo(referencedNodesProvider, rel);
}
}