
org.beangle.commons.dao.query.builder.OqlBuilder Maven / Gradle / Ivy
The newest version!
/*
* Beangle, Agile Development Scaffold and Toolkits.
*
* Copyright © 2005, The Beangle Software.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
package org.beangle.commons.dao.query.builder;
import static org.beangle.commons.lang.Strings.concat;
import static org.beangle.commons.lang.Strings.contains;
import static org.beangle.commons.lang.Strings.isEmpty;
import static org.beangle.commons.lang.Strings.isNotEmpty;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.beangle.commons.collection.Order;
import org.beangle.commons.collection.page.PageLimit;
import org.beangle.commons.dao.query.Lang;
import org.beangle.commons.entity.metadata.EntityType;
import org.beangle.commons.entity.metadata.Model;
import org.beangle.commons.entity.util.EntityUtils;
import org.beangle.commons.lang.Assert;
import org.beangle.commons.lang.Strings;
/**
* 实体类查询 Object Query Language Builder
*
* @author chaostone
* @version $Id: $
*/
public class OqlBuilder extends AbstractQueryBuilder {
/** 查询实体类 */
protected Class entityClass;
/**
* Constructor for OqlBuilder.
*/
protected OqlBuilder() {
super();
}
/**
* hql.
*
* @param hql a {@link java.lang.String} object.
* @param a E object.
* @return a {@link org.beangle.commons.dao.query.builder.OqlBuilder} object.
*/
public static OqlBuilder hql(final String hql) {
OqlBuilder query = new OqlBuilder();
query.statement = hql;
return query;
}
/**
* from.
*
* @param from a {@link java.lang.String} object.
* @param a E object.
* @return a {@link org.beangle.commons.dao.query.builder.OqlBuilder} object.
*/
public static OqlBuilder from(final String from) {
OqlBuilder query = new OqlBuilder();
query.newFrom(from);
return query;
}
/**
* from.
*
* @param entityName a {@link java.lang.String} object.
* @param alias a {@link java.lang.String} object.
* @param a E object.
* @return a {@link org.beangle.commons.dao.query.builder.OqlBuilder} object.
*/
@SuppressWarnings("unchecked")
public static OqlBuilder from(final String entityName, final String alias) {
EntityType type = Model.getType(entityName);
OqlBuilder query = new OqlBuilder();
if (null != type) query.entityClass = (Class) type.getEntityClass();
query.alias = alias;
query.select = "select " + alias;
query.from = concat("from ", entityName, " ", alias);
return query;
}
/**
* from.
*
* @param entityClass a {@link java.lang.Class} object.
* @param a E object.
* @return a {@link org.beangle.commons.dao.query.builder.OqlBuilder} object.
*/
public static OqlBuilder from(final Class entityClass) {
EntityType type = Model.getType(entityClass.getName());
if (null == type) type = Model.getType(entityClass);
return from(entityClass, EntityUtils.getCommandName(type.getEntityName()));
}
/**
* from.
*
* @param entityClass a {@link java.lang.Class} object.
* @param alias a {@link java.lang.String} object.
* @param a E object.
* @return a {@link org.beangle.commons.dao.query.builder.OqlBuilder} object.
*/
@SuppressWarnings("unchecked")
public static OqlBuilder from(final Class entityClass, final String alias) {
EntityType type = Model.getType(entityClass.getName());
if (null == type) type = Model.getType(entityClass);
OqlBuilder query = new OqlBuilder();
query.entityClass = (Class) type.getEntityClass();
query.alias = alias;
query.select = "select " + alias;
query.from = concat("from ", type.getEntityName(), " ", alias);
return query;
}
/**
* alias.
*
* @param alias a {@link java.lang.String} object.
* @return a {@link org.beangle.commons.dao.query.builder.OqlBuilder} object.
*/
public OqlBuilder alias(final String alias) {
this.alias = alias;
return this;
}
/**
* join.
*
* @param path a {@link java.lang.String} object.
* @param alias a {@link java.lang.String} object.
* @return a {@link org.beangle.commons.dao.query.builder.OqlBuilder} object.
*/
public OqlBuilder join(final String path, final String alias) {
from = concat(from, " join ", path, " ", alias);
return this;
}
/**
* join.
*
* @param joinMode a {@link java.lang.String} object.
* @param path a {@link java.lang.String} object.
* @param alias a {@link java.lang.String} object.
* @return a {@link org.beangle.commons.dao.query.builder.OqlBuilder} object.
*/
public OqlBuilder join(final String joinMode, final String path, final String alias) {
from = concat(from, " ", joinMode, " join ", path, " ", alias);
return this;
}
public OqlBuilder params(final Map params) {
this.params.putAll(params);
return this;
}
/**
* param.
*
* @param name a {@link java.lang.String} object.
* @param value a {@link java.lang.Object} object.
* @return a {@link org.beangle.commons.dao.query.builder.OqlBuilder} object.
*/
public OqlBuilder param(String name, Object value) {
params.put(name, value);
return this;
}
public OqlBuilder limit(final PageLimit limit) {
this.limit = limit;
return this;
}
/**
* limit.
*
* @param pageIndex a int.
* @param pageSize a int.
* @return a {@link org.beangle.commons.dao.query.builder.OqlBuilder} object.
*/
public OqlBuilder limit(final int pageIndex, final int pageSize) {
this.limit = new PageLimit(pageIndex, pageSize);
return this;
}
/**
* cacheable.
*
* @return a {@link org.beangle.commons.dao.query.builder.OqlBuilder} object.
*/
public OqlBuilder cacheable() {
this.cacheable = true;
return this;
}
/**
* cacheable.
*
* @param cacheable a boolean.
* @return a {@link org.beangle.commons.dao.query.builder.OqlBuilder} object.
*/
public OqlBuilder cacheable(final boolean cacheable) {
this.cacheable = cacheable;
return this;
}
/**
* where.
*
* @param conditions a {@link org.beangle.commons.dao.query.builder.Condition} object.
* @return a {@link org.beangle.commons.dao.query.builder.OqlBuilder} object.
*/
public OqlBuilder where(final Condition... conditions) {
if (isNotEmpty(statement)) throw new RuntimeException("cannot add condition to a exists statement");
return where(Arrays.asList(conditions));
}
/**
* @param content
* @return
*/
public OqlBuilder where(String content) {
Condition con = new Condition(content);
return where(con);
}
public OqlBuilder where(String content, Object param1) {
Condition con = new Condition(content);
con.param(param1);
return where(con);
}
public OqlBuilder where(String content, Object param1, Object param2) {
Condition con = new Condition(content);
con.param(param1);
con.param(param2);
return where(con);
}
/**
* 为了接受数组作为参数,防止java将数组展开为可变参数特定以下几个重致where函数,
*
* @param content
* @param param1
* @param param2
* @param param3
* @param varparams
* @see https://github.com/beangle/library/issues/231
* @return
*/
public OqlBuilder where(final String content, Object param1, Object param2, Object param3,
Object... varparams) {
Condition con = new Condition(content);
con.param(param1);
con.param(param2);
con.param(param3);
if (varparams != null && varparams.length > 0) {
for (Object a : varparams) {
con.param(a);
}
}
return where(con);
}
/**
* 添加一组条件
* query中不能添加条件集合作为一个条件,因此这里命名没有采用有区别性的addAll
*
* @param cons a {@link java.util.Collection} object.
* @return a {@link org.beangle.commons.dao.query.builder.OqlBuilder} object.
*/
public OqlBuilder where(final Collection cons) {
conditions.addAll(cons);
return params(Conditions.getParamMap(cons));
}
public OqlBuilder tailOrder(final String orderBy) {
List os=Order.parse(orderBy);
if(os.isEmpty()){
this.tailOrder=null;
}else{
this.tailOrder=os.get(0);
}
return this;
}
/**
* 声明排序字符串
*
* @param orderBy 排序字符串
* @return 查询构建器
*/
public OqlBuilder orderBy(final String orderBy) {
return orderBy(Order.parse(orderBy));
}
/**
* 指定排序字符串的位置
*
* @param index 从0开始
* @param orderBy 排序字符串
* @return 查询构建器
*/
public OqlBuilder orderBy(final int index, final String orderBy) {
if (null != orders) {
if (isNotEmpty(statement)) { throw new RuntimeException("cannot add order by to a exists statement."); }
this.orders.addAll(index, Order.parse(orderBy));
}
return this;
}
/**
* orderBy.
*
* @param order a {@link org.beangle.commons.collection.Order} object.
* @return a {@link org.beangle.commons.dao.query.builder.OqlBuilder} object.
*/
public OqlBuilder orderBy(final Order order) {
if (null != order) { return orderBy(Collections.singletonList(order)); }
return this;
}
/**
* cleanOrders.
*
* @return a {@link org.beangle.commons.dao.query.builder.OqlBuilder} object.
*/
public OqlBuilder clearOrders() {
this.orders.clear();
return this;
}
/**
* orderBy.
*
* @param orders a {@link java.util.List} object.
* @return a {@link org.beangle.commons.dao.query.builder.OqlBuilder} object.
*/
public OqlBuilder orderBy(final List orders) {
if (null != orders) {
if (isNotEmpty(statement)) { throw new RuntimeException("cannot add order by to a exists statement."); }
this.orders.addAll(orders);
}
return this;
}
/**
*
* select.
*
*
* @param what a {@link java.lang.String} object.
* @return a {@link org.beangle.commons.dao.query.builder.OqlBuilder} object.
*/
public OqlBuilder select(final String what) {
if (null == what) {
this.select = null;
} else {
if (what.toLowerCase().trim().startsWith("select")) {
this.select = what;
} else {
this.select = "select " + what;
}
}
return this;
}
/**
* newFrom.
*
* @param from a {@link java.lang.String} object.
* @return a {@link org.beangle.commons.dao.query.builder.OqlBuilder} object.
*/
public OqlBuilder newFrom(final String from) {
if (null == from) {
this.from = null;
} else {
if (Strings.contains(from.toLowerCase(), "from")) {
this.from = from;
} else {
this.from = "from " + from;
}
}
return this;
}
/**
* groupBy.
*
* @param what a {@link java.lang.String} object.
* @return a {@link org.beangle.commons.dao.query.builder.OqlBuilder} object.
*/
public OqlBuilder groupBy(final String what) {
if (Strings.isNotEmpty(what)) {
groups.add(what);
}
return this;
}
/**
*
* Having subclause.
*
*
* @param what having subclause
* @return this
*/
public OqlBuilder having(final String what) {
Assert.isTrue(null != groups && !groups.isEmpty());
if (Strings.isNotEmpty(what)) having = what;
return this;
}
/**
* 形成计数查询语句,如果不能形成,则返回""
*
* @return a {@link java.lang.String} object.
*/
protected String genCountStatement() {
StringBuilder countString = new StringBuilder("select count(*) ");
// 原始查询语句
final String genQueryStr = genQueryStatement(false);
if (isEmpty(genQueryStr)) { return ""; }
final String lowerCaseQueryStr = genQueryStr.toLowerCase();
if (contains(lowerCaseQueryStr, " group ")) { return ""; }
if (contains(lowerCaseQueryStr, " union ")) { return ""; }
final int indexOfFrom = findIndexOfFrom(lowerCaseQueryStr);
final String selectWhat = lowerCaseQueryStr.substring(0, indexOfFrom);
final int indexOfDistinct = selectWhat.indexOf("distinct");
// select distinct a from table;
if (-1 != indexOfDistinct) {
if (contains(selectWhat, ",")) {
return "";
} else {
countString = new StringBuilder("select count(");
countString.append(genQueryStr.substring(indexOfDistinct, indexOfFrom)).append(") ");
}
}
int orderIdx = genQueryStr.lastIndexOf(" order ");
if (-1 == orderIdx) orderIdx = genQueryStr.length();
countString.append(genQueryStr.substring(indexOfFrom, orderIdx));
return countString.toString();
}
/**
* Find index of from
*
* @param query
* @return -1 or from index
*/
private int findIndexOfFrom(String query) {
if (query.startsWith("from")) return 0;
int fromIdx = query.indexOf(" from ");
if (-1 == fromIdx) return -1;
final int first = query.substring(0, fromIdx).indexOf("(");
if (first > 0) {
int leftCnt = 1;
int i = first + 1;
while (leftCnt != 0 && i < query.length()) {
if (query.charAt(i) == '(') leftCnt++;
else if (query.charAt(i) == ')') leftCnt--;
i++;
}
if (leftCnt > 0) return -1;
else {
fromIdx = query.indexOf(" from ", i);
return (fromIdx == -1) ? -1 : fromIdx + 1;
}
} else {
return fromIdx + 1;
}
}
/**
* forEntity.
*
* @param entityClass a {@link java.lang.Class} object.
* @return a {@link org.beangle.commons.dao.query.builder.OqlBuilder} object.
*/
public OqlBuilder forEntity(final Class entityClass) {
this.entityClass = entityClass;
return this;
}
@Override
protected Lang getLang() {
return Lang.HQL;
}
/**
* Getter for the field entityClass
.
*
* @return a {@link java.lang.Class} object.
*/
public Class getEntityClass() {
return entityClass;
}
}