* @param visitor
* @param nearest value, or null if not supported
* @throws IOException
*/
private boolean handleNearestVisitor(Query query, FeatureVisitor visitor) throws IOException {
NearestVisitor nearest = (NearestVisitor) visitor;
Object targetValue = nearest.getValueToMatch();
Expression expr = nearest.getExpression();
String attribute = null;
if( expr != null && expr instanceof PropertyName){
attribute = ((PropertyName)expr).getPropertyName();
}
if( attribute == null ) {
return false; // optimization restricted to column evaulation
}
// check what we're dealing with (and mind, Geometry is Comparable for JTS, but not for databases
AttributeDescriptor descriptor = getSchema().getDescriptor(attribute);
if( descriptor == null ) {
return false; // optimization restricted to column evaulation
}
Class binding = descriptor.getType().getBinding();
if(Geometry.class.isAssignableFrom(binding) || !(Comparable.class.isAssignableFrom(binding))) {
// we may roll out KNN support in the dialect for geometries, but for the moment, we say we can't
return false;
}
// grab max of values lower than the target
FilterFactory ff = getDataStore().getFilterFactory();
Query qBelow = new Query(query);
Filter lessFilter = ff.lessOrEqual(ff.property(attribute), ff.literal(targetValue));
qBelow.setFilter(ff.and(query.getFilter(), lessFilter));
MaxVisitor max = new MaxVisitor(attribute);
handleVisitor(qBelow, max);
Comparable maxBelow = (Comparable) max.getResult().getValue();
if(maxBelow != null && maxBelow.equals(targetValue)) {
// shortcut exit, we had a exact match
nearest.setValue(maxBelow, null);
} else {
// grab mind of values higher than the target
Query qAbove = new Query(query);
Filter aboveFilter = ff.greater(ff.property(attribute), ff.literal(targetValue));
qAbove.setFilter(ff.and(query.getFilter(), aboveFilter));
MinVisitor min = new MinVisitor(attribute);
handleVisitor(qAbove, min);
Comparable minAbove = (Comparable) min.getResult().getValue();
nearest.setValue(maxBelow, minAbove);
}
return true;
}