Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

新增、优化相关功能点 #487

Merged
merged 3 commits into from
Dec 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions APIJSONORM/src/main/java/apijson/JSONObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ public JSONObject setUserIdIn(List<Object> list) {
TABLE_KEY_LIST.add(KEY_ORDER);
TABLE_KEY_LIST.add(KEY_RAW);
TABLE_KEY_LIST.add(KEY_JSON);
TABLE_KEY_LIST.add(KEY_METHOD);
}

//@key关键字都放这个类 >>>>>>>>>>>>>>>>>>>>>>
Expand Down
2 changes: 1 addition & 1 deletion APIJSONORM/src/main/java/apijson/StringUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ public static boolean isNotEmpty(String s, boolean trim) {
PATTERN_ALPHA = Pattern.compile("^[a-zA-Z]+$");
PATTERN_ALPHA_BIG = Pattern.compile("^[A-Z]+$");
PATTERN_ALPHA_SMALL = Pattern.compile("^[a-z]+$");
PATTERN_NAME = Pattern.compile("^[0-9a-zA-Z_:]+$");//已用55个中英字符测试通过
PATTERN_NAME = Pattern.compile("^[0-9a-zA-Z_.:]+$");//已用55个中英字符测试通过
//newest phone regex expression reference https://github.com/VincentSit/ChinaMobilePhoneNumberRegex
PATTERN_PHONE = Pattern.compile("^1(?:3\\d{3}|5[^4\\D]\\d{2}|8\\d{3}|7(?:[0-35-9]\\d{2}|4(?:0\\d|1[0-2]|9\\d))|9[0-35-9]\\d{2}|6[2567]\\d{2}|4(?:(?:10|4[01])\\d{3}|[68]\\d{4}|[579]\\d{2}))\\d{6}$");
PATTERN_EMAIL = Pattern.compile("^([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)$");
Expand Down
128 changes: 104 additions & 24 deletions APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@
*/
public abstract class AbstractParser<T extends Object> implements Parser<T>, ParserCreator<T>, VerifierCreator<T>, SQLCreator {
protected static final String TAG = "AbstractParser";
protected Map<Object, RequestMethod> keyMethodMap = new HashMap<>();

/**
* json对象、数组对应的数据源、版本、角色、method等
*/
protected Map<Object, Map<String, Object>> keyObjectAttributesMap = new HashMap<>();
/**
* 可以通过切换该变量来控制是否打印关键的接口请求内容。保守起见,该值默认为false。
* 与 {@link Log#DEBUG} 任何一个为 true 都会打印关键的接口请求内容。
Expand Down Expand Up @@ -1158,7 +1162,8 @@ public JSONArray onArrayParse(JSONObject request, String parentPath, String name
}

//不能允许GETS,否则会被通过"[]":{"@role":"ADMIN"},"Table":{},"tag":"Table"绕过权限并能批量查询
if (isSubquery == false && RequestMethod.isGetMethod(requestMethod, true) == false) {
RequestMethod _method = request.get(apijson.JSONObject.KEY_METHOD) == null ? requestMethod : RequestMethod.valueOf(request.getString(apijson.JSONObject.KEY_METHOD));
if (isSubquery == false && RequestMethod.isGetMethod(_method, true) == false) {
throw new UnsupportedOperationException("key[]:{} 只支持 GET, GETS 方法!其它方法不允许传 " + name + ":{} 等这种 key[]:{} 格式!");
}
if (request == null || request.isEmpty()) { // jsonKey-jsonValue 条件
Expand Down Expand Up @@ -1913,7 +1918,7 @@ public JSONObject executeSQL(SQLConfig config, boolean isSubquery) throws Except
JSONObject res = getSQLExecutor().execute(config, false);

//如果是查询方法,才能执行explain
if (RequestMethod.isQueryMethod(config.getMethod())){
if (RequestMethod.isQueryMethod(config.getMethod()) && config.isElasticsearch() == false){
config.setExplain(explain);
JSONObject explainResult = config.isMain() && config.getPosition() != 0 ? null : getSQLExecutor().execute(config, false);

Expand Down Expand Up @@ -2083,6 +2088,7 @@ protected JSONObject getRequestStructure(RequestMethod method, String tag, int v

private JSONObject batchVerify(RequestMethod method, String tag, int version, String name, @NotNull JSONObject request, int maxUpdateCount, SQLCreator creator) throws Exception {
JSONObject jsonObject = new JSONObject(true);
List<String> removeTmpKeys = new ArrayList<>(); // 请求json里面的临时变量,不需要带入后面的业务中,比如 @post、@get等
if (request.keySet() == null || request.keySet().size() == 0) {
throw new IllegalArgumentException("json对象格式不正确 !,例如 \"User\": {}");
}
Expand All @@ -2098,59 +2104,117 @@ private JSONObject batchVerify(RequestMethod method, String tag, int version, St
if (key.startsWith("@")) {
try {
// 如果不匹配,异常不处理即可
RequestMethod l_method = RequestMethod.valueOf(key.substring(1).toUpperCase());
for(String objKey : StringUtil.split(request.getString(key))) {
keyMethodMap.put(objKey, l_method);
RequestMethod _method = RequestMethod.valueOf(key.substring(1).toUpperCase());
removeTmpKeys.add(key);
for (String objKey : request.getJSONObject(key).keySet()) {
Map<String, Object> object_attributes_map = new HashMap<>();
object_attributes_map.put(apijson.JSONObject.KEY_METHOD, _method);
keyObjectAttributesMap.put(objKey, object_attributes_map);
JSONObject objAttrJson = request.getJSONObject(key).getJSONObject(objKey);
for (String objAttr : objAttrJson.keySet()) {
switch (objAttr) {
case apijson.JSONObject.KEY_DATASOURCE:
object_attributes_map.put(apijson.JSONObject.KEY_DATASOURCE, objAttrJson.getString(objAttr));
break;
case apijson.JSONObject.KEY_SCHEMA:
object_attributes_map.put(apijson.JSONObject.KEY_SCHEMA, objAttrJson.getString(objAttr));
break;
case apijson.JSONObject.KEY_DATABASE:
object_attributes_map.put(apijson.JSONObject.KEY_DATABASE, objAttrJson.getString(objAttr));
break;
case apijson.JSONObject.VERSION:
object_attributes_map.put(apijson.JSONObject.VERSION, objAttrJson.getString(objAttr));
break;
case apijson.JSONObject.KEY_ROLE:
object_attributes_map.put(apijson.JSONObject.KEY_ROLE, objAttrJson.getString(objAttr));
break;
default:
break;
}
}
}
continue;
} catch (Exception e) {
}
}

//

// 1、非crud,对于没有显式声明操作方法的,直接用 URL(/get, /post 等) 对应的默认操作方法
// 2、crud, 没有声明就用 GET
// 3、兼容 sql@ JSONObject,设置 GET方法
// 将method 设置到每个object, op执行会解析
if (request.get(key) instanceof JSONObject) {
if (keyMethodMap.get(key) == null) {
if (keyObjectAttributesMap.get(key) == null) {
// 数组会解析为对象进行校验,做一下兼容
if (keyMethodMap.get(key + apijson.JSONObject.KEY_ARRAY) == null) {
if (method == RequestMethod.CRUD || (key.endsWith("@") && request.get(key) instanceof JSONObject)) {
if (keyObjectAttributesMap.get(key + apijson.JSONObject.KEY_ARRAY) == null) {
if (method == RequestMethod.CRUD || key.endsWith("@")) {
request.getJSONObject(key).put(apijson.JSONObject.KEY_METHOD, GET);
keyMethodMap.put(key, GET);
if(keyObjectAttributesMap.get(key) == null) {
Map<String, Object> object_attributes_map = new HashMap<>();
object_attributes_map.put(apijson.JSONObject.KEY_METHOD, GET);
keyObjectAttributesMap.put(key, object_attributes_map);
}else {
keyObjectAttributesMap.get(key).put(apijson.JSONObject.KEY_METHOD, GET);
}
} else {
request.getJSONObject(key).put(apijson.JSONObject.KEY_METHOD, method);
keyMethodMap.put(key, method);
if(keyObjectAttributesMap.get(key) == null) {
Map<String, Object> object_attributes_map = new HashMap<>();
object_attributes_map.put(apijson.JSONObject.KEY_METHOD, method);
keyObjectAttributesMap.put(key, object_attributes_map);
}else {
keyObjectAttributesMap.get(key).put(apijson.JSONObject.KEY_METHOD, method);
}
}
} else {
request.getJSONObject(key).put(apijson.JSONObject.KEY_METHOD, keyMethodMap.get(key + apijson.JSONObject.KEY_ARRAY));
setRequestAttribute(key, true, apijson.JSONObject.KEY_METHOD, request);
setRequestAttribute(key, true, apijson.JSONObject.KEY_DATASOURCE, request);
setRequestAttribute(key, true, apijson.JSONObject.KEY_SCHEMA, request);
setRequestAttribute(key, true, apijson.JSONObject.KEY_DATABASE, request);
setRequestAttribute(key, true, apijson.JSONObject.VERSION, request);
setRequestAttribute(key, true, apijson.JSONObject.KEY_ROLE, request);
}
} else {
request.getJSONObject(key).put(apijson.JSONObject.KEY_METHOD, keyMethodMap.get(key));
setRequestAttribute(key, false, apijson.JSONObject.KEY_METHOD, request);
setRequestAttribute(key, false, apijson.JSONObject.KEY_DATASOURCE, request);
setRequestAttribute(key, false, apijson.JSONObject.KEY_SCHEMA, request);
setRequestAttribute(key, false, apijson.JSONObject.KEY_DATABASE, request);
setRequestAttribute(key, false, apijson.JSONObject.VERSION, request);
setRequestAttribute(key, false, apijson.JSONObject.KEY_ROLE, request);
}
}

if (key.startsWith("@") || key.endsWith("@")) {
jsonObject.put(key, request.get(key));
continue;
}


if (request.get(key) instanceof JSONObject || request.get(key) instanceof JSONArray) {
RequestMethod _method = null;
if (request.get(key) instanceof JSONObject) {
_method = RequestMethod.valueOf(request.getJSONObject(key).getString(apijson.JSONObject.KEY_METHOD).toUpperCase());
} else {
if (keyMethodMap.get(key) == null) {
if (keyObjectAttributesMap.get(key) == null) {
if (method == RequestMethod.CRUD) {
_method = GET;
keyMethodMap.put(key, GET);
if(keyObjectAttributesMap.get(key) == null) {
Map<String, Object> object_attributes_map = new HashMap<>();
object_attributes_map.put(apijson.JSONObject.KEY_METHOD, GET);
keyObjectAttributesMap.put(key, object_attributes_map);
}else {
keyObjectAttributesMap.get(key).put(apijson.JSONObject.KEY_METHOD, GET);
}
} else {
_method = method;
keyMethodMap.put(key, method);
if(keyObjectAttributesMap.get(key) == null) {
Map<String, Object> object_attributes_map = new HashMap<>();
object_attributes_map.put(apijson.JSONObject.KEY_METHOD, method);
keyObjectAttributesMap.put(key, object_attributes_map);
}else {
keyObjectAttributesMap.get(key).put(apijson.JSONObject.KEY_METHOD, method);
}
}
} else {
_method = keyMethodMap.get(key);
_method = (RequestMethod) keyObjectAttributesMap.get(key).get(apijson.JSONObject.KEY_METHOD);
}
}

Expand Down Expand Up @@ -2179,10 +2243,26 @@ private JSONObject batchVerify(RequestMethod method, String tag, int version, St
throw new Exception(e);
}
}

// 这里是requestObject ref request 的引用, 删除不需要的临时变量
for(String removeKey : removeTmpKeys) {
request.remove(removeKey);
}
return jsonObject;
}

private void setRequestAttribute(String key, boolean isArray, String attrKey, @NotNull JSONObject request) {
Object attrVal = null;
if(isArray) {
attrVal = keyObjectAttributesMap.get(key + apijson.JSONObject.KEY_ARRAY).get(attrKey);
}else {
attrVal = keyObjectAttributesMap.get(key).get(attrKey);
}

if(attrVal != null && request.getJSONObject(key).get(attrKey) == null) {
// 如果对象内部已经包含该属性,不覆盖
request.getJSONObject(key).put(attrKey, attrVal);
}
}
/**
* { "xxx:aa":{ "@tag": "" }}
* 生成规则:
Expand Down Expand Up @@ -2231,8 +2311,8 @@ protected JSONObject objectVerify(RequestMethod method, String tag, int version,
* @return
*/
public RequestMethod getRealMethod(RequestMethod method, String key, Object value) {
if(method == CRUD && (value instanceof JSONObject || value instanceof JSONArray)) {
return this.keyMethodMap.get(key);
if(method == CRUD && key.startsWith("@") == false && (value instanceof JSONObject || value instanceof JSONArray)) {
return (RequestMethod)this.keyObjectAttributesMap.get(key).get(apijson.JSONObject.KEY_METHOD);
}
return method;
}
Expand Down
17 changes: 15 additions & 2 deletions APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
import static apijson.RequestMethod.HEADS;
import static apijson.RequestMethod.POST;
import static apijson.RequestMethod.PUT;
import static apijson.JSONObject.KEY_METHOD;
import static apijson.SQL.AND;
import static apijson.SQL.NOT;
import static apijson.SQL.ON;
Expand Down Expand Up @@ -1119,6 +1120,9 @@ public static boolean isTDengine(String db) {

@Override
public String getQuote() {
if(isElasticsearch()) {
return "";
}
return isMySQL() || isMariaDB() || isTiDB() || isClickHouse() || isTDengine() ? "`" : "\"";
}

Expand Down Expand Up @@ -3967,6 +3971,10 @@ public String getSubqueryString(Subquery subquery) throws Exception {
String range = subquery.getRange();
SQLConfig cfg = subquery.getConfig();

// 子查询 = 主语句 datasource
if(StringUtil.equals(this.getTable(), subquery.getFrom() ) == false && cfg.hasJoin() == false) {
cfg.setDatasource(this.getDatasource());
}
cfg.setPreparedValueList(new ArrayList<>());
String withAsExpreSql = withAsExpreSubqueryString(cfg, subquery);
String sql = (range == null || range.isEmpty() ? "" : range) + "(" + withAsExpreSql + ") ";
Expand Down Expand Up @@ -4213,6 +4221,9 @@ public static String getSQL(AbstractSQLConfig config) throws Exception {

cSql = "SELECT " + (config.getCache() == JSONRequest.CACHE_RAM ? "SQL_NO_CACHE " : "") + column + " FROM " + getConditionString(tablePath, config) + config.getLimitString();
cSql = buildWithAsExpreSql(config, cSql);
if(config.isElasticsearch()) { // elasticSearch 不支持 explain
return cSql;
}
return explain + cSql;
}
}
Expand Down Expand Up @@ -4354,7 +4365,8 @@ public String getJoinString() throws Exception {
// <"INNER JOIN User ON User.id = Moment.userId", UserConfig> TODO AS 放 getSQLTable 内
SQLConfig jc = j.getJoinConfig();
jc.setPrepared(isPrepared());

// 将关联表所属数据源配置为主表数据源
jc.setDatasource(this.getDatasource());
String jt = StringUtil.isEmpty(jc.getAlias(), true) ? jc.getTable() : jc.getAlias();
List<On> onList = j.getOnList();

Expand Down Expand Up @@ -4648,7 +4660,7 @@ public static <T extends Object> SQLConfig newSQLConfig(RequestMethod method, St

boolean explain = request.getBooleanValue(KEY_EXPLAIN);
if (explain && Log.DEBUG == false) { //不在 config.setExplain 抛异常,一方面处理更早性能更好,另一方面为了内部调用可以绕过这个限制
throw new UnsupportedOperationException("DEBUG 模式下不允许传 " + KEY_EXPLAIN + " !");
throw new UnsupportedOperationException("非DEBUG模式, 不允许传 " + KEY_EXPLAIN + " !");
}

String database = request.getString(KEY_DATABASE);
Expand Down Expand Up @@ -4835,6 +4847,7 @@ else if (userId instanceof Subquery) {}
request.remove(KEY_ORDER);
request.remove(KEY_RAW);
request.remove(KEY_JSON);
request.remove(KEY_METHOD);


// @null <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Expand Down
Loading