【性能】通过缓存及复用数组主表 ObjectParser 来大幅提升查询数组的性能
This commit is contained in:
parent
6831cb6a6d
commit
a406242a81
@ -61,12 +61,6 @@ public abstract class AbstractObjectParser implements ObjectParser {
|
||||
protected final List<Join> joinList;
|
||||
protected final boolean isTable;
|
||||
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;
|
||||
/**
|
||||
@ -80,26 +74,23 @@ public abstract class AbstractObjectParser implements ObjectParser {
|
||||
* @param name
|
||||
* @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) {
|
||||
throw new IllegalArgumentException(TAG + ".ObjectParser request == null!!!");
|
||||
}
|
||||
this.request = request;
|
||||
this.parentPath = parentPath;
|
||||
|
||||
this.arrayConfig = arrayConfig;
|
||||
this.isSubquery = isSubquery;
|
||||
|
||||
this.type = arrayConfig == null ? 0 : arrayConfig.getType();
|
||||
this.joinList = arrayConfig == null ? null : arrayConfig.getJoinList();
|
||||
this.name = name;
|
||||
this.path = AbstractParser.getAbsPath(parentPath, name);
|
||||
|
||||
apijson.orm.Entry<String, String> entry = Pair.parseEntry(name, true);
|
||||
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.isTable = isTable; // apijson.JSONObject.isTableKey(table);
|
||||
this.isArrayMainTable = isArrayMainTable; // isSubquery == false && this.isTable && this.type == SQLConfig.TYPE_ITEM_CHILD_0 && RequestMethod.isGetMethod(method, true);
|
||||
// this.isReuse = isReuse; // isArrayMainTable && arrayConfig != null && arrayConfig.getPosition() > 0;
|
||||
|
||||
this.objectCount = 0;
|
||||
this.arrayCount = 0;
|
||||
@ -117,11 +108,10 @@ public abstract class AbstractObjectParser implements ObjectParser {
|
||||
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;
|
||||
public int getPosition() {
|
||||
return position;
|
||||
@ -148,6 +138,12 @@ public abstract class AbstractObjectParser implements ObjectParser {
|
||||
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 sqlRequest;
|
||||
@ -177,118 +173,135 @@ public abstract class AbstractObjectParser implements ObjectParser {
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public AbstractObjectParser parse() throws Exception {
|
||||
public AbstractObjectParser parse(String name, boolean isReuse) throws Exception {
|
||||
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;
|
||||
|
||||
response = new JSONObject(true);//must init
|
||||
|
||||
sqlRequest = new JSONObject(true);//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 (set != null && set.isEmpty() == false) {//判断换取少几个变量的初始化是否值得?
|
||||
if (isTable) {//非Table下必须保证原有顺序!否则 count,page 会丢, total@:"/[]/total" 会在[]:{}前执行!
|
||||
customMap = new LinkedHashMap<String, Object>();
|
||||
childMap = new LinkedHashMap<String, JSONObject>();
|
||||
}
|
||||
functionMap = new LinkedHashMap<String, Map<String, String>>();//必须执行
|
||||
if (isReuse == false) {
|
||||
sqlRequest = new JSONObject(true);//must init
|
||||
|
||||
customMap = null;//must init
|
||||
functionMap = null;//must init
|
||||
childMap = null;//must init
|
||||
|
||||
//条件<<<<<<<<<<<<<<<<<<<
|
||||
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);
|
||||
Set<Entry<String, Object>> set = request.isEmpty() ? null : new LinkedHashSet<Entry<String, Object>>(request.entrySet());
|
||||
if (set != null && set.isEmpty() == false) {//判断换取少几个变量的初始化是否值得?
|
||||
if (isTable) {//非Table下必须保证原有顺序!否则 count,page 会丢, total@:"/[]/total" 会在[]:{}前执行!
|
||||
customMap = new LinkedHashMap<String, Object>();
|
||||
childMap = new LinkedHashMap<String, JSONObject>();
|
||||
}
|
||||
functionMap = new LinkedHashMap<String, Map<String, String>>();//必须执行
|
||||
|
||||
//条件<<<<<<<<<<<<<<<<<<<
|
||||
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;
|
||||
Object value;
|
||||
int index = 0;
|
||||
String key;
|
||||
Object value;
|
||||
int index = 0;
|
||||
|
||||
for (Entry<String, Object> entry : set) {
|
||||
if (isBreakParse()) {
|
||||
break;
|
||||
for (Entry<String, Object> entry : set) {
|
||||
if (isBreakParse()) {
|
||||
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 (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 (isTable) {
|
||||
if (parser.getGlobleDatabase() != null && sqlRequest.get(JSONRequest.KEY_DATABASE) == null) {
|
||||
sqlRequest.put(JSONRequest.KEY_DATABASE, parser.getGlobleDatabase());
|
||||
}
|
||||
if (parser.getGlobleCache() != null && sqlRequest.get(JSONRequest.KEY_CACHE) == null) {
|
||||
sqlRequest.put(JSONRequest.KEY_CACHE, parser.getGlobleCache());
|
||||
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) {
|
||||
sqlRequest.put(JSONRequest.KEY_CACHE, parser.getGlobleCache());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isTable) { // 非Table内的函数会被滞后在onChildParse后调用
|
||||
onFunctionResponse("-");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (isInvalidate()) {
|
||||
@ -311,95 +324,93 @@ public abstract class AbstractObjectParser implements ObjectParser {
|
||||
@Override
|
||||
public boolean onParse(@NotNull String key, @NotNull Object value) throws Exception {
|
||||
if (key.endsWith("@")) { // StringUtil.isPath((String) value)) {
|
||||
String replaceKey = key.substring(0, key.length() - 1);
|
||||
|
||||
// [] 内主表 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;
|
||||
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) {
|
||||
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));
|
||||
JSONObject subquery = (JSONObject) value;
|
||||
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) {
|
||||
throw new IllegalArgumentException("子查询 " + path + "/" + key + ":{ range:value } 中 value 只能为 [" + JSONRequest.SUBQUERY_RANGE_ALL + ", " + JSONRequest.SUBQUERY_RANGE_ANY + "] 中的一个!");
|
||||
}
|
||||
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)会出错
|
||||
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) >>");
|
||||
JSONArray arr = parser.onArrayParse(subquery, path, key, true);
|
||||
|
||||
//非查询关键词 @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);
|
||||
JSONObject obj = arr == null || arr.isEmpty() ? null : arr.getJSONObject(0);
|
||||
if (obj == null) {
|
||||
throw new Exception("服务器内部错误,解析子查询 " + path + "/" + key + ":{ } 为 Subquery 对象失败!");
|
||||
}
|
||||
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("()")) {
|
||||
@ -410,21 +421,24 @@ public abstract class AbstractObjectParser implements ObjectParser {
|
||||
String k = key.substring(0, key.length() - 2);
|
||||
|
||||
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 = "-";
|
||||
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 {
|
||||
if (k.endsWith("+")) {
|
||||
type = "+";
|
||||
k = k.substring(0, k.length() - 1);
|
||||
}
|
||||
else {
|
||||
type = "0";
|
||||
}
|
||||
type = "0";
|
||||
}
|
||||
|
||||
if (isMinus == false || isTable) {
|
||||
//远程函数比较少用,一般一个Table:{}内用到也就一两个,所以这里循环里new出来对性能影响不大。
|
||||
Map<String, String> map = functionMap.get(type);
|
||||
if (map == null) {
|
||||
@ -439,9 +453,7 @@ public abstract class AbstractObjectParser implements ObjectParser {
|
||||
customMap.put(key, value);
|
||||
}
|
||||
else {
|
||||
// 导致副表从 1 开始都不查了 if (isReuse == false) {
|
||||
sqlRequest.put(key, value);
|
||||
// }
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -590,7 +602,7 @@ public abstract class AbstractObjectParser implements ObjectParser {
|
||||
|
||||
String idKey = parser.createSQLConfig().getIdKey(); //Table[]: [{}] arrayConfig 为 null
|
||||
boolean isNeedVerifyContent = parser.isNeedVerifyContent();
|
||||
|
||||
|
||||
for (int i = 0; i < valueArray.size(); i++) { //只要有一条失败,则抛出异常,全部失败
|
||||
//TODO 改成一条多 VALUES 的 SQL 性能更高,报错也更会更好处理,更人性化
|
||||
JSONObject item;
|
||||
@ -693,28 +705,27 @@ public abstract class AbstractObjectParser implements ObjectParser {
|
||||
sqlReponse = new JSONObject(sqlRequest);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
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;
|
||||
// }
|
||||
}
|
||||
try {
|
||||
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;
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
if (drop) {//丢弃Table,只为了向下提供条件
|
||||
sqlReponse = null;
|
||||
}
|
||||
if (drop) {//丢弃Table,只为了向下提供条件
|
||||
sqlReponse = null;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
@ -799,10 +810,16 @@ public abstract class AbstractObjectParser implements ObjectParser {
|
||||
if (set != null) {
|
||||
int index = 0;
|
||||
for (Entry<String, JSONObject> entry : set) {
|
||||
if (entry != null) {
|
||||
response.put(entry.getKey(), onChildParse(index, entry.getKey(), entry.getValue()));
|
||||
index ++;
|
||||
Object child = entry == null ? null : onChildParse(index, entry.getKey(), entry.getValue());
|
||||
if (child == null
|
||||
|| (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 已经处理过
|
||||
JSONObject obj = parser.parseCorrectResponse(table, list.get(i));
|
||||
list.set(i, obj);
|
||||
|
||||
|
||||
if (obj != null) {
|
||||
parser.putQueryResult(arrayPath + "/" + i + "/" + table, obj); //解决获取关联数据时requestObject里不存在需要的关联数据
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
parser.putArrayMainCache(arrayPath, list);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (isSubquery == false && result != null) {
|
||||
parser.putQueryResult(path, result);//解决获取关联数据时requestObject里不存在需要的关联数据
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -752,6 +752,8 @@ public abstract class AbstractParser<T> implements Parser<T>, ParserCreator<T>,
|
||||
|
||||
|
||||
|
||||
protected Map<String, ObjectParser> arrayObjectParserCacheMap = new HashMap<>();
|
||||
|
||||
// protected SQLConfig itemConfig;
|
||||
/**获取单个对象,该对象处于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 position = arrayConfig == null ? 0 : arrayConfig.getPosition();
|
||||
|
||||
String[] arr = StringUtil.split(parentPath, "/");
|
||||
if (arrayConfig == null || arrayConfig.getPosition() == 0) {
|
||||
if (position == 0) {
|
||||
int d = arr == null ? 1 : arr.length + 1;
|
||||
if (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;
|
||||
if (op != null) {//SQL查询结果为空时,functionMap和customMap没有意义
|
||||
|
||||
if (arrayConfig == null) { //Common
|
||||
response = op.setSQLConfig().executeSQL().response();
|
||||
}
|
||||
@ -799,9 +814,12 @@ public abstract class AbstractParser<T> implements Parser<T>, ParserCreator<T>,
|
||||
int query = arrayConfig.getQuery();
|
||||
|
||||
//total 这里不能用arrayConfig.getType(),因为在createObjectParser.onChildParse传到onObjectParse时已被改掉
|
||||
if (type == SQLConfig.TYPE_ITEM_CHILD_0 && query != JSONRequest.QUERY_TABLE
|
||||
&& arrayConfig.getPosition() == 0) {
|
||||
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);
|
||||
|
||||
if (rp != null) {
|
||||
int index = parentPath.lastIndexOf("]/");
|
||||
if (index >= 0) {
|
||||
@ -842,14 +860,21 @@ public abstract class AbstractParser<T> implements Parser<T>, ParserCreator<T>,
|
||||
response = null;//不再往后查询
|
||||
} else {
|
||||
response = op
|
||||
.setSQLConfig(arrayConfig.getCount(), arrayConfig.getPage(), arrayConfig.getPosition())
|
||||
.setSQLConfig(arrayConfig.getCount(), arrayConfig.getPage(), position)
|
||||
.executeSQL()
|
||||
.response();
|
||||
// itemConfig = op.getConfig();
|
||||
}
|
||||
}
|
||||
|
||||
op.recycle();
|
||||
if (isArrayMainTable) {
|
||||
if (position == 0) { // 提取并缓存数组主表的列表数据
|
||||
arrayObjectParserCacheMap.put(parentPath.substring(0, parentPath.lastIndexOf("[]") + 2), op);
|
||||
}
|
||||
}
|
||||
// else {
|
||||
// op.recycle();
|
||||
// }
|
||||
op = null;
|
||||
}
|
||||
|
||||
|
@ -84,7 +84,7 @@ public abstract class AbstractSQLConfig implements SQLConfig {
|
||||
// * 和 / 不能同时出现,防止 /* */ 段注释! # 和 -- 不能出现,防止行注释! ; 不能出现,防止隔断SQL语句!空格不能出现,防止 CRUD,DROP,SHOW TABLES等语句!
|
||||
private static final Pattern PATTERN_RANGE;
|
||||
private static final Pattern PATTERN_FUNCTION;
|
||||
|
||||
|
||||
/**
|
||||
* 表名映射,隐藏真实表名,对安全要求很高的表可以这么做
|
||||
*/
|
||||
@ -96,8 +96,8 @@ public abstract class AbstractSQLConfig implements SQLConfig {
|
||||
static { // 凡是 SQL 边界符、分隔符、注释符 都不允许,例如 ' " ` ( ) ; # -- ,以免拼接 SQL 时被注入意外可执行指令
|
||||
PATTERN_RANGE = Pattern.compile("^[0-9%,!=\\<\\>/\\.\\+\\-\\*\\^]+$"); // ^[a-zA-Z0-9_*%!=<>(),"]+$ 导致 exists(select*from(Comment)) 通过!
|
||||
PATTERN_FUNCTION = Pattern.compile("^[A-Za-z0-9%,:_@&~!=\\<\\>\\|\\[\\]\\{\\} /\\.\\+\\-\\*\\^\\?\\$]+$"); //TODO 改成更好的正则,校验前面为单词,中间为操作符,后面为值
|
||||
|
||||
|
||||
|
||||
|
||||
TABLE_KEY_MAP = new HashMap<String, String>();
|
||||
TABLE_KEY_MAP.put(Table.class.getSimpleName(), Table.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) {
|
||||
return StringUtil.isEmpty(joinHaving, true) ? "" : (hasPrefix ? " HAVING " : "") + joinHaving;
|
||||
}
|
||||
|
||||
|
||||
String quote = getQuote();
|
||||
String tableAlias = getAliasWithQuote();
|
||||
|
||||
List<String> raw = getRaw();
|
||||
boolean containRaw = raw != null && raw.contains(KEY_HAVING);
|
||||
|
||||
|
||||
String expression;
|
||||
String method;
|
||||
//暂时不允许 String prefix;
|
||||
@ -560,7 +560,7 @@ public abstract class AbstractSQLConfig implements SQLConfig {
|
||||
+ "} catch (Exception e) = " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (expression.length() > 50) {
|
||||
throw new UnsupportedOperationException("@having:value 的 value 中字符串 " + expression + " 不合法!"
|
||||
+ "不允许传超过 50 个字符的函数或表达式!请用 @raw 简化传参!");
|
||||
@ -958,13 +958,13 @@ public abstract class AbstractSQLConfig implements SQLConfig {
|
||||
method = expression.substring(0, start);
|
||||
boolean distinct = i <= 0 && method.startsWith(PREFFIX_DISTINCT);
|
||||
String fun = distinct ? method.substring(PREFFIX_DISTINCT.length()) : method;
|
||||
|
||||
|
||||
if (fun.isEmpty() == false && StringUtil.isName(fun) == false) {
|
||||
throw new IllegalArgumentException("字符 " + method + " 不合法!"
|
||||
+ "预编译模式下 @column:\"column0,column1:alias;function0(arg0,arg1,...);function1(...):alias...\""
|
||||
+ " 中SQL函数名 function 必须符合正则表达式 ^[0-9a-zA-Z_]+$ !");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
boolean isColumn = start < 0;
|
||||
@ -1049,13 +1049,13 @@ public abstract class AbstractSQLConfig implements SQLConfig {
|
||||
int index = suffix.lastIndexOf(":");
|
||||
String alias = index < 0 ? "" : suffix.substring(index + 1); //contactCount
|
||||
suffix = index < 0 ? suffix : suffix.substring(0, index);
|
||||
|
||||
|
||||
if (alias.isEmpty() == false && StringUtil.isName(alias) == false) {
|
||||
throw new IllegalArgumentException("字符串 " + alias + " 不合法!"
|
||||
+ "预编译模式下 @column:value 中 value里面用 ; 分割的每一项"
|
||||
+ " function(arg0,arg1,...):alias 中 alias 必须是1个单词!并且不要有多余的空格!");
|
||||
}
|
||||
|
||||
|
||||
if (suffix.isEmpty() == false && (((String) suffix).contains("--") || ((String) suffix).contains("/*") || PATTERN_RANGE.matcher((String) suffix).matches() == false)) {
|
||||
throw new UnsupportedOperationException("字符串 " + suffix + " 不合法!"
|
||||
+ "预编译模式下 @column:\"column?value;function(arg0,arg1,...)?value...\""
|
||||
@ -2393,9 +2393,9 @@ public abstract class AbstractSQLConfig implements SQLConfig {
|
||||
case POST:
|
||||
return "INSERT INTO " + tablePath + config.getColumnString() + " VALUES" + config.getValuesString();
|
||||
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:
|
||||
return "DELETE FROM " + tablePath + config.getWhereString(true) + config.getLimitString();
|
||||
return "DELETE FROM " + tablePath + config.getWhereString(true) + (config.isMySQL() ? config.getLimitString() : ""); // PostgreSQL 不允许 LIMIT
|
||||
default:
|
||||
String explain = (config.isExplain() ? (config.isSQLServer() || config.isOracle() ? "SET STATISTICS PROFILE ON " : "EXPLAIN ") : "");
|
||||
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 userIdInKey = userIdKey + "{}";
|
||||
|
||||
//对id和id{}处理,这两个一定会作为条件
|
||||
|
||||
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 值
|
||||
List<?> ids = ((List<?>) idIn);
|
||||
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()");
|
||||
}
|
||||
idIn = newIdIn;
|
||||
|
||||
|
||||
if (method == DELETE || method == PUT) {
|
||||
config.setCount(newIdIn.size());
|
||||
}
|
||||
}
|
||||
|
||||
//对id和id{}处理,这两个一定会作为条件
|
||||
|
||||
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 instanceof Number) {
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (method == DELETE || method == PUT) {
|
||||
config.setCount(1);
|
||||
}
|
||||
@ -2695,272 +2693,277 @@ public abstract class AbstractSQLConfig implements SQLConfig {
|
||||
String raw = request.getString(KEY_RAW);
|
||||
String json = request.getString(KEY_JSON);
|
||||
|
||||
//强制作为条件且放在最前面优化性能
|
||||
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<>();
|
||||
|
||||
try {
|
||||
//强制作为条件且放在最前面优化性能
|
||||
if (id != null) {
|
||||
tableWhere.put(idKey, id);
|
||||
andList.add(idKey);
|
||||
}
|
||||
if (idIn != null) {
|
||||
tableWhere.put(idInKey, idIn);
|
||||
andList.add(idInKey);
|
||||
}
|
||||
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[] ws = StringUtil.split(combine);
|
||||
if (ws != null) {
|
||||
if (method == DELETE || method == GETS || method == HEADS) {
|
||||
throw new IllegalArgumentException("DELETE,GETS,HEADS 请求不允许传 @combine:value !");
|
||||
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 + " !");
|
||||
}
|
||||
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 (set != null && set.isEmpty() == false) { //不能直接return,要走完下面的流程
|
||||
String[] columns = set.toArray(new String[]{});
|
||||
|
||||
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 + "] 其中任何一个!");
|
||||
}
|
||||
}
|
||||
Collection<Object> valueCollection = request.values();
|
||||
Object[] values = valueCollection == null ? null : valueCollection.toArray();
|
||||
|
||||
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
|
||||
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);
|
||||
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) {
|
||||
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没有作为条件,而是作为内容,导致PUT,DELETE出错
|
||||
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>();
|
||||
Object value;
|
||||
for (String key : set) {
|
||||
value = request.get(key);
|
||||
List<String> cs = new ArrayList<>();
|
||||
|
||||
if (value instanceof Map) {//只允许常规Object
|
||||
throw new IllegalArgumentException("不允许 " + key + " 等任何key的value类型为 {JSONObject} !");
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
//解决AccessVerifier新增userId没有作为条件,而是作为内容,导致PUT,DELETE出错
|
||||
if (isWhere) {
|
||||
tableWhere.put(key, value);
|
||||
if (whereList == null || whereList.contains(key) == false) {
|
||||
andList.add(key);
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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.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 等要合并
|
||||
|
||||
config.setContent(tableContent);
|
||||
}
|
||||
|
||||
|
||||
List<String> cs = new ArrayList<>();
|
||||
|
||||
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());
|
||||
finally {//后面还可能用到,要还原
|
||||
//id或id{}条件
|
||||
if (hasId) {
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -20,14 +20,15 @@ import apijson.RequestMethod;
|
||||
*/
|
||||
public interface ObjectParser {
|
||||
|
||||
|
||||
/**解析成员
|
||||
* response重新赋值
|
||||
* @param config 传递给第0个Table
|
||||
* @param parentPath
|
||||
* @param name
|
||||
* @param isReuse
|
||||
* @return null or this
|
||||
* @throws Exception
|
||||
*/
|
||||
ObjectParser parse() throws Exception;
|
||||
ObjectParser parse(String name, boolean isReuse) throws Exception;
|
||||
|
||||
/**调用 parser 的 sqlExecutor 来解析结果
|
||||
* @param method
|
||||
@ -159,4 +160,5 @@ public interface ObjectParser {
|
||||
Map<String, Map<String, String>> getFunctionMap();
|
||||
Map<String, JSONObject> getChildMap();
|
||||
|
||||
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ public interface Parser<T> {
|
||||
*/
|
||||
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 getMaxQueryPage();
|
||||
|
Loading…
Reference in New Issue
Block a user