新增数组关键词 compat 解决对聚合函数字段通过 query:2 分页查总数返回值错误
This commit is contained in:
parent
38c19975ea
commit
c39cd1ec7c
@ -87,6 +87,7 @@ public class JSONRequest extends JSONObject {
|
||||
public static final String SUBQUERY_RANGE_ANY = "ANY";
|
||||
|
||||
public static final String KEY_QUERY = "query";
|
||||
public static final String KEY_COMPAT = "compat";
|
||||
public static final String KEY_COUNT = "count";
|
||||
public static final String KEY_PAGE = "page";
|
||||
public static final String KEY_JOIN = "join";
|
||||
@ -97,6 +98,7 @@ public class JSONRequest extends JSONObject {
|
||||
static {
|
||||
ARRAY_KEY_LIST = new ArrayList<String>();
|
||||
ARRAY_KEY_LIST.add(KEY_QUERY);
|
||||
ARRAY_KEY_LIST.add(KEY_COMPAT);
|
||||
ARRAY_KEY_LIST.add(KEY_COUNT);
|
||||
ARRAY_KEY_LIST.add(KEY_PAGE);
|
||||
ARRAY_KEY_LIST.add(KEY_JOIN);
|
||||
|
@ -21,7 +21,7 @@ public class SQL {
|
||||
public static final String IS_NOT = " IS NOT ";
|
||||
public static final String IS_NULL = " IS NULL ";
|
||||
public static final String IS_NOT_NULL = " IS NOT NULL ";
|
||||
|
||||
|
||||
//括号必须紧跟函数名! count (...) 报错!
|
||||
public static final String COUNT = "count";
|
||||
public static final String SUM = "sum";
|
||||
@ -191,7 +191,7 @@ public class SQL {
|
||||
public static String replace(String s, String c1, String c2) {
|
||||
return "replace(" + s + ", " + c1 + ", " + c2 + ")";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param s1
|
||||
* @param s2
|
||||
@ -225,11 +225,11 @@ public class SQL {
|
||||
return "lower(" + s + ")";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//column and function<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
/**字段
|
||||
* @param column
|
||||
* @return column.isEmpty() ? "*" : column;
|
||||
@ -245,15 +245,16 @@ public class SQL {
|
||||
public static String columnAs(String column) {
|
||||
return count(column) + AS;
|
||||
}
|
||||
|
||||
|
||||
/**函数
|
||||
* @param column if (StringUtil.isEmpty(column, true) || column.contains(",")) -> column = null;
|
||||
* @return " " + fun + "(" + {@link #column(String)} + ") ";
|
||||
*/
|
||||
public static String function(String fun, String column) {
|
||||
if (StringUtil.isEmpty(column, true) || column.contains(",")) {
|
||||
column = null; //解决 count(id,name) 这种多个字段导致的SQL异常
|
||||
}
|
||||
// 支持 fun(col1,col2..)
|
||||
// if (StringUtil.isEmpty(column, true) || column.contains(",")) {
|
||||
// column = null; //解决 count(id,name) 这种多个字段导致的SQL异常
|
||||
// }
|
||||
return " " + fun + "(" + column(column) + ") ";
|
||||
}
|
||||
/**有别名的函数
|
||||
@ -263,7 +264,7 @@ public class SQL {
|
||||
public static String functionAs(String fun, String column) {
|
||||
return function(fun, column) + AS + fun + " ";
|
||||
}
|
||||
|
||||
|
||||
/**计数
|
||||
* column = null
|
||||
* @return {@link #count(String)}
|
||||
@ -313,9 +314,9 @@ public class SQL {
|
||||
}
|
||||
|
||||
//column and function>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//search<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
public static final int SEARCH_TYPE_CONTAIN_FULL = 0;
|
||||
@ -391,13 +392,13 @@ public class SQL {
|
||||
|
||||
//search>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
|
||||
|
||||
|
||||
public static boolean isBooleanOrNumber(String type) {
|
||||
type = StringUtil.toUpperCase(type, true);
|
||||
return type.isEmpty() || (type.endsWith("INT") && type.endsWith("POINT") == false)
|
||||
|| type.endsWith("BOOLEAN") || type.endsWith("ENUM")
|
||||
|| type.endsWith("FLOAT") || type.endsWith("DOUBLE") || type.endsWith("DECIMAL");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ import apijson.JSONResponse;
|
||||
import apijson.Log;
|
||||
import apijson.NotNull;
|
||||
import apijson.RequestMethod;
|
||||
import apijson.SQL;
|
||||
import apijson.StringUtil;
|
||||
import apijson.orm.exception.ConditionErrorException;
|
||||
import apijson.orm.exception.ConflictException;
|
||||
@ -1051,9 +1052,33 @@ public abstract class AbstractParser<T> implements Parser<T>, ParserCreator<T>,
|
||||
//total 这里不能用arrayConfig.getType(),因为在createObjectParser.onChildParse传到onObjectParse时已被改掉
|
||||
if (type == SQLConfig.TYPE_ITEM_CHILD_0 && query != JSONRequest.QUERY_TABLE && position == 0) {
|
||||
|
||||
RequestMethod method = op.getMethod();
|
||||
JSONObject rp = op.setMethod(RequestMethod.HEAD).setSQLConfig().executeSQL().getSqlReponse();
|
||||
op.setMethod(method);
|
||||
JSONObject rp;
|
||||
Boolean compat = arrayConfig.getCompat();
|
||||
if (compat != null && compat) {
|
||||
// 解决对聚合函数字段通过 query:2 分页查总数返回值错误
|
||||
// 这里可能改变了内部的一些数据,下方通过 arrayConfig 还原
|
||||
SQLConfig cfg = op.setSQLConfig(0, 0, 0).getSQLConfig();
|
||||
boolean isExplain = cfg.isExplain();
|
||||
cfg.setExplain(false);
|
||||
|
||||
Subquery subq = new Subquery();
|
||||
subq.setFrom(cfg.getTable());
|
||||
subq.setConfig(cfg);
|
||||
|
||||
SQLConfig countSQLCfg = createSQLConfig();
|
||||
countSQLCfg.setColumn(Arrays.asList("count(*):count"));
|
||||
countSQLCfg.setFrom(subq);
|
||||
|
||||
rp = executeSQL(countSQLCfg, false);
|
||||
|
||||
cfg.setExplain(isExplain);
|
||||
}
|
||||
else {
|
||||
// 对聚合函数字段通过 query:2 分页查总数返回值错误
|
||||
RequestMethod method = op.getMethod();
|
||||
rp = op.setMethod(RequestMethod.HEAD).setSQLConfig().executeSQL().getSqlReponse();
|
||||
op.setMethod(method);
|
||||
}
|
||||
|
||||
if (rp != null) {
|
||||
int index = parentPath.lastIndexOf("]/");
|
||||
@ -1147,6 +1172,7 @@ public abstract class AbstractParser<T> implements Parser<T>, ParserCreator<T>,
|
||||
|
||||
//不能改变,因为后面可能继续用到,导致1以上都改变 []:{0:{Comment[]:{0:{Comment:{}},1:{...},...}},1:{...},...}
|
||||
final String query = request.getString(JSONRequest.KEY_QUERY);
|
||||
final Boolean compat = request.getBoolean(JSONRequest.KEY_COMPAT);
|
||||
final Integer count = request.getInteger(JSONRequest.KEY_COUNT); //TODO 如果不想用默认数量可以改成 getIntValue(JSONRequest.KEY_COUNT);
|
||||
final Integer page = request.getInteger(JSONRequest.KEY_PAGE);
|
||||
final Object join = request.get(JSONRequest.KEY_JOIN);
|
||||
@ -1189,6 +1215,7 @@ public abstract class AbstractParser<T> implements Parser<T>, ParserCreator<T>,
|
||||
}
|
||||
|
||||
request.remove(JSONRequest.KEY_QUERY);
|
||||
request.remove(JSONRequest.KEY_COMPAT);
|
||||
request.remove(JSONRequest.KEY_COUNT);
|
||||
request.remove(JSONRequest.KEY_PAGE);
|
||||
request.remove(JSONRequest.KEY_JOIN);
|
||||
@ -1227,6 +1254,7 @@ public abstract class AbstractParser<T> implements Parser<T>, ParserCreator<T>,
|
||||
.setCount(size)
|
||||
.setPage(page2)
|
||||
.setQuery(query2)
|
||||
.setCompat(compat)
|
||||
.setTable(arrTableKey)
|
||||
.setJoinList(onJoinParse(join, request));
|
||||
|
||||
@ -1301,6 +1329,7 @@ public abstract class AbstractParser<T> implements Parser<T>, ParserCreator<T>,
|
||||
} finally {
|
||||
//后面还可能用到,要还原
|
||||
request.put(JSONRequest.KEY_QUERY, query);
|
||||
request.put(JSONRequest.KEY_COMPAT, compat);
|
||||
request.put(JSONRequest.KEY_COUNT, count);
|
||||
request.put(JSONRequest.KEY_PAGE, page);
|
||||
request.put(JSONRequest.KEY_JOIN, join);
|
||||
|
@ -104,6 +104,7 @@ public abstract class AbstractSQLConfig implements SQLConfig {
|
||||
// 自定义原始 SQL 片段 Map<key, substring>:当 substring 为 null 时忽略;当 substring 为 "" 时整个 value 是 raw SQL;其它情况则只是 substring 这段为 raw SQL
|
||||
public static final Map<String, String> RAW_MAP;
|
||||
// 允许调用的 SQL 函数:当 substring 为 null 时忽略;当 substring 为 "" 时整个 value 是 raw SQL;其它情况则只是 substring 这段为 raw SQL
|
||||
public static final Map<String, String> SQL_AGGREGATE_FUNCTION_MAP;
|
||||
public static final Map<String, String> SQL_FUNCTION_MAP;
|
||||
|
||||
|
||||
@ -242,6 +243,13 @@ public abstract class AbstractSQLConfig implements SQLConfig {
|
||||
|
||||
|
||||
|
||||
SQL_AGGREGATE_FUNCTION_MAP = new LinkedHashMap<>(); // 保证顺序,避免配置冲突等意外情况
|
||||
SQL_AGGREGATE_FUNCTION_MAP.put("max", "");
|
||||
SQL_AGGREGATE_FUNCTION_MAP.put("min", "");
|
||||
SQL_AGGREGATE_FUNCTION_MAP.put("avg", "");
|
||||
SQL_AGGREGATE_FUNCTION_MAP.put("count", "");
|
||||
SQL_AGGREGATE_FUNCTION_MAP.put("sum", "");
|
||||
|
||||
SQL_FUNCTION_MAP = new LinkedHashMap<>(); // 保证顺序,避免配置冲突等意外情况
|
||||
|
||||
//窗口函数
|
||||
@ -761,6 +769,7 @@ public abstract class AbstractSQLConfig implements SQLConfig {
|
||||
private int page; //Table所在页码
|
||||
private int position; //Table在[]中的位置
|
||||
private int query; //JSONRequest.query
|
||||
private Boolean compat; //JSONRequest.compat query total
|
||||
private int type; //ObjectParser.type
|
||||
private int cache;
|
||||
private boolean explain;
|
||||
@ -1458,14 +1467,9 @@ public abstract class AbstractSQLConfig implements SQLConfig {
|
||||
case HEAD:
|
||||
case HEADS: //StringUtil.isEmpty(column, true) || column.contains(",") 时SQL.count(column)会return "*"
|
||||
if (isPrepared() && column != null) {
|
||||
|
||||
List<String> raw = getRaw();
|
||||
boolean containRaw = raw != null && raw.contains(KEY_COLUMN);
|
||||
|
||||
String origin;
|
||||
String alias;
|
||||
int index;
|
||||
|
||||
|
||||
for (String c : column) {
|
||||
if (containRaw) {
|
||||
// 由于 HashMap 对 key 做了 hash 处理,所以 get 比 containsValue 更快
|
||||
@ -1476,9 +1480,9 @@ public abstract class AbstractSQLConfig implements SQLConfig {
|
||||
}
|
||||
}
|
||||
|
||||
index = c.lastIndexOf(":"); //StringUtil.split返回数组中,子项不会有null
|
||||
origin = index < 0 ? c : c.substring(0, index);
|
||||
alias = index < 0 ? null : c.substring(index + 1);
|
||||
int index = c.lastIndexOf(":"); //StringUtil.split返回数组中,子项不会有null
|
||||
String origin = index < 0 ? c : c.substring(0, index);
|
||||
String alias = index < 0 ? null : c.substring(index + 1);
|
||||
|
||||
if (alias != null && StringUtil.isName(alias) == false) {
|
||||
throw new IllegalArgumentException("HEAD请求: 字符 " + alias + " 不合法!预编译模式下 @column:value 中 value里面用 , 分割的每一项"
|
||||
@ -1499,8 +1503,41 @@ public abstract class AbstractSQLConfig implements SQLConfig {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean onlyOne = column != null && column.size() == 1;
|
||||
String c0 = onlyOne ? column.get(0) : null;
|
||||
|
||||
if (onlyOne) {
|
||||
int index = c0 == null ? -1 : c0.lastIndexOf(":");
|
||||
if (index > 0) {
|
||||
c0 = c0.substring(0, index);
|
||||
}
|
||||
|
||||
return SQL.count(column != null && column.size() == 1 && StringUtil.isName(column.get(0)) ? getKey(column.get(0)) : "*");
|
||||
int start = c0 == null ? -1 : c0.indexOf("(");
|
||||
int end = start <= 0 ? -1 : c0.lastIndexOf(")");
|
||||
if (start > 0 && end > start) {
|
||||
String fun = c0.substring(0, start);
|
||||
|
||||
// Invalid use of group function SELECT count(max(`id`)) AS count FROM `sys`.`Comment`
|
||||
if (SQL_AGGREGATE_FUNCTION_MAP.containsKey(fun)) {
|
||||
String group = getGroup(); // TODO 唯一 100% 兼容的可能只有 SELECT count(*) FROM (原语句) AS table
|
||||
return StringUtil.isEmpty(group, true) ? "1" : "count(DISTINCT " + group + ")";
|
||||
}
|
||||
|
||||
String[] args = start == end - 1 ? null : StringUtil.split(c0.substring(start + 1, end));
|
||||
if (args == null || args.length <= 0) {
|
||||
return SQL.count(c0);
|
||||
}
|
||||
|
||||
List<String> raw = getRaw();
|
||||
boolean containRaw = raw != null && raw.contains(KEY_COLUMN);
|
||||
|
||||
return SQL.count(parseColumn(c0, containRaw));
|
||||
}
|
||||
}
|
||||
|
||||
return SQL.count(onlyOne ? getKey(c0) : "*");
|
||||
// return SQL.count(onlyOne && StringUtil.isName(column.get(0)) ? getKey(column.get(0)) : "*");
|
||||
case POST:
|
||||
if (column == null || column.isEmpty()) {
|
||||
throw new IllegalArgumentException("POST 请求必须在Table内设置要保存的 key:value !");
|
||||
@ -1997,6 +2034,16 @@ public abstract class AbstractSQLConfig implements SQLConfig {
|
||||
this.query = query;
|
||||
return this;
|
||||
}
|
||||
@Override
|
||||
public Boolean getCompat() {
|
||||
return compat;
|
||||
}
|
||||
@Override
|
||||
public AbstractSQLConfig setCompat(Boolean compat) {
|
||||
this.compat = compat;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType() {
|
||||
return type;
|
||||
@ -3753,14 +3800,13 @@ public abstract class AbstractSQLConfig implements SQLConfig {
|
||||
|
||||
//根据方法不同,聚合语句不同。GROUP BY 和 HAVING 可以加在 HEAD 上, HAVING 可以加在 PUT, DELETE 上,GET 全加,POST 全都不加
|
||||
String aggregation = "";
|
||||
if (RequestMethod.isGetMethod(config.getMethod(), true)){
|
||||
aggregation = config.getGroupString(true) + config.getHavingString(true) +
|
||||
config.getOrderString(true);
|
||||
if (RequestMethod.isGetMethod(config.getMethod(), true)) {
|
||||
aggregation = config.getGroupString(true) + config.getHavingString(true) + config.getOrderString(true);
|
||||
}
|
||||
if (RequestMethod.isHeadMethod(config.getMethod(), true)){
|
||||
if (RequestMethod.isHeadMethod(config.getMethod(), true)) { // TODO 加参数 isPagenation 判断是 GET 内分页 query:2 查总数,不用加这些条件
|
||||
aggregation = config.getGroupString(true) + config.getHavingString(true) ;
|
||||
}
|
||||
if (config.getMethod() == PUT || config.getMethod() == DELETE){
|
||||
if (config.getMethod() == PUT || config.getMethod() == DELETE) {
|
||||
aggregation = config.getHavingString(true) ;
|
||||
}
|
||||
|
||||
@ -3825,6 +3871,8 @@ public abstract class AbstractSQLConfig implements SQLConfig {
|
||||
|
||||
// 主表不用别名 String ta;
|
||||
for (Join j : joinList) {
|
||||
onGetJoinString(j);
|
||||
|
||||
if (j.isAppJoin()) { // APP JOIN,只是作为一个标记,执行完主表的查询后自动执行副表的查询 User.id IN($commentIdList)
|
||||
continue;
|
||||
}
|
||||
@ -4089,6 +4137,9 @@ public abstract class AbstractSQLConfig implements SQLConfig {
|
||||
protected void onJoinComplextRelation(String sql, String quote, Join j, String jt, List<On> onList, On on) {
|
||||
throw new UnsupportedOperationException("JOIN 已禁用 $, ~, {}, <>, >, <, >=, <= 等复杂关联 !性能很差、需求极少,默认只允许 = 等价关联,如要取消禁用可在后端重写相关方法!");
|
||||
}
|
||||
|
||||
protected void onGetJoinString(Join j) throws UnsupportedOperationException {
|
||||
}
|
||||
protected void onGetCrossJoinString(Join j) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("已禁用 * CROSS JOIN !性能很差、需求极少,如要取消禁用可在后端重写相关方法!");
|
||||
}
|
||||
|
@ -98,6 +98,9 @@ public interface SQLConfig {
|
||||
int getQuery();
|
||||
SQLConfig setQuery(int query);
|
||||
|
||||
Boolean getCompat();
|
||||
SQLConfig setCompat(Boolean compat);
|
||||
|
||||
int getPosition();
|
||||
SQLConfig setPosition(int position);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user