package br.com.citframework.integracao.core;
import org.apache.commons.lang3.StringUtils;
import br.com.citframework.util.Assert;
/**
* Utilit�rio para cria��o de queries que incluam par�metros para pagina��o
*
* @author bruno.ribeiro - <a href="mailto:bruno.ribeiro@centrait.com.br">bruno.ribeiro@centrait.com.br</a>
* @since 02/10/2014
*
*/
public final class PagingQueryUtil {
private PagingQueryUtil() {}
private static final String PAGINATION_MYSQL_PATTERN = "LIMIT %s, %s";
private static final String PAGINATION_POSTGRES_PATTERN = "LIMIT %s OFFSET %s";
/**
* Concatena em uma query o trecho para pagina��o, de acordo com o SGBD
*
* @param pageable
* informa��o da pagina��o
* @param query
* query a ser concatenada a parte para pagina��o
* @param dataBase
* informa��o da base de dados para gera��o do trecho de pagina��o
* @return
* @author bruno.ribeiro - <a href="mailto:bruno.ribeiro@centrait.com.br">bruno.ribeiro@centrait.com.br</a>
* @since 02/10/2014
*/
public static String concatPagingPieceOnQuery(final Pageable pageable, final String query, final DataBase dataBase) {
Assert.notNull(pageable, "Pageable information must not be null.");
Assert.notNullAndNotEmpty(query, "Query must not be null or empty.");
Assert.notNull(dataBase, "Database information must not be null.");
String result = null;
switch (dataBase) {
case ORACLE:
result = constructsOraclePagingPiece(pageable, query);
break;
case MSSQLSERVER:
result = constructsSQLServerPagingPiece(pageable, query);
break;
case POSTGRESQL:
case MYSQL:
result = constructsPostgreSQLAndMySQLPagingPiece(pageable, query, dataBase);
break;
}
return result;
}
/**
* Gera o trecho de query para pagina��o para {@code Oracle}
*
* @param pageable
* informa��o da pagina��o
* @param query
* query a ser concatenada a parte para pagina��o
* @return query para ser executado, j� com o padr�o de pagina��o para o banco
* @author bruno.ribeiro - <a href="mailto:bruno.ribeiro@centrait.com.br">bruno.ribeiro@centrait.com.br</a>
* @date 02/10/2014
*/
private static String constructsOraclePagingPiece(final Pageable pageable, final String query) {
int lastElement = 0;
int pageNumber = pageable.getPageNumber();
final int pageSize = pageable.getPageSize();
if (pageNumber > 1) {
lastElement = pageSize * pageNumber;
pageNumber = pageNumber * pageSize - pageSize;
pageNumber = pageNumber + 1;
} else {
lastElement = pageSize;
}
final StringBuilder oracle = new StringBuilder();
oracle.append("SELECT * FROM (");
oracle.append(" SELECT PAGING.*, ROWNUM PAGING_RN FROM ( ");
oracle.append(query);
oracle.append(" ) ");
oracle.append(" PAGING WHERE (");
oracle.append(" ROWNUM <= ");
oracle.append(lastElement);
oracle.append(" )");
oracle.append(") ");
oracle.append(" WHERE (");
oracle.append(" PAGING_RN >= ");
oracle.append(pageNumber);
oracle.append(" ) ");
return oracle.toString();
}
/**
* Gera o trecho de query para pagina��o para {@code PotgreSQL} e {@code MySQL}
*
* @param pageable
* informa��o da pagina��o
* @param query
* query a ser concatenada a parte para pagina��o
* @param dataBase
* informa��o da base de dados para gera��o do trecho de pagina��o
* @return query para ser executado, j� com o padr�o de pagina��o para o banco
* @author bruno.ribeiro - <a href="mailto:bruno.ribeiro@centrait.com.br">bruno.ribeiro@centrait.com.br</a>
* @since 02/10/2014
*/
private static String constructsPostgreSQLAndMySQLPagingPiece(final Pageable pageable, final String query, final DataBase dataBase) {
final int pageNumber = pageable.getPageNumber();
final int pageSize = pageable.getPageSize();
int offset;
if (pageNumber == 0) {
offset = pageNumber;
} else {
offset = pageNumber * pageSize;
}
final StringBuilder sql = new StringBuilder(query).append(" ");
switch (dataBase) {
case POSTGRESQL:
sql.append(String.format(PAGINATION_POSTGRES_PATTERN, pageSize, offset));
break;
default:
sql.append(String.format(PAGINATION_MYSQL_PATTERN, offset, pageSize));
break;
}
return sql.toString();
}
/**
* Gera o trecho de query para pagina��o para {@code Microsoft SQL Server}
*
* @param pageable
* informa��o da pagina��o
* @param query
* query a ser concatenada a parte para pagina��o
* @return query para ser executado, j� com o padr�o de pagina��o para o banco
* @author bruno.ribeiro - <a href="mailto:bruno.ribeiro@centrait.com.br">bruno.ribeiro@centrait.com.br</a>
* @date 02/10/2014
*/
private static String constructsSQLServerPagingPiece(final Pageable pageable, final String query) {
final int querySize = query.length();
final int fromIndex = StringUtils.indexOfIgnoreCase(query, "from");
final int orderIndex = StringUtils.indexOfIgnoreCase(query, "order", fromIndex);
final String selectPortion = query.substring(0, fromIndex);
final String fromPortion = query.substring(fromIndex, orderIndex);
final String orderPortion = query.substring(orderIndex, querySize - 1);
return constructsSQLServerPagingPiece(pageable, selectPortion, orderPortion, fromPortion);
}
/**
* TODO FIXME este m�todo foi criado por que anteriormente n�o estava previsto forma��es mais elaboradas de queries.<br>
*
* Gera o trecho de query para pagina��o para {@code Microsoft SQL Server}
*
* @param pageable
* informa��o da pagina��o
* @param selectPortion
* trecho da query contendo apenas os campos a serem filtrados {@code SELECT}
* @param orderPortion
* trecho da query contendo apenas a cl�usula {@code ORDER BY} e os campos para filtro
* @param fromPortion
* trecho da query contendo apenas as cl�sulas {@code FROM} e {@code WHERE}
* @return query para ser executado, j� com o padr�o de pagina��o para o banco
* @author bruno.ribeiro - <a href="mailto:bruno.ribeiro@centrait.com.br">bruno.ribeiro@centrait.com.br</a>
* @since 29/01/2015
*/
public static String constructsSQLServerPagingPiece(final Pageable pageable, final String selectPortion, final String orderPortion, final String fromPortion) {
int firstElement = pageable.getPageNumber();
int lastElement = pageable.getPageSize();
final int pageNumber = pageable.getPageNumber();
final int pageSize = pageable.getPageSize();
if (pageNumber > 0) {
firstElement = pageNumber * pageSize;
lastElement = firstElement + pageSize;
}
final StringBuilder sqlServer = new StringBuilder();
sqlServer.append(" ;WITH TempTable AS ( ");
sqlServer.append(selectPortion);
sqlServer.append(" , ROW_NUMBER() ");
sqlServer.append(" OVER ( ");
sqlServer.append(orderPortion);
sqlServer.append(" ) ");
sqlServer.append(" AS Row ");
sqlServer.append(fromPortion);
sqlServer.append(" ) SELECT * FROM TempTable WHERE Row > ");
sqlServer.append(firstElement);
sqlServer.append(" and Row <= ");
sqlServer.append(lastElement);
return sqlServer.toString();
}
}