package com.spun.util.database;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import com.spun.util.DatabaseUtils;
import com.spun.util.ObjectUtils;
import com.spun.util.StringUtils;
public class SQLQuery
{
public static final class JOINS
{
public static final String INNER_JOIN = "INNER JOIN";
public static final String LEFT_OUTER_JOIN = "LEFT OUTER JOIN";
public static final String RIGHT_OUTER_JOIN = "RIGHT OUTER JOIN";
}
public static final String BREAK = "\n";
private ArrayList<String> select = null;
private ArrayList<FromPart> from = null;
private SQLWhere where = null;
private ArrayList<OrderByPart> orderBy = null;
private ArrayList<String> groupBy = null;
private ArrayList<String> having = null;
private boolean reversed = false;
private LimitPart limitPart;
private int tableAliasOffset;
private boolean distinct;
/**************************************************************************/
public SQLQuery()
{
this(0);
}
/**************************************************************************/
public SQLQuery(int tableAliasOffset)
{
this.tableAliasOffset = tableAliasOffset;
select = new ArrayList<String>();
from = new ArrayList<FromPart>();
where = null;
orderBy = new ArrayList<OrderByPart>();
groupBy = new ArrayList<String>();
having = new ArrayList<String>();
}
/**************************************************************************/
public void addSelect(String part)
{
select.add(part);
}
/**************************************************************************/
public void addSelect(String part, String alias)
{
select.add(part + " AS " + alias);
}
/**************************************************************************/
public void addDistinct()
{
distinct = true;
}
/***********************************************************************/
public boolean isDistinct()
{
return distinct;
}
/**************************************************************************/
public String getFirstAliasForTableName(String tableName)
{
for (int i = 0; i < from.size(); i++)
{
FromPart part = (FromPart) from.get(i);
if (part.part.indexOf(tableName + " AS") != -1) { return "" + ((char) ('a' + i)); }
}
return null;
}
/**************************************************************************/
public void addFromPart(FromPart from)
{
this.from.add(from);
}
/**************************************************************************/
public void addOrderByPart(OrderByPart orderBy)
{
this.orderBy.add(orderBy);
}
/**************************************************************************/
public void setLimitPart(LimitPart limit)
{
this.limitPart = limit;
}
/***********************************************************************/
public int getAliasCount()
{
return getFromParts().length;
}
/**************************************************************************/
public String addFrom(String table)
{
String alias = "" + (char) ('a' + tableAliasOffset + from.size());
from.add(new FromPart(table + " AS " + alias, false));
return alias;
}
/**************************************************************************/
public String addFromWithInnerJoin(String table, String joinWith, String joinOn)
{
return addFromWithJoin(table, joinWith, joinOn, JOINS.INNER_JOIN);
}
/**************************************************************************/
public String addFromWithLeftOuterJoin(String table, String joinWith, String joinOn)
{
return addFromWithJoin(table, joinWith, joinOn, JOINS.LEFT_OUTER_JOIN);
}
/***********************************************************************/
public String addFromWithRightOuterJoin(String table, String joinWith, String joinOn)
{
return addFromWithJoin(table, joinWith, joinOn, JOINS.RIGHT_OUTER_JOIN);
}
/**************************************************************************/
public String addFromWithJoin(String table, String joinWith, String joinOn, String joinType)
{
String alias = "" + (char) ('a' + tableAliasOffset + from.size());
String sql = (joinType + " " + table + " AS " + alias + " ON " + joinWith + " = " + alias + "." + joinOn);
from.add(new FromPart(sql, true));
return alias;
}
/**************************************************************************/
public void addWhere(String part)
{
addWhere(new SQLWhere(part), true);
}
/**************************************************************************/
public void addWhere(SQLWhere part)
{
addWhere(part, true);
}
/**************************************************************************/
public void addWhere(String part, boolean joinWithAnd)
{
addWhere(new SQLWhere(part), joinWithAnd);
}
/**************************************************************************/
public void addWhere(SQLWhere part, boolean joinWithAnd)
{
where = joinWithAnd ? SQLWhere.joinByAnd(where, part) : SQLWhere.joinByOr(where, part);
}
/**************************************************************************/
public String toString()
{
return toString(DatabaseUtils.SQLSERVER);
}
/**************************************************************************/
public String toString(Statement stmt)
{
try
{
return toString(DatabaseUtils.getDatabaseType(stmt));
}
catch (SQLException e)
{
throw ObjectUtils.throwAsError(e);
}
}
/**************************************************************************/
public String toString(int databaseType)
{
SQLQueryWriter writer = getSQLQueryWriter(databaseType);
return writer.toString(this);
}
/***********************************************************************/
private SQLQueryWriter getSQLQueryWriter(int databaseType)
{
if (limitPart == null || DatabaseUtils.MY_SQL == databaseType)
{
return new SimpleQueryWriter(databaseType);
}
else if (limitPart.startingZeroBasedIndex == 0)
{
return new SimpleQueryWriter(databaseType);
}
else
{
return new ReverseOrderLimitQueryWriter(databaseType);
}
}
/***********************************************************************/
public void addOrderBy(String orderByClause, boolean ascending)
{
orderBy.add(new OrderByPart(orderByClause, ascending));
}
/***********************************************************************/
public void addOrderBy(ColumnMetadata submitted, String alias, boolean ascending)
{
addOrderBy(submitted.getNameWithPrefix(alias),ascending);
}
/***********************************************************************/
public void addGroupBy(String groupByClause)
{
groupBy.add(groupByClause);
}
/***********************************************************************/
public void addHaving(String havingClause)
{
having.add(havingClause);
}
/***********************************************************************/
public void setOrderReversed(boolean reversed)
{
this.reversed = reversed;
}
/***********************************************************************/
public boolean isOrderReversed()
{
return reversed;
}
/***********************************************************************/
public void addLimit(int startingZeroBasedIndex, int numberOfRowsDesired, String mainTableAlias, String mainTablePkeyColumn)
{
this.limitPart = new LimitPart(startingZeroBasedIndex, numberOfRowsDesired, mainTableAlias, mainTablePkeyColumn);
}
/***********************************************************************/
public void addLimit(int startingZeroBasedIndex, int numberOfRowsDesired, String mainTableAlias, ColumnMetadata mainTablePkeyColumn)
{
addLimit(startingZeroBasedIndex, numberOfRowsDesired, mainTableAlias, mainTablePkeyColumn.getName());
}
/***********************************************************************/
public LimitPart getLimitPart()
{
return limitPart;
}
/***********************************************************************/
public String[] getSelectParts()
{
return StringUtils.toArray(select);
}
/***********************************************************************/
public String[] getGroupByParts()
{
return StringUtils.toArray(groupBy);
}
/***********************************************************************/
public String[] getHavingParts()
{
return StringUtils.toArray(having);
}
/***********************************************************************/
public FromPart[] getFromParts()
{
return (FromPart[]) from.toArray(new FromPart[from.size()]);
}
/***********************************************************************/
public SQLWhere getWherePart()
{
return where;
}
/***********************************************************************/
public OrderByPart[] getOrderByParts()
{
return (OrderByPart[]) orderBy.toArray(new OrderByPart[orderBy.size()]);
}
/**************************************************************************/
/** INNER CLASSES **/
/**************************************************************************/
public static class LimitPart implements Cloneable
{
private int startingZeroBasedIndex;
public int numberOfRowsDesired;
public String mainTableAlias;
public String mainTablePkeyColumn;
/**************************************************************************/
public LimitPart(int startingZeroBasedIndex, int numberOfRowsDesired, String mainTableAlias, String mainTablePkeyColumn)
{
this.setStartingZeroBasedIndex(startingZeroBasedIndex);
this.numberOfRowsDesired = numberOfRowsDesired;
this.mainTableAlias = mainTableAlias;
this.mainTablePkeyColumn = mainTablePkeyColumn;
}
/***********************************************************************/
public int getStartingZeroBasedIndex()
{
return startingZeroBasedIndex;
}
/***********************************************************************/
public void setStartingZeroBasedIndex(int startingZeroBasedIndex)
{
if (startingZeroBasedIndex < 0) { throw new Error("startingZeroBasedIndex: " + startingZeroBasedIndex + " must be greater than 0."); }
this.startingZeroBasedIndex = startingZeroBasedIndex;
}
/**************************************************************************/
/**************************************************************************/
}
public static class OrderByPart implements Cloneable
{
public String part = null;
public boolean ascending = false;
/**************************************************************************/
public OrderByPart(String part, boolean ascending)
{
this.part = part;
this.ascending = ascending;
}
/**************************************************************************/
public String toString(boolean isFirst)
{
String sql = part + (ascending ? " ASC " : " DESC ");
if (!isFirst)
{
sql = (isFirst ? " " : ", ") + sql;
}
return sql;
}
/**************************************************************************/
/**************************************************************************/
}
public static class FromPart implements Cloneable
{
public String part = null;
public boolean isJoin = false;
/**************************************************************************/
public FromPart(String part, boolean isJoin)
{
this.part = part;
this.isJoin = isJoin;
}
/**************************************************************************/
public String toString(boolean isFirst)
{
String sql = part;
if (!isFirst)
{
sql = (isJoin ? " " : ", ") + sql;
}
return sql;
}
/**************************************************************************/
/**************************************************************************/
}
}