ExpressionBooleanColumn.java

package org.microspace.table.query.sql;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.microspace.table.Entry;
import org.microspace.table.column.Accessor;
import org.microspace.table.column.ColumnReferences;
import org.microspace.table.column.GetSetPair;
import org.microspace.table.column.IndexedMap;
import org.microspace.table.query.SqlFormat;
import org.microspace.util.PojoUtil;

/**
 *
 * @author Gaspar Sinai - {@literal gaspar.sinai@microspace.org}
 * @version 2017-09-29
 * @param <T> The type of the Table.
 */
public class ExpressionBooleanColumn<T> implements Expression<T> {

	private static final long serialVersionUID = 1L;
	
	
	final Class<T> tableClass;
	final Class<?> columnClass;
	final String columnNameL;
	final OperatorType operator;
	final String columnNameR;
	final String columnEscL;
	final String columnEscR;

	boolean needsBracket = false;
	
	public void setNeedsBracket (boolean needsBracket) {
		this.needsBracket = needsBracket;
	}


	public ExpressionBooleanColumn(Class<T> tableClass, 
			OperatorType operator, String columnNameL, String columnEscL,
			String columnNameR, String columnEscR) {
		this.tableClass = tableClass;
		this.columnEscL = columnEscL;
		this.columnEscR = columnEscR;
		Accessor<T> accessor = PojoUtil.getUnannotateAccessor(tableClass);
		GetSetPair<T> gettterL = accessor.getGetSetPair(columnNameL);
		if (gettterL == null) {
			throw new IllegalArgumentException("Unkown Column: " + columnNameL);
		}
		this.columnClass = PojoUtil.getColumnClass(tableClass, columnNameL);
		gettterL = accessor.getGetSetPair(columnNameR);
		if (gettterL == null) {
			throw new IllegalArgumentException("Unkown Column: " + columnNameR);
		}
		Class<?> columnClassR = PojoUtil.getColumnClass(tableClass, columnNameR);
		if (!columnClassR.equals(columnClass)) {
			throw new IllegalArgumentException("Column Type Mismatch: " + columnNameL + " " + columnNameR);
		}

		this.operator = operator;
		this.columnNameL = columnNameL;
		this.columnNameR = columnNameR;
		if (columnClass == null) {
			throw new IllegalArgumentException("Unkown Column");
		}
	}

	public IndexedMap<Object, Entry<T>> apply(Accessor<T> accessor, 
			IndexedMap<Object, Entry<T>> entries,
			ColumnReferences<T>[] indexedColumns, InnerSelectContext<?> innerSelectContext) {
		IndexedMap<Object, Entry<T>> retMap = new IndexedMap<Object, Entry<T>>(
				accessor.getPrimaryKeyGetSetPair().getIndexType());

		GetSetPair<T> getSetPairL = accessor.getGetSetPair(columnNameL);
		GetSetPair<T> getSetPairR = accessor.getGetSetPair(columnNameR);
		int columnNumberL = getSetPairL.getIndex();
		int columnNumberR = getSetPairR.getIndex();

		switch (operator) {
		case EQ:
			for (Entry<T> entry : entries.values()) {
				Object fieldL = entry.getField(columnNumberL);
				Object fieldR = entry.getField(columnNumberR);
				if (fieldL == null && fieldR == null) {
					retMap.put(entry.getPrimaryKey(), entry);
					continue;
				}
				if (fieldL == null) continue;
				if (fieldR == null) continue;
				if (ExpressionBoolean.equals(fieldL, fieldR)) {
					retMap.put(entry.getPrimaryKey(), entry);
				}
			}
			break;

		case NOT_EQ:
			for (Entry<T> entry : entries.values()) {
				Object fieldL = entry.getField(columnNumberL);
				Object fieldR = entry.getField(columnNumberR);
				if (fieldL == null && fieldR == null) {
					continue;
				}
				if (fieldL == null) {
					retMap.put(entry.getPrimaryKey(), entry);
					continue;
				}
				if (fieldR == null) {
					retMap.put(entry.getPrimaryKey(), entry);
					continue;
				}
				if (!ExpressionBoolean.equals(fieldL, fieldR)) {
					retMap.put(entry.getPrimaryKey(), entry);
				}
			}
			
			break;

		case GTH:
			for (Entry<T> entry : entries.values()) {
				Object fieldL = entry.getField(columnNumberL);
				Object fieldR = entry.getField(columnNumberR);
				if (fieldL == null && fieldR == null) {
					continue;
				}
				if (fieldL == null) {
					continue;
				}
				if (fieldR == null) {
					retMap.put(entry.getPrimaryKey(), entry);
					continue;
				}
				if (ExpressionBoolean.compare(fieldL, fieldR) > 0) {
					retMap.put(entry.getPrimaryKey(), entry);
				}
			}
			break;
			
		case GET:
			for (Entry<T> entry : entries.values()) {
				Object fieldL = entry.getField(columnNumberL);
				Object fieldR = entry.getField(columnNumberR);
				if (fieldL == null && fieldR == null) {
					retMap.put(entry.getPrimaryKey(), entry);
					continue;
				}
				if (fieldL == null) {
					continue;
				}
				if (fieldR == null) {
					retMap.put(entry.getPrimaryKey(), entry);
					continue;
				}
				if (ExpressionBoolean.compare(fieldL, fieldR) >= 0) {
					retMap.put(entry.getPrimaryKey(), entry);
				}
			}
			break;

		case LET:
			for (Entry<T> entry : entries.values()) {
				Object fieldL = entry.getField(columnNumberL);
				Object fieldR = entry.getField(columnNumberR);
				if (fieldL == null && fieldR == null) {
					retMap.put(entry.getPrimaryKey(), entry);
					continue;
				}
				if (fieldL == null) {
					retMap.put(entry.getPrimaryKey(), entry);
					continue;
				}
				if (fieldR == null) {
					continue;
				}
				if (ExpressionBoolean.compare(fieldL, fieldR) <= 0) {
					retMap.put(entry.getPrimaryKey(), entry);
				}
			}
			break;

		case LTH: 
			for (Entry<T> entry : entries.values()) {
				Object fieldL = entry.getField(columnNumberL);
				Object fieldR = entry.getField(columnNumberR);
				if (fieldL == null && fieldR == null) {
					retMap.put(entry.getPrimaryKey(), entry);
					continue;
				}
				if (fieldL == null) {
					retMap.put(entry.getPrimaryKey(), entry);
					continue;
				}
				if (fieldR == null) {
					continue;
				}
				if (ExpressionBoolean.compare(fieldL, fieldR) < 0) {
					retMap.put(entry.getPrimaryKey(), entry);
				}
			}
			break;

		case IS_NULL:
		case IS_NOT_NULL:
			break;

		case LIKE: 
		case NOT_LIKE:
			for (Entry<T> entry : entries.values()) {
				Object fieldL = entry.getField(columnNumberL);
				Object fieldR = entry.getField(columnNumberR);
				if (fieldL == null && fieldR == null) {
					if ((operator == OperatorType.LIKE)) {
						retMap.put(entry.getPrimaryKey(), entry);
					}
					continue;
				}
				if (fieldL == null) {
					continue;
				}
				if (fieldR == null) {
					continue;
				}
				String expr = fieldR.toString();
				expr = expr.toUpperCase();
				expr = expr.replace(".", "\\.");
				// TODO Add more.
				expr = expr.replace("?", ".");
				expr = expr.replace("%", ".*");
				Pattern pattern = Pattern.compile(expr);
				
				String str = fieldL.toString().toUpperCase();
				Matcher m = pattern.matcher(str);
				if (m.matches() == (operator == OperatorType.LIKE)) {
					retMap.put(entry.getPrimaryKey(), entry);
				}
			}
			break;
		default:
			break;

		}
		return retMap;
	}
	
	@Override
	public boolean match(T object, Accessor<T> accessor) {
		GetSetPair<T> getSetPairL = accessor.getGetSetPair(columnNameL);
		Object fieldL = getSetPairL.get(object);
		GetSetPair<T> getSetPairR = accessor.getGetSetPair(columnNameR);
		Object fieldR = getSetPairR.get(object);
		if (fieldL == null && fieldR == null) {
			return true;
		}
		if (fieldL == null) return false;
		if (fieldR == null) return false;
		return ExpressionBoolean.equals(fieldL, fieldR);
	}

	@Override
	public String formatSqlQuery (SqlFormat format) {
		String escL = columnEscL;
		String escR = columnEscR;
		if (format == SqlFormat.GIGASPACES) {
			escL = "`";
			escR =  "`";
		}
		String ret = escL + columnNameL + escL + " " 
			+ operator.constructSqlString(format) + " " 
			+ escR + columnNameR + escR;
		if (format == SqlFormat.GIGASPACES || format == SqlFormat.GIGASPACES_LITERAL) {
			throw new IllegalArgumentException ("Expression not supported by GigaSpaces: " + ret);
		}
		return ret;
	}
	
}