package com.pugwoo.dbhelper.sql; import com.pugwoo.dbhelper.annotation.*; import com.pugwoo.dbhelper.enums.JoinTypeEnum; import com.pugwoo.dbhelper.exception.*; import com.pugwoo.dbhelper.impl.DBHelperContext; import com.pugwoo.dbhelper.json.NimbleOrmJSON; import com.pugwoo.dbhelper.model.SubQuery; import com.pugwoo.dbhelper.utils.DOInfoReader; import com.pugwoo.dbhelper.utils.ScriptUtils; import com.pugwoo.dbhelper.utils.TypeAutoCast; import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.select.PlainSelect; import net.sf.jsqlparser.statement.select.Select; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.Field; import java.text.SimpleDateFormat; import java.util.*; /** * SQL解析工具类 * * @author pugwoo * 2017年3月16日 23:02:47 */ public class SQLUtils { private static final Logger LOGGER = LoggerFactory.getLogger(SQLUtils.class); /** * 展开子查询SubQuery子句。该方法不支持子查询嵌套,由上一层方法来嵌套调用以实现SubQuery子句嵌套。 * 该方法会自动处理软删除标记。 * @param subQuery * @param values 带回去的参数列表 * @return */ public static String expandSubQuery(SubQuery subQuery, List<Object> values) { StringBuilder sql = new StringBuilder(); sql.append("SELECT * FROM (SELECT "); sql.append(subQuery.getField()); sql.append(" FROM ").append(getTableName(subQuery.getClazz())); // 注意:subQuery这里不用table的alias sql.append(" ").append(SQLUtils.autoSetSoftDeleted(subQuery.getPostSql(), subQuery.getClazz())); sql.append(") sub "); if(subQuery.getArgs() != null) { values.addAll(Arrays.asList(subQuery.getArgs())); } return sql.toString(); } /** * select 字段 from t_table, 不包含where子句及以后的语句 * @param clazz * @param selectOnlyKey 是否只查询key * @param isSelect1 是否只select 1,不查询实际字段;当该值为true时,selectOnlyKey无效。 * @return */ public static String getSelectSQL(Class<?> clazz, boolean selectOnlyKey, boolean isSelect1) { StringBuilder sql = new StringBuilder(); sql.append("SELECT "); // 处理join方式clazz JoinTable joinTable = DOInfoReader.getJoinTable(clazz); if(joinTable != null) { Field leftTableField = DOInfoReader.getJoinLeftTable(clazz); Field rightTableField = DOInfoReader.getJoinRightTable(clazz); JoinLeftTable joinLeftTable = leftTableField.getAnnotation(JoinLeftTable.class); JoinRightTable joinRightTable = rightTableField.getAnnotation(JoinRightTable.class); if(isSelect1) { sql.append("1"); } else { List<Field> fields1 = DOInfoReader.getColumnsForSelect(leftTableField.getType(), selectOnlyKey); List<Field> fields2 = DOInfoReader.getColumnsForSelect(rightTableField.getType(), selectOnlyKey); sql.append(join(fields1, ",", joinLeftTable.alias() + ".")); sql.append(","); sql.append(join(fields2, ",", joinRightTable.alias() + ".")); } sql.append(" FROM ").append(getTableName(leftTableField.getType())) .append(" ").append(joinLeftTable.alias()).append(" "); sql.append(joinTable.joinType().getCode()).append(" "); sql.append(getTableName(rightTableField.getType())).append(" ").append(joinRightTable.alias()); if(joinTable.on().trim().isEmpty()) { throw new OnConditionIsNeedException("join table :" + clazz.getName()); } sql.append(" on ").append(joinTable.on().trim()); } else { Table table = DOInfoReader.getTable(clazz); if(isSelect1) { sql.append("1"); } else { List<Field> fields = DOInfoReader.getColumnsForSelect(clazz, selectOnlyKey); sql.append(join(fields, ",")); } sql.append(" FROM ").append(getTableName(clazz)).append(" ").append(table.alias()); } return sql.toString(); } /** * select count(1) from t_table, 不包含where子句及以后的语句 * @param clazz * @return */ public static String getSelectCountSQL(Class<?> clazz) { StringBuilder sql = new StringBuilder(); sql.append("SELECT count(*)"); // 处理join方式clazz JoinTable joinTable = DOInfoReader.getJoinTable(clazz); if(joinTable != null) { Field leftTableField = DOInfoReader.getJoinLeftTable(clazz); Field rightTableField = DOInfoReader.getJoinRightTable(clazz); JoinLeftTable joinLeftTable = leftTableField.getAnnotation(JoinLeftTable.class); JoinRightTable joinRightTable = rightTableField.getAnnotation(JoinRightTable.class); sql.append(" FROM ").append(getTableName(leftTableField.getType())) .append(" ").append(joinLeftTable.alias()).append(" "); sql.append(joinTable.joinType().getCode()).append(" "); sql.append(getTableName(rightTableField.getType())).append(" ").append(joinRightTable.alias()); if(joinTable.on().trim().isEmpty()) { throw new OnConditionIsNeedException("join table VO:" + clazz.getName()); } sql.append(" on ").append(joinTable.on().trim()); } else { Table table = DOInfoReader.getTable(clazz); sql.append(" FROM ").append(getTableName(clazz)).append(" ").append(table.alias()); } return sql.toString(); } /** * 获得主键where子句,包含where关键字。会自动处理软删除条件 * * @param t * @param keyValues 返回传入sql的参数,如果提供list则写入 * @return 返回值前面会带空格,以确保安全。 * @throws NoKeyColumnAnnotationException * @throws NullKeyValueException */ public static <T> String getKeysWhereSQL(T t, List<Object> keyValues) throws NoKeyColumnAnnotationException, NullKeyValueException { List<Field> keyFields = DOInfoReader.getKeyColumns(t.getClass()); List<Object> _keyValues = new ArrayList<Object>(); String where = joinWhereAndGetValue(keyFields, "AND", _keyValues, t); // 检查主键不允许为null for(Object value : _keyValues) { if(value == null) { throw new NullKeyValueException(); } } if(keyValues != null) { keyValues.addAll(_keyValues); } return autoSetSoftDeleted("WHERE " + where, t.getClass()); } /** * 获得主键where子句,包含where关键字。会自动处理软删除条件 * * @param clazz * @throws NoKeyColumnAnnotationException */ public static String getKeysWhereSQL(Class<?> clazz) throws NoKeyColumnAnnotationException { List<Field> keyFields = DOInfoReader.getKeyColumns(clazz); String where = joinWhere(keyFields, "AND"); return autoSetSoftDeleted("WHERE " + where, clazz); } /** * 获得主键in(?)的where子句,包含where关键字。会自动处理软删除条件 * @param clazz * @return */ public static String getKeyInWhereSQL(Class<?> clazz) { Field keyField = DOInfoReader.getOneKeyColumn(clazz); return autoSetSoftDeleted("WHERE " + getColumnName(keyField.getAnnotation(Column.class)) + " in (?)", clazz); } /** * 生成insert语句,将值放到values中。 * @param t * @param values 必须 * @param isWithNullValue 标记是否将null字段放到insert语句中 * @return */ public static <T> String getInsertSQL(T t, List<Object> values, boolean isWithNullValue) { StringBuilder sql = new StringBuilder("INSERT INTO "); List<Field> fields = DOInfoReader.getColumns(t.getClass()); sql.append(getTableName(t.getClass())).append(" ("); List<Object> _values = new ArrayList<Object>(); // 之所以增加一个临时变量,是避免values初始不是空的易错情况 String fieldSql = joinAndGetValue(fields, ",", _values, t, isWithNullValue); sql.append(fieldSql); sql.append(") VALUES "); String dotSql = "(" + join("?", _values.size(), ",") + ")"; sql.append(dotSql); values.addAll(_values); return sql.toString(); } /** * 生成insert into (...) select ?,?,? from where not exists (select 1 from where)语句 * @param t * @param values * @param whereSql * @return */ public static <T> String getInsertWhereNotExistSQL(T t, List<Object> values, boolean isWithNullValue, String whereSql) { StringBuilder sql = new StringBuilder("INSERT INTO "); List<Field> fields = DOInfoReader.getColumns(t.getClass()); String tableName = getTableName(t.getClass()); sql.append(tableName).append(" ("); sql.append(joinAndGetValue(fields, ",", values, t, isWithNullValue)); sql.append(") select "); sql.append(join("?", values.size(), ",")); sql.append(" from dual where not exists (select 1 from "); if(!whereSql.trim().toUpperCase().startsWith("WHERE ")) { whereSql = "where " + whereSql; } whereSql = autoSetSoftDeleted(whereSql, t.getClass()); sql.append(tableName).append(" ").append(whereSql).append(" limit 1)"); return sql.toString(); } /** * 生成update语句 * @param t * @param values * @param withNull * @param postSql * @return 返回值为null表示不需要更新操作,这个是这个方法特别之处 */ public static <T> String getUpdateSQL(T t, List<Object> values, boolean withNull, String postSql) { StringBuilder sql = new StringBuilder(); sql.append("UPDATE "); List<Field> keyFields = DOInfoReader.getKeyColumns(t.getClass()); List<Field> notKeyFields = DOInfoReader.getNotKeyColumns(t.getClass()); sql.append(getTableName(t.getClass())).append(" SET "); List<Object> setValues = new ArrayList<Object>(); String setSql = joinSetAndGetValue(notKeyFields, setValues, t, withNull); if(setValues.isEmpty()) { return null; // all field is empty, not need to update } sql.append(setSql); values.addAll(setValues); List<Object> whereValues = new ArrayList<Object>(); String where = "WHERE " + joinWhereAndGetValue(keyFields, "AND", whereValues, t); // 检查key值是否有null的,不允许有null for(Object v : whereValues) { if(v == null) { throw new NullKeyValueException(); } } values.addAll(whereValues); Field casVersionField = DOInfoReader.getCasVersionColumn(t.getClass()); if(casVersionField != null) { List<Field> casVersionFields = new ArrayList<Field>(); casVersionFields.add(casVersionField); List<Object> casValues = new ArrayList<Object>(); String casWhere = joinWhereAndGetValue(casVersionFields, "AND", casValues, t); if(casValues.size() != 1 || casValues.get(0) == null) { throw new CasVersionNotMatchException("casVersion column value is null"); } values.add(casValues.get(0)); where = where + " AND " + casWhere; } // 带上postSql if(postSql != null) { postSql = postSql.trim(); if(!postSql.isEmpty()) { if(postSql.startsWith("where")) { postSql = " AND " + postSql.substring(5); } where = where + postSql; } } sql.append(autoSetSoftDeleted(where, t.getClass())); return sql.toString(); } /** * 获得批量更新sql * @param clazz * @param setSql * @param whereSql * @param extraWhereSql 会放在最后,以满足update子select语句的要求 * @return */ public static <T> String getUpdateAllSQL(Class<T> clazz, String setSql, String whereSql, String extraWhereSql) { StringBuilder sql = new StringBuilder(); sql.append("UPDATE "); List<Field> fields = DOInfoReader.getColumns(clazz); sql.append(getTableName(clazz)).append(" "); if(setSql.trim().toLowerCase().startsWith("set ")) { sql.append(setSql); } else { sql.append("SET ").append(setSql); } // 加上更新时间和updateValueScript for(Field field : fields) { Column column = field.getAnnotation(Column.class); if(column.setTimeWhenUpdate() && Date.class.isAssignableFrom(field.getType())) { sql.append(",").append(getColumnName(column)) .append("=").append(getDateString(new Date())); } String updateValueScript = column.updateValueScript().trim(); if(!updateValueScript.isEmpty()) { Object value = ScriptUtils.getValueFromScript(column.ignoreScriptError(), updateValueScript); if(value != null) { sql.append(",").append(getColumnName(column)).append("=") .append(TypeAutoCast.toSqlValueStr(value)); } } } sql.append(autoSetSoftDeleted(whereSql, clazz, extraWhereSql)); return sql.toString(); } /** * 获得自定义更新的sql * @param t * @param values * @param setSql * @return */ public static <T> String getCustomUpdateSQL(T t, List<Object> values, String setSql) { StringBuilder sql = new StringBuilder(); sql.append("UPDATE "); List<Field> fields = DOInfoReader.getColumns(t.getClass()); List<Field> keyFields = DOInfoReader.getKeyColumns(t.getClass()); sql.append(getTableName(t.getClass())).append(" "); if(setSql.trim().toLowerCase().startsWith("set ")) { sql.append(setSql); } else { sql.append("SET ").append(setSql); } // 加上更新时间和casVersion字段、updateValueScript字段 for(Field field : fields) { Column column = field.getAnnotation(Column.class); if(column.setTimeWhenUpdate() && Date.class.isAssignableFrom(field.getType())) { sql.append(",").append(getColumnName(column)) .append("=").append(getDateString(new Date())); } if(column.casVersion()) { Object value = DOInfoReader.getValue(field, t); if(value == null) { throw new CasVersionNotMatchException("casVersion column value is null"); } Long _v = null; if(value instanceof Long) { _v = (Long) value; } else if (value instanceof Integer) { _v = ((Integer) value).longValue(); } else { throw new CasVersionNotMatchException("casVersion column value type must be Integer or Long"); } sql.append(",").append(getColumnName(column)).append("=").append(_v + 1); } String updateValueScript = column.updateValueScript().trim(); if(!updateValueScript.isEmpty()) { Object value = ScriptUtils.getValueFromScript(t, column.ignoreScriptError(), updateValueScript); if(value != null) { sql.append(",").append(getColumnName(column)).append("=") .append(TypeAutoCast.toSqlValueStr(value)); } } } List<Object> whereValues = new ArrayList<Object>(); String where = "WHERE " + joinWhereAndGetValue(keyFields, "AND", whereValues, t); for(Object value : whereValues) { if(value == null) { throw new NullKeyValueException(); } } values.addAll(whereValues); Field casVersionField = DOInfoReader.getCasVersionColumn(t.getClass()); if(casVersionField != null) { List<Field> casVersionFields = new ArrayList<Field>(); casVersionFields.add(casVersionField); List<Object> casValues = new ArrayList<Object>(); String casWhere = joinWhereAndGetValue(casVersionFields, "AND", casValues, t); if(casValues.size() != 1 || casValues.get(0) == null) { throw new CasVersionNotMatchException("casVersion column value is null"); } values.add(casValues.get(0)); where = where + " AND " + casWhere; } sql.append(autoSetSoftDeleted(where, t.getClass())); return sql.toString(); } /** * 获得软删除SQL * @param t * @param values * @return */ public static <T> String getSoftDeleteSQL(T t, Column softDeleteColumn, List<Object> values) { String setSql = getColumnName(softDeleteColumn) + "=" + softDeleteColumn.softDelete()[1]; // 处理deleteValueScript List<Field> notKeyFields = DOInfoReader.getNotKeyColumns(t.getClass()); for(Field field : notKeyFields) { Column column = field.getAnnotation(Column.class); String deleteValueScript = column.deleteValueScript().trim(); if(!deleteValueScript.isEmpty()) { Object value = DOInfoReader.getValue(field, t); if(value != null) { setSql = setSql + "," + getColumnName(column) + "=" + TypeAutoCast.toSqlValueStr(value); } } } return getCustomDeleteSQL(t, values, setSql); } /** * 获得自定义删除SQL * @param clazz * @param postSql * @return */ public static <T> String getCustomDeleteSQL(Class<T> clazz, String postSql) { StringBuilder sql = new StringBuilder(); sql.append("DELETE FROM "); sql.append(getTableName(clazz)); sql.append(autoSetSoftDeleted(postSql, clazz)); // 物理删除也执行deleteValueScript,但是不关心其返回值 List<Field> fields = DOInfoReader.getColumns(clazz); for(Field field : fields) { Column column = field.getAnnotation(Column.class); String deleteValueScript = column.deleteValueScript().trim(); if(!deleteValueScript.isEmpty()) { ScriptUtils.getValueFromScript(column.ignoreScriptError(), deleteValueScript); } } return sql.toString(); } public static <T> String getCustomSoftDeleteSQL(Class<T> clazz, String postSql) { List<Field> fields = DOInfoReader.getColumns(clazz); Field softDelete = DOInfoReader.getSoftDeleteColumn(clazz); Column softDeleteColumn = softDelete.getAnnotation(Column.class); StringBuilder sql = new StringBuilder(); sql.append("UPDATE ").append(getTableName(clazz)); sql.append(" SET ").append(getColumnName(softDeleteColumn)); sql.append("=").append(softDeleteColumn.softDelete()[1]); // 特殊处理@Column setTimeWhenDelete时间,还有deleteValueScript for(Field field : fields) { Column column = field.getAnnotation(Column.class); if(column.setTimeWhenDelete() && Date.class.isAssignableFrom(field.getType())) { sql.append(",").append(getColumnName(column)).append("='"); SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); sql.append(df.format(new Date())).append("'"); } String deleteValueScript = column.deleteValueScript().trim(); if(!deleteValueScript.isEmpty()) { Object value = ScriptUtils.getValueFromScript(column.ignoreScriptError(), deleteValueScript); if(value != null) { sql.append(",").append(getColumnName(column)).append("=") .append(TypeAutoCast.toSqlValueStr(value)); } } } sql.append(autoSetSoftDeleted(postSql, clazz)); return sql.toString(); } /** * 获得自定义更新的sql * @param t * @param values * @param setSql * @return */ public static <T> String getCustomDeleteSQL(T t, List<Object> values, String setSql) { StringBuilder sql = new StringBuilder(); sql.append("UPDATE "); List<Field> fields = DOInfoReader.getColumns(t.getClass()); List<Field> keyFields = DOInfoReader.getKeyColumns(t.getClass()); sql.append(getTableName(t.getClass())).append(" "); if(setSql.trim().toLowerCase().startsWith("set ")) { sql.append(setSql); } else { sql.append("SET ").append(setSql); } // 加上删除时间 for(Field field : fields) { Column column = field.getAnnotation(Column.class); if(column.setTimeWhenDelete() && Date.class.isAssignableFrom(field.getType())) { sql.append(",").append(getColumnName(column)) .append("=").append(getDateString(new Date())); } } List<Object> whereValues = new ArrayList<Object>(); String where = "WHERE " + joinWhereAndGetValue(keyFields, "AND", whereValues, t); for(Object value : whereValues) { if(value == null) { throw new NullKeyValueException(); } } values.addAll(whereValues); sql.append(autoSetSoftDeleted(where, t.getClass())); return sql.toString(); } /** * 获得硬删除SQL * @param t * @param values * @return */ public static <T> String getDeleteSQL(T t, List<Object> values) { List<Field> keyFields = DOInfoReader.getKeyColumns(t.getClass()); StringBuilder sql = new StringBuilder(); sql.append("DELETE FROM "); sql.append(getTableName(t.getClass())); List<Object> _values = new ArrayList<Object>(); String where = "WHERE " + joinWhereAndGetValue(keyFields, "AND", _values, t); for(Object value : _values) { // 检查key的值是不是null if(value == null) { throw new NullKeyValueException(); } } values.addAll(_values); sql.append(autoSetSoftDeleted(where, t.getClass())); return sql.toString(); } /** * 往where sql里面插入AND关系的表达式。 * * 例如:whereSql为 where a!=3 or a!=2 limit 1 * condExpress为 deleted=0 * 那么返回:where (deleted=0 and (a!=3 or a!=2)) limit 1 * * @param whereSql 从where起的sql子句,如果有where必须带上where关键字。 * @param condExpression 例如a=? 不带where或and关键字。 * @return 注意返回字符串前面没有空格 * @throws JSQLParserException */ public static String insertWhereAndExpression(String whereSql, String condExpression) throws JSQLParserException { if(condExpression == null || condExpression.trim().isEmpty()) { return whereSql == null ? "" : whereSql; } if(whereSql == null || whereSql.trim().isEmpty()) { return "WHERE " + condExpression; } whereSql = whereSql.trim(); if(!whereSql.toUpperCase().startsWith("WHERE ")) { return "WHERE " + condExpression + " " + whereSql; } // 为解决JSqlParse对复杂的condExpression不支持的问题,这里用替换的形式来达到目的 String magic = "A" + UUID.randomUUID().toString().replace("-", ""); String selectSql = "select * from dual "; // 辅助where sql解析用 Statement statement = CCJSqlParserUtil.parse(selectSql + whereSql); Select selectStatement = (Select) statement; PlainSelect plainSelect = (PlainSelect)selectStatement.getSelectBody(); Expression ce = CCJSqlParserUtil.parseCondExpression(magic); Expression oldWhere = plainSelect.getWhere(); Expression newWhere = new FixedAndExpression(oldWhere, ce); plainSelect.setWhere(newWhere); String result = plainSelect.toString().substring(selectSql.length()); return result.replace(magic, condExpression); } public static <T> String autoSetSoftDeleted(String whereSql, Class<?> clazz) { return autoSetSoftDeleted(whereSql, clazz, ""); } /** * 自动为【最后】where sql字句加上软删除查询字段 * @param whereSql 如果有where条件的,【必须】带上where关键字;如果是group by或空的字符串或null都可以 * @param clazz 要操作的DO类 * @param extraWhere 附带的where语句,会加进去,不能带where关键字,仅能是where的条件字句,该子句会放到最后 * @return 无论如何前面会加空格,更安全 */ public static <T> String autoSetSoftDeleted(String whereSql, Class<?> clazz, String extraWhere) { if(whereSql == null) { whereSql = ""; } extraWhere = extraWhere == null ? "" : extraWhere.trim(); if(!extraWhere.isEmpty()) { extraWhere = "(" + extraWhere + ")"; } String deletedExpression = ""; // 处理join方式clazz JoinTable joinTable = DOInfoReader.getJoinTable(clazz); if(joinTable != null) { Field leftTableField = DOInfoReader.getJoinLeftTable(clazz); Field rightTableField = DOInfoReader.getJoinRightTable(clazz); JoinLeftTable joinLeftTable = leftTableField.getAnnotation(JoinLeftTable.class); JoinRightTable joinRightTable = rightTableField.getAnnotation(JoinRightTable.class); Field softDeleteT1 = DOInfoReader.getSoftDeleteColumn(leftTableField.getType()); Field softDeleteT2 = DOInfoReader.getSoftDeleteColumn(rightTableField.getType()); if(softDeleteT1 == null && softDeleteT2 == null) { try { return " " + insertWhereAndExpression(whereSql, extraWhere); } catch (JSQLParserException e) { LOGGER.error("Bad sql syntax,whereSql:{},deletedExpression:{}", whereSql, deletedExpression, e); throw new BadSQLSyntaxException(e); } } StringBuilder deletedExpressionSb = new StringBuilder(); if(softDeleteT1 != null) { Column softDeleteColumn = softDeleteT1.getAnnotation(Column.class); String columnName = getColumnName(softDeleteColumn); if(joinTable.joinType() == JoinTypeEnum.RIGHT_JOIN) { deletedExpressionSb.append("(").append(joinLeftTable.alias()).append(".").append( columnName + "=" + softDeleteColumn.softDelete()[0]) .append(" or ").append(joinLeftTable.alias()).append(".") .append(columnName).append(" is null)"); } else { deletedExpressionSb.append(joinLeftTable.alias()).append(".").append( columnName + "=" + softDeleteColumn.softDelete()[0]); } } if(softDeleteT2 != null) { if(softDeleteT1 != null) { deletedExpressionSb.append(" AND "); } Column softDeleteColumn = softDeleteT2.getAnnotation(Column.class); String columnName = getColumnName(softDeleteColumn); if(joinTable.joinType() == JoinTypeEnum.LEFT_JOIN) { deletedExpressionSb.append("(").append(joinRightTable.alias()).append(".").append( columnName + "=" + softDeleteColumn.softDelete()[0]) .append(" or ").append(joinRightTable.alias()).append(".") .append(columnName).append(" is null)"); } else { deletedExpressionSb.append(joinRightTable.alias()).append(".").append( columnName + "=" + softDeleteColumn.softDelete()[0]); } } deletedExpression = deletedExpressionSb.toString(); } else { Field softDelete = DOInfoReader.getSoftDeleteColumn(clazz); if(softDelete == null) { try { return " " + insertWhereAndExpression(whereSql, extraWhere); } catch (JSQLParserException e) { LOGGER.error("Bad sql syntax,whereSql:{},deletedExpression:{}", whereSql, deletedExpression, e); throw new BadSQLSyntaxException(e); } } Column softDeleteColumn = softDelete.getAnnotation(Column.class); deletedExpression = getColumnName(softDeleteColumn) + "=" + softDeleteColumn.softDelete()[0]; } try { if(!extraWhere.isEmpty()) { deletedExpression = "(" + deletedExpression + " and " + extraWhere + ")"; } return " " + SQLUtils.insertWhereAndExpression(whereSql, deletedExpression); } catch (JSQLParserException e) { LOGGER.error("Bad sql syntax,whereSql:{},deletedExpression:{}", whereSql, deletedExpression, e); throw new BadSQLSyntaxException(e); } } /** * 拼凑limit字句。前面有空格。 * @param offset 可以为null * @param limit 不能为null * @return */ public static String genLimitSQL(Integer offset, Integer limit) { StringBuilder sb = new StringBuilder(); if (limit != null) { sb.append(" limit "); if(offset != null) { sb.append(offset).append(","); } sb.append(limit); } return sb.toString(); } /** * 拼凑select的field的语句 * @param fields * @param sep * @return */ private static String join(List<Field> fields, String sep) { return join(fields, sep, null); } /** * 拼凑select的field的语句 * @param fields * @param sep * @param fieldPrefix * @return */ private static String join(List<Field> fields, String sep, String fieldPrefix) { return joinAndGetValueForSelect(fields, sep, fieldPrefix); } /** * 拼凑where子句,并把需要的参数写入到values中。返回sql【不】包含where关键字 * * @param fields * @param logicOperate 操作符,例如AND * @param values * @param obj * @return */ private static String joinWhereAndGetValue(List<Field> fields, String logicOperate, List<Object> values, Object obj) { StringBuilder sb = new StringBuilder(); int fieldSize = fields.size(); for(int i = 0; i < fieldSize; i++) { Column column = fields.get(i).getAnnotation(Column.class); sb.append(getColumnName(column)).append("=?"); if(i < fieldSize - 1) { sb.append(" ").append(logicOperate).append(" "); } Object val = DOInfoReader.getValue(fields.get(i), obj); if(val != null && column.isJSON()) { val = NimbleOrmJSON.toJson(val); } values.add(val); } return sb.toString(); } /** * 拼凑where子句。返回sql【不】包含where关键字 * @param fields * @param logicOperate 操作符,例如AND * @return */ private static String joinWhere(List<Field> fields, String logicOperate) { StringBuilder sb = new StringBuilder(); int fieldSize = fields.size(); for(int i = 0; i < fieldSize; i++) { Column column = fields.get(i).getAnnotation(Column.class); sb.append(getColumnName(column)).append("=?"); if(i < fieldSize - 1) { sb.append(" ").append(logicOperate).append(" "); } } return sb.toString(); } /** * 拼凑字段逗号,分隔子句(用于insert),并把参数obj的值放到values中 * @param fields * @param sep * @param values * @param obj * @param isWithNullValue 是否把null值放到values中 * @return */ private static String joinAndGetValue(List<Field> fields, String sep, List<Object> values, Object obj, boolean isWithNullValue) { return joinAndGetValueForInsert(fields, sep, null, values, obj, isWithNullValue); } /** * 拼凑字段逗号,分隔子句(用于select)。会处理computed的@Column字段 * @param fields * @param sep * @param fieldPrefix * @return */ private static String joinAndGetValueForSelect(List<Field> fields, String sep, String fieldPrefix) { fieldPrefix = fieldPrefix == null ? "" : fieldPrefix.trim(); StringBuilder sb = new StringBuilder(); for(Field field : fields) { Column column = field.getAnnotation(Column.class); String computed = column.computed().trim(); if(!computed.isEmpty()) { sb.append("(").append(computed).append(") AS "); } else { sb.append(fieldPrefix); // 计算列不支持默认前缀,当join时,请自行区分计算字段的命名 } sb.append(getColumnName(column)).append(sep); } int len = sb.length(); return len == 0 ? "" : sb.toString().substring(0, len - 1); } /** * 拼凑字段逗号,分隔子句(用于insert),并把参数obj的值放到values中。会排除掉computed的@Column字段 * * @param fields * @param sep * @param fieldPrefix * @param values 不应该为null * @param obj 不应该为null * @param isWithNullValue 是否把null值放到values中 * @return */ private static String joinAndGetValueForInsert(List<Field> fields, String sep, String fieldPrefix, List<Object> values, Object obj, boolean isWithNullValue) { if(values == null || obj == null) { throw new InvalidParameterException("joinAndGetValueForInsert require values and obj"); } fieldPrefix = fieldPrefix == null ? "" : fieldPrefix.trim(); StringBuilder sb = new StringBuilder(); for(Field field : fields) { Column column = field.getAnnotation(Column.class); if(!(column.computed().trim().isEmpty())) { continue; // insert不加入computed字段 } Object value = DOInfoReader.getValue(field, obj); if(value != null && column.isJSON()) { value = NimbleOrmJSON.toJson(value); } if(isWithNullValue) { values.add(value); } else { if(value == null) { continue; // 不加入该column } else { values.add(value); } } sb.append(fieldPrefix).append(getColumnName(column)).append(sep); } int len = sb.length(); return len == 0 ? "" : sb.toString().substring(0, len - 1); } /** * 例如:str=?,times=3,sep=, 返回 ?,?,? */ private static String join(String str, int times, String sep) { StringBuilder sb = new StringBuilder(); for(int i = 0; i < times; i++) { sb.append(str); if(i < times - 1) { sb.append(sep); } } return sb.toString(); } /** * 拼凑set子句,将会处理casVersion的字段自动+1 * @param fields * @param values * @param obj * @param withNull 当为true时,如果field的值为null,也加入 * @return */ private static String joinSetAndGetValue(List<Field> fields, List<Object> values, Object obj, boolean withNull) { StringBuilder sb = new StringBuilder(); int fieldSize = fields.size(); for(int i = 0; i < fieldSize; i++) { Column column = fields.get(i).getAnnotation(Column.class); Object value = DOInfoReader.getValue(fields.get(i), obj); if(column.casVersion()) { if(value == null) { throw new CasVersionNotMatchException("casVersion column value is null"); } Long _v = null; if(value instanceof Long) { _v = (Long) value; } else if (value instanceof Integer) { _v = ((Integer) value).longValue(); } else { throw new CasVersionNotMatchException("casVersion column type must be Integer or Long"); } sb.append(getColumnName(column)).append("=").append(_v + 1).append(","); } else { if(value != null && column.isJSON()) { value = NimbleOrmJSON.toJson(value); } if(withNull || value != null) { sb.append(getColumnName(column)).append("=?,"); values.add(value); } } } return sb.length() == 0 ? "" : sb.substring(0, sb.length() - 1); } private static String getTableName(Class<?> clazz) { String tableName = DBHelperContext.getTableName(clazz); if(tableName != null) { return "`" + tableName + "`"; } Table table = DOInfoReader.getTable(clazz); return "`" + table.value() + "`"; } private static String getColumnName(Column column) { return "`" + column.value() + "`"; } /** * 输出类似:'2017-05-25 11:22:33' * @param date * @return */ private static String getDateString(Date date) { SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); return "'" + df.format(date) + "'"; } }