package er.neo4jadaptor.query.neo4j_eval;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.regex.Pattern;
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 com.webobjects.foundation.NSArray;
import er.neo4jadaptor.query.QueryConverter;
import er.neo4jadaptor.query.expression.sentence.operators.ComparisonOperator;
import er.neo4jadaptor.query.neo4j_eval.evaluators.AlwaysTrue;
import er.neo4jadaptor.query.neo4j_eval.evaluators.BoolEvaluator;
import er.neo4jadaptor.query.neo4j_eval.evaluators.Comparison;
import er.neo4jadaptor.query.neo4j_eval.evaluators.Evaluator;
import er.neo4jadaptor.query.neo4j_eval.evaluators.Negate;
import er.neo4jadaptor.query.neo4j_eval.evaluators.RegexMatch;
import er.neo4jadaptor.query.neo4j_eval.retrievers.AttributeRetriever;
import er.neo4jadaptor.query.neo4j_eval.retrievers.ChainedRetriever;
import er.neo4jadaptor.query.neo4j_eval.retrievers.LowercaseRetriever;
import er.neo4jadaptor.query.neo4j_eval.retrievers.PrimaryKeyRetriever;
import er.neo4jadaptor.query.neo4j_eval.retrievers.RelationshipRetriever;
import er.neo4jadaptor.query.neo4j_eval.retrievers.Retriever;
import er.neo4jadaptor.utils.EOUtilities;
/**
* Converts {@link EOQualifier} to {@link Evaluator} having exactly the same semantics.
*
* @author Jedrzej Sobanski
*
* @param <T>
*/
public class EvaluationQueryConverter <T extends PropertyContainer> extends QueryConverter<Evaluator<T>> {
@SuppressWarnings("unused")
private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(EvaluationQueryConverter.class);
public EvaluationQueryConverter() {
}
@SuppressWarnings("unchecked")
@Override
protected Evaluator<T> comparison(EOEntity entity, String key, ComparisonOperator operator, Object value) {
Retriever<T, ?> retriever = buildRetriever(entity, key);
if (operator.equals(ComparisonOperator.LIKE) || operator.equals(ComparisonOperator.ILIKE)) {
Retriever<T, String> textRetriever = (Retriever<T, String>) retriever;
if (operator.equals(ComparisonOperator.ILIKE)) {
value = ((String) value).toLowerCase();
textRetriever = new LowercaseRetriever<T>(textRetriever);
}
return RegexMatch.wildcardMatch(textRetriever, (String) value);
} else {
return new Comparison<T>(retriever, operator, value);
}
}
private static final Pattern DOT_PATTERN = Pattern.compile("\\.");
@SuppressWarnings("unchecked")
private <V> Retriever<T, V> buildRetriever(EOEntity entity, String keypath) {
keypath = EOUtilities.unflattenedKey(entity, keypath);
EOEntity current = entity;
String [] splits = DOT_PATTERN.split(keypath);
List<Retriever<? extends PropertyContainer, ? extends PropertyContainer>> interimRetrievers = new ArrayList();
Retriever<? extends PropertyContainer, V> lastRetriever;
// iterate over splits except for the last one
for (int i=0; i<splits.length-1; i++) {
String key = splits[i];
EORelationship rel = current.relationshipNamed(key);
RelationshipRetriever<? extends PropertyContainer, ? extends PropertyContainer> r = RelationshipRetriever.create(rel);
interimRetrievers.add(r);
current = rel.destinationEntity();
}
// now handle last one (which could be attribute or relationship)
{
String key = splits[splits.length - 1];
EORelationship rel = current.relationshipNamed(key);
if (rel != null) {
lastRetriever = (Retriever<? extends PropertyContainer, V>) RelationshipRetriever.create(rel);
} else {
EOAttribute att = current.attributeNamed(key);
NSArray<EOAttribute> pks = current.primaryKeyAttributes();
if (pks.size() == 1 && pks.get(0).equals(att)) {
lastRetriever = (Retriever<? extends PropertyContainer, V>) PrimaryKeyRetriever.create(current);
} else {
// it must be an attribute
lastRetriever = (Retriever<? extends PropertyContainer, V>) AttributeRetriever.create(current, att);
}
}
}
if (interimRetrievers.isEmpty()) {
return (Retriever<T, V>) lastRetriever;
} else {
return new ChainedRetriever<T, V>(interimRetrievers, lastRetriever);
}
}
@Override
public Evaluator<T> fullQuery(EOEntity entity, EOQualifier qualifier) {
return convert(entity, qualifier);
}
@Override
protected Evaluator<T> joinWithAndOperator(Collection<Evaluator<T>> queries) {
return BoolEvaluator.and(queries);
}
@Override
protected Evaluator<T> joinWithOrOperator(Collection<Evaluator<T>> queries) {
return BoolEvaluator.or(queries);
}
@Override
protected Evaluator<T> matchAll() {
return AlwaysTrue.instance();
}
@Override
protected Evaluator<T> negate(Evaluator<T> query) {
return new Negate<T>(query);
}
}