package org.mongodb.morphia.query.validation;
import com.mongodb.DBObject;
import org.mongodb.morphia.mapping.MappedField;
import org.mongodb.morphia.query.FilterOperator;
import java.util.List;
import static java.lang.String.format;
import static org.mongodb.morphia.query.FilterOperator.GEO_WITHIN;
import static org.mongodb.morphia.query.validation.MappedFieldTypeValidator.isArrayOfNumbers;
import static org.mongodb.morphia.query.validation.MappedFieldTypeValidator.isIterableOfNumbers;
public final class GeoWithinOperationValidator extends OperationValidator {
private static final GeoWithinOperationValidator INSTANCE = new GeoWithinOperationValidator();
private GeoWithinOperationValidator() {
}
public static GeoWithinOperationValidator getInstance() {
return INSTANCE;
}
private static boolean isValueAValidGeoQuery(final Object value) {
if (value instanceof DBObject) {
String key = ((DBObject) value).keySet().iterator().next();
return key.equals("$box") || key.equals("$center") || key.equals("$centerSphere") || key.equals("$polygon");
}
return false;
}
@Override
protected FilterOperator getOperator() {
return GEO_WITHIN;
}
@Override
protected void validate(final MappedField mappedField, final Object value,
final List<ValidationFailure> validationFailures) {
if (!isArrayOfNumbers(mappedField) && !isIterableOfNumbers(mappedField)) {
validationFailures.add(new ValidationFailure(format("For a $geoWithin operation, if field '%s' is an array or iterable it "
+ "should have numeric values. Instead it had: %s",
mappedField, mappedField.getSubClass()
)));
}
if (!isValueAValidGeoQuery(value)) {
validationFailures.add(new ValidationFailure(format("For a $geoWithin operation, the value should be a valid geo query. "
+ "Instead it was: %s", value)));
}
}
}