RowNumSortExpression.java

package org.microspace.table.query.sql;


import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;

import org.microspace.table.Entry;
import org.microspace.table.column.Accessor;
import org.microspace.table.column.IndexedMap;
import org.microspace.table.query.SqlFormat;

/**
 *
 * @author Gaspar Sinai - {@literal gaspar.sinai@microspace.org}
 * @version 2017-07-06
 * @param <T>
 *            The type of the Table.
 */
public class RowNumSortExpression<T> implements Serializable {

	private static final long serialVersionUID = -5348440896112518581L;

	final Class<T> tableClass;

	Integer lowLimit = null;
	Integer highLimit = null;
	EntryComparator<T> comparator = null;

	public RowNumSortExpression(Class<T> tableClass) {
		this.tableClass = tableClass;
	}

	public Integer getLowLimit() {
		if (lowLimit == null) {
			return null;
		}
		if (lowLimit == Integer.MAX_VALUE) {
			return Integer.MAX_VALUE;
		}
		return lowLimit + 1;
	}

	/**
	 * Set the lowLimit record number.
	 * 
	 * @param lowLimit
	 *            starting from zero.
	 * 
	 */
	public void setLowLimit(Integer lowLimit) {
		if (this.lowLimit != null) {
			throw new IllegalArgumentException("Duplicate Low Limit");
		}
		this.lowLimit = lowLimit - 1;
	}

	public Integer getHighLimit() {
		if (highLimit == null) {
			return null;
		}
		if (highLimit == Integer.MAX_VALUE) {
			return Integer.MAX_VALUE;
		}
		return highLimit +1;
	}

	/**
	 * Set the high limit record number.
	 * 
	 * @param highLimit
	 *            starting from zero.
	 */
	public void setHighLimit(Integer highLimit) {
		if (this.highLimit != null) {
			throw new IllegalArgumentException("Duplicate High Limit");
		}
		this.highLimit = highLimit - 1;
	}

	public EntryComparator<T> getComparator() {
		return comparator;
	}

	public void setComparator(EntryComparator<T> comparator) {
		if (this.comparator != null) {
			throw new IllegalArgumentException("Duplicate Sort Comparator");
		}
		this.comparator = comparator;
	}

	public List<Entry<T>> sortApply(Accessor<T> accessor, IndexedMap<Object, Entry<T>> entries,
			List<String> columnNames, boolean distinct) {

		int min = lowLimit == null ? 0 : lowLimit;
		int max = highLimit == null ? Integer.MAX_VALUE : highLimit;
		if (min < 0)
			min = 0;

		ArrayList<Entry<T>> matches = new ArrayList<Entry<T>>(entries.size());
		if (entries.size() == 0)
			return matches;

		if (columnNames.size() > 0) {
			List<EntryComparator.Type> types = new LinkedList<>();
			for (int i=0; i<columnNames.size(); i++) {
				types.add(EntryComparator.Type.ASC);
			}
			// second columnNames is not used.
			EntryComparator<T> distinctComp = new EntryComparator<>(tableClass, 
					EntryComparator.Type.SKIP,
					columnNames, types, columnNames);
			SortedSet<Entry<T>> uniqueMap = new TreeSet<>(distinctComp);
			for (Entry<T> entry : entries.values()) {
				uniqueMap.add(entry);
			}
			for (Entry<T> entry : uniqueMap) {
				matches.add(entry);
			}
		} else {
			for (Entry<T> entry : entries.values()) {
				matches.add(entry);
			}
		}
		if (comparator == null) {
			Collections.sort(matches);
		} else {
			Collections.sort(matches, comparator);
		}
		ArrayList<Entry<T>> ret = new ArrayList<Entry<T>>(matches.size());
		for (int index = min; index < max; index++) {
			if (matches.size() <= index)
				break;
			Entry<T> entry = matches.get(index);
			ret.add(entry);
		}
		return ret;
	}

	public boolean hasLimits() {
		return lowLimit != null || highLimit != null;
	}

	public String formatRowNumString(SqlFormat format) {
		StringBuffer ret = new StringBuffer();
		if (format == SqlFormat.MICROSPACE) {
			if (getLowLimit() != null) {
				ret.append("ROWNUM >= ");
				ret.append("" + getLowLimit());
			}
			if (getHighLimit() != null) {
				if (ret.length() != 0)
					ret.append(" AND ");
				ret.append("ROWNUM < ");
				ret.append("" + getHighLimit());
			}
		} else if (format == SqlFormat.GIGASPACES || format == SqlFormat.GIGASPACES_LITERAL) {
			if (getLowLimit() != null && getHighLimit() != null) {
				// GigaSpaces is inclusive.
				int from = getLowLimit ();
				int to = getHighLimit() -1;
				ret.append("ROWNUM ( " + from + ", " + to + " )" );
			} else {
				if (lowLimit != null) {
					ret.append("ROWNUM >= ");
					ret.append("" + getLowLimit ());
				}
				if (highLimit != null) {
					ret.append("ROWNUM < ");
					ret.append("" + getHighLimit());
				}
			}
		} else {
			throw new IllegalArgumentException ("Format Not Supported: " + format);
		}
		return ret.toString();
	}
	
	public String formatCmpString(SqlFormat format) {
		if (comparator != null) {
			return comparator.constructSqlString(format);
		}
		return "";
	}

}