diff --git a/APIJSONORM/README.md b/APIJSONORM/README.md
index 0cb431e2..745733b4 100644
--- a/APIJSONORM/README.md
+++ b/APIJSONORM/README.md
@@ -21,7 +21,7 @@ Tencent [APIJSON](https://github.com/Tencent/APIJSON) ORM library for remote dep
com.github.Tencent
APIJSON
- LATEST
+ 8.1.8
```
@@ -45,7 +45,7 @@ Tencent [APIJSON](https://github.com/Tencent/APIJSON) ORM library for remote dep
#### 2. Add the APIJSON dependency in one of your modules(such as `app`)
```gradle
dependencies {
- implementation 'com.github.Tencent:APIJSON:latest'
+ implementation 'com.github.Tencent:APIJSON:8.1.8'
}
```
diff --git a/APIJSONORM/pom.xml b/APIJSONORM/pom.xml
index 7a35eb01..00ff59dc 100644
--- a/APIJSONORM/pom.xml
+++ b/APIJSONORM/pom.xml
@@ -5,7 +5,7 @@
com.github.Tencent
APIJSON
- 8.1.8
+ 8.2.0
jar
APIJSONORM
@@ -21,6 +21,12 @@
+
+ junit
+ junit
+ 4.13.2
+ test
+
diff --git a/APIJSONORM/src/main/java/apijson/Log.java b/APIJSONORM/src/main/java/apijson/Log.java
index f00e495a..736877f9 100755
--- a/APIJSONORM/src/main/java/apijson/Log.java
+++ b/APIJSONORM/src/main/java/apijson/Log.java
@@ -12,7 +12,7 @@
*/
public class Log {
public static boolean DEBUG = false;
- public static final String VERSION = "8.1.8";
+ public static final String VERSION = "8.2.0";
public static final String LEVEL_VERBOSE = "VERBOSE";
public static final String LEVEL_INFO = "INFO";
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java
index c4f7c5ff..5fd00c17 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java
@@ -375,7 +375,7 @@ else if (_method == PUT && value instanceof List> && (whereList == null || whe
if (isSubquery == false) { // 解决 SQL 语法报错,子查询不能 EXPLAIN
Boolean exp = parser.getGlobalExplain();
- if (sch != null) {
+ if (exp != null) {
sqlRequest.putIfAbsent(JSONMap.KEY_EXPLAIN, exp);
}
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
index defccc93..26e63a9c 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
@@ -2303,6 +2303,86 @@ protected M getRequestStructure(RequestMethod method, String tag, int version) t
KEY_METHOD_ENUM_MAP.put(KEY_DELETE, RequestMethod.DELETE);
}
+ private void parseMethodDirective(String key, RequestMethod keyMethod, @NotNull M request) throws Exception {
+ boolean isPost = KEY_POST.equals(key);
+ Object val = request.get(key);
+ Map obj = val instanceof Map, ?> ? JSON.get(request, key) : null;
+ if (obj == null) {
+ if (val instanceof String) {
+ String[] tbls = StringUtil.split((String) val);
+ if (tbls != null && tbls.length > 0) {
+ obj = new LinkedHashMap();
+ for (String tbl : tbls) {
+ if (obj.containsKey(tbl)) {
+ throw new ConflictException(key + ": value 中 " + tbl + " 已经存在,不能重复!");
+ }
+
+ obj.put(tbl, isPost && isTableArray(tbl)
+ ? tbl.substring(0, tbl.length() - 2) + ":[]" : "");
+ }
+ }
+ }
+ else {
+ throw new IllegalArgumentException(key + ": value 中 value 类型错误,只能是 String 或 Map {} !");
+ }
+ }
+
+ Set> set = obj == null ? new HashSet<>() : obj.entrySet();
+ for (Entry objEntry : set) {
+ String objKey = objEntry == null ? null : objEntry.getKey();
+ if (objKey == null) {
+ continue;
+ }
+
+ Map objAttrMap = new HashMap<>();
+ objAttrMap.put(KEY_METHOD, keyMethod);
+ keyObjectAttributesMap.put(objKey, objAttrMap);
+
+ Object objVal = objEntry.getValue();
+ Map objAttrJson = objVal instanceof Map, ?> ? JSON.getMap(obj, objKey) : null;
+ if (objAttrJson == null) {
+ if (objVal instanceof String) {
+ objAttrMap.put(KEY_TAG, "".equals(objVal) ? objKey : objVal);
+ }
+ else {
+ throw new IllegalArgumentException(key + ": { " + objKey + ": value 中 value 类型错误,只能是 String 或 Map {} !");
+ }
+ }
+ else {
+ boolean hasTag = false;
+ for (Entry entry : objAttrJson.entrySet()) {
+ String objAttrKey = entry == null ? null : entry.getKey();
+ if (objAttrKey == null) {
+ continue;
+ }
+
+ switch (objAttrKey) {
+ case KEY_DATABASE:
+ case KEY_DATASOURCE:
+ case KEY_NAMESPACE:
+ case KEY_CATALOG:
+ case KEY_SCHEMA:
+ case KEY_VERSION:
+ case KEY_ROLE:
+ objAttrMap.put(objAttrKey, entry.getValue());
+ break;
+ case KEY_TAG:
+ hasTag = true;
+ objAttrMap.put(objAttrKey, entry.getValue());
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (hasTag == false) {
+ objAttrMap.put(KEY_TAG, isPost && isTableArray(objKey)
+ ? objKey.substring(0, objKey.length() - 2) + ":[]" : objKey);
+ }
+ }
+ }
+ }
+
protected M batchVerify(RequestMethod method, String tag, int version, String name, @NotNull M request, int maxUpdateCount, SQLCreator creator) throws Exception {
M correctRequest = JSON.createJSONObject();
List removeTmpKeys = new ArrayList<>(); // 请求json里面的临时变量,不需要带入后面的业务中,比如 @post、@get等
@@ -2312,103 +2392,34 @@ protected M batchVerify(RequestMethod method, String tag, int version, String na
throw new IllegalArgumentException("JSON 对象格式不正确 !正确示例例如 \"User\": {}");
}
+ // 先收集所有显式方法,避免同一请求中方法指令的字段顺序影响对象解析结果。
for (String key : reqSet) {
- // key 重复直接抛错(xxx:alias, xxx:alias[])
- if (correctRequest.containsKey(key) || correctRequest.containsKey(key + KEY_ARRAY)) {
- throw new IllegalArgumentException("对象名重复,请添加别名区分 ! 重复对象名为: " + key);
+ RequestMethod keyMethod = KEY_POST.equals(key) ? RequestMethod.POST : KEY_METHOD_ENUM_MAP.get(key);
+ if (keyMethod == null) {
+ continue;
}
- boolean isPost = KEY_POST.equals(key);
- // @post、@get 等 RequestMethod
+ removeTmpKeys.add(key);
try {
- RequestMethod keyMethod = isPost ? RequestMethod.POST : KEY_METHOD_ENUM_MAP.get(key);
- if (keyMethod != null) {
- // 如果不匹配,异常不处理即可
- removeTmpKeys.add(key);
-
- Object val = request.get(key);
- Map obj = val instanceof Map, ?> ? JSON.get(request, key) : null;
- if (obj == null) {
- if (val instanceof String) {
- String[] tbls = StringUtil.split((String) val);
- if (tbls != null && tbls.length > 0) {
- obj = new LinkedHashMap();
- for (int i = 0; i < tbls.length; i++) {
- String tbl = tbls[i];
- if (obj.containsKey(tbl)) {
- throw new ConflictException(key + ": value 中 " + tbl + " 已经存在,不能重复!");
- }
-
- obj.put(tbl, isPost && isTableArray(tbl)
- ? tbl.substring(0, tbl.length() - 2) + ":[]" : "");
- }
- }
- }
- else {
- throw new IllegalArgumentException(key + ": value 中 value 类型错误,只能是 String 或 Map {} !");
- }
- }
-
- Set> set = obj == null ? new HashSet<>() : obj.entrySet();
-
- for (Entry objEntry : set) {
- String objKey = objEntry == null ? null : objEntry.getKey();
- if (objKey == null) {
- continue;
- }
-
- Map objAttrMap = new HashMap<>();
- objAttrMap.put(KEY_METHOD, keyMethod);
- keyObjectAttributesMap.put(objKey, objAttrMap);
-
- Object objVal = objEntry.getValue();
- Map objAttrJson = objVal instanceof Map, ?> ? JSON.getMap(obj, objKey) : null;
- if (objAttrJson == null) {
- if (objVal instanceof String) {
- objAttrMap.put(KEY_TAG, "".equals(objVal) ? objKey : objVal);
- }
- else {
- throw new IllegalArgumentException(key + ": { " + objKey + ": value 中 value 类型错误,只能是 String 或 Map {} !");
- }
- }
- else {
- Set> objSet = objAttrJson.entrySet();
-
- boolean hasTag = false;
- for (Entry entry : objSet) {
- String objAttrKey = entry == null ? null : entry.getKey();
- if (objAttrKey == null) {
- continue;
- }
+ parseMethodDirective(key, keyMethod, request);
+ }
+ catch (Exception e) {
+ Log.e(TAG, "parse method directive failed", e);
+ throw e;
+ }
+ }
- switch (objAttrKey) {
- case KEY_DATABASE:
- case KEY_DATASOURCE:
- case KEY_NAMESPACE:
- case KEY_CATALOG:
- case KEY_SCHEMA:
- case KEY_VERSION:
- case KEY_ROLE:
- objAttrMap.put(objAttrKey, entry.getValue());
- break;
- case KEY_TAG:
- hasTag = true;
- objAttrMap.put(objAttrKey, entry.getValue());
- break;
- default:
- break;
- }
- }
+ for (String key : reqSet) {
+ // key 重复直接抛错(xxx:alias, xxx:alias[])
+ if (correctRequest.containsKey(key) || correctRequest.containsKey(key + KEY_ARRAY)) {
+ throw new IllegalArgumentException("对象名重复,请添加别名区分 ! 重复对象名为: " + key);
+ }
- if (hasTag == false) {
- objAttrMap.put(KEY_TAG, isPost && isTableArray(objKey)
- ? objKey.substring(0, objKey.length() - 2) + ":[]" : objKey);
- }
- }
- }
- continue;
- }
+ if (KEY_POST.equals(key) || KEY_METHOD_ENUM_MAP.containsKey(key)) {
+ continue;
+ }
+ try {
// 1、非crud,对于没有显式声明操作方法的,直接用 URL(/get, /post 等) 对应的默认操作方法
// 2、crud, 没有声明就用 GET
// 3、兼容 sql@ Map,设置 GET方法
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
index 05e9f04e..66cf0214 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
@@ -154,6 +154,9 @@ public abstract class AbstractSQLConfig, L exte
DATABASE_LIST.add(DATABASE_COCKROACHDB);
DATABASE_LIST.add(DATABASE_DAMENG);
DATABASE_LIST.add(DATABASE_KINGBASE);
+ DATABASE_LIST.add(DATABASE_KINGBASE_MYSQL);
+ DATABASE_LIST.add(DATABASE_KINGBASE_ORACLE);
+ DATABASE_LIST.add(DATABASE_KINGBASE_SQLSERVER);
DATABASE_LIST.add(DATABASE_ELASTICSEARCH);
DATABASE_LIST.add(DATABASE_MANTICORE);
DATABASE_LIST.add(DATABASE_CLICKHOUSE);
@@ -178,6 +181,7 @@ public abstract class AbstractSQLConfig, L exte
DATABASE_LIST.add(DATABASE_SURREALDB);
DATABASE_LIST.add(DATABASE_OPENGAUSS);
DATABASE_LIST.add(DATABASE_DORIS);
+ DATABASE_LIST.add(DATABASE_STARROCKS);
RAW_MAP = new LinkedHashMap<>(); // 保证顺序,避免配置冲突等意外情况
@@ -893,6 +897,7 @@ public String getUserIdKey() {
private boolean main = true;
private Object id; // Table 的 id
+ private boolean idGeneratedByAPIJSON;
private Object idIn; // User Table 的 id IN
private Object userId; // Table 的 userId
private Object userIdIn; // Table 的 userId IN
@@ -1010,6 +1015,15 @@ public AbstractSQLConfig setId(Object id) {
this.id = id;
return this;
}
+ @Override
+ public boolean isIdGeneratedByAPIJSON() {
+ return idGeneratedByAPIJSON;
+ }
+ @Override
+ public AbstractSQLConfig setIdGeneratedByAPIJSON(boolean generated) {
+ this.idGeneratedByAPIJSON = generated;
+ return this;
+ }
@Override
public Object getIdIn() {
@@ -1083,11 +1097,11 @@ public String gainSQLDatabase() {
@Override
public boolean isTSQL() { // 兼容 TSQL 语法
- return isOracle() || isSQLServer() || isDb2();
+ return isOracle() || isSQLServer() || isDb2() || isKingBaseOracle() || isKingBaseSQLServer();
}
@Override
public boolean isMSQL() { // 兼容 MySQL 语法,但不一定可以使用它的 JDBC/ODBC
- return isMySQL() || isTiDB() || isMariaDB() || isSQLite() || isTDengine();
+ return isMySQL() || isTiDB() || isMariaDB() || isSQLite() || isTDengine() || isKingBaseMySQL();
}
@Override
public boolean isPSQL() { // 兼容 PostgreSQL 语法,但不一定可以使用它的 JDBC/ODBC
@@ -1171,7 +1185,31 @@ public boolean isKingBase() {
return isKingBase(gainSQLDatabase());
}
public static boolean isKingBase(String db) {
- return DATABASE_KINGBASE.equals(db);
+ return KingbaseSQLDialect.from(db).isKingbase();
+ }
+
+ @Override
+ public boolean isKingBaseMySQL() {
+ return isKingBaseMySQL(gainSQLDatabase());
+ }
+ public static boolean isKingBaseMySQL(String db) {
+ return KingbaseSQLDialect.from(db).isMySQL();
+ }
+
+ @Override
+ public boolean isKingBaseOracle() {
+ return isKingBaseOracle(gainSQLDatabase());
+ }
+ public static boolean isKingBaseOracle(String db) {
+ return KingbaseSQLDialect.from(db).isOracle();
+ }
+
+ @Override
+ public boolean isKingBaseSQLServer() {
+ return isKingBaseSQLServer(gainSQLDatabase());
+ }
+ public static boolean isKingBaseSQLServer(String db) {
+ return KingbaseSQLDialect.from(db).isSQLServer();
}
@Override
@@ -1375,12 +1413,24 @@ public static boolean isDoris(String db) {
return DATABASE_DORIS.equals(db);
}
+ @Override
+ public boolean isStarRocks() {
+ return isStarRocks(gainSQLDatabase());
+ }
+ public static boolean isStarRocks(String db) {
+ return DATABASE_STARROCKS.equals(db);
+ }
+
@Override
public String getQuote() { // MongoDB 同时支持 `tbl` 反引号 和 "col" 双引号
if(isElasticsearch() || isManticore() || isIoTDB() || isSurrealDB()) {
return "";
}
- return isMySQL() || isMariaDB() || isTiDB() || isClickHouse() || isTDengine() || isMilvus() || isDoris() ? "`" : "\"";
+ KingbaseSQLDialect kingbaseDialect = KingbaseSQLDialect.from(gainSQLDatabase());
+ if (kingbaseDialect.isKingbase()) {
+ return kingbaseDialect.getIdentifierQuote();
+ }
+ return isMySQL() || isMariaDB() || isTiDB() || isClickHouse() || isTDengine() || isMilvus() || isDoris() || isStarRocks() ? "`" : "\"";
}
public String quote(String s) {
@@ -1516,7 +1566,7 @@ public AbstractSQLConfig setTable(String table) { //Table已经在Parse
}
public String gainAs() {
- return isOracle() || isManticore() ? " " : " AS ";
+ return isOracle() || isKingBaseOracle() || isManticore() ? " " : " AS ";
}
@Override
@@ -2065,7 +2115,7 @@ public String gainOrderString(boolean hasPrefix) {
// return (hasPrefix ? " ORDER BY " : "") + StringUtil.concat(order, joinOrder, ", ");
// }
- if (getCount() > 0 && (isSQLServer() || isDb2())) {
+ if (getCount() > 0 && (isSQLServer() || isKingBaseSQLServer() || isDb2())) {
// Oracle, SQL Server, DB2 的 OFFSET 必须加 ORDER BY.去掉Oracle,Oracle里面没有offset关键字
// String[] ss = StringUtil.split(order);
@@ -3064,8 +3114,14 @@ else if (isSurrealDB()) {
}
}
+ KingbaseSQLDialect kingbaseDialect = KingbaseSQLDialect.from(gainSQLDatabase());
+ String kingbaseLimit = kingbaseDialect.getSelectLimit(getOffset(page, count), count);
+ if (kingbaseLimit != null) {
+ return kingbaseLimit;
+ }
+
boolean isOracle = isOracle();
- return gainLimitString(page, count, isTSQL(), isOracle || isDameng() || isKingBase(), isPresto() || isTrino());
+ return gainLimitString(page, count, isTSQL(), isOracle || isDameng() || isKingBaseOracle(), isPresto() || isTrino());
}
/**获取限制数量及偏移量
* @param page
@@ -4005,7 +4061,7 @@ public String gainCompareString(String key, String column, Object value, String
public String gainKey(@NotNull String key) {
String lenFun = "";
if (key.endsWith("[")) {
- lenFun = isSQLServer() ? "datalength" : "length";
+ lenFun = isSQLServer() || isKingBaseSQLServer() ? "datalength" : "length";
key = key.substring(0, key.length() - 1);
}
else if (key.endsWith("{")) {
@@ -4293,10 +4349,11 @@ public String gainRegExpString(String key, String column, Object[] values, int t
* @return key REGEXP 'value'
*/
public String gainRegExpString(String key, String column, String value, boolean ignoreCase) {
- if (isPSQL()) {
+ if (isPSQL() || isKingBaseSQLServer()) {
return gainKey(column) + " ~" + (ignoreCase ? "* " : " ") + gainValue(key, column, value);
}
- if (isOracle() || isDameng() || isKingBase() || (isMySQL() && gainDBVersionNums()[0] >= 8)) {
+ if (isOracle() || isDameng() || DATABASE_KINGBASE.equals(gainSQLDatabase())
+ || isKingBaseOracle() || isKingBaseMySQL() || (isMySQL() && gainDBVersionNums()[0] >= 8)) {
return "regexp_like(" + gainKey(column) + ", " + gainValue(key, column, value) + (ignoreCase ? ", 'i'" : ", 'c'") + ")";
}
if (isPresto() || isTrino()) {
@@ -4615,7 +4672,10 @@ public String gainContainString(String key, String column, Object[] childs, int
condition += (gainKey(column) + " @> " + gainValue(key, column, newJSONArray(c)));
// operator does not exist: jsonb @> character varying "[" + c + "]");
}
- else if (isOracle() || isDameng() || isKingBase()) {
+ else if (isKingBase() && isKingBaseOracle() == false) {
+ condition += (gainKey(column) + "::jsonb @> " + gainValue(key, column, newJSONArray(c)) + "::jsonb");
+ }
+ else if (isOracle() || isDameng() || isKingBaseOracle()) {
condition += ("json_textcontains(" + gainKey(column) + ", " + (StringUtil.isEmpty(path, true)
? "'$'" : gainValue(key, column, path)) + ", " + gainValue(key, column, c == null ? null : c.toString()) + ")");
}
@@ -4662,7 +4722,7 @@ public List getWithAsExprSQLList() {
}
private void clearWithAsExprListIfNeed() {
// mysql8版本以上,子查询支持with as表达式
- if(this.isMySQL() && this.gainDBVersionNums()[0] >= 8) {
+ if((this.isMySQL() || this.isKingBaseMySQL()) && this.gainDBVersionNums()[0] >= 8) {
this.withAsExprSQLList = new ArrayList<>();
}
}
@@ -4716,7 +4776,7 @@ private String withAsExprSubqueryString(SQLConfig cfg, Subquery, L extends List