@SuppressWarnings("rawtypes")
@Override
public <E extends IEntity> List<E> findEntities(Criteria<E> criteria, final Sorting sorting)
throws InvalidCriteriaException, DataAccessException {
if(criteria == null) throw new InvalidCriteriaException("No criteria specified.");
final Query query = getDb4oTemplate().query();
if(criteria.getCriteriaType().isQuery()) {
if(nqt == null) throw new InvalidCriteriaException("No db4o named query translator specified.");
nqt.translateNamedQuery(criteria.getNamedQueryDefinition(), criteria.getQueryParams(), query);
}
else {
query.constrain(criteria.getEntityClass());
final CriterionGroup pg = criteria.getPrimaryGroup();
if(pg != null && pg.isSet()) {
for(final ICriterion ic : pg) {
if(ic.isGroup()) throw new InvalidCriteriaException("Nested criterion groups are not supported");
if(!ic.isSet()) throw new InvalidCriteriaException("criterion not set");
final Criterion ctn = (Criterion) ic;
final Object checkValue = ctn.getValue();
final String pname = ctn.getPropertyName();
Query pquery;
if(pname.indexOf('.') > 0) {
pquery = query;
// descend one time for each node in the pname (which may be a dot
// notated property path)
final PropertyPath path = new PropertyPath(pname);
for(final String node : path.nodes()) {
pquery = pquery.descend(node);
}
}
else {
pquery = query.descend(pname);
}
switch(ctn.getComparator()) {
case BETWEEN: {
Object min, max;
if(checkValue instanceof NumberRange) {
final NumberRange range = (NumberRange) checkValue;
min = range.getMinimumNumber();
max = range.getMaximumNumber();
}
else if(checkValue instanceof DateRange) {
final DateRange range = (DateRange) checkValue;
min = range.getStartDate();
max = range.getEndDate();
}
else {
// presume an object array
final Object[] oarr = (Object[]) checkValue;
min = oarr[0];
max = oarr[1];
}
pquery.constrain(min).greater().equal().or(pquery.constrain(max).smaller().equal());
break;
}
case CONTAINS:
pquery.constrain(checkValue).contains();
break;
case ENDS_WITH:
pquery.constrain(checkValue).endsWith(ctn.isCaseSensitive());
break;
case EQUALS:
if(!ctn.isCaseSensitive())
throw new InvalidCriteriaException("Case insensitive equals checking is currently not supported");
pquery.constrain(checkValue);
break;
case GREATER_THAN:
pquery.constrain(checkValue).greater();
break;
case GREATER_THAN_EQUALS:
pquery.constrain(checkValue).greater().equal();
break;
case IN: {
Object[] arr;
if(checkValue.getClass().isArray()) {
arr = (Object[]) checkValue;
}
else if(checkValue instanceof Collection<?>) {
arr = ((Collection) checkValue).toArray();
}
else if(checkValue instanceof String) {
// assume comma-delimited string
arr =
org.springframework.util.ObjectUtils.toObjectArray(org.springframework.util.StringUtils
.commaDelimitedListToStringArray((String) checkValue));
}
else {
throw new InvalidCriteriaException(
"Unsupported or null type for IN comparator: " + checkValue == null ? "<null>" : checkValue
.getClass().toString());
}
Constraint c = null;
for(final Object o : arr) {
if(c == null) {
c = pquery.constrain(o);
}
else {
c.or(pquery.constrain(o));
}
}
break;
}
case IS:
if(checkValue instanceof DBType == false) {
throw new InvalidCriteriaException("IS clauses support only check values of type: "
+ DBType.class.getSimpleName());
}
final DBType dbType = (DBType) checkValue;
if(dbType == DBType.NULL) {
// null