package org.sothis.dal.sql; import java.lang.reflect.Array; import java.util.Collection; import java.util.Iterator; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.Query; import org.sothis.dal.query.Chain; import org.sothis.dal.query.Cnd; import org.sothis.dal.query.Logic; import org.sothis.dal.query.Op; import org.sothis.dal.query.OrderBy; import org.sothis.dal.query.Sort; /** * sql的查询生成器,基本JPA * * @author velna * */ public class SqlQueryBuilder { public final static String WHERE_PARAM_PREFIX = "w_"; public final static String SET_PARAM_PREFIX = "s_"; private final static int SQL_LEN_CAPACITY = 128; private final static String[] OP_MAP; private final static String[] LOGIC_MAP; static { OP_MAP = new String[Op.values().length]; OP_MAP[Op.EQ.ordinal()] = " = "; OP_MAP[Op.GT.ordinal()] = " > "; OP_MAP[Op.GTE.ordinal()] = " >= "; OP_MAP[Op.IN.ordinal()] = " in "; OP_MAP[Op.LIKE.ordinal()] = " like "; OP_MAP[Op.LT.ordinal()] = " < "; OP_MAP[Op.LTE.ordinal()] = " <= "; OP_MAP[Op.NE.ordinal()] = " <> "; OP_MAP[Op.NIN.ordinal()] = " not in "; LOGIC_MAP = new String[Logic.values().length]; LOGIC_MAP[Logic.AND.ordinal()] = " and "; LOGIC_MAP[Logic.OR.ordinal()] = " or "; } public static void main(String[] args) { StringBuilder sql = new StringBuilder(); appendWhere(Cnd.make("a", "a").and(Cnd.make("c", "de").or("e", "f")).or(Cnd.make("g", "h").and("i", "k")), sql); System.out.println(sql); } public static Query select(Class<?> entityClass, Cnd cnd, Chain chain, EntityManager entityManager) { StringBuilder sql = new StringBuilder(SQL_LEN_CAPACITY); sql.append("select "); if (chain != null) { sql.append("new ").append(entityClass.getName()).append('('); for (Iterator<Chain> i = chain.iterator(); i.hasNext();) { sql.append(i.next().name()); if (i.hasNext()) { sql.append(", "); } } sql.append(')'); } else { sql.append('o'); } sql.append(" from ").append(entityClass.getName()).append(" o"); appendWhere(cnd, sql); appendOrderBy(cnd, sql); Query query = entityManager.createQuery(sql.toString()); setParamValues(query, cnd, new IntegerHolder(0)); return query; } public static Query update(Class<?> entityClass, Cnd cnd, Chain chain, EntityManager entityManager) { if (chain == null) { throw new IllegalArgumentException("chain can not be null"); } StringBuilder sql = new StringBuilder(SQL_LEN_CAPACITY); sql.append("update ").append(entityClass.getName()).append(" o set "); int index = 0; for (Iterator<Chain> i = chain.iterator(); i.hasNext();) { Chain c = i.next(); sql.append("o.").append(c.name()).append("=:").append(SET_PARAM_PREFIX).append(index++); if (i.hasNext()) { sql.append(", "); } } appendWhere(cnd, sql); Query query = entityManager.createQuery(sql.toString()); index = 0; for (Iterator<Chain> i = chain.iterator(); i.hasNext();) { Chain c = i.next(); query.setParameter(SET_PARAM_PREFIX + index++, c.value()); } setParamValues(query, cnd, new IntegerHolder(0)); return query; } public static Query delete(Class<?> entityClass, Cnd cnd, EntityManager entityManager) { StringBuilder sql = new StringBuilder(SQL_LEN_CAPACITY); sql.append("delete from ").append(entityClass.getName()).append(" o"); appendWhere(cnd, sql); Query query = entityManager.createQuery(sql.toString()); setParamValues(query, cnd, new IntegerHolder(0)); return query; } public static Query count(Class<?> entityClass, Cnd cnd, EntityManager entityManager) { StringBuilder sql = new StringBuilder(SQL_LEN_CAPACITY); sql.append("select count(*) from ").append(entityClass.getName()).append(" o"); appendWhere(cnd, sql); Query query = entityManager.createQuery(sql.toString()); setParamValues(query, cnd, new IntegerHolder(0)); return query; } private static void appendWhere(Cnd cnd, StringBuilder sql) { if (null != cnd && !cnd.isOrderByOnly()) { sql.append(" where "); appendCndToSql(cnd, sql, new IntegerHolder(0)); } } private static void appendOrderBy(OrderBy orderBy, StringBuilder sql) { if (null != orderBy) { List<Sort> sorts = orderBy.getSorts(); if (sorts.size() > 0) { sql.append(" order by "); for (Iterator<Sort> i = sorts.iterator(); i.hasNext();) { Sort sort = i.next(); sql.append(sort.getField()).append(' ').append(sort.isAsc() ? "asc" : "desc"); if (i.hasNext()) { sql.append(", "); } } } } } private static void appendCndToSql(Cnd cnd, StringBuilder sql, IntegerHolder paramIndex) { Object op = cnd.getOp(); if (op instanceof Op) { if (cnd.isNot()) { sql.append(" not "); } Op _op = (Op) op; sql.append(cnd.getLeft()).append(OP_MAP[_op.ordinal()]); if (_op == Op.IN || _op == Op.NIN) { sql.append('('); if (cnd.getRight() instanceof Collection) { Collection<?> values = (Collection<?>) cnd.getRight(); for (Iterator<?> i = values.iterator(); i.hasNext();) { i.next(); sql.append(':').append(WHERE_PARAM_PREFIX).append(paramIndex.getAndIncrease()); if (i.hasNext()) { sql.append(", "); } } } else if (cnd.getRight().getClass().isArray()) { for (int i = 0; i < Array.getLength(cnd.getRight()); i++) { sql.append(':').append(WHERE_PARAM_PREFIX).append(paramIndex.getAndIncrease()); if (i < Array.getLength(cnd.getRight()) - 1) { sql.append(", "); } } } sql.append(')'); } else { sql.append(':').append(WHERE_PARAM_PREFIX).append(paramIndex.getAndIncrease()); } } else if (op instanceof Logic) { if (cnd.isNot()) { sql.append(" not ("); } Cnd left = (Cnd) cnd.getLeft(); if (left.getOp() instanceof Logic) { sql.append(" ("); } appendCndToSql(left, sql, paramIndex); if (left.getOp() instanceof Logic) { sql.append(") "); } sql.append(LOGIC_MAP[((Logic) op).ordinal()]); Cnd right = (Cnd) cnd.getRight(); if (right.getOp() instanceof Logic) { sql.append(" ("); } appendCndToSql(right, sql, paramIndex); if (right.getOp() instanceof Logic) { sql.append(") "); } if (cnd.isNot()) { sql.append(") "); } } else { throw new RuntimeException("unknown op: " + op); } } private static void setParamValues(Query query, Cnd cnd, IntegerHolder paramIndex) { if (null == cnd || null == cnd.getOp()) { return; } Object op = cnd.getOp(); if (op instanceof Op) { Op _op = (Op) op; if (_op == Op.IN || _op == Op.NIN) { if (cnd.getRight() instanceof Collection) { Collection<?> values = (Collection<?>) cnd.getRight(); for (Iterator<?> i = values.iterator(); i.hasNext();) { query.setParameter(WHERE_PARAM_PREFIX + paramIndex.getAndIncrease(), i.next()); } } else if (cnd.getRight().getClass().isArray()) { for (int i = 0; i < Array.getLength(cnd.getRight()); i++) { query.setParameter(WHERE_PARAM_PREFIX + paramIndex.getAndIncrease(), Array.get(cnd.getRight(), i)); } } } else { query.setParameter(WHERE_PARAM_PREFIX + paramIndex.getAndIncrease(), cnd.getRight()); } } else if (op instanceof Logic) { setParamValues(query, (Cnd) cnd.getLeft(), paramIndex); setParamValues(query, (Cnd) cnd.getRight(), paramIndex); } else { throw new RuntimeException("unknown op: " + op); } } private static class IntegerHolder { private int value; public IntegerHolder(int initValue) { this.value = initValue; } public int getAndIncrease() { return value++; } } }