【性能】通过缓存及复用数组主表 ObjectParser 来大幅提升查询数组的性能

This commit is contained in:
TommyLemon 2021-01-31 19:35:52 +08:00
parent 6831cb6a6d
commit a406242a81
5 changed files with 553 additions and 506 deletions

View File

@ -61,12 +61,6 @@ public abstract class AbstractObjectParser implements ObjectParser {
protected final List<Join> joinList; protected final List<Join> joinList;
protected final boolean isTable; protected final boolean isTable;
protected final boolean isArrayMainTable; protected final boolean isArrayMainTable;
protected final boolean isReuse;
protected final String path;
protected final String name;
protected final String table;
protected final String alias;
protected final boolean tri; protected final boolean tri;
/** /**
@ -80,26 +74,23 @@ public abstract class AbstractObjectParser implements ObjectParser {
* @param name * @param name
* @throws Exception * @throws Exception
*/ */
public AbstractObjectParser(@NotNull JSONObject request, String parentPath, String name, SQLConfig arrayConfig, boolean isSubquery) throws Exception { public AbstractObjectParser(@NotNull JSONObject request, String parentPath, SQLConfig arrayConfig
, boolean isSubquery, boolean isTable, boolean isArrayMainTable) throws Exception {
if (request == null) { if (request == null) {
throw new IllegalArgumentException(TAG + ".ObjectParser request == null!!!"); throw new IllegalArgumentException(TAG + ".ObjectParser request == null!!!");
} }
this.request = request; this.request = request;
this.parentPath = parentPath; this.parentPath = parentPath;
this.arrayConfig = arrayConfig; this.arrayConfig = arrayConfig;
this.isSubquery = isSubquery; this.isSubquery = isSubquery;
this.type = arrayConfig == null ? 0 : arrayConfig.getType(); this.type = arrayConfig == null ? 0 : arrayConfig.getType();
this.joinList = arrayConfig == null ? null : arrayConfig.getJoinList(); this.joinList = arrayConfig == null ? null : arrayConfig.getJoinList();
this.name = name;
this.path = AbstractParser.getAbsPath(parentPath, name); this.isTable = isTable; // apijson.JSONObject.isTableKey(table);
this.isArrayMainTable = isArrayMainTable; // isSubquery == false && this.isTable && this.type == SQLConfig.TYPE_ITEM_CHILD_0 && RequestMethod.isGetMethod(method, true);
apijson.orm.Entry<String, String> entry = Pair.parseEntry(name, true); // this.isReuse = isReuse; // isArrayMainTable && arrayConfig != null && arrayConfig.getPosition() > 0;
this.table = entry.getKey();
this.alias = entry.getValue();
this.isTable = apijson.JSONObject.isTableKey(table);
this.isArrayMainTable = isSubquery == false && this.isTable && this.type == SQLConfig.TYPE_ITEM_CHILD_0 && RequestMethod.isGetMethod(method, true);
this.isReuse = isArrayMainTable && arrayConfig != null && arrayConfig.getPosition() > 0;
this.objectCount = 0; this.objectCount = 0;
this.arrayCount = 0; this.arrayCount = 0;
@ -117,11 +108,10 @@ public abstract class AbstractObjectParser implements ObjectParser {
request.remove(KEY_DROP); request.remove(KEY_DROP);
} }
Log.d(TAG, "AbstractObjectParser table = " + table + "; isTable = " + isTable);
Log.d(TAG, "AbstractObjectParser isEmpty = " + isEmpty + "; tri = " + tri + "; drop = " + drop);
} }
protected int position; protected int position;
public int getPosition() { public int getPosition() {
return position; return position;
@ -148,6 +138,12 @@ public abstract class AbstractObjectParser implements ObjectParser {
return breakParse || isInvalidate(); return breakParse || isInvalidate();
} }
protected String name;
protected String table;
protected String alias;
protected boolean isReuse;
protected String parentName;
protected String path;
protected JSONObject response; protected JSONObject response;
protected JSONObject sqlRequest; protected JSONObject sqlRequest;
@ -177,118 +173,135 @@ public abstract class AbstractObjectParser implements ObjectParser {
* @throws Exception * @throws Exception
*/ */
@Override @Override
public AbstractObjectParser parse() throws Exception { public AbstractObjectParser parse(String name, boolean isReuse) throws Exception {
if (isInvalidate() == false) { if (isInvalidate() == false) {
this.isReuse = isReuse;
this.name = name;
this.path = AbstractParser.getAbsPath(parentPath, name);
apijson.orm.Entry<String, String> tentry = Pair.parseEntry(name, true);
this.table = tentry.getKey();
this.alias = tentry.getValue();
Log.d(TAG, "AbstractObjectParser parentPath = " + parentPath + "; name = " + name + "; table = " + table + "; alias = " + alias);
Log.d(TAG, "AbstractObjectParser type = " + type + "; isTable = " + isTable + "; isArrayMainTable = " + isArrayMainTable);
Log.d(TAG, "AbstractObjectParser isEmpty = " + request.isEmpty() + "; tri = " + tri + "; drop = " + drop);
breakParse = false; breakParse = false;
response = new JSONObject(true);//must init response = new JSONObject(true);//must init
sqlRequest = new JSONObject(true);//must init
sqlReponse = null;//must init sqlReponse = null;//must init
customMap = null;//must init
functionMap = null;//must init
childMap = null;//must init
Set<Entry<String, Object>> set = request.isEmpty() ? null : new LinkedHashSet<Entry<String, Object>>(request.entrySet()); if (isReuse == false) {
if (set != null && set.isEmpty() == false) {//判断换取少几个变量的初始化是否值得 sqlRequest = new JSONObject(true);//must init
if (isTable) {//非Table下必须保证原有顺序否则 count,page 会丢, total@:"/[]/total" 会在[]:{}前执行
customMap = new LinkedHashMap<String, Object>();
childMap = new LinkedHashMap<String, JSONObject>();
}
functionMap = new LinkedHashMap<String, Map<String, String>>();//必须执行
customMap = null;//must init
functionMap = null;//must init
childMap = null;//must init
//条件<<<<<<<<<<<<<<<<<<< Set<Entry<String, Object>> set = request.isEmpty() ? null : new LinkedHashSet<Entry<String, Object>>(request.entrySet());
List<String> whereList = null; if (set != null && set.isEmpty() == false) {//判断换取少几个变量的初始化是否值得
if (method == PUT) { //这里只有PUTArray需要处理 || method == DELETE) { if (isTable) {//非Table下必须保证原有顺序否则 count,page 会丢, total@:"/[]/total" 会在[]:{}前执行
String[] combine = StringUtil.split(request.getString(KEY_COMBINE)); customMap = new LinkedHashMap<String, Object>();
if (combine != null) { childMap = new LinkedHashMap<String, JSONObject>();
String w; }
for (int i = 0; i < combine.length; i++) { //去除 &,|,! 前缀 functionMap = new LinkedHashMap<String, Map<String, String>>();//必须执行
w = combine[i];
if (w != null && (w.startsWith("&") || w.startsWith("|") || w.startsWith("!"))) { //条件<<<<<<<<<<<<<<<<<<<
combine[i] = w.substring(1); List<String> whereList = null;
if (method == PUT) { //这里只有PUTArray需要处理 || method == DELETE) {
String[] combine = StringUtil.split(request.getString(KEY_COMBINE));
if (combine != null) {
String w;
for (int i = 0; i < combine.length; i++) { //去除 &,|,! 前缀
w = combine[i];
if (w != null && (w.startsWith("&") || w.startsWith("|") || w.startsWith("!"))) {
combine[i] = w.substring(1);
}
} }
} }
//Arrays.asList()返回值不支持add方法
whereList = new ArrayList<String>(Arrays.asList(combine != null ? combine : new String[]{}));
whereList.add(apijson.JSONRequest.KEY_ID);
whereList.add(apijson.JSONRequest.KEY_ID_IN);
} }
//Arrays.asList()返回值不支持add方法 //条件>>>>>>>>>>>>>>>>>>>
whereList = new ArrayList<String>(Arrays.asList(combine != null ? combine : new String[]{}));
whereList.add(apijson.JSONRequest.KEY_ID);
whereList.add(apijson.JSONRequest.KEY_ID_IN);
}
//条件>>>>>>>>>>>>>>>>>>>
String key; String key;
Object value; Object value;
int index = 0; int index = 0;
for (Entry<String, Object> entry : set) { for (Entry<String, Object> entry : set) {
if (isBreakParse()) { if (isBreakParse()) {
break; break;
}
value = entry.getValue();
if (value == null) {
continue;
}
key = entry.getKey();
try {
if (key.startsWith("@") || key.endsWith("@")) {
if (onParse(key, value) == false) {
invalidate();
}
}
else if (value instanceof JSONObject) { // JSONObject往下一级提取
if (childMap != null) { // 添加到childMap最后再解析
childMap.put(key, (JSONObject)value);
}
else { // 直接解析并替换原来的[]:{} 内必须直接解析否则会因为丢掉count等属性并且total@:"/[]/total"必须在[]:{}
response.put(key, onChildParse(index, key, (JSONObject)value));
index ++;
}
}
else if ((method == POST || method == PUT) && value instanceof JSONArray
&& JSONRequest.isTableArray(key)) { // JSONArray批量新增或修改往下一级提取
onTableArrayParse(key, (JSONArray) value);
}
else if (method == PUT && value instanceof JSONArray
&& (whereList == null || whereList.contains(key) == false)) { // PUT JSONArray
onPUTArrayParse(key, (JSONArray) value);
}
else { // JSONArray或其它Object直接填充
if (onParse(key, value) == false) {
invalidate();
}
}
} catch (Exception e) {
if (tri == false) {
throw e; // 不忽略错误抛异常
}
invalidate(); // 忽略错误还原request
}
} }
value = entry.getValue();
if (value == null) {
continue;
}
key = entry.getKey();
try {
if (key.startsWith("@") || key.endsWith("@")) {
if (onParse(key, value) == false) {
invalidate();
}
}
else if (value instanceof JSONObject) { // JSONObject往下一级提取
if (childMap != null) { // 添加到childMap最后再解析
childMap.put(key, (JSONObject)value);
}
else { // 直接解析并替换原来的[]:{} 内必须直接解析否则会因为丢掉count等属性并且total@:"/[]/total"必须在[]:{}
response.put(key, onChildParse(index, key, (JSONObject)value));
index ++;
}
}
else if ((method == POST || method == PUT) && value instanceof JSONArray
&& JSONRequest.isTableArray(key)) { // JSONArray批量新增或修改往下一级提取
onTableArrayParse(key, (JSONArray) value);
}
else if (method == PUT && value instanceof JSONArray
&& (whereList == null || whereList.contains(key) == false)) { // PUT JSONArray
onPUTArrayParse(key, (JSONArray) value);
}
else { // JSONArray或其它Object直接填充
if (onParse(key, value) == false) {
invalidate();
}
}
} catch (Exception e) {
if (tri == false) {
throw e; // 不忽略错误抛异常
}
invalidate(); // 忽略错误还原request
}
} }
// 非Table内的函数会被滞后在onChildParse后调用 onFunctionResponse("-"); if (isTable) {
} if (parser.getGlobleDatabase() != null && sqlRequest.get(JSONRequest.KEY_DATABASE) == null) {
sqlRequest.put(JSONRequest.KEY_DATABASE, parser.getGlobleDatabase());
if (isReuse == false && isTable) {
if (parser.getGlobleDatabase() != null && sqlRequest.get(JSONRequest.KEY_DATABASE) == null) {
sqlRequest.put(JSONRequest.KEY_DATABASE, parser.getGlobleDatabase());
}
if (parser.getGlobleSchema() != null && sqlRequest.get(JSONRequest.KEY_SCHEMA) == null) {
sqlRequest.put(JSONRequest.KEY_SCHEMA, parser.getGlobleSchema());
}
if (isSubquery == false) { //解决 SQL 语法报错子查询不能 EXPLAIN
if (parser.getGlobleExplain() != null && sqlRequest.get(JSONRequest.KEY_EXPLAIN) == null) {
sqlRequest.put(JSONRequest.KEY_EXPLAIN, parser.getGlobleExplain());
} }
if (parser.getGlobleCache() != null && sqlRequest.get(JSONRequest.KEY_CACHE) == null) { if (parser.getGlobleSchema() != null && sqlRequest.get(JSONRequest.KEY_SCHEMA) == null) {
sqlRequest.put(JSONRequest.KEY_CACHE, parser.getGlobleCache()); sqlRequest.put(JSONRequest.KEY_SCHEMA, parser.getGlobleSchema());
}
if (isSubquery == false) { //解决 SQL 语法报错子查询不能 EXPLAIN
if (parser.getGlobleExplain() != null && sqlRequest.get(JSONRequest.KEY_EXPLAIN) == null) {
sqlRequest.put(JSONRequest.KEY_EXPLAIN, parser.getGlobleExplain());
}
if (parser.getGlobleCache() != null && sqlRequest.get(JSONRequest.KEY_CACHE) == null) {
sqlRequest.put(JSONRequest.KEY_CACHE, parser.getGlobleCache());
}
} }
} }
} }
if (isTable) { // 非Table内的函数会被滞后在onChildParse后调用
onFunctionResponse("-");
}
} }
if (isInvalidate()) { if (isInvalidate()) {
@ -311,95 +324,93 @@ public abstract class AbstractObjectParser implements ObjectParser {
@Override @Override
public boolean onParse(@NotNull String key, @NotNull Object value) throws Exception { public boolean onParse(@NotNull String key, @NotNull Object value) throws Exception {
if (key.endsWith("@")) { // StringUtil.isPath((String) value)) { if (key.endsWith("@")) { // StringUtil.isPath((String) value)) {
String replaceKey = key.substring(0, key.length() - 1);
// [] 内主表 position > 0 用来生成 SQLConfig 的键值对全都忽略不解析 // [] 内主表 position > 0 用来生成 SQLConfig 的键值对全都忽略不解析
// if (isReuse == false || replaceKey.endsWith("()") || (replaceKey.startsWith("@") && JSONRequest.TABLE_KEY_LIST.contains(replaceKey) == false)) { if (value instanceof JSONObject) { // key{}@ getRealKey, SQL 子查询对象JSONObject -> SQLConfig.getSQL
if (value instanceof JSONObject) { // key{}@ getRealKey, SQL 子查询对象JSONObject -> SQLConfig.getSQL String replaceKey = key.substring(0, key.length() - 1);
JSONObject subquery = (JSONObject) value; JSONObject subquery = (JSONObject) value;
String range = subquery.getString(JSONRequest.KEY_SUBQUERY_RANGE); String range = subquery.getString(JSONRequest.KEY_SUBQUERY_RANGE);
if (range != null && JSONRequest.SUBQUERY_RANGE_ALL.equals(range) == false && JSONRequest.SUBQUERY_RANGE_ANY.equals(range) == false) { if (range != null && JSONRequest.SUBQUERY_RANGE_ALL.equals(range) == false && JSONRequest.SUBQUERY_RANGE_ANY.equals(range) == false) {
throw new IllegalArgumentException("子查询 " + path + "/" + key + ":{ range:value } 中 value 只能为 [" + JSONRequest.SUBQUERY_RANGE_ALL + ", " + JSONRequest.SUBQUERY_RANGE_ANY + "] 中的一个!"); throw new IllegalArgumentException("子查询 " + path + "/" + key + ":{ range:value } 中 value 只能为 [" + JSONRequest.SUBQUERY_RANGE_ALL + ", " + JSONRequest.SUBQUERY_RANGE_ANY + "] 中的一个!");
}
JSONArray arr = parser.onArrayParse(subquery, path, key, true);
JSONObject obj = arr == null || arr.isEmpty() ? null : arr.getJSONObject(0);
if (obj == null) {
throw new Exception("服务器内部错误,解析子查询 " + path + "/" + key + ":{ } 为 Subquery 对象失败!");
}
String from = subquery.getString(JSONRequest.KEY_SUBQUERY_FROM);
JSONObject arrObj = from == null ? null : obj.getJSONObject(from);
if (arrObj == null) {
throw new IllegalArgumentException("子查询 " + path + "/" + key + ":{ from:value } 中 value 对应的主表对象 " + from + ":{} 不存在!");
}
//
SQLConfig cfg = (SQLConfig) arrObj.get(AbstractParser.KEY_CONFIG);
if (cfg == null) {
throw new NotExistException(TAG + ".onParse cfg == null");
}
Subquery s = new Subquery();
s.setPath(path);
s.setOriginKey(key);
s.setOriginValue(subquery);
s.setFrom(from);
s.setRange(range);
s.setKey(replaceKey);
s.setConfig(cfg);
key = replaceKey;
value = s; //(range == null || range.isEmpty() ? "" : "range") + "(" + cfg.getSQL(false) + ") ";
parser.putQueryResult(AbstractParser.getAbsPath(path, key), s); //字符串引用保证不了安全性 parser.getSQL(cfg));
} }
else if (value instanceof String) { // //key{}@ getRealKey, 引用赋值路径
// System.out.println("getObject key.endsWith(@) >> parseRelation = " + parseRelation);
String targetPath = AbstractParser.getValuePath(type == TYPE_ITEM
? path : parentPath, new String((String) value));
//先尝试获取尽量保留缺省依赖路径这样就不需要担心路径改变
Object target = onReferenceParse(targetPath);
Log.i(TAG, "onParse targetPath = " + targetPath + "; target = " + target);
if (target == null) {//String#equals(null)会出错 JSONArray arr = parser.onArrayParse(subquery, path, key, true);
Log.d(TAG, "onParse target == null >> return true;");
return true;
}
if (target instanceof Map) { //target可能是从requestObject里取出的 {}
if (isTable || targetPath.endsWith("[]/" + JSONResponse.KEY_INFO) == false) {
Log.d(TAG, "onParse target instanceof Map >> return false;");
return false; //FIXME 这个判断现在来看是否还有必要为啥不允许为 JSONObject 以前可能因为防止二次遍历再解析现在只有一次遍历
}
}
if (targetPath.equals(target)) {//必须valuePath和保证getValueByPath传进去的一致
Log.d(TAG, "onParse targetPath.equals(target) >>");
//非查询关键词 @key 不影响查询直接跳过 JSONObject obj = arr == null || arr.isEmpty() ? null : arr.getJSONObject(0);
if (isTable && (key.startsWith("@") == false || JSONRequest.TABLE_KEY_LIST.contains(key))) { if (obj == null) {
Log.e(TAG, "onParse isTable && (key.startsWith(@) == false" throw new Exception("服务器内部错误,解析子查询 " + path + "/" + key + ":{ } 为 Subquery 对象失败!");
+ " || JSONRequest.TABLE_KEY_LIST.contains(key)) >> return null;");
return false;//获取不到就不用再做无效的query了不考虑 Table:{Table:{}}嵌套
} else {
Log.d(TAG, "onParse isTable(table) == false >> return true;");
return true;//舍去对Table无影响
}
}
//直接替换原来的key@:path为key:target
Log.i(TAG, "onParse >> key = replaceKey; value = target;");
key = replaceKey;
value = target;
Log.d(TAG, "onParse key = " + key + "; value = " + value);
} }
else {
throw new IllegalArgumentException(path + "/" + key + ":value 中 value 必须为 依赖路径String 或 SQL子查询JSONObject "); String from = subquery.getString(JSONRequest.KEY_SUBQUERY_FROM);
JSONObject arrObj = from == null ? null : obj.getJSONObject(from);
if (arrObj == null) {
throw new IllegalArgumentException("子查询 " + path + "/" + key + ":{ from:value } 中 value 对应的主表对象 " + from + ":{} 不存在!");
} }
// } //
SQLConfig cfg = (SQLConfig) arrObj.get(AbstractParser.KEY_CONFIG);
if (cfg == null) {
throw new NotExistException(TAG + ".onParse cfg == null");
}
Subquery s = new Subquery();
s.setPath(path);
s.setOriginKey(key);
s.setOriginValue(subquery);
s.setFrom(from);
s.setRange(range);
s.setKey(replaceKey);
s.setConfig(cfg);
key = replaceKey;
value = s; //(range == null || range.isEmpty() ? "" : "range") + "(" + cfg.getSQL(false) + ") ";
parser.putQueryResult(AbstractParser.getAbsPath(path, key), s); //字符串引用保证不了安全性 parser.getSQL(cfg));
}
else if (value instanceof String) { // //key{}@ getRealKey, 引用赋值路径
String replaceKey = key.substring(0, key.length() - 1);
// System.out.println("getObject key.endsWith(@) >> parseRelation = " + parseRelation);
String targetPath = AbstractParser.getValuePath(type == TYPE_ITEM ? path : parentPath, new String((String) value));
//先尝试获取尽量保留缺省依赖路径这样就不需要担心路径改变
Object target = onReferenceParse(targetPath);
Log.i(TAG, "onParse targetPath = " + targetPath + "; target = " + target);
if (target == null) {//String#equals(null)会出错
Log.d(TAG, "onParse target == null >> return true;");
return true;
}
if (target instanceof Map) { //target可能是从requestObject里取出的 {}
if (isTable || targetPath.endsWith("[]/" + JSONResponse.KEY_INFO) == false) {
Log.d(TAG, "onParse target instanceof Map >> return false;");
return false; //FIXME 这个判断现在来看是否还有必要为啥不允许为 JSONObject 以前可能因为防止二次遍历再解析现在只有一次遍历
}
}
if (targetPath.equals(target)) {//必须valuePath和保证getValueByPath传进去的一致
Log.d(TAG, "onParse targetPath.equals(target) >>");
//非查询关键词 @key 不影响查询直接跳过
if (isTable && (key.startsWith("@") == false || JSONRequest.TABLE_KEY_LIST.contains(key))) {
Log.e(TAG, "onParse isTable && (key.startsWith(@) == false"
+ " || JSONRequest.TABLE_KEY_LIST.contains(key)) >> return null;");
return false;//获取不到就不用再做无效的query了不考虑 Table:{Table:{}}嵌套
} else {
Log.d(TAG, "onParse isTable(table) == false >> return true;");
return true;//舍去对Table无影响
}
}
//直接替换原来的key@:path为key:target
Log.i(TAG, "onParse >> key = replaceKey; value = target;");
key = replaceKey;
value = target;
Log.d(TAG, "onParse key = " + key + "; value = " + value);
}
else {
throw new IllegalArgumentException(path + "/" + key + ":value 中 value 必须为 依赖路径String 或 SQL子查询JSONObject ");
}
} }
if (key.endsWith("()")) { if (key.endsWith("()")) {
@ -410,21 +421,24 @@ public abstract class AbstractObjectParser implements ObjectParser {
String k = key.substring(0, key.length() - 2); String k = key.substring(0, key.length() - 2);
String type; //远程函数比较少用一般一个Table:{}内用到也就一两个所以这里用 "-","0","+" 更直观转用 -1,0,1 对性能提升不大 String type; //远程函数比较少用一般一个Table:{}内用到也就一两个所以这里用 "-","0","+" 更直观转用 -1,0,1 对性能提升不大
if (k.endsWith("-")) { //不能封装到functionMap后批量执行否则会导致非Table内的 key-():function() 在onChildParse后执行 boolean isMinus = k.endsWith("-");
if (isMinus) { //不能封装到functionMap后批量执行否则会导致非Table内的 key-():function() 在onChildParse后执行
type = "-"; type = "-";
k = k.substring(0, k.length() - 1); k = k.substring(0, k.length() - 1);
parseFunction(k, (String) value, parentPath, name, request); if (isTable == false) {
parseFunction(k, (String) value, parentPath, name, request);
}
}
else if (k.endsWith("+")) {
type = "+";
k = k.substring(0, k.length() - 1);
} }
else { else {
if (k.endsWith("+")) { type = "0";
type = "+"; }
k = k.substring(0, k.length() - 1);
}
else {
type = "0";
}
if (isMinus == false || isTable) {
//远程函数比较少用一般一个Table:{}内用到也就一两个所以这里循环里new出来对性能影响不大 //远程函数比较少用一般一个Table:{}内用到也就一两个所以这里循环里new出来对性能影响不大
Map<String, String> map = functionMap.get(type); Map<String, String> map = functionMap.get(type);
if (map == null) { if (map == null) {
@ -439,9 +453,7 @@ public abstract class AbstractObjectParser implements ObjectParser {
customMap.put(key, value); customMap.put(key, value);
} }
else { else {
// 导致副表从 1 开始都不查了 if (isReuse == false) {
sqlRequest.put(key, value); sqlRequest.put(key, value);
// }
} }
return true; return true;
@ -590,7 +602,7 @@ public abstract class AbstractObjectParser implements ObjectParser {
String idKey = parser.createSQLConfig().getIdKey(); //Table[]: [{}] arrayConfig null String idKey = parser.createSQLConfig().getIdKey(); //Table[]: [{}] arrayConfig null
boolean isNeedVerifyContent = parser.isNeedVerifyContent(); boolean isNeedVerifyContent = parser.isNeedVerifyContent();
for (int i = 0; i < valueArray.size(); i++) { //只要有一条失败则抛出异常全部失败 for (int i = 0; i < valueArray.size(); i++) { //只要有一条失败则抛出异常全部失败
//TODO 改成一条多 VALUES SQL 性能更高报错也更会更好处理更人性化 //TODO 改成一条多 VALUES SQL 性能更高报错也更会更好处理更人性化
JSONObject item; JSONObject item;
@ -693,28 +705,27 @@ public abstract class AbstractObjectParser implements ObjectParser {
sqlReponse = new JSONObject(sqlRequest); sqlReponse = new JSONObject(sqlRequest);
} }
else { else {
try { try {
sqlReponse = onSQLExecute(); sqlReponse = onSQLExecute();
}
catch (NotExistException e) {
// Log.e(TAG, "getObject try { response = getSQLObject(config2); } catch (Exception e) {");
// if (e instanceof NotExistException) {//非严重异常有时候只是数据不存在
// // e.printStackTrace();
sqlReponse = null;//内部吃掉异常put到最外层
// requestObject.put(JSONResponse.KEY_MSG
// , StringUtil.getString(requestObject.get(JSONResponse.KEY_MSG)
// + "; query " + path + " cath NotExistException:"
// + newErrorResult(e).getString(JSONResponse.KEY_MSG)));
// } else {
// throw e;
// }
}
} }
catch (NotExistException e) {
// Log.e(TAG, "getObject try { response = getSQLObject(config2); } catch (Exception e) {");
// if (e instanceof NotExistException) {//非严重异常有时候只是数据不存在
// // e.printStackTrace();
sqlReponse = null;//内部吃掉异常put到最外层
// requestObject.put(JSONResponse.KEY_MSG
// , StringUtil.getString(requestObject.get(JSONResponse.KEY_MSG)
// + "; query " + path + " cath NotExistException:"
// + newErrorResult(e).getString(JSONResponse.KEY_MSG)));
// } else {
// throw e;
// }
}
}
if (drop) {//丢弃Table只为了向下提供条件 if (drop) {//丢弃Table只为了向下提供条件
sqlReponse = null; sqlReponse = null;
} }
return this; return this;
} }
@ -799,10 +810,16 @@ public abstract class AbstractObjectParser implements ObjectParser {
if (set != null) { if (set != null) {
int index = 0; int index = 0;
for (Entry<String, JSONObject> entry : set) { for (Entry<String, JSONObject> entry : set) {
if (entry != null) { Object child = entry == null ? null : onChildParse(index, entry.getKey(), entry.getValue());
response.put(entry.getKey(), onChildParse(index, entry.getKey(), entry.getValue())); if (child == null
index ++; || (child instanceof JSONObject && ((JSONObject) child).isEmpty())
|| (child instanceof JSONArray && ((JSONArray) child).isEmpty())
) {
continue;
} }
response.put(entry.getKey(), child );
index ++;
} }
} }
} }
@ -834,21 +851,21 @@ public abstract class AbstractObjectParser implements ObjectParser {
for (int i = 1; i < list.size(); i++) { // 1 开始0 已经处理过 for (int i = 1; i < list.size(); i++) { // 1 开始0 已经处理过
JSONObject obj = parser.parseCorrectResponse(table, list.get(i)); JSONObject obj = parser.parseCorrectResponse(table, list.get(i));
list.set(i, obj); list.set(i, obj);
if (obj != null) { if (obj != null) {
parser.putQueryResult(arrayPath + "/" + i + "/" + table, obj); //解决获取关联数据时requestObject里不存在需要的关联数据 parser.putQueryResult(arrayPath + "/" + i + "/" + table, obj); //解决获取关联数据时requestObject里不存在需要的关联数据
} }
} }
parser.putArrayMainCache(arrayPath, list); parser.putArrayMainCache(arrayPath, list);
} }
} }
if (isSubquery == false && result != null) { if (isSubquery == false && result != null) {
parser.putQueryResult(path, result);//解决获取关联数据时requestObject里不存在需要的关联数据 parser.putQueryResult(path, result);//解决获取关联数据时requestObject里不存在需要的关联数据
} }
} }
return result; return result;
} }

View File

@ -752,6 +752,8 @@ public abstract class AbstractParser<T> implements Parser<T>, ParserCreator<T>,
protected Map<String, ObjectParser> arrayObjectParserCacheMap = new HashMap<>();
// protected SQLConfig itemConfig; // protected SQLConfig itemConfig;
/**获取单个对象该对象处于parentObject内 /**获取单个对象该对象处于parentObject内
* @param parentPath parentObject的路径 * @param parentPath parentObject的路径
@ -774,9 +776,10 @@ public abstract class AbstractParser<T> implements Parser<T>, ParserCreator<T>,
} }
int type = arrayConfig == null ? 0 : arrayConfig.getType(); int type = arrayConfig == null ? 0 : arrayConfig.getType();
int position = arrayConfig == null ? 0 : arrayConfig.getPosition();
String[] arr = StringUtil.split(parentPath, "/"); String[] arr = StringUtil.split(parentPath, "/");
if (arrayConfig == null || arrayConfig.getPosition() == 0) { if (position == 0) {
int d = arr == null ? 1 : arr.length + 1; int d = arr == null ? 1 : arr.length + 1;
if (queryDepth < d) { if (queryDepth < d) {
queryDepth = d; queryDepth = d;
@ -786,12 +789,24 @@ public abstract class AbstractParser<T> implements Parser<T>, ParserCreator<T>,
} }
} }
} }
boolean isTable = apijson.JSONObject.isTableKey(name);
boolean isArrayMainTable = isSubquery == false && isTable && type == SQLConfig.TYPE_ITEM_CHILD_0 && arrayConfig != null && RequestMethod.isGetMethod(arrayConfig.getMethod(), true);
boolean isReuse = isArrayMainTable && position > 0;
ObjectParser op = createObjectParser(request, parentPath, name, arrayConfig, isSubquery).parse(); ObjectParser op = null;
if (isReuse) { // 数组主表使用专门的缓存数据
op = arrayObjectParserCacheMap.get(parentPath.substring(0, parentPath.lastIndexOf("[]") + 2));
}
if (op == null) {
op = createObjectParser(request, parentPath, arrayConfig, isSubquery, isTable, isArrayMainTable);
}
op = op.parse(name, isReuse);
JSONObject response = null; JSONObject response = null;
if (op != null) {//SQL查询结果为空时functionMap和customMap没有意义 if (op != null) {//SQL查询结果为空时functionMap和customMap没有意义
if (arrayConfig == null) { //Common if (arrayConfig == null) { //Common
response = op.setSQLConfig().executeSQL().response(); response = op.setSQLConfig().executeSQL().response();
} }
@ -799,9 +814,12 @@ public abstract class AbstractParser<T> implements Parser<T>, ParserCreator<T>,
int query = arrayConfig.getQuery(); int query = arrayConfig.getQuery();
//total 这里不能用arrayConfig.getType()因为在createObjectParser.onChildParse传到onObjectParse时已被改掉 //total 这里不能用arrayConfig.getType()因为在createObjectParser.onChildParse传到onObjectParse时已被改掉
if (type == SQLConfig.TYPE_ITEM_CHILD_0 && query != JSONRequest.QUERY_TABLE if (type == SQLConfig.TYPE_ITEM_CHILD_0 && query != JSONRequest.QUERY_TABLE && position == 0) {
&& arrayConfig.getPosition() == 0) {
RequestMethod method = op.getMethod();
JSONObject rp = op.setMethod(RequestMethod.HEAD).setSQLConfig().executeSQL().getSqlReponse(); JSONObject rp = op.setMethod(RequestMethod.HEAD).setSQLConfig().executeSQL().getSqlReponse();
op.setMethod(method);
if (rp != null) { if (rp != null) {
int index = parentPath.lastIndexOf("]/"); int index = parentPath.lastIndexOf("]/");
if (index >= 0) { if (index >= 0) {
@ -842,14 +860,21 @@ public abstract class AbstractParser<T> implements Parser<T>, ParserCreator<T>,
response = null;//不再往后查询 response = null;//不再往后查询
} else { } else {
response = op response = op
.setSQLConfig(arrayConfig.getCount(), arrayConfig.getPage(), arrayConfig.getPosition()) .setSQLConfig(arrayConfig.getCount(), arrayConfig.getPage(), position)
.executeSQL() .executeSQL()
.response(); .response();
// itemConfig = op.getConfig(); // itemConfig = op.getConfig();
} }
} }
op.recycle(); if (isArrayMainTable) {
if (position == 0) { // 提取并缓存数组主表的列表数据
arrayObjectParserCacheMap.put(parentPath.substring(0, parentPath.lastIndexOf("[]") + 2), op);
}
}
// else {
// op.recycle();
// }
op = null; op = null;
} }

View File

@ -84,7 +84,7 @@ public abstract class AbstractSQLConfig implements SQLConfig {
// * / 不能同时出现防止 /* */ 段注释 # -- 不能出现防止行注释 ; 不能出现防止隔断SQL语句空格不能出现防止 CRUD,DROP,SHOW TABLES等语句 // * / 不能同时出现防止 /* */ 段注释 # -- 不能出现防止行注释 ; 不能出现防止隔断SQL语句空格不能出现防止 CRUD,DROP,SHOW TABLES等语句
private static final Pattern PATTERN_RANGE; private static final Pattern PATTERN_RANGE;
private static final Pattern PATTERN_FUNCTION; private static final Pattern PATTERN_FUNCTION;
/** /**
* 表名映射隐藏真实表名对安全要求很高的表可以这么做 * 表名映射隐藏真实表名对安全要求很高的表可以这么做
*/ */
@ -96,8 +96,8 @@ public abstract class AbstractSQLConfig implements SQLConfig {
static { // 凡是 SQL 边界符分隔符注释符 都不允许例如 ' " ` ( ) ; # -- ,以免拼接 SQL 时被注入意外可执行指令 static { // 凡是 SQL 边界符分隔符注释符 都不允许例如 ' " ` ( ) ; # -- ,以免拼接 SQL 时被注入意外可执行指令
PATTERN_RANGE = Pattern.compile("^[0-9%,!=\\<\\>/\\.\\+\\-\\*\\^]+$"); // ^[a-zA-Z0-9_*%!=<>(),"]+$ 导致 exists(select*from(Comment)) 通过! PATTERN_RANGE = Pattern.compile("^[0-9%,!=\\<\\>/\\.\\+\\-\\*\\^]+$"); // ^[a-zA-Z0-9_*%!=<>(),"]+$ 导致 exists(select*from(Comment)) 通过!
PATTERN_FUNCTION = Pattern.compile("^[A-Za-z0-9%,:_@&~!=\\<\\>\\|\\[\\]\\{\\} /\\.\\+\\-\\*\\^\\?\\$]+$"); //TODO 改成更好的正则校验前面为单词中间为操作符后面为值 PATTERN_FUNCTION = Pattern.compile("^[A-Za-z0-9%,:_@&~!=\\<\\>\\|\\[\\]\\{\\} /\\.\\+\\-\\*\\^\\?\\$]+$"); //TODO 改成更好的正则校验前面为单词中间为操作符后面为值
TABLE_KEY_MAP = new HashMap<String, String>(); TABLE_KEY_MAP = new HashMap<String, String>();
TABLE_KEY_MAP.put(Table.class.getSimpleName(), Table.TABLE_NAME); TABLE_KEY_MAP.put(Table.class.getSimpleName(), Table.TABLE_NAME);
TABLE_KEY_MAP.put(Column.class.getSimpleName(), Column.TABLE_NAME); TABLE_KEY_MAP.put(Column.class.getSimpleName(), Column.TABLE_NAME);
@ -530,13 +530,13 @@ public abstract class AbstractSQLConfig implements SQLConfig {
if (keys == null || keys.length <= 0) { if (keys == null || keys.length <= 0) {
return StringUtil.isEmpty(joinHaving, true) ? "" : (hasPrefix ? " HAVING " : "") + joinHaving; return StringUtil.isEmpty(joinHaving, true) ? "" : (hasPrefix ? " HAVING " : "") + joinHaving;
} }
String quote = getQuote(); String quote = getQuote();
String tableAlias = getAliasWithQuote(); String tableAlias = getAliasWithQuote();
List<String> raw = getRaw(); List<String> raw = getRaw();
boolean containRaw = raw != null && raw.contains(KEY_HAVING); boolean containRaw = raw != null && raw.contains(KEY_HAVING);
String expression; String expression;
String method; String method;
//暂时不允许 String prefix; //暂时不允许 String prefix;
@ -560,7 +560,7 @@ public abstract class AbstractSQLConfig implements SQLConfig {
+ "} catch (Exception e) = " + e.getMessage()); + "} catch (Exception e) = " + e.getMessage());
} }
} }
if (expression.length() > 50) { if (expression.length() > 50) {
throw new UnsupportedOperationException("@having:value 的 value 中字符串 " + expression + " 不合法!" throw new UnsupportedOperationException("@having:value 的 value 中字符串 " + expression + " 不合法!"
+ "不允许传超过 50 个字符的函数或表达式!请用 @raw 简化传参!"); + "不允许传超过 50 个字符的函数或表达式!请用 @raw 简化传参!");
@ -958,13 +958,13 @@ public abstract class AbstractSQLConfig implements SQLConfig {
method = expression.substring(0, start); method = expression.substring(0, start);
boolean distinct = i <= 0 && method.startsWith(PREFFIX_DISTINCT); boolean distinct = i <= 0 && method.startsWith(PREFFIX_DISTINCT);
String fun = distinct ? method.substring(PREFFIX_DISTINCT.length()) : method; String fun = distinct ? method.substring(PREFFIX_DISTINCT.length()) : method;
if (fun.isEmpty() == false && StringUtil.isName(fun) == false) { if (fun.isEmpty() == false && StringUtil.isName(fun) == false) {
throw new IllegalArgumentException("字符 " + method + " 不合法!" throw new IllegalArgumentException("字符 " + method + " 不合法!"
+ "预编译模式下 @column:\"column0,column1:alias;function0(arg0,arg1,...);function1(...):alias...\"" + "预编译模式下 @column:\"column0,column1:alias;function0(arg0,arg1,...);function1(...):alias...\""
+ " 中SQL函数名 function 必须符合正则表达式 ^[0-9a-zA-Z_]+$ "); + " 中SQL函数名 function 必须符合正则表达式 ^[0-9a-zA-Z_]+$ ");
} }
} }
boolean isColumn = start < 0; boolean isColumn = start < 0;
@ -1049,13 +1049,13 @@ public abstract class AbstractSQLConfig implements SQLConfig {
int index = suffix.lastIndexOf(":"); int index = suffix.lastIndexOf(":");
String alias = index < 0 ? "" : suffix.substring(index + 1); //contactCount String alias = index < 0 ? "" : suffix.substring(index + 1); //contactCount
suffix = index < 0 ? suffix : suffix.substring(0, index); suffix = index < 0 ? suffix : suffix.substring(0, index);
if (alias.isEmpty() == false && StringUtil.isName(alias) == false) { if (alias.isEmpty() == false && StringUtil.isName(alias) == false) {
throw new IllegalArgumentException("字符串 " + alias + " 不合法!" throw new IllegalArgumentException("字符串 " + alias + " 不合法!"
+ "预编译模式下 @column:value 中 value里面用 ; 分割的每一项" + "预编译模式下 @column:value 中 value里面用 ; 分割的每一项"
+ " function(arg0,arg1,...):alias 中 alias 必须是1个单词并且不要有多余的空格"); + " function(arg0,arg1,...):alias 中 alias 必须是1个单词并且不要有多余的空格");
} }
if (suffix.isEmpty() == false && (((String) suffix).contains("--") || ((String) suffix).contains("/*") || PATTERN_RANGE.matcher((String) suffix).matches() == false)) { if (suffix.isEmpty() == false && (((String) suffix).contains("--") || ((String) suffix).contains("/*") || PATTERN_RANGE.matcher((String) suffix).matches() == false)) {
throw new UnsupportedOperationException("字符串 " + suffix + " 不合法!" throw new UnsupportedOperationException("字符串 " + suffix + " 不合法!"
+ "预编译模式下 @column:\"column?value;function(arg0,arg1,...)?value...\"" + "预编译模式下 @column:\"column?value;function(arg0,arg1,...)?value...\""
@ -2393,9 +2393,9 @@ public abstract class AbstractSQLConfig implements SQLConfig {
case POST: case POST:
return "INSERT INTO " + tablePath + config.getColumnString() + " VALUES" + config.getValuesString(); return "INSERT INTO " + tablePath + config.getColumnString() + " VALUES" + config.getValuesString();
case PUT: case PUT:
return "UPDATE " + tablePath + config.getSetString() + config.getWhereString(true) + config.getLimitString(); return "UPDATE " + tablePath + config.getSetString() + config.getWhereString(true) + (config.isMySQL() ? config.getLimitString() : "");
case DELETE: case DELETE:
return "DELETE FROM " + tablePath + config.getWhereString(true) + config.getLimitString(); return "DELETE FROM " + tablePath + config.getWhereString(true) + (config.isMySQL() ? config.getLimitString() : ""); // PostgreSQL 不允许 LIMIT
default: default:
String explain = (config.isExplain() ? (config.isSQLServer() || config.isOracle() ? "SET STATISTICS PROFILE ON " : "EXPLAIN ") : ""); String explain = (config.isExplain() ? (config.isSQLServer() || config.isOracle() ? "SET STATISTICS PROFILE ON " : "EXPLAIN ") : "");
if (config.isTest() && RequestMethod.isGetMethod(config.getMethod(), true)) { if (config.isTest() && RequestMethod.isGetMethod(config.getMethod(), true)) {
@ -2615,15 +2615,9 @@ public abstract class AbstractSQLConfig implements SQLConfig {
String userIdKey = callback.getUserIdKey(database, schema, table); String userIdKey = callback.getUserIdKey(database, schema, table);
String userIdInKey = userIdKey + "{}"; String userIdInKey = userIdKey + "{}";
//对id和id{}处理这两个一定会作为条件
Object idIn = request.get(idInKey); //可能是 id{}:">0" Object idIn = request.get(idInKey); //可能是 id{}:">0"
if (method == POST && request.get(idKey) == null) {
Object newId = callback.newId(method, database, schema, table); // null 表示数据库自增 id
if (newId != null) {
request.put(idKey, newId);
}
}
if (idIn instanceof List) { // 排除掉 0, 负数, 空字符串 等无效 id if (idIn instanceof List) { // 排除掉 0, 负数, 空字符串 等无效 id
List<?> ids = ((List<?>) idIn); List<?> ids = ((List<?>) idIn);
List<Object> newIdIn = new ArrayList<>(); List<Object> newIdIn = new ArrayList<>();
@ -2638,14 +2632,18 @@ public abstract class AbstractSQLConfig implements SQLConfig {
throw new NotExistException(TAG + ": newSQLConfig idIn instanceof List >> 去掉无效 id 后 newIdIn.isEmpty()"); throw new NotExistException(TAG + ": newSQLConfig idIn instanceof List >> 去掉无效 id 后 newIdIn.isEmpty()");
} }
idIn = newIdIn; idIn = newIdIn;
if (method == DELETE || method == PUT) { if (method == DELETE || method == PUT) {
config.setCount(newIdIn.size()); config.setCount(newIdIn.size());
} }
} }
//对id和id{}处理这两个一定会作为条件
Object id = request.get(idKey); Object id = request.get(idKey);
boolean hasId = id != null;
if (method == POST && hasId == false) {
id = callback.newId(method, database, schema, table); // null 表示数据库自增 id
}
if (id != null) { //null无效 if (id != null) { //null无效
if (id instanceof Number) { if (id instanceof Number) {
if (((Number) id).longValue() <= 0) { //一定没有值 if (((Number) id).longValue() <= 0) { //一定没有值
@ -2677,7 +2675,7 @@ public abstract class AbstractSQLConfig implements SQLConfig {
throw new NotExistException(TAG + ": newSQLConfig idIn != null && (((List<?>) idIn).contains(id) == false"); throw new NotExistException(TAG + ": newSQLConfig idIn != null && (((List<?>) idIn).contains(id) == false");
} }
} }
if (method == DELETE || method == PUT) { if (method == DELETE || method == PUT) {
config.setCount(1); config.setCount(1);
} }
@ -2695,272 +2693,277 @@ public abstract class AbstractSQLConfig implements SQLConfig {
String raw = request.getString(KEY_RAW); String raw = request.getString(KEY_RAW);
String json = request.getString(KEY_JSON); String json = request.getString(KEY_JSON);
//强制作为条件且放在最前面优化性能 try {
request.remove(idKey);
request.remove(idInKey);
//关键词
request.remove(KEY_ROLE);
request.remove(KEY_EXPLAIN);
request.remove(KEY_CACHE);
request.remove(KEY_DATABASE);
request.remove(KEY_SCHEMA);
request.remove(KEY_COMBINE);
request.remove(KEY_FROM);
request.remove(KEY_COLUMN);
request.remove(KEY_GROUP);
request.remove(KEY_HAVING);
request.remove(KEY_ORDER);
request.remove(KEY_RAW);
request.remove(KEY_JSON);
String[] rawArr = StringUtil.split(raw);
config.setRaw(rawArr == null || rawArr.length <= 0 ? null : new ArrayList<>(Arrays.asList(rawArr)));
Map<String, Object> tableWhere = new LinkedHashMap<String, Object>();//保证顺序好优化 WHERE id > 1 AND name LIKE...
//已经remove了id和id{}以及@key
Set<String> set = request.keySet(); //前面已经判断request是否为空
if (method == POST) { //POST操作
if (idIn != null) {
throw new IllegalArgumentException("POST 请求中不允许传 " + idInKey + " !");
}
if (set != null && set.isEmpty() == false) { //不能直接return要走完下面的流程
String[] columns = set.toArray(new String[]{});
Collection<Object> valueCollection = request.values();
Object[] values = valueCollection == null ? null : valueCollection.toArray();
if (values == null || values.length != columns.length) {
throw new Exception("服务器内部错误:\n" + TAG
+ " newSQLConfig values == null || values.length != columns.length !");
}
column = (id == null ? "" : idKey + ",") + StringUtil.getString(columns); //set已经判断过不为空
List<List<Object>> valuess = new ArrayList<>(1);
List<Object> items; //(item0, item1, ...)
if (id == null) { //数据库自增 id
items = Arrays.asList(values); //FIXME 是否还需要进行 add remove 操作Arrays.ArrayList 不允许修改会抛异常
}
else {
int size = columns.length + (id == null ? 0 : 1); //以key数量为准
items = new ArrayList<>(size);
items.add(id); //idList.get(i)); //第0个就是id
for (int j = 1; j < size; j++) {
items.add(values[j-1]); //从第1个开始允许"null"
}
}
valuess.add(items);
config.setValues(valuess);
}
}
else { //非POST操作
final boolean isWhere = method != PUT;//除了POST,PUT其它全是条件
//条件<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
List<String> whereList = null;
Map<String, List<String>> combineMap = new LinkedHashMap<>();
List<String> andList = new ArrayList<>();
List<String> orList = new ArrayList<>();
List<String> notList = new ArrayList<>();
//强制作为条件且放在最前面优化性能 //强制作为条件且放在最前面优化性能
if (id != null) { request.remove(idKey);
tableWhere.put(idKey, id); request.remove(idInKey);
andList.add(idKey); //关键词
} request.remove(KEY_ROLE);
if (idIn != null) { request.remove(KEY_EXPLAIN);
tableWhere.put(idInKey, idIn); request.remove(KEY_CACHE);
andList.add(idInKey); request.remove(KEY_DATABASE);
} request.remove(KEY_SCHEMA);
request.remove(KEY_COMBINE);
request.remove(KEY_FROM);
request.remove(KEY_COLUMN);
request.remove(KEY_GROUP);
request.remove(KEY_HAVING);
request.remove(KEY_ORDER);
request.remove(KEY_RAW);
request.remove(KEY_JSON);
String[] ws = StringUtil.split(combine); String[] rawArr = StringUtil.split(raw);
if (ws != null) { config.setRaw(rawArr == null || rawArr.length <= 0 ? null : new ArrayList<>(Arrays.asList(rawArr)));
if (method == DELETE || method == GETS || method == HEADS) {
throw new IllegalArgumentException("DELETE,GETS,HEADS 请求不允许传 @combine:value !"); Map<String, Object> tableWhere = new LinkedHashMap<String, Object>();//保证顺序好优化 WHERE id > 1 AND name LIKE...
//已经remove了id和id{}以及@key
Set<String> set = request.keySet(); //前面已经判断request是否为空
if (method == POST) { //POST操作
if (idIn != null) {
throw new IllegalArgumentException("POST 请求中不允许传 " + idInKey + " !");
} }
whereList = new ArrayList<>();
String w; if (set != null && set.isEmpty() == false) { //不能直接return要走完下面的流程
for (int i = 0; i < ws.length; i++) { //去除 &,|,! 前缀 String[] columns = set.toArray(new String[]{});
w = ws[i];
if (w != null) {
if (w.startsWith("&")) {
w = w.substring(1);
andList.add(w);
}
else if (w.startsWith("|")) {
if (method == PUT) {
throw new IllegalArgumentException(table + ":{} 里的 @combine:value 中的value里条件 " + ws[i] + " 不合法!"
+ "PUT请求的 @combine:\"key0,key1,...\" 不允许传 |key 或 !key !");
}
w = w.substring(1);
orList.add(w);
}
else if (w.startsWith("!")) {
if (method == PUT) {
throw new IllegalArgumentException(table + ":{} 里的 @combine:value 中的value里条件 " + ws[i] + " 不合法!"
+ "PUT请求的 @combine:\"key0,key1,...\" 不允许传 |key 或 !key !");
}
w = w.substring(1);
notList.add(w);
}
else {
orList.add(w);
}
if (w.isEmpty()) { Collection<Object> valueCollection = request.values();
throw new IllegalArgumentException(table + ":{} 里的 @combine:value 中的value里条件 " + ws[i] + " 不合法!不允许为空值!"); Object[] values = valueCollection == null ? null : valueCollection.toArray();
}
else {
if (idKey.equals(w) || idInKey.equals(w) || userIdKey.equals(w) || userIdInKey.equals(w)) {
throw new UnsupportedOperationException(table + ":{} 里的 @combine:value 中的value里 " + ws[i] + " 不合法!"
+ "不允许传 [" + idKey + ", " + idInKey + ", " + userIdKey + ", " + userIdInKey + "] 其中任何一个!");
}
}
whereList.add(w); if (values == null || values.length != columns.length) {
throw new Exception("服务器内部错误:\n" + TAG
+ " newSQLConfig values == null || values.length != columns.length !");
}
column = (id == null ? "" : idKey + ",") + StringUtil.getString(columns); //set已经判断过不为空
List<List<Object>> valuess = new ArrayList<>(1);
List<Object> items; //(item0, item1, ...)
if (id == null) { //数据库自增 id
items = Arrays.asList(values); //FIXME 是否还需要进行 add remove 操作Arrays.ArrayList 不允许修改会抛异常
}
else {
int size = columns.length + (id == null ? 0 : 1); //以key数量为准
items = new ArrayList<>(size);
items.add(id); //idList.get(i)); //第0个就是id
for (int j = 1; j < size; j++) {
items.add(values[j-1]); //从第1个开始允许"null"
}
} }
// 可重写回调方法自定义处理 // 动态设置的场景似乎很少而且去掉后不方便用户排错//去掉判断有时候不在没关系如果是对增删改等非开放请求强制要求传对应的条件可以用 Operation.NECESSARY valuess.add(items);
if (request.containsKey(w) == false) { // request.get(w) == null 没区别前面 Parser 已经过滤了 null config.setValues(valuess);
// throw new IllegalArgumentException(table + ":{} 里的 @combine:value 中的value里 " + ws[i] + " 对应的 " + w + " 不在它里面!"); }
callback.onMissingKey4Combine(table, request, combine, ws[i], w); }
else { //非POST操作
final boolean isWhere = method != PUT;//除了POST,PUT其它全是条件
//条件<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
List<String> whereList = null;
Map<String, List<String>> combineMap = new LinkedHashMap<>();
List<String> andList = new ArrayList<>();
List<String> orList = new ArrayList<>();
List<String> notList = new ArrayList<>();
//强制作为条件且放在最前面优化性能
if (id != null) {
tableWhere.put(idKey, id);
andList.add(idKey);
}
if (idIn != null) {
tableWhere.put(idInKey, idIn);
andList.add(idInKey);
}
String[] ws = StringUtil.split(combine);
if (ws != null) {
if (method == DELETE || method == GETS || method == HEADS) {
throw new IllegalArgumentException("DELETE,GETS,HEADS 请求不允许传 @combine:value !");
}
whereList = new ArrayList<>();
String w;
for (int i = 0; i < ws.length; i++) { //去除 &,|,! 前缀
w = ws[i];
if (w != null) {
if (w.startsWith("&")) {
w = w.substring(1);
andList.add(w);
}
else if (w.startsWith("|")) {
if (method == PUT) {
throw new IllegalArgumentException(table + ":{} 里的 @combine:value 中的value里条件 " + ws[i] + " 不合法!"
+ "PUT请求的 @combine:\"key0,key1,...\" 不允许传 |key 或 !key !");
}
w = w.substring(1);
orList.add(w);
}
else if (w.startsWith("!")) {
if (method == PUT) {
throw new IllegalArgumentException(table + ":{} 里的 @combine:value 中的value里条件 " + ws[i] + " 不合法!"
+ "PUT请求的 @combine:\"key0,key1,...\" 不允许传 |key 或 !key !");
}
w = w.substring(1);
notList.add(w);
}
else {
orList.add(w);
}
if (w.isEmpty()) {
throw new IllegalArgumentException(table + ":{} 里的 @combine:value 中的value里条件 " + ws[i] + " 不合法!不允许为空值!");
}
else {
if (idKey.equals(w) || idInKey.equals(w) || userIdKey.equals(w) || userIdInKey.equals(w)) {
throw new UnsupportedOperationException(table + ":{} 里的 @combine:value 中的value里 " + ws[i] + " 不合法!"
+ "不允许传 [" + idKey + ", " + idInKey + ", " + userIdKey + ", " + userIdInKey + "] 其中任何一个!");
}
}
whereList.add(w);
}
// 可重写回调方法自定义处理 // 动态设置的场景似乎很少而且去掉后不方便用户排错//去掉判断有时候不在没关系如果是对增删改等非开放请求强制要求传对应的条件可以用 Operation.NECESSARY
if (request.containsKey(w) == false) { // request.get(w) == null 没区别前面 Parser 已经过滤了 null
// throw new IllegalArgumentException(table + ":{} 里的 @combine:value 中的value里 " + ws[i] + " 对应的 " + w + " 不在它里面!");
callback.onMissingKey4Combine(table, request, combine, ws[i], w);
}
}
}
//条件>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Map<String, Object> tableContent = new LinkedHashMap<String, Object>();
Object value;
for (String key : set) {
value = request.get(key);
if (value instanceof Map) {//只允许常规Object
throw new IllegalArgumentException("不允许 " + key + " 等任何key的value类型为 {JSONObject} !");
}
//解决AccessVerifier新增userId没有作为条件而是作为内容导致PUTDELETE出错
if (isWhere) {
tableWhere.put(key, value);
if (whereList == null || whereList.contains(key) == false) {
andList.add(key);
}
}
else if (whereList != null && whereList.contains(key)) {
tableWhere.put(key, value);
}
else {
tableContent.put(key, value);//一样 instanceof JSONArray ? JSON.toJSONString(value) : value);
} }
} }
combineMap.put("&", andList);
combineMap.put("|", orList);
combineMap.put("!", notList);
config.setCombine(combineMap);
config.setContent(tableContent);
} }
//条件>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Map<String, Object> tableContent = new LinkedHashMap<String, Object>(); List<String> cs = new ArrayList<>();
Object value;
for (String key : set) {
value = request.get(key);
if (value instanceof Map) {//只允许常规Object List<String> rawList = config.getRaw();
throw new IllegalArgumentException("不允许 " + key + " 等任何key的value类型为 {JSONObject} !"); boolean containColumnRaw = rawList != null && rawList.contains(KEY_COLUMN);
String rawColumnSQL = null;
if (containColumnRaw) {
try {
rawColumnSQL = config.getRawSQL(KEY_COLUMN, column);
if (rawColumnSQL != null) {
cs.add(rawColumnSQL);
}
} catch (Exception e) {
Log.e(TAG, "newSQLConfig config instanceof AbstractSQLConfig >> try { "
+ " rawColumnSQL = ((AbstractSQLConfig) config).getRawSQL(KEY_COLUMN, column); "
+ "} catch (Exception e) = " + e.getMessage());
} }
}
//解决AccessVerifier新增userId没有作为条件而是作为内容导致PUTDELETE出错 boolean distinct = column == null || rawColumnSQL != null ? false : column.startsWith(PREFFIX_DISTINCT);
if (isWhere) { if (rawColumnSQL == null) {
tableWhere.put(key, value); String[] fks = StringUtil.split(distinct ? column.substring(PREFFIX_DISTINCT.length()) : column, ";"); // key0,key1;fun0(key0,...);fun1(key0,...);key3;fun2(key0,...)
if (whereList == null || whereList.contains(key) == false) { if (fks != null) {
andList.add(key); String[] ks;
for (String fk : fks) {
if (containColumnRaw) {
try {
String rawSQL = config.getRawSQL(KEY_COLUMN, fk);
if (rawSQL != null) {
cs.add(rawSQL);
continue;
}
} catch (Exception e) {
Log.e(TAG, "newSQLConfig rawColumnSQL == null >> try { "
+ " String rawSQL = ((AbstractSQLConfig) config).getRawSQL(KEY_COLUMN, fk); ... "
+ "} catch (Exception e) = " + e.getMessage());
}
}
if (fk.contains("(")) { // fun0(key0,...)
cs.add(fk);
}
else { //key0,key1...
ks = StringUtil.split(fk);
if (ks != null && ks.length > 0) {
cs.addAll(Arrays.asList(ks));
}
}
} }
} }
else if (whereList != null && whereList.contains(key)) {
tableWhere.put(key, value);
}
else {
tableContent.put(key, value);//一样 instanceof JSONArray ? JSON.toJSONString(value) : value);
}
} }
combineMap.put("&", andList); config.setExplain(explain);
combineMap.put("|", orList); config.setCache(getCache(cache));
combineMap.put("!", notList); config.setFrom(from);
config.setCombine(combineMap); config.setDistinct(distinct);
config.setColumn(column == null ? null : cs); //解决总是 config.column != null总是不能得到 *
config.setWhere(tableWhere);
config.setId(id);
// tableWhere 第0个 config.setIdIn(idIn);
config.setRole(RequestRole.get(role));
config.setGroup(group);
config.setHaving(having);
config.setOrder(order);
String[] jsonArr = StringUtil.split(json);
config.setJson(jsonArr == null || jsonArr.length <= 0 ? null : new ArrayList<>(Arrays.asList(jsonArr)));
//TODO 解析JOIN包括 @column@group 等要合并
config.setContent(tableContent);
} }
finally {//后面还可能用到要还原
//id或id{}条件
List<String> cs = new ArrayList<>(); if (hasId) {
request.put(idKey, id);
List<String> rawList = config.getRaw();
boolean containColumnRaw = rawList != null && rawList.contains(KEY_COLUMN);
String rawColumnSQL = null;
if (containColumnRaw) {
try {
rawColumnSQL = config.getRawSQL(KEY_COLUMN, column);
if (rawColumnSQL != null) {
cs.add(rawColumnSQL);
}
} catch (Exception e) {
Log.e(TAG, "newSQLConfig config instanceof AbstractSQLConfig >> try { "
+ " rawColumnSQL = ((AbstractSQLConfig) config).getRawSQL(KEY_COLUMN, column); "
+ "} catch (Exception e) = " + e.getMessage());
} }
request.put(idInKey, idIn);
//关键词
request.put(KEY_DATABASE, database);
request.put(KEY_ROLE, role);
request.put(KEY_EXPLAIN, explain);
request.put(KEY_CACHE, cache);
request.put(KEY_SCHEMA, schema);
request.put(KEY_COMBINE, combine);
request.put(KEY_FROM, from);
request.put(KEY_COLUMN, column);
request.put(KEY_GROUP, group);
request.put(KEY_HAVING, having);
request.put(KEY_ORDER, order);
request.put(KEY_RAW, raw);
request.put(KEY_JSON, json);
} }
boolean distinct = column == null || rawColumnSQL != null ? false : column.startsWith(PREFFIX_DISTINCT);
if (rawColumnSQL == null) {
String[] fks = StringUtil.split(distinct ? column.substring(PREFFIX_DISTINCT.length()) : column, ";"); // key0,key1;fun0(key0,...);fun1(key0,...);key3;fun2(key0,...)
if (fks != null) {
String[] ks;
for (String fk : fks) {
if (containColumnRaw) {
try {
String rawSQL = config.getRawSQL(KEY_COLUMN, fk);
if (rawSQL != null) {
cs.add(rawSQL);
continue;
}
} catch (Exception e) {
Log.e(TAG, "newSQLConfig rawColumnSQL == null >> try { "
+ " String rawSQL = ((AbstractSQLConfig) config).getRawSQL(KEY_COLUMN, fk); ... "
+ "} catch (Exception e) = " + e.getMessage());
}
}
if (fk.contains("(")) { // fun0(key0,...)
cs.add(fk);
}
else { //key0,key1...
ks = StringUtil.split(fk);
if (ks != null && ks.length > 0) {
cs.addAll(Arrays.asList(ks));
}
}
}
}
}
config.setExplain(explain);
config.setCache(getCache(cache));
config.setFrom(from);
config.setDistinct(distinct);
config.setColumn(column == null ? null : cs); //解决总是 config.column != null总是不能得到 *
config.setWhere(tableWhere);
config.setId(id);
// tableWhere 第0个 config.setIdIn(idIn);
config.setRole(RequestRole.get(role));
config.setGroup(group);
config.setHaving(having);
config.setOrder(order);
String[] jsonArr = StringUtil.split(json);
config.setJson(jsonArr == null || jsonArr.length <= 0 ? null : new ArrayList<>(Arrays.asList(jsonArr)));
//TODO 解析JOIN包括 @column@group 等要合并
//后面还可能用到要还原
//id或id{}条件
request.put(idKey, id);
request.put(idInKey, idIn);
//关键词
request.put(KEY_DATABASE, database);
request.put(KEY_ROLE, role);
request.put(KEY_EXPLAIN, explain);
request.put(KEY_CACHE, cache);
request.put(KEY_SCHEMA, schema);
request.put(KEY_COMBINE, combine);
request.put(KEY_FROM, from);
request.put(KEY_COLUMN, column);
request.put(KEY_GROUP, group);
request.put(KEY_HAVING, having);
request.put(KEY_ORDER, order);
request.put(KEY_RAW, raw);
request.put(KEY_JSON, json);
return config; return config;
} }

View File

@ -20,14 +20,15 @@ import apijson.RequestMethod;
*/ */
public interface ObjectParser { public interface ObjectParser {
/**解析成员 /**解析成员
* response重新赋值 * response重新赋值
* @param config 传递给第0个Table * @param parentPath
* @param name
* @param isReuse
* @return null or this * @return null or this
* @throws Exception * @throws Exception
*/ */
ObjectParser parse() throws Exception; ObjectParser parse(String name, boolean isReuse) throws Exception;
/**调用 parser sqlExecutor 来解析结果 /**调用 parser sqlExecutor 来解析结果
* @param method * @param method
@ -159,4 +160,5 @@ public interface ObjectParser {
Map<String, Map<String, String>> getFunctionMap(); Map<String, Map<String, String>> getFunctionMap();
Map<String, JSONObject> getChildMap(); Map<String, JSONObject> getChildMap();
} }

View File

@ -93,7 +93,7 @@ public interface Parser<T> {
*/ */
Object onFunctionParse(String key, String function, String parentPath, String currentName, JSONObject currentObject) throws Exception; Object onFunctionParse(String key, String function, String parentPath, String currentName, JSONObject currentObject) throws Exception;
ObjectParser createObjectParser(JSONObject request, String parentPath, String name, SQLConfig arrayConfig, boolean isSubquery) throws Exception; ObjectParser createObjectParser(JSONObject request, String parentPath, SQLConfig arrayConfig, boolean isSubquery, boolean isTable, boolean isArrayMainTable) throws Exception;
int getDefaultQueryCount(); int getDefaultQueryCount();
int getMaxQueryPage(); int getMaxQueryPage();