/** * DataCleaner (community edition) * Copyright (C) 2014 Neopost - Customer Information Management * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution; if not, write to: * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ package org.datacleaner.beans.filter; import java.util.Comparator; import org.apache.metamodel.query.FilterItem; import org.apache.metamodel.query.OperatorType; import org.apache.metamodel.query.Query; import org.apache.metamodel.query.SelectItem; import org.apache.metamodel.schema.Column; import org.datacleaner.api.Distributed; import org.datacleaner.api.HasLabelAdvice; import org.datacleaner.api.InputColumn; import org.datacleaner.api.InputRow; import org.datacleaner.api.QueryOptimizedFilter; import org.datacleaner.api.Validate; /** * Abstract {@link QueryOptimizedFilter} which implementation for range filters * which demarcate valid value bounds. */ @Distributed(true) abstract class AbstractQueryOptimizedRangeFilter<E> implements QueryOptimizedFilter<RangeFilterCategory>, Comparator<E>, HasLabelAdvice { @Validate public void validate() { if (compare(getLowestValue(), getHighestValue()) > 0) { throw new IllegalStateException("Lowest value is greater than the highest value"); } } public abstract InputColumn<? extends E> getColumn(); public abstract E getHighestValue(); public abstract E getLowestValue(); @Override public RangeFilterCategory categorize(final InputRow inputRow) { final E value = inputRow.getValue(getColumn()); return categorize(value); } protected RangeFilterCategory categorize(final E value) { if (value == null) { return RangeFilterCategory.LOWER; } if (compare(value, getLowestValue()) < 0) { return RangeFilterCategory.LOWER; } if (compare(value, getHighestValue()) > 0) { return RangeFilterCategory.HIGHER; } return RangeFilterCategory.VALID; } @Override public boolean isOptimizable(final RangeFilterCategory category) { return true; } @Override public String getSuggestedLabel() { final E highestValue = getHighestValue(); final E lowestValue = getLowestValue(); if (highestValue == null || lowestValue == null) { return null; } final InputColumn<? extends E> column = getColumn(); if (column == null) { return null; } return lowestValue + " =< " + column.getName() + " =< " + highestValue; } @Override public Query optimizeQuery(final Query q, final RangeFilterCategory category) { final Column col = getColumn().getPhysicalColumn(); final SelectItem selectItem = new SelectItem(col); switch (category) { case LOWER: return lowerQuery(q, selectItem); case HIGHER: return higherQuery(q, selectItem); case VALID: return validQuery(q, col, selectItem); default: throw new UnsupportedOperationException(); } } private Query validQuery(final Query query, final Column col, final SelectItem selectItem) { final E lowestValue = getLowestValue(); final E highestValue = getHighestValue(); if (compare(lowestValue, highestValue) == 0) { // special case where highest and lowest value are equal query.where(col, OperatorType.EQUALS_TO, lowestValue); return query; } final FilterItem orFilter1; { final FilterItem f1 = new FilterItem(selectItem, OperatorType.GREATER_THAN, lowestValue); final FilterItem f2 = new FilterItem(selectItem, OperatorType.EQUALS_TO, lowestValue); orFilter1 = new FilterItem(f1, f2); } final FilterItem orFilter2; { final FilterItem f3 = new FilterItem(selectItem, OperatorType.LESS_THAN, highestValue); final FilterItem f4 = new FilterItem(selectItem, OperatorType.EQUALS_TO, highestValue); orFilter2 = new FilterItem(f3, f4); } query.where(orFilter1); query.where(orFilter2); return query; } private Query higherQuery(final Query query, final SelectItem selectItem) { query.where(selectItem, OperatorType.GREATER_THAN, getHighestValue()); return query; } private Query lowerQuery(final Query query, final SelectItem selectItem) { // special case, null is also considered "lower" final FilterItem isNullFilter = new FilterItem(selectItem, OperatorType.EQUALS_TO, null); final FilterItem isLowerThanFilter = new FilterItem(selectItem, OperatorType.LESS_THAN, getLowestValue()); query.where(new FilterItem(isNullFilter, isLowerThanFilter)); return query; } }