package org.dayatang.querychannel;
import org.apache.commons.lang3.StringUtils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 一个辅助类,处理查询语句,根据原始查询语句生成计算查询结果总数的查询语句
* 因为客户代码不会直接使用该类,所以设置为包级可见性。
* Created by yyang on 14-2-25.
*/
class CountQueryStringBuilder {
private final String queryString;
public CountQueryStringBuilder(String queryString) {
this.queryString = queryString;
}
/**
* 构造一个查询数据条数的语句,不能用于union
* @return 查询数据条数的语句
*/
public String buildQueryStringOfCount() {
String result = removeOrderByClause();
int index = StringUtils.indexOfIgnoreCase(result, " from ");
StringBuilder builder = new StringBuilder("select count(" + stringInCount(result, index) + ") ");
if (index != -1) {
builder.append(result.substring(index));
} else {
builder.append(result);
}
return builder.toString();
}
/**
* 去除查询语句的orderby 子句
*
* @return
*/
public String removeOrderByClause() {
Matcher m = Pattern.compile("order\\s*by[\\w|\\W|\\s|\\S]*", Pattern.CASE_INSENSITIVE).matcher(queryString);
StringBuffer sb = new StringBuffer();
while (m.find()) {
m.appendReplacement(sb, "");
}
m.appendTail(sb);
return sb.toString();
}
private static String stringInCount(String queryString, int fromIndex) {
int distinctIndex = getPositionOfDistinct(queryString);
if (distinctIndex == -1) {
return "*";
}
String distinctToFrom = queryString.substring(distinctIndex, fromIndex);
// 除去“,”之后的语句
int commaIndex = distinctToFrom.indexOf(",");
String strMayBeWithAs = commaIndex == -1 ? distinctToFrom : distinctToFrom.substring(0, commaIndex);
// 除去as语句
int asIndex = StringUtils.indexOfIgnoreCase(strMayBeWithAs, " as ");
String strInCount = asIndex == -1 ? strMayBeWithAs : strMayBeWithAs.substring(0, asIndex);
// 除去(),因为HQL不支持 select count(distinct (...)),但支持select count(distinct ...)
return strInCount.replace("(", " ").replace(")", " ");
}
private static int getPositionOfDistinct(String queryString) {
return StringUtils.indexOfIgnoreCase(queryString, "distinct");
}
/**
* 判断查询语句中是否包含group by子句。
* @return 如果查询语句中包含group by子句,返回true,否则返回false
*/
public boolean containsGroupByClause() {
Matcher m = Pattern.compile("group\\s*by[\\w|\\W|\\s|\\S]*",
Pattern.CASE_INSENSITIVE).matcher(queryString);
return m.find();
}
}