package er.neo4jadaptor.query;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import com.webobjects.eoaccess.EOEntity;
import com.webobjects.eocontrol.EOAndQualifier;
import com.webobjects.eocontrol.EOKeyValueQualifier;
import com.webobjects.eocontrol.EONotQualifier;
import com.webobjects.eocontrol.EOOrQualifier;
import com.webobjects.eocontrol.EOQualifier;
import com.webobjects.foundation.NSSelector;
import er.extensions.eof.qualifiers.ERXInQualifier;
import er.neo4jadaptor.ersatz.webobjects.NSTranslator;
import er.neo4jadaptor.query.expression.sentence.operators.ComparisonOperator;
/**
* Converts {@link EOQualifier}s to custom type of queries.
*
* @author Jedrzej Sobanski
*
* @param <ClauseType> query clause type
*/
public abstract class QueryConverter <ClauseType> {
/**
* @param entity
* @param qualifier
* @return search criteria equivalent to the given qualifier
*/
public abstract ClauseType fullQuery(EOEntity entity, EOQualifier qualifier);
protected ClauseType convert(EOEntity entity, EOQualifier qualifier) {
if (qualifier == null) {
return matchAll();
} else if (qualifier instanceof EOKeyValueQualifier) {
return convertKeyValueQualifier(entity, (EOKeyValueQualifier) qualifier);
} else if (qualifier instanceof EONotQualifier) {
ClauseType query = convert(entity, ((EONotQualifier) qualifier).qualifier());
return negate(query);
} else if (qualifier instanceof EOAndQualifier || qualifier instanceof EOOrQualifier) {
List<ClauseType> list = new ArrayList<>();
Collection<EOQualifier> qualifiers = qualifier instanceof EOAndQualifier
? ((EOAndQualifier) qualifier).qualifiers()
: ((EOOrQualifier) qualifier).qualifiers();
for (EOQualifier q : qualifiers) {
ClauseType clause = convert(entity, q);
if (clause != null) {
list.add(clause);
}
}
if (list.isEmpty()) {
return null;
} else if (qualifier instanceof EOAndQualifier) {
return joinWithAndOperator(list);
} else {
return joinWithOrOperator(list);
}
} else {
throw new UnsupportedOperationException(qualifier.toString());
}
}
protected ClauseType convertKeyValueQualifier(EOEntity entity, EOKeyValueQualifier qual) {
NSSelector<?> operator = qual.selector();
String key = qual.key();
Object value = NSTranslator.instance.toNeutralValue(qual.value(), entity.attributeNamed(key));
if (operator.equals(EOKeyValueQualifier.QualifierOperatorEqual)) {
if (qual instanceof ERXInQualifier) {
ERXInQualifier inQualifier = (ERXInQualifier) qual;
List<ClauseType> clauses = new ArrayList<>();
for (Object o : inQualifier.values()) {
clauses.add(comparison(entity, key, ComparisonOperator.EQUAL, o));
}
return joinWithOrOperator(clauses);
} else {
return comparison(entity, key, ComparisonOperator.EQUAL, value);
}
} else if (operator.equals(EOKeyValueQualifier.QualifierOperatorNotEqual)) {
ClauseType equal = comparison(entity, key, ComparisonOperator.EQUAL, value);
if (equal == null) {
return null;
} else {
return negate(equal);
}
} else if (operator.equals(EOKeyValueQualifier.QualifierOperatorLessThanOrEqualTo)) {
return comparison(entity, key, ComparisonOperator.LESS_OR_EQUAL, value);
} else if (operator.equals(EOKeyValueQualifier.QualifierOperatorLessThan)) {
return comparison(entity, key, ComparisonOperator.LESS_THAN, value);
} else if (operator.equals(EOKeyValueQualifier.QualifierOperatorGreaterThanOrEqualTo)) {
return comparison(entity, key, ComparisonOperator.GREATER_OR_EQUAL, value);
} else if (operator.equals(EOKeyValueQualifier.QualifierOperatorGreaterThan)) {
return comparison(entity, key, ComparisonOperator.GREATER_THAN, value);
} else if (operator.equals(EOKeyValueQualifier.QualifierOperatorLike)) {
return comparison(entity, key, ComparisonOperator.LIKE, value);
} else if (operator.equals(EOKeyValueQualifier.QualifierOperatorCaseInsensitiveLike)) {
return comparison(entity, key, ComparisonOperator.ILIKE, value);
} else if (ComparisonOperator.MATCHES.asString.equals(operator.name())) {
return comparison(entity, key, ComparisonOperator.MATCHES, value);
} else if (operator.equals(EOKeyValueQualifier.QualifierOperatorContains)) {
// unsupported
throw new UnsupportedOperationException(qual.toString());
} else {
// case not covered
throw new UnsupportedOperationException(qual.toString());
}
}
/**
* Creates clause that matches records where the given entity key matches given value using comparison operator.
* @param entity
* @param key
* @param operator
* @param value
* @return a ClauseType object
*/
protected abstract ClauseType comparison(EOEntity entity, String key, ComparisonOperator operator, Object value);
/**
* Creates negation of the given clause.
* @param query clause to negate
* @return negated clause
*/
protected abstract ClauseType negate(ClauseType query);
/**
* @param queries clauses to join with logical conjunction
* @return clause that would evaluate to <code>true</code> if all of queries evaluate to <code>true</code>
*/
protected abstract ClauseType joinWithAndOperator(Collection<ClauseType> queries);
/**
* @param queries clauses to join with logical alternative
* @return clause that would evaluate to <code>true</code> if at least one of queries evaluates to <code>true</code>
*/
protected abstract ClauseType joinWithOrOperator(Collection<ClauseType> queries);
/**
* @return clause that would match everyting
*/
protected abstract ClauseType matchAll();
}