From 90b896c9d59cb6883b2e4469d3806e1c3ed815b9 Mon Sep 17 00:00:00 2001
From: TommyLemon <1184482681@qq.com>
Date: Sun, 27 Oct 2024 21:50:51 +0800
Subject: [PATCH 001/122] =?UTF-8?q?=E5=A4=9A=E5=B9=B4=E6=8C=81=E7=BB=AD?=
=?UTF-8?q?=E8=BF=AD=E4=BB=A3:=20=E8=87=AA=202016=20=E5=B9=B4=E8=B5=B7?=
=?UTF-8?q?=E5=B7=B2=E8=BF=9E=E7=BB=AD=E7=BB=B4=E6=8A=A4=207=20=E5=B9=B4?=
=?UTF-8?q?=E5=A4=9A=EF=BC=8C70+=20=E8=B4=A1=E7=8C=AE=E8=80=85=E3=80=8190+?=
=?UTF-8?q?=20=E5=8F=91=E7=89=88=E3=80=813000+=20=E6=8F=90=E4=BA=A4?=
=?UTF-8?q?=EF=BC=8C=E4=B8=8D=E6=96=AD=E6=9B=B4=E6=96=B0=E8=BF=AD=E4=BB=A3?=
=?UTF-8?q?=E4=B8=AD...?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
https://github.com/Tencent/APIJSON?tab=readme-ov-file#%E4%B8%BA%E4%BB%80%E4%B9%88%E9%80%89%E6%8B%A9-apijson
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 4acdba485..0f69856ab 100644
--- a/README.md
+++ b/README.md
@@ -191,7 +191,7 @@ https://github.com/Tencent/APIJSON/wiki
* **高质可靠代码** (代码严谨规范,商业分析软件源伞 Pinpoint 代码扫描报告平均每行代码 Bug 率低至 0.15%)
* **兼容各种项目** (协议不限 HTTP,与其它库无冲突,对各类 Web 框架集成友好且提供 SpringBoot, JFinal 的示例)
* **工程轻量小巧** (仅依赖 fastjson,Jar 仅 280KB,Java 文件仅 59 个共 13719 行代码,例如 APIJSONORM 4.3.1)
-* **多年持续迭代** (自 2016 年起已连续维护 7 年多,60+ 贡献者、90+ 发版、3000+ 提交,不断更新迭代中...)
+* **多年持续迭代** (自 2016 年起已连续维护 7 年多,70+ 贡献者、90+ 发版、3000+ 提交,不断更新迭代中...)
**按照一般互联网中小型项目情况可得出以下对比表格:**
From 64042e59bd80146c1b589b95242e234a06fd5efb Mon Sep 17 00:00:00 2001
From: TommyLemon <1184482681@qq.com>
Date: Sun, 3 Nov 2024 20:25:18 +0800
Subject: [PATCH 002/122] =?UTF-8?q?=E5=AE=9E=E6=97=B6=20=E9=9B=B6=E4=BB=A3?=
=?UTF-8?q?=E7=A0=81=E3=80=81=E5=85=A8=E5=8A=9F=E8=83=BD=E3=80=81=E5=BC=BA?=
=?UTF-8?q?=E5=AE=89=E5=85=A8=20ORM=20=E5=BA=93?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 0f69856ab..c1d70c7fe 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ This source code is licensed under the Apache License Version 2.0
APIJSON
-
🏆 零代码、全功能、强安全 ORM 库 🚀 后端接口和文档零代码,前端(客户端) 定制返回 JSON 的数据和结构
+ 🏆 实时 零代码、全功能、强安全 ORM 库 🚀 后端接口和文档零代码,前端(客户端) 定制返回 JSON 的数据和结构
English
From 4f6066cffaf1d06a41a7b4f6a127f22ae56c80c0 Mon Sep 17 00:00:00 2001
From: TommyLemon <1184482681@qq.com>
Date: Sun, 3 Nov 2024 20:27:54 +0800
Subject: [PATCH 003/122] =?UTF-8?q?=E7=94=9F=E6=80=81=E9=A1=B9=E7=9B=AE?=
=?UTF-8?q?=E6=96=B0=E5=A2=9E=20review=5Fplan-=E5=A4=8D=E4=B9=A0=E6=8F=90?=
=?UTF-8?q?=E9=86=92Web=E7=89=88=EF=BC=88Java=E6=8A=80=E6=9C=AF=E7=BB=83?=
=?UTF-8?q?=E4=B9=A0=E9=A1=B9=E7=9B=AE=EF=BC=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
创作不易,右上角点亮 ⭐️ Star 支持热心的作者吧 ^_^
https://gitee.com/TommyLemon/review_plan
---
README.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/README.md b/README.md
index c1d70c7fe..f668756d4 100644
--- a/README.md
+++ b/README.md
@@ -716,6 +716,8 @@ Issue/问卷 一般解答顺序:贡献者 > 帮助他人的用户 > 提供任
[apijson-builder](https://github.com/yeli19950109/apijson-builder) 简单包装 APIJSON,相比直接构造查询 JSON 更好记,ts 编写,调整了一些参数和使用方式
[lanmuc](https://gitee.com/element-admin/lanmuc) 后端低代码生产接口的平台,兼容配置式接口和编写式接口,可做到快速生产接口,上线项目
+
+[review_plan](https://gitee.com/PPXcodeTry/review_plan) 复习提醒Web版(Java技术练习项目)
感谢热心的作者们的贡献,点 ⭐Star 支持下他们吧~
From 8f55a3cef023a155e4bbadabdcea85df9175a059 Mon Sep 17 00:00:00 2001
From: TommyLemon <1184482681@qq.com>
Date: Mon, 11 Nov 2024 00:45:01 +0800
Subject: [PATCH 004/122] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20APIJSON=20+=20Nutz?=
=?UTF-8?q?=20=E6=A1=86=E6=9E=B6=20+=20NutzBoot=20=E7=9A=84=20Demo?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
创作不易,右上角点亮 ⭐️ Star 支持下热心的作者吧 ^_^
https://github.com/vincent109/apijson-nutz
---
README.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/README.md b/README.md
index f668756d4..0d43b0302 100644
--- a/README.md
+++ b/README.md
@@ -718,6 +718,8 @@ Issue/问卷 一般解答顺序:贡献者 > 帮助他人的用户 > 提供任
[lanmuc](https://gitee.com/element-admin/lanmuc) 后端低代码生产接口的平台,兼容配置式接口和编写式接口,可做到快速生产接口,上线项目
[review_plan](https://gitee.com/PPXcodeTry/review_plan) 复习提醒Web版(Java技术练习项目)
+
+[apijson-nutz](https://github.com/vincent109/apijson-nutz) APIJSON + Nutz 框架 + NutzBoot 的 Demo
感谢热心的作者们的贡献,点 ⭐Star 支持下他们吧~
From d9b5405290f0b745d98e57c02eb54a00ca3803a1 Mon Sep 17 00:00:00 2001
From: TommyLemon <1184482681@qq.com>
Date: Mon, 18 Nov 2024 00:41:57 +0800
Subject: [PATCH 005/122] =?UTF-8?q?=F0=9F=8F=86=20Tencent=20Top=206=20Open?=
=?UTF-8?q?=20Source=20Project,=20Achieved=205=20Awards=20Inside=20&=20Out?=
=?UTF-8?q?side=20Tencent=20=F0=9F=9A=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
https://github.com/Tencent/APIJSON/blob/master/README-English.md
---
README-English.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README-English.md b/README-English.md
index 4d4aacb19..9329faf0e 100644
--- a/README-English.md
+++ b/README-English.md
@@ -7,7 +7,7 @@ This source code is licensed under the Apache License Version 2.0
-
🏆 Tencent Top 7 Open Source Project, Achieved 5 Awards Inside & Outside Tencent 🚀 A JSON Transmission Protocol and an ORM Library for providing APIs and Documents without writing any code.
+🏆 Tencent Top 6 Open Source Project, Achieved 5 Awards Inside & Outside Tencent 🚀 A JSON Transmission Protocol and an ORM Library for providing APIs and Documents without writing any code.
中文版
From 1f3b59b5583eb2d0a7739dabfc2ef841525ff2ce Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sun, 24 Nov 2024 23:57:06 +0800
Subject: [PATCH 006/122] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81=20?=
=?UTF-8?q?key[=20=E8=A1=A8=E7=A4=BA=20length(key)=20=E5=92=8C=20key{=20?=
=?UTF-8?q?=E8=A1=A8=E7=A4=BA=20json=5Flength(key)=EF=BC=8C=E5=8F=AF?=
=?UTF-8?q?=E4=B8=8E=20=E4=B8=8E=E6=88=96=E9=9D=9E=E9=80=BB=E8=BE=91?=
=?UTF-8?q?=E7=AC=A6=E3=80=81=E5=85=B6=E5=AE=83=E5=90=84=E7=A7=8D=E5=8A=9F?=
=?UTF-8?q?=E8=83=BD=E7=AC=A6=20=E7=BB=84=E5=90=88=E4=BD=BF=E7=94=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
APIJSONORM/pom.xml | 2 +-
.../src/main/java/apijson/JSONObject.java | 25 +++++++++
APIJSONORM/src/main/java/apijson/Log.java | 2 +-
APIJSONORM/src/main/java/apijson/SQL.java | 7 +++
.../java/apijson/orm/AbstractSQLConfig.java | 51 ++++++++++++++-----
5 files changed, 72 insertions(+), 15 deletions(-)
diff --git a/APIJSONORM/pom.xml b/APIJSONORM/pom.xml
index d466682ca..f668c0d49 100644
--- a/APIJSONORM/pom.xml
+++ b/APIJSONORM/pom.xml
@@ -5,7 +5,7 @@
com.github.Tencent
APIJSON
- 7.0.3
+ 7.0.5
jar
APIJSONORM
diff --git a/APIJSONORM/src/main/java/apijson/JSONObject.java b/APIJSONORM/src/main/java/apijson/JSONObject.java
index 8aa8eac3d..32c5caabb 100755
--- a/APIJSONORM/src/main/java/apijson/JSONObject.java
+++ b/APIJSONORM/src/main/java/apijson/JSONObject.java
@@ -480,6 +480,31 @@ public JSONObject putsEmpty(String key, boolean isEmpty, boolean trim) {
public JSONObject putsLength(String key, String compare) {
return puts(key+"{}", SQL.length(key) + compare);
}
+ /**
+ * @param key
+ * @param compare <=, > ...
+ * @param value 1, 5, 3.14, -99 ...
+ * @return {@link #puts(String, Object)}
+ */
+ public JSONObject putsLength(String key, String compare, Object value) {
+ return puts(key+"["+(StringUtil.isEmpty(compare) || "=".equals(compare) ? "" : ("!=".equals(compare) ? "!" : compare)), value);
+ }
+ /**
+ * @param key
+ * @param compare <=0, >5 ...
+ * @return {@link #puts(String, Object)}
+ */
+ public JSONObject putsJSONLength(String key, String compare) {
+ return puts(key+"{}", SQL.json_length(key) + compare);
+ }
+ /**
+ * @param key
+ * @param compare <=0, >5 ...
+ * @return {@link #puts(String, Object)}
+ */
+ public JSONObject putsJSONLength(String key, String compare, Object value) {
+ return puts(key + "{" + (StringUtil.isEmpty(compare) || "=".equals(compare) ? "" : ("!=".equals(compare) ? "!" : compare)), value);
+ }
/**设置搜索
* type = SEARCH_TYPE_CONTAIN_FULL
diff --git a/APIJSONORM/src/main/java/apijson/Log.java b/APIJSONORM/src/main/java/apijson/Log.java
index 662dc912c..7252eb5a7 100755
--- a/APIJSONORM/src/main/java/apijson/Log.java
+++ b/APIJSONORM/src/main/java/apijson/Log.java
@@ -14,7 +14,7 @@ public class Log {
public static boolean DEBUG = true;
- public static final String VERSION = "7.0.3";
+ public static final String VERSION = "7.0.5";
public static final String KEY_SYSTEM_INFO_DIVIDER = "\n---|-----APIJSON SYSTEM INFO-----|---\n";
public static final String OS_NAME;
diff --git a/APIJSONORM/src/main/java/apijson/SQL.java b/APIJSONORM/src/main/java/apijson/SQL.java
index 391d5db48..6cec79bd2 100755
--- a/APIJSONORM/src/main/java/apijson/SQL.java
+++ b/APIJSONORM/src/main/java/apijson/SQL.java
@@ -116,6 +116,13 @@ public static String lengthCompare(String s, String compare) {
public static String length(String s) {
return "length(" + s + ")";
}
+ /**
+ * @param s 因为POWER(x,y)等函数含有不只一个key,所以需要客户端添加进去,服务端检测到条件中有'('和')'时就不转换,直接当SQL语句查询
+ * @return "json_length(" + s + ")"
+ */
+ public static String json_length(String s) {
+ return "json_length(" + s + ")";
+ }
/**
* @param s 因为POWER(x,y)等函数含有不只一个key,所以需要客户端添加进去,服务端检测到条件中有'('和')'时就不转换,直接当SQL语句查询
* @return "char_length(" + s + ")"
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
index bcb1af598..4c82ea30e 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
@@ -3585,7 +3585,9 @@ public String getCompareString(String key, String column, Object value, String t
if (value != null && JSON.isBooleanOrNumberOrString(value) == false && value instanceof Subquery == false) {
throw new IllegalArgumentException(key + ":value 中 value 不合法!比较运算 [>, <, >=, <=] 只支持 [Boolean, Number, String] 内的类型 !");
}
- if (StringUtil.isName(column) == false) {
+
+ String rc = column.endsWith("[") || column.endsWith("{") ? column.substring(0, column.length() - 1) : column;
+ if ( ! StringUtil.isName(rc)) {
throw new IllegalArgumentException(key + ":value 中 key 不合法!比较运算 [>, <, >=, <=] 不支持 [&, !, |] 中任何逻辑运算符 !");
}
@@ -3594,7 +3596,16 @@ public String getCompareString(String key, String column, Object value, String t
}
public String getKey(String key) {
- if (isTest()) {
+ String lenFun = "";
+ if (key.endsWith("[")) {
+ lenFun = isSQLServer() ? "datalength" : "length";
+ key = key.substring(0, key.length() - 1);
+ }
+ else if (key.endsWith("{")) {
+ lenFun = "json_length";
+ key = key.substring(0, key.length() - 1);
+ }
+ else if (isTest()) {
if (key.contains("'")) { // || key.contains("#") || key.contains("--")) {
throw new IllegalArgumentException("参数 " + key + " 不合法!key 中不允许有单引号 ' !");
}
@@ -3606,13 +3617,18 @@ public String getKey(String key) {
if (expression == null) {
expression = COLUMN_KEY_MAP == null ? null : COLUMN_KEY_MAP.get(key);
}
+
+ String sqlKey;
if (expression == null) {
- return getSQLKey(key);
+ sqlKey = getSQLKey(key);
+ }
+ else {
+ // (name,tag) left(date,4) 等
+ List raw = getRaw();
+ sqlKey = parseSQLExpression(KEY_KEY, expression, raw != null && raw.contains(KEY_KEY), false);
}
- // (name,tag) left(date,4) 等
- List raw = getRaw();
- return parseSQLExpression(KEY_KEY, expression, raw != null && raw.contains(KEY_KEY), false);
+ return lenFun.isEmpty() ? sqlKey : lenFun + "(" + sqlKey + ")";
}
public String getSQLKey(String key) {
String q = getQuote();
@@ -6016,9 +6032,15 @@ else if (key.endsWith("-")) {//缩减,PUT查询时处理
}
}
- //TODO if (key.endsWith("-")) { // 表示 key 和 value 顺序反过来: value LIKE key
+ String len = "";
+ if (key.endsWith("[") || key.endsWith("{")) {
+ len = key.substring(key.length() - 1);
+ key = key.substring(0, key.length() - 1);
+ }
+
+ // TODO if (key.endsWith("-")) { // 表示 key 和 value 顺序反过来: value LIKE key ?
- //不用Logic优化代码,否则 key 可能变为 key| 导致 key=value 变成 key|=value 而出错
+ // 不用Logic优化代码,否则 key 可能变为 key| 导致 key=value 变成 key|=value 而出错
String last = key.isEmpty() ? "" : key.substring(key.length() - 1);
if ("&".equals(last) || "|".equals(last) || "!".equals(last)) {
key = key.substring(0, key.length() - 1);
@@ -6026,18 +6048,21 @@ else if (key.endsWith("-")) {//缩减,PUT查询时处理
last = null;//避免key + StringUtil.getString(last)错误延长
}
- //"User:toUser":User转换"toUser":User, User为查询同名Table得到的JSONObject。交给客户端处理更好
- if (isTableKey) {//不允许在column key中使用Type:key形式
- key = Pair.parseEntry(key, true).getKey();//table以左边为准
+ // "User:toUser":User转换"toUser":User, User为查询同名Table得到的JSONObject。交给客户端处理更好
+ if (isTableKey) { // 不允许在column key中使用Type:key形式
+ key = Pair.parseEntry(key, true).getKey(); // table以左边为准
} else {
- key = Pair.parseEntry(key).getValue();//column以右边为准
+ key = Pair.parseEntry(key).getValue();// column 以右边为准
}
if (verifyName && StringUtil.isName(key.startsWith("@") ? key.substring(1) : key) == false) {
throw new IllegalArgumentException(method + "请求,字符 " + originKey + " 不合法!"
- + " key:value 中的key只能关键词 '@key' 或 'key[逻辑符][条件符]' 或 PUT请求下的 'key+' / 'key-' !");
+ + " key:value 中的 key 只能关键词 '@key' 或 'key[长度符][逻辑符][条件符]' 或 PUT 请求下的 'key+' / 'key-' !"
+ + "长度符 只能为 [ - length 和 { - json_length,逻辑符 只能是 & - 与、| - 或、! - 非 !");
}
+ key += len;
+
if (saveLogic && last != null) {
key = key + last;
}
From d9555eab0babbfff7d5fc48d5c10c58895cd9ec3 Mon Sep 17 00:00:00 2001
From: TommyLemon <1184482681@qq.com>
Date: Sun, 24 Nov 2024 23:59:58 +0800
Subject: [PATCH 007/122] =?UTF-8?q?=E5=90=84=E9=A1=B9=E8=8D=A3=E8=AA=89?=
=?UTF-8?q?=E6=88=90=E5=B0=B1=20(=E8=85=BE=E8=AE=AF=E5=86=85=E5=A4=96=205?=
=?UTF-8?q?=20=E4=B8=AA=E5=A5=96=E9=A1=B9=E3=80=81=E8=85=BE=E8=AE=AF?=
=?UTF-8?q?=E5=BC=80=E6=BA=90=E5=89=8D=E5=85=AD=E3=80=81=E8=85=BE=E8=AE=AF?=
=?UTF-8?q?=E5=90=8E=E7=AB=AF=20Star=20=E7=AC=AC=E4=B8=80=E3=80=81Trending?=
=?UTF-8?q?=20=E6=97=A5=E5=91=A8=E6=9C=88=E6=A6=9C=E5=A4=A7=E6=BB=A1?=
=?UTF-8?q?=E8=B4=AF=20=E7=AD=89)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
https://github.com/Tencent/APIJSON?tab=readme-ov-file#%E4%B8%BA%E4%BB%80%E4%B9%88%E9%80%89%E6%8B%A9-apijson
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 0d43b0302..ea6ffa173 100644
--- a/README.md
+++ b/README.md
@@ -180,7 +180,7 @@ https://github.com/Tencent/APIJSON/wiki
* **开发提速很大** (CRUD 零代码热更新全自动,APIJSONBoot 对比 SSM、SSH 等保守估计可提速 20 倍以上)
* **腾讯官方开源** (使用 GitHub、Gitee、工蜂 等平台的官方账号开源,微信公众号、腾讯云+社区 等官方公告)
* **社区影响力大** (GitHub 17K+ Star 在 400W Java 项目排名前 100,远超 FLAG, BAT 等国内外绝大部分开源项目)
-* **各项荣誉成就** (腾讯内外 5 个奖项、腾讯开源前七、腾讯后端 Star 第一、Trending 日周月榜大满贯 等)
+* **各项荣誉成就** (腾讯内外 5 个奖项、腾讯开源前六、腾讯后端 Star 第一、Trending 日周月榜大满贯 等)
* **多样用户案例** (腾讯内有互娱、音乐、微信、云与智慧,外部有华为、华能、百度、快手、中兴、圆通、传音等)
* **适用场景广泛** (社交聊天、阅读资讯、影音娱乐、办公学习 等各种 App、网站、小程序、公众号 等非金融类项目)
* **周边生态丰富** (Android, iOS, Web 等各种 Demo、继承 JSON 的海量生态、零代码 接口测试 和 单元测试 工具等)
From 067e7b9f5bb1d5bc0794741c0ffb31ca75dfff92 Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Mon, 25 Nov 2024 00:05:11 +0800
Subject: [PATCH 008/122] =?UTF-8?q?=E8=A7=A3=E5=86=B3=20key[=20=E8=A1=A8?=
=?UTF-8?q?=E7=A4=BA=20length(key)=20=E5=92=8C=20key{=20=E8=A1=A8=E7=A4=BA?=
=?UTF-8?q?=20json=5Flength(key)=20=E4=B8=8D=E6=94=AF=E6=8C=81=20=3D=20?=
=?UTF-8?q?=E5=92=8C=20!=3D=20=E6=AF=94=E8=BE=83?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../java/apijson/orm/AbstractSQLConfig.java | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
index 4c82ea30e..4bbd6f578 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
@@ -3571,7 +3571,9 @@ public String getEqualString(String key, String column, Object value, String raw
if (not) {
column = column.substring(0, column.length() - 1);
}
- if (StringUtil.isName(column) == false) {
+
+ String rc = column.endsWith("[") || column.endsWith("{") ? column.substring(0, column.length() - 1) : column;
+ if (StringUtil.isName(rc) == false) {
throw new IllegalArgumentException(key + ":value 中key不合法!不支持 ! 以外的逻辑符 !");
}
@@ -6032,12 +6034,6 @@ else if (key.endsWith("-")) {//缩减,PUT查询时处理
}
}
- String len = "";
- if (key.endsWith("[") || key.endsWith("{")) {
- len = key.substring(key.length() - 1);
- key = key.substring(0, key.length() - 1);
- }
-
// TODO if (key.endsWith("-")) { // 表示 key 和 value 顺序反过来: value LIKE key ?
// 不用Logic优化代码,否则 key 可能变为 key| 导致 key=value 变成 key|=value 而出错
@@ -6045,7 +6041,13 @@ else if (key.endsWith("-")) {//缩减,PUT查询时处理
if ("&".equals(last) || "|".equals(last) || "!".equals(last)) {
key = key.substring(0, key.length() - 1);
} else {
- last = null;//避免key + StringUtil.getString(last)错误延长
+ last = null; // 避免key + StringUtil.getString(last) 错误延长
+ }
+
+ String len = "";
+ if (key.endsWith("[") || key.endsWith("{")) {
+ len = key.substring(key.length() - 1);
+ key = key.substring(0, key.length() - 1);
}
// "User:toUser":User转换"toUser":User, User为查询同名Table得到的JSONObject。交给客户端处理更好
From 95d281da2bfe559bd749960daf8136f14ce03e8b Mon Sep 17 00:00:00 2001
From: TommyLemon <1184482681@qq.com>
Date: Sat, 30 Nov 2024 22:34:51 +0800
Subject: [PATCH 009/122] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=99=BB=E8=AE=B0=20?=
=?UTF-8?q?APIJSON=20+=20NutzBoot(=E5=9F=BA=E4=BA=8E=20Nutz=20=E6=A1=86?=
=?UTF-8?q?=E6=9E=B6)=20=E6=8E=A5=E8=BF=91=E6=88=90=E5=93=81=E7=9A=84=20De?=
=?UTF-8?q?mo?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
创作不易、坚持更难,右上角点亮 ⭐️ Star 支持下热心的作者吧 ^_^
https://github.com/vincent109/apijson-nutz
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index ea6ffa173..810386451 100644
--- a/README.md
+++ b/README.md
@@ -54,6 +54,7 @@ This source code is licensed under the Apache License Version 2.0
+
From 2b6a2a9c6a99053c0aee3a734ca8461be87afbdc Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sun, 8 Dec 2024 22:28:53 +0800
Subject: [PATCH 010/122] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81?=
=?UTF-8?q?=E5=88=86=E9=A1=B5=E9=A1=B5=E7=A0=81=20page=20=E4=BB=8E=201=20?=
=?UTF-8?q?=E5=BC=80=E5=A7=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../src/main/java/apijson/JSONRequest.java | 2 +-
.../main/java/apijson/orm/AbstractParser.java | 34 ++++++++++++++-----
.../src/main/java/apijson/orm/Parser.java | 3 +-
3 files changed, 29 insertions(+), 10 deletions(-)
diff --git a/APIJSONORM/src/main/java/apijson/JSONRequest.java b/APIJSONORM/src/main/java/apijson/JSONRequest.java
index cf64f1875..62d724199 100755
--- a/APIJSONORM/src/main/java/apijson/JSONRequest.java
+++ b/APIJSONORM/src/main/java/apijson/JSONRequest.java
@@ -152,7 +152,7 @@ public JSONRequest setSubqueryRange(String range) {
}
/**set from for Subquery
- * @param range
+ * @param from
* @return
*/
public JSONRequest setSubqueryFrom(String from) {
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
index 4da6aa249..3a3822d25 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
@@ -70,8 +70,12 @@ public abstract class AbstractParser implements Parser, Par
public static boolean IS_PRINT_REQUEST_ENDTIME_LOG = false;
- public static int DEFAULT_QUERY_COUNT = 10;
+ /**
+ * 分页页码是否从 1 开始,默认为从 0 开始
+ */
+ public static boolean IS_START_FROM_1 = false;
public static int MAX_QUERY_PAGE = 100;
+ public static int DEFAULT_QUERY_COUNT = 10;
public static int MAX_QUERY_COUNT = 100;
public static int MAX_UPDATE_COUNT = 10;
public static int MAX_SQL_COUNT = 200;
@@ -79,15 +83,22 @@ public abstract class AbstractParser implements Parser, Par
public static int MAX_ARRAY_COUNT = 5;
public static int MAX_QUERY_DEPTH = 5;
+ public boolean isStartFrom1() {
+ return IS_START_FROM_1;
+ }
@Override
- public int getDefaultQueryCount() {
- return DEFAULT_QUERY_COUNT;
+ public int getMinQueryPage() {
+ return isStartFrom1() ? 1 : 0;
}
@Override
public int getMaxQueryPage() {
return MAX_QUERY_PAGE;
}
@Override
+ public int getDefaultQueryCount() {
+ return DEFAULT_QUERY_COUNT;
+ }
+ @Override
public int getMaxQueryCount() {
return MAX_QUERY_COUNT;
}
@@ -1183,23 +1194,28 @@ public JSONObject onObjectParse(final JSONObject request
if (max < 0) {
max = 0;
}
+ int min = getMinQueryPage();
+
+ page += min;
+ max += min;
JSONObject pagination = new JSONObject(true);
Object explain = rp.get(JSONResponse.KEY_EXPLAIN);
if (explain instanceof JSONObject) {
pagination.put(JSONResponse.KEY_EXPLAIN, explain);
}
+
pagination.put(JSONResponse.KEY_TOTAL, total);
pagination.put(JSONRequest.KEY_COUNT, count);
pagination.put(JSONRequest.KEY_PAGE, page);
pagination.put(JSONResponse.KEY_MAX, max);
pagination.put(JSONResponse.KEY_MORE, page < max);
- pagination.put(JSONResponse.KEY_FIRST, page == 0);
+ pagination.put(JSONResponse.KEY_FIRST, page == min);
pagination.put(JSONResponse.KEY_LAST, page == max);
putQueryResult(pathPrefix + JSONResponse.KEY_INFO, pagination);
- if (total <= count*page) {
+ if (total <= count*(page - min)) {
query = JSONRequest.QUERY_TOTAL;//数量不够了,不再往后查询
}
}
@@ -1285,14 +1301,16 @@ public JSONArray onArrayParse(JSONObject request, String parentPath, String name
query2 = JSONRequest.QUERY_ALL;
break;
default:
- throw new IllegalArgumentException(path + "/" + JSONRequest.KEY_QUERY + ":value 中 value 的值不合法!必须在 [0,1,2] 或 [TABLE, TOTAL, ALL] 内 !");
+ throw new IllegalArgumentException(path + "/" + JSONRequest.KEY_QUERY + ":value 中 value 的值不合法!必须在 [0, 1, 2] 或 [TABLE, TOTAL, ALL] 内 !");
}
}
- int page2 = page == null ? 0 : page;
+ int minPage = getMinQueryPage(); // 兼容各种传 0 或 null/undefined 自动转 0 导致的问题
+ int page2 = page == null || page == 0 ? 0 : page - minPage;
+
int maxPage = getMaxQueryPage();
if (page2 < 0 || page2 > maxPage) {
- throw new IllegalArgumentException(path + "/" + JSONRequest.KEY_PAGE + ":value 中 value 的值不合法!必须在 0-" + maxPage + " 内 !");
+ throw new IllegalArgumentException(path + "/" + JSONRequest.KEY_PAGE + ":value 中 value 的值不合法!必须在 " + minPage + "-" + maxPage + " 内 !");
}
//不用total限制数量了,只用中断机制,total只在query = 1,2的时候才获取
diff --git a/APIJSONORM/src/main/java/apijson/orm/Parser.java b/APIJSONORM/src/main/java/apijson/orm/Parser.java
index 969dff95b..7ed0d1b1c 100755
--- a/APIJSONORM/src/main/java/apijson/orm/Parser.java
+++ b/APIJSONORM/src/main/java/apijson/orm/Parser.java
@@ -83,8 +83,9 @@ JSONObject parseCorrectRequest(RequestMethod method, String tag, int version, St
ObjectParser createObjectParser(JSONObject request, String parentPath, SQLConfig arrayConfig, boolean isSubquery, boolean isTable, boolean isArrayMainTable) throws Exception;
- int getDefaultQueryCount();
+ int getMinQueryPage();
int getMaxQueryPage();
+ int getDefaultQueryCount();
int getMaxQueryCount();
int getMaxUpdateCount();
int getMaxSQLCount();
From f35e89c37a2282cb03abcdb8cf5817968433930a Mon Sep 17 00:00:00 2001
From: TommyLemon <1184482681@qq.com>
Date: Sun, 8 Dec 2024 22:48:52 +0800
Subject: [PATCH 011/122] =?UTF-8?q?=E5=A4=9A=E5=B9=B4=E6=8C=81=E7=BB=AD?=
=?UTF-8?q?=E8=BF=AD=E4=BB=A3=20(=E8=87=AA=202016=20=E5=B9=B4=E8=B5=B7?=
=?UTF-8?q?=E5=B7=B2=E8=BF=9E=E7=BB=AD=E7=BB=B4=E6=8A=A4=208=20=E5=B9=B4?=
=?UTF-8?q?=E5=A4=9A=EF=BC=8C70+=20=E8=B4=A1=E7=8C=AE=E8=80=85=E3=80=8190+?=
=?UTF-8?q?=20=E5=8F=91=E7=89=88=E3=80=813000+=20=E6=8F=90=E4=BA=A4?=
=?UTF-8?q?=EF=BC=8C=E4=B8=8D=E6=96=AD=E6=9B=B4=E6=96=B0=E8=BF=AD=E4=BB=A3?=
=?UTF-8?q?=E4=B8=AD...)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
https://github.com/Tencent/APIJSON#%E4%B8%BA%E4%BB%80%E4%B9%88%E9%80%89%E6%8B%A9-apijson
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 810386451..85c7d267b 100644
--- a/README.md
+++ b/README.md
@@ -192,7 +192,7 @@ https://github.com/Tencent/APIJSON/wiki
* **高质可靠代码** (代码严谨规范,商业分析软件源伞 Pinpoint 代码扫描报告平均每行代码 Bug 率低至 0.15%)
* **兼容各种项目** (协议不限 HTTP,与其它库无冲突,对各类 Web 框架集成友好且提供 SpringBoot, JFinal 的示例)
* **工程轻量小巧** (仅依赖 fastjson,Jar 仅 280KB,Java 文件仅 59 个共 13719 行代码,例如 APIJSONORM 4.3.1)
-* **多年持续迭代** (自 2016 年起已连续维护 7 年多,70+ 贡献者、90+ 发版、3000+ 提交,不断更新迭代中...)
+* **多年持续迭代** (自 2016 年起已连续维护 8 年多,70+ 贡献者、90+ 发版、3000+ 提交,不断更新迭代中...)
**按照一般互联网中小型项目情况可得出以下对比表格:**
From 86be77f6c5b375a7b0af0741b512fe782e1cd9fa Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sun, 8 Dec 2024 22:52:15 +0800
Subject: [PATCH 012/122] =?UTF-8?q?=E5=8D=87=E7=BA=A7=E7=89=88=E6=9C=AC?=
=?UTF-8?q?=E4=B8=BA=207.1.0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
APIJSONORM/pom.xml | 2 +-
APIJSONORM/src/main/java/apijson/Log.java | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/APIJSONORM/pom.xml b/APIJSONORM/pom.xml
index f668c0d49..a0a31fa94 100644
--- a/APIJSONORM/pom.xml
+++ b/APIJSONORM/pom.xml
@@ -5,7 +5,7 @@
com.github.Tencent
APIJSON
- 7.0.5
+ 7.1.0
jar
APIJSONORM
diff --git a/APIJSONORM/src/main/java/apijson/Log.java b/APIJSONORM/src/main/java/apijson/Log.java
index 7252eb5a7..73c913169 100755
--- a/APIJSONORM/src/main/java/apijson/Log.java
+++ b/APIJSONORM/src/main/java/apijson/Log.java
@@ -14,7 +14,7 @@ public class Log {
public static boolean DEBUG = true;
- public static final String VERSION = "7.0.5";
+ public static final String VERSION = "7.1.0";
public static final String KEY_SYSTEM_INFO_DIVIDER = "\n---|-----APIJSON SYSTEM INFO-----|---\n";
public static final String OS_NAME;
From cddf465cb911d844d18cd19f72151a7b3d0189f4 Mon Sep 17 00:00:00 2001
From: TommyLemon <1184482681@qq.com>
Date: Sun, 8 Dec 2024 23:21:51 +0800
Subject: [PATCH 013/122] =?UTF-8?q?=E5=A4=9A=E5=B9=B4=E6=8C=81=E7=BB=AD?=
=?UTF-8?q?=E8=BF=AD=E4=BB=A3=20(=E8=87=AA=202016=20=E5=B9=B4=E8=B5=B7?=
=?UTF-8?q?=E5=B7=B2=E8=BF=9E=E7=BB=AD=E7=BB=B4=E6=8A=A4=208=20=E5=B9=B4?=
=?UTF-8?q?=EF=BC=8C70+=20=E8=B4=A1=E7=8C=AE=E8=80=85=E3=80=81100+=20?=
=?UTF-8?q?=E5=8F=91=E7=89=88=E3=80=813000+=20=E6=8F=90=E4=BA=A4=EF=BC=8C?=
=?UTF-8?q?=E4=B8=8D=E6=96=AD=E6=9B=B4=E6=96=B0=E8=BF=AD=E4=BB=A3=E4=B8=AD?=
=?UTF-8?q?...)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
https://github.com/Tencent/APIJSON?tab=readme-ov-file#%E4%B8%BA%E4%BB%80%E4%B9%88%E9%80%89%E6%8B%A9-apijson
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 85c7d267b..2a2ab91b9 100644
--- a/README.md
+++ b/README.md
@@ -192,7 +192,7 @@ https://github.com/Tencent/APIJSON/wiki
* **高质可靠代码** (代码严谨规范,商业分析软件源伞 Pinpoint 代码扫描报告平均每行代码 Bug 率低至 0.15%)
* **兼容各种项目** (协议不限 HTTP,与其它库无冲突,对各类 Web 框架集成友好且提供 SpringBoot, JFinal 的示例)
* **工程轻量小巧** (仅依赖 fastjson,Jar 仅 280KB,Java 文件仅 59 个共 13719 行代码,例如 APIJSONORM 4.3.1)
-* **多年持续迭代** (自 2016 年起已连续维护 8 年多,70+ 贡献者、90+ 发版、3000+ 提交,不断更新迭代中...)
+* **多年持续迭代** (自 2016 年起已连续维护 8 年,70+ 贡献者、100+ 发版、3000+ 提交,不断更新迭代中...)
**按照一般互联网中小型项目情况可得出以下对比表格:**
From 70f65fe10dca3fa3f865e69d50fbd79e4bca3e27 Mon Sep 17 00:00:00 2001
From: TommyLemon <1184482681@qq.com>
Date: Sun, 15 Dec 2024 23:21:19 +0800
Subject: [PATCH 014/122] =?UTF-8?q?=E8=B4=A1=E7=8C=AE=E8=80=85=E6=96=B0?=
=?UTF-8?q?=E5=A2=9E=20gorm-plus=20=E4=BD=9C=E8=80=85=EF=BC=8C=E6=84=9F?=
=?UTF-8?q?=E8=B0=A2=E7=83=AD=E5=BF=83=E8=B4=A1=E7=8C=AE~?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
https://github.com/Tencent/APIJSON?tab=readme-ov-file#%E8%B4%A1%E7%8C%AE%E8%80%85%E4%BB%AC
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 2a2ab91b9..2c96007d6 100644
--- a/README.md
+++ b/README.md
@@ -360,7 +360,7 @@ https://github.com/Tencent/APIJSON/issues/187
* [上海钰亿环保科技有限公司](#)
### 贡献者们
-主项目 APIJSON 的贡献者们(6 个腾讯工程师、1 个微软工程师、1 个阿里云工程师、1 个字节跳动工程师、1 个网易工程师、1 个 Zoom 工程师、1 个圆通工程师、1 个知乎基础研发架构师、1 个智联招聘工程师、1 个美国加州大学学生、3 个 SUSTech 学生等):
+主项目 APIJSON 的贡献者们(6 个腾讯工程师、1 个微软工程师、1 个阿里云工程师、1 个字节跳动工程师、1 个网易工程师、1 个 Zoom 工程师、1 个圆通工程师、1 个知乎基础研发架构师、1 个智联招聘工程师、gorm-plus 作者、1 个美国加州大学学生、3 个 SUSTech 学生等):
https://github.com/Tencent/APIJSON/blob/master/CONTRIBUTING.md
Date: Tue, 17 Dec 2024 09:13:55 +0800
Subject: [PATCH 015/122] =?UTF-8?q?commit=20update=20join=E6=94=AF?=
=?UTF-8?q?=E6=8C=81@cast=E5=AD=97=E6=AE=B5=E7=B1=BB=E5=9E=8B=E8=BD=AC?=
=?UTF-8?q?=E6=8D=A2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../main/java/apijson/orm/AbstractSQLConfig.java | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
index 4bbd6f578..c7539f613 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
@@ -4847,8 +4847,20 @@ protected String concatJoinOn(@NotNull String sql, @NotNull String quote, @NotNu
String rt = on.getRelateType();
if (StringUtil.isEmpty(rt, false)) {
- sql += (first ? ON : AND) + quote + jt + quote + "." + quote + on.getKey() + quote + (isNot ? " != " : " = ")
- + quote + getSQLTableWithAlias(on.getTargetTable(), on.getTargetAlias()) + quote + "." + quote + on.getTargetKey() + quote;
+ //解决join不支持@cast问题
+ Map castMap = j.getJoinConfig().getCast();
+ if (castMap.isEmpty()) {
+ sql += (first ? ON : AND) + quote + jt + quote + "." + quote + on.getKey() + quote + (isNot ? " != " : " = ")
+ + quote + on.getTargetTable() + quote + "." + quote + on.getTargetKey() + quote;
+ } else {
+ String leftTableRelationSql = quote + jt + quote + "." + quote + on.getKey() + quote;
+ Object castValueType = castMap.get(on.getOriginKey());
+ if (castValueType != null) {
+ leftTableRelationSql = "CAST(" + leftTableRelationSql + " AS " + castValueType + ")";
+ }
+ sql += (first ? ON : AND) + leftTableRelationSql + (isNot ? " != " : " = ")
+ + quote + on.getTargetTable() + quote + "." + quote + on.getTargetKey() + quote;
+ }
}
else {
onJoinComplexRelation(sql, quote, j, jt, onList, on);
From 1f2d304cb62c8295ccaed308a7ed3582072d0f3d Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sun, 22 Dec 2024 20:17:51 +0800
Subject: [PATCH 016/122] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81=20?=
=?UTF-8?q?Apache/IoTDB=20-=20=E4=B8=80=E4=BD=93=E5=8C=96=E6=94=B6?=
=?UTF-8?q?=E9=9B=86=E3=80=81=E5=AD=98=E5=82=A8=E3=80=81=E7=AE=A1=E7=90=86?=
=?UTF-8?q?=E4=B8=8E=E5=88=86=E6=9E=90=E7=89=A9=E8=81=94=E7=BD=91=E6=97=B6?=
=?UTF-8?q?=E5=BA=8F=E6=95=B0=E6=8D=AE=E7=9A=84=E8=BD=AF=E4=BB=B6=E7=B3=BB?=
=?UTF-8?q?=E7=BB=9F=EF=BC=9B=E5=AE=8C=E5=96=84=20AI=20=E5=90=91=E9=87=8F?=
=?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93=20Milvus=20=E7=9A=84=20SQL=20?=
=?UTF-8?q?=E5=87=BD=E6=95=B0=E6=B3=A8=E5=86=8C=EF=BC=9B=E5=8D=87=E7=BA=A7?=
=?UTF-8?q?=E7=89=88=E6=9C=AC=E6=94=AF=207.2.0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
APIJSONORM/pom.xml | 2 +-
APIJSONORM/src/main/java/apijson/Log.java | 2 +-
.../java/apijson/orm/AbstractSQLConfig.java | 29 +++++++++++++++++--
.../src/main/java/apijson/orm/SQLConfig.java | 6 +++-
4 files changed, 33 insertions(+), 6 deletions(-)
diff --git a/APIJSONORM/pom.xml b/APIJSONORM/pom.xml
index a0a31fa94..ada599ad7 100644
--- a/APIJSONORM/pom.xml
+++ b/APIJSONORM/pom.xml
@@ -5,7 +5,7 @@
com.github.Tencent
APIJSON
- 7.1.0
+ 7.2.0
jar
APIJSONORM
diff --git a/APIJSONORM/src/main/java/apijson/Log.java b/APIJSONORM/src/main/java/apijson/Log.java
index 73c913169..2b6e28d93 100755
--- a/APIJSONORM/src/main/java/apijson/Log.java
+++ b/APIJSONORM/src/main/java/apijson/Log.java
@@ -14,7 +14,7 @@ public class Log {
public static boolean DEBUG = true;
- public static final String VERSION = "7.1.0";
+ public static final String VERSION = "7.2.0";
public static final String KEY_SYSTEM_INFO_DIVIDER = "\n---|-----APIJSON SYSTEM INFO-----|---\n";
public static final String OS_NAME;
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
index 4bbd6f578..11192f073 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
@@ -216,6 +216,7 @@ public abstract class AbstractSQLConfig implements SQLConfig implements SQLConfig(); // 保证顺序,避免配置冲突等意外情况
RAW_MAP.put("+", "");
@@ -820,6 +822,18 @@ public abstract class AbstractSQLConfig implements SQLConfig parser;
@@ -1011,7 +1025,7 @@ public AbstractSQLConfig setMethod(RequestMethod method) {
}
@Override
public boolean isPrepared() {
- return prepared;
+ return prepared && ! isMongoDB(); // MongoDB JDBC 还不支持预编译;
}
@Override
public AbstractSQLConfig setPrepared(boolean prepared) {
@@ -1269,6 +1283,15 @@ public static boolean isTDengine(String db) {
return DATABASE_TDENGINE.equals(db);
}
+
+ public boolean isIoTDB() {
+ return isIoTDB(getDatabase());
+ }
+ public static boolean isIoTDB(String db) {
+ return DATABASE_IOTDB.equals(db);
+ }
+
+
@Override
public boolean isRedis() {
return isRedis(getSQLDatabase());
@@ -1310,8 +1333,8 @@ public static boolean isSQLite(String db) {
}
@Override
- public String getQuote() {
- if(isElasticsearch()) {
+ public String getQuote() { // MongoDB 同时支持 `tbl` 反引号 和 "col" 双引号
+ if(isElasticsearch() || isIoTDB()) {
return "";
}
return isMySQL() || isMariaDB() || isTiDB() || isClickHouse() || isTDengine() || isMilvus() ? "`" : "\"";
diff --git a/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
index 7ed6cf663..08ba86131 100755
--- a/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
@@ -37,12 +37,15 @@ public interface SQLConfig {
String DATABASE_MILVUS = "MILVUS"; // https://milvus.io
String DATABASE_INFLUXDB = "INFLUXDB"; // https://www.influxdata.com/products/influxdb-overview
String DATABASE_TDENGINE = "TDENGINE"; // https://tdengine.com
+ String DATABASE_IOTDB = "IOTDB"; // https://iotdb.apache.org/zh/UserGuide/latest/API/Programming-JDBC.html
+
String DATABASE_REDIS = "REDIS"; // https://redisql.com
String DATABASE_MONGODB = "MONGODB"; // https://www.mongodb.com/docs/atlas/data-federation/query/query-with-sql
String DATABASE_KAFKA = "KAFKA"; // https://github.com/APIJSON/APIJSON-Demo/tree/master/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-Kafka
- String DATABASE_MQ = "MQ"; //
String DATABASE_SQLITE = "SQLITE"; // https://www.sqlite.org
+ String DATABASE_MQ = "MQ"; //
+
String SCHEMA_INFORMATION = "information_schema"; //MySQL, PostgreSQL, SQL Server 都有的系统模式
String SCHEMA_SYS = "sys"; //SQL Server 系统模式
String TABLE_SCHEMA = "table_schema";
@@ -88,6 +91,7 @@ public interface SQLConfig {
boolean isMilvus();
boolean isInfluxDB();
boolean isTDengine();
+ boolean isIoTDB();
boolean isRedis();
boolean isMongoDB();
boolean isKafka();
From 99b910a769317978ea73a210950e11b1afa1f947 Mon Sep 17 00:00:00 2001
From: TommyLemon <1184482681@qq.com>
Date: Sun, 22 Dec 2024 20:26:36 +0800
Subject: [PATCH 017/122] =?UTF-8?q?=E8=A7=A3=E5=86=B3=20JOIN=20ON=20?=
=?UTF-8?q?=E4=B8=8D=E6=94=AF=E6=8C=81=20@cast=EF=BC=8C=E6=84=9F=E8=B0=A2?=
=?UTF-8?q?=20lindaifeng=20=E7=9A=84=E8=B4=A1=E7=8C=AE~=20#785?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
https://github.com/Tencent/APIJSON/pull/785
---
.../src/main/java/apijson/orm/AbstractSQLConfig.java | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
index c7539f613..c492dd420 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
@@ -4847,9 +4847,10 @@ protected String concatJoinOn(@NotNull String sql, @NotNull String quote, @NotNu
String rt = on.getRelateType();
if (StringUtil.isEmpty(rt, false)) {
- //解决join不支持@cast问题
- Map castMap = j.getJoinConfig().getCast();
- if (castMap.isEmpty()) {
+ // 解决 JOIN ON 不支持 @cast 问题
+ SQLConfig jc = j.getJoinConfig();
+ Map castMap = jc == null ? null : jc.getCast();
+ if (castMap == null || castMap.isEmpty()) {
sql += (first ? ON : AND) + quote + jt + quote + "." + quote + on.getKey() + quote + (isNot ? " != " : " = ")
+ quote + on.getTargetTable() + quote + "." + quote + on.getTargetKey() + quote;
} else {
From 0cae115bef0ce7611b435240a3bf1ba326ac5d51 Mon Sep 17 00:00:00 2001
From: TommyLemon <1184482681@qq.com>
Date: Sun, 29 Dec 2024 21:45:15 +0800
Subject: [PATCH 018/122] =?UTF-8?q?=E8=9A=82=E8=9A=81=E9=9B=86=E5=9B=A2?=
=?UTF-8?q?=E6=BA=90=E4=BC=9E=E6=89=AB=E6=8F=8F=20APIJSON=20=E8=B4=A1?=
=?UTF-8?q?=E7=8C=AE=E4=BA=86=20issue=EF=BC=8C=E6=84=9F=E8=B0=A2=E8=B4=A1?=
=?UTF-8?q?=E7=8C=AE~?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
https://www.sourcebrella.com
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 2c96007d6..632fdc148 100644
--- a/README.md
+++ b/README.md
@@ -474,10 +474,10 @@ https://search.gitee.com/?skin=rec&type=repository&q=apijson&sort=stars_count
-还有为 APIJSON 扫描代码贡献 Issue 的 [奇安信代码卫士](https://github.com/QiAnXinCodeSafe) 和 [源伞科技](https://www.sourcebrella.com)
+还有为 APIJSON 扫描代码贡献 Issue 的 [蚂蚁集团源伞](https://www.sourcebrella.com) 和 [奇安信代码卫士](https://github.com/QiAnXinCodeSafe)
From 989499c6549e2d4860a43db0bf872a66e325c4a8 Mon Sep 17 00:00:00 2001
From: TommyLemon <1184482681@qq.com>
Date: Sun, 29 Dec 2024 22:20:46 +0800
Subject: [PATCH 019/122] =?UTF-8?q?=E8=9A=82=E8=9A=81=E9=9B=86=E5=9B=A2?=
=?UTF-8?q?=E6=BA=90=E4=BC=9E=E6=89=AB=E6=8F=8F=20APIJSON=20=E8=B4=A1?=
=?UTF-8?q?=E7=8C=AE=E4=BA=86=20issue=EF=BC=8C=E6=84=9F=E8=B0=A2=E8=B4=A1?=
=?UTF-8?q?=E7=8C=AE~?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
https://www.sourcebrella.com
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 632fdc148..34b06f07a 100644
--- a/README.md
+++ b/README.md
@@ -476,7 +476,7 @@ https://search.gitee.com/?skin=rec&type=repository&q=apijson&sort=stars_count
-
+
From 07b4acee9c6a2aad2b5b4ea83cf48e0e418c0b81 Mon Sep 17 00:00:00 2001
From: TommyLemon <1184482681@qq.com>
Date: Sun, 5 Jan 2025 23:13:18 +0800
Subject: [PATCH 020/122] =?UTF-8?q?=E6=96=87=E7=AB=A0=E6=96=B0=E5=A2=9E=20?=
=?UTF-8?q?wend=E7=9C=8B=E6=BA=90=E7=A0=81-ORM-APIJSON=EF=BC=8C=E6=84=9F?=
=?UTF-8?q?=E8=B0=A2=E5=8D=9A=E4=B8=BB=E7=9A=84=E8=B4=A1=E7=8C=AE~?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
点赞、收藏 支持下热心的作者吧 ^_^
https://itwend.blog.csdn.net/article/details/143980281
---
README.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 34b06f07a..41c0af399 100644
--- a/README.md
+++ b/README.md
@@ -610,7 +610,8 @@ Issue/问卷 一般解答顺序:贡献者 > 帮助他人的用户 > 提供任
[APIJSON语法使用,超详细](https://blog.csdn.net/qq_36565607/article/details/139167040)
-
+[wend看源码-ORM-APIJSON](https://itwend.blog.csdn.net/article/details/143980281)
+
### 生态项目
[APIJSON-Demo](https://github.com/APIJSON/APIJSON-Demo) APIJSON 各种语言、各种框架 的 使用示例项目、上手文档、测试数据 SQL 文件 等
From 138205c44f708a943aa10ac849d4c9376175cb0d Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sat, 11 Jan 2025 00:38:08 +0800
Subject: [PATCH 021/122] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81=20?=
=?UTF-8?q?DuckDB-=E9=AB=98=E6=80=A7=E8=83=BD=E5=A4=9A=E6=96=87=E4=BB=B6?=
=?UTF-8?q?=E6=A0=BC=E5=BC=8F=20OLAP=20=E6=95=B0=E6=8D=AE=E5=BA=93?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../src/main/java/apijson/orm/AbstractSQLConfig.java | 9 +++++++++
APIJSONORM/src/main/java/apijson/orm/SQLConfig.java | 2 ++
2 files changed, 11 insertions(+)
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
index 821cfe112..4f098e069 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
@@ -224,6 +224,7 @@ public abstract class AbstractSQLConfig implements SQLConfig(); // 保证顺序,避免配置冲突等意外情况
@@ -1332,6 +1333,14 @@ public static boolean isSQLite(String db) {
return DATABASE_SQLITE.equals(db);
}
+ @Override
+ public boolean isDuckDB() {
+ return isDuckDB(getSQLDatabase());
+ }
+ public static boolean isDuckDB(String db) {
+ return DATABASE_DUCKDB.equals(db);
+ }
+
@Override
public String getQuote() { // MongoDB 同时支持 `tbl` 反引号 和 "col" 双引号
if(isElasticsearch() || isIoTDB()) {
diff --git a/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
index 08ba86131..1f8519383 100755
--- a/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
@@ -43,6 +43,7 @@ public interface SQLConfig {
String DATABASE_MONGODB = "MONGODB"; // https://www.mongodb.com/docs/atlas/data-federation/query/query-with-sql
String DATABASE_KAFKA = "KAFKA"; // https://github.com/APIJSON/APIJSON-Demo/tree/master/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-Kafka
String DATABASE_SQLITE = "SQLITE"; // https://www.sqlite.org
+ String DATABASE_DUCKDB = "DUCKDB"; // https://duckdb.org
String DATABASE_MQ = "MQ"; //
@@ -97,6 +98,7 @@ public interface SQLConfig {
boolean isKafka();
boolean isMQ();
boolean isSQLite();
+ boolean isDuckDB();
// 暂时只兼容以上几种
From 2cb277e12b71908ccd309de06d8c48d33981f2fe Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sat, 11 Jan 2025 00:44:43 +0800
Subject: [PATCH 022/122] =?UTF-8?q?=E5=8D=87=E7=BA=A7=E7=89=88=E6=9C=AC?=
=?UTF-8?q?=E8=87=B3=207.3.0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
APIJSONORM/pom.xml | 2 +-
APIJSONORM/src/main/java/apijson/Log.java | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/APIJSONORM/pom.xml b/APIJSONORM/pom.xml
index ada599ad7..b40f66e5e 100644
--- a/APIJSONORM/pom.xml
+++ b/APIJSONORM/pom.xml
@@ -5,7 +5,7 @@
com.github.Tencent
APIJSON
- 7.2.0
+ 7.3.0
jar
APIJSONORM
diff --git a/APIJSONORM/src/main/java/apijson/Log.java b/APIJSONORM/src/main/java/apijson/Log.java
index 2b6e28d93..3bfe4af98 100755
--- a/APIJSONORM/src/main/java/apijson/Log.java
+++ b/APIJSONORM/src/main/java/apijson/Log.java
@@ -14,7 +14,7 @@ public class Log {
public static boolean DEBUG = true;
- public static final String VERSION = "7.2.0";
+ public static final String VERSION = "7.3.0";
public static final String KEY_SYSTEM_INFO_DIVIDER = "\n---|-----APIJSON SYSTEM INFO-----|---\n";
public static final String OS_NAME;
From 3461521d3a438cd0818c77fcc46097624427bae6 Mon Sep 17 00:00:00 2001
From: TommyLemon <1184482681@qq.com>
Date: Mon, 13 Jan 2025 00:06:13 +0800
Subject: [PATCH 023/122] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=B8=A5=E8=B0=A8?=
=?UTF-8?q?=E8=A7=84=E8=8C=83=EF=BC=8C=E8=9A=82=E8=9A=81=E9=9B=86=E5=9B=A2?=
=?UTF-8?q?=E6=BA=90=E4=BC=9E=20Pinpoint=20=E4=BB=A3=E7=A0=81=E6=89=AB?=
=?UTF-8?q?=E6=8F=8F=E5=88=86=E6=9E=90=E6=8A=A5=E5=91=8A=E5=B9=B3=E5=9D=87?=
=?UTF-8?q?=E6=AF=8F=E8=A1=8C=E4=BB=A3=E7=A0=81=20Bug=20=E7=8E=87=E4=BD=8E?=
=?UTF-8?q?=E8=87=B3=200.15%?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
https://github.com/Tencent/APIJSON/blob/master/README.md#%E4%B8%BA%E4%BB%80%E4%B9%88%E9%80%89%E6%8B%A9-apijson
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 41c0af399..5ccf60161 100644
--- a/README.md
+++ b/README.md
@@ -189,10 +189,10 @@ https://github.com/Tencent/APIJSON/wiki
* **功能丰富强大** (增删改查、分页排序、分组聚合、各种条件、各种 JOIN、各种子查询、跨库连表 等零代码实现)
* **使用安全简单** (自动增删改查、自动生成文档、自动管理版本、自动控制权限、自动校验参数、自动防 SQL 注入)
* **灵活定制业务** (在后端编写 远程函数,可以拿到 session、version、当前 JSON 对象 等,然后自定义处理)
-* **高质可靠代码** (代码严谨规范,商业分析软件源伞 Pinpoint 代码扫描报告平均每行代码 Bug 率低至 0.15%)
+* **高质可靠代码** (代码严谨规范,蚂蚁集团源伞 Pinpoint 代码扫描分析报告平均每行代码 Bug 率低至 0.15%)
* **兼容各种项目** (协议不限 HTTP,与其它库无冲突,对各类 Web 框架集成友好且提供 SpringBoot, JFinal 的示例)
* **工程轻量小巧** (仅依赖 fastjson,Jar 仅 280KB,Java 文件仅 59 个共 13719 行代码,例如 APIJSONORM 4.3.1)
-* **多年持续迭代** (自 2016 年起已连续维护 8 年,70+ 贡献者、100+ 发版、3000+ 提交,不断更新迭代中...)
+* **多年持续迭代** (自 2016 年起已连续维护 8 年多,70+ 贡献者、100+ 发版、3000+ 提交,不断更新迭代中...)
**按照一般互联网中小型项目情况可得出以下对比表格:**
From 5b2c1ed83996e3db7e21d0e683d48daac6659afc Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Thu, 30 Jan 2025 11:20:12 +0800
Subject: [PATCH 024/122] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81=20?=
=?UTF-8?q?SurrealDB-=E5=85=B3=E7=B3=BB=E3=80=81=E6=97=B6=E5=BA=8F?=
=?UTF-8?q?=E3=80=81=E5=9B=BE=E3=80=81=E9=94=AE=E5=80=BC=E3=80=81=E6=90=9C?=
=?UTF-8?q?=E7=B4=A2=E3=80=81=E6=96=87=E6=A1=A3=20=E7=AD=89=E5=A4=9A?=
=?UTF-8?q?=E6=A8=A1=E5=9E=8B=E6=95=B0=E6=8D=AE=E5=BA=93?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
https://github.com/APIJSON/apijson-surrealdb
---
APIJSONORM/pom.xml | 2 +-
.../src/main/java/apijson/JSONObject.java | 27 ++++---
APIJSONORM/src/main/java/apijson/Log.java | 2 +-
.../java/apijson/orm/AbstractSQLConfig.java | 75 ++++++++++++-------
.../src/main/java/apijson/orm/SQLConfig.java | 6 ++
5 files changed, 72 insertions(+), 40 deletions(-)
diff --git a/APIJSONORM/pom.xml b/APIJSONORM/pom.xml
index b40f66e5e..b301c6d95 100644
--- a/APIJSONORM/pom.xml
+++ b/APIJSONORM/pom.xml
@@ -5,7 +5,7 @@
com.github.Tencent
APIJSON
- 7.3.0
+ 7.4.0
jar
APIJSONORM
diff --git a/APIJSONORM/src/main/java/apijson/JSONObject.java b/APIJSONORM/src/main/java/apijson/JSONObject.java
index 32c5caabb..68fb30c57 100755
--- a/APIJSONORM/src/main/java/apijson/JSONObject.java
+++ b/APIJSONORM/src/main/java/apijson/JSONObject.java
@@ -139,8 +139,9 @@ public JSONObject setUserIdIn(List list) {
public static final String KEY_ROLE = "@role"; //角色,拥有对某些数据的某些操作的权限
public static final String KEY_DATABASE = "@database"; //数据库类型,默认为MySQL
- public static final String KEY_SCHEMA = "@schema"; //数据库,Table在非默认schema内时需要声明
public static final String KEY_DATASOURCE = "@datasource"; //数据源
+ public static final String KEY_NAMESPACE = "@namespace"; //命名空间,Table在非默认namespace内时需要声明
+ public static final String KEY_SCHEMA = "@schema"; //数据库,Table在非默认schema内时需要声明
public static final String KEY_EXPLAIN = "@explain"; //分析 true/false
public static final String KEY_CACHE = "@cache"; //缓存 RAM/ROM/ALL
public static final String KEY_COLUMN = "@column"; //查询的Table字段或SQL函数
@@ -169,8 +170,9 @@ public JSONObject setUserIdIn(List list) {
TABLE_KEY_LIST = new ArrayList();
TABLE_KEY_LIST.add(KEY_ROLE);
TABLE_KEY_LIST.add(KEY_DATABASE);
- TABLE_KEY_LIST.add(KEY_SCHEMA);
TABLE_KEY_LIST.add(KEY_DATASOURCE);
+ TABLE_KEY_LIST.add(KEY_NAMESPACE);
+ TABLE_KEY_LIST.add(KEY_SCHEMA);
TABLE_KEY_LIST.add(KEY_EXPLAIN);
TABLE_KEY_LIST.add(KEY_CACHE);
TABLE_KEY_LIST.add(KEY_COLUMN);
@@ -253,13 +255,6 @@ public JSONObject setRole(String role) {
public JSONObject setDatabase(String database) {
return puts(KEY_DATABASE, database);
}
- /**set schema where table was puts
- * @param schema
- * @return this
- */
- public JSONObject setSchema(String schema) {
- return puts(KEY_SCHEMA, schema);
- }
/**set datasource where table was puts
* @param datasource
* @return this
@@ -267,6 +262,20 @@ public JSONObject setSchema(String schema) {
public JSONObject setDatasource(String datasource) {
return puts(KEY_DATASOURCE, datasource);
}
+ /**set namespace where table was puts
+ * @param namespace
+ * @return this
+ */
+ public JSONObject setNamespace(String namespace) {
+ return puts(KEY_NAMESPACE, namespace);
+ }
+ /**set schema where table was puts
+ * @param schema
+ * @return this
+ */
+ public JSONObject setSchema(String schema) {
+ return puts(KEY_SCHEMA, schema);
+ }
/**set if return explain informations
* @param explain
* @return
diff --git a/APIJSONORM/src/main/java/apijson/Log.java b/APIJSONORM/src/main/java/apijson/Log.java
index 3bfe4af98..3484638cb 100755
--- a/APIJSONORM/src/main/java/apijson/Log.java
+++ b/APIJSONORM/src/main/java/apijson/Log.java
@@ -14,7 +14,7 @@ public class Log {
public static boolean DEBUG = true;
- public static final String VERSION = "7.3.0";
+ public static final String VERSION = "7.4.0";
public static final String KEY_SYSTEM_INFO_DIVIDER = "\n---|-----APIJSON SYSTEM INFO-----|---\n";
public static final String OS_NAME;
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
index 4f098e069..51b76e193 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
@@ -47,31 +47,11 @@
import apijson.orm.model.Table;
import apijson.orm.model.TestRecord;
-import static apijson.JSONObject.KEY_CACHE;
-import static apijson.JSONObject.KEY_CAST;
-import static apijson.JSONObject.KEY_COLUMN;
-import static apijson.JSONObject.KEY_COMBINE;
-import static apijson.JSONObject.KEY_DATABASE;
-import static apijson.JSONObject.KEY_DATASOURCE;
-import static apijson.JSONObject.KEY_EXPLAIN;
-import static apijson.JSONObject.KEY_FROM;
-import static apijson.JSONObject.KEY_GROUP;
-import static apijson.JSONObject.KEY_HAVING;
-import static apijson.JSONObject.KEY_HAVING_AND;
-import static apijson.JSONObject.KEY_ID;
-import static apijson.JSONObject.KEY_JSON;
-import static apijson.JSONObject.KEY_NULL;
-import static apijson.JSONObject.KEY_ORDER;
-import static apijson.JSONObject.KEY_KEY;
-import static apijson.JSONObject.KEY_RAW;
-import static apijson.JSONObject.KEY_ROLE;
-import static apijson.JSONObject.KEY_SCHEMA;
-import static apijson.JSONObject.KEY_USER_ID;
+import static apijson.JSONObject.*;
import static apijson.RequestMethod.DELETE;
import static apijson.RequestMethod.GET;
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;
@@ -122,6 +102,7 @@ public abstract class AbstractSQLConfig implements SQLConfig implements SQLConfig(); // 保证顺序,避免配置冲突等意外情况
@@ -300,7 +282,6 @@ public abstract class AbstractSQLConfig implements SQLConfig implements SQLConfig setNamespace(String namespace) {
+ this.namespace = namespace;
+ return this;
+ }
+
@Override
public String getSchema() {
return schema;
@@ -1374,7 +1379,7 @@ public String getSQLSchema() {
return SCHEMA_SYS; //SQL Server 在 sys 中的属性比 information_schema 中的要全,能拿到注释
}
if (AllTable.TAG.equals(table) || AllColumn.TAG.equals(table)
- || AllTableComment.TAG.equals(table) || AllTableComment.TAG.equals(table)) {
+ || AllTableComment.TAG.equals(table) || AllColumnComment.TAG.equals(table)) {
return ""; //Oracle, Dameng 的 all_tables, dba_tables 和 all_tab_columns, dba_columns 表好像不属于任何 Schema
}
@@ -1384,6 +1389,7 @@ public String getSQLSchema() {
}
return sch == null ? DEFAULT_SCHEMA : sch; // 最后代码默认兜底配置
}
+
@Override
public AbstractSQLConfig setSchema(String schema) {
if (schema != null) {
@@ -2696,6 +2702,14 @@ public String getLimitString() {
int offset = getOffset(getPage(), count);
return " LIMIT " + offset + ", " + count; // 目前 moql-transx 的限制
+ } else if (isSurrealDB()) {
+ if (count == 0) {
+ Parser parser = getParser();
+ count = parser == null ? AbstractParser.MAX_QUERY_COUNT : parser.getMaxQueryCount();
+ }
+
+ int offset = getOffset(getPage(), count);
+ return " START " + offset + " LIMIT " + count;
}
if (count <= 0 || RequestMethod.isHeadMethod(getMethod(), true)) { // TODO HEAD 真的不需要 LIMIT ?
@@ -5116,15 +5130,17 @@ public static SQLConfig newSQLConfig(RequestMethod method,
+ StringUtil.getString(DATABASE_LIST.toArray()) + "] 中的一种!");
}
- String schema = request.getString(KEY_SCHEMA);
String datasource = request.getString(KEY_DATASOURCE);
+ String namespace = request.getString(KEY_NAMESPACE);
+ String schema = request.getString(KEY_SCHEMA);
SQLConfig config = callback.getSQLConfig(method, database, schema, datasource, table);
config.setAlias(alias);
config.setDatabase(database); // 不删,后面表对象还要用的,必须放在 parseJoin 前
- config.setSchema(schema); // 不删,后面表对象还要用的
config.setDatasource(datasource); // 不删,后面表对象还要用的
+ config.setNamespace(namespace); // 不删,后面表对象还要用的
+ config.setSchema(schema); // 不删,后面表对象还要用的
if (isProcedure) {
return config;
@@ -5282,8 +5298,9 @@ else if (userId instanceof Subquery) {}
request.remove(KEY_ROLE);
request.remove(KEY_EXPLAIN);
request.remove(KEY_CACHE);
- request.remove(KEY_DATASOURCE);
request.remove(KEY_DATABASE);
+ request.remove(KEY_DATASOURCE);
+ request.remove(KEY_NAMESPACE);
request.remove(KEY_SCHEMA);
request.remove(KEY_FROM);
request.remove(KEY_COLUMN);
diff --git a/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
index 1f8519383..8e5755f89 100755
--- a/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
@@ -44,6 +44,7 @@ public interface SQLConfig {
String DATABASE_KAFKA = "KAFKA"; // https://github.com/APIJSON/APIJSON-Demo/tree/master/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-Kafka
String DATABASE_SQLITE = "SQLITE"; // https://www.sqlite.org
String DATABASE_DUCKDB = "DUCKDB"; // https://duckdb.org
+ String DATABASE_SURREALDB = "SURREALDB"; // https://surrealdb.com
String DATABASE_MQ = "MQ"; //
@@ -99,6 +100,7 @@ public interface SQLConfig {
boolean isMQ();
boolean isSQLite();
boolean isDuckDB();
+ boolean isSurrealDB();
// 暂时只兼容以上几种
@@ -229,6 +231,10 @@ default int[] getDBVersionNums() {
String getDatabase();
SQLConfig setDatabase(String database);
+ String getSQLNamespace();
+ String getNamespace();
+ SQLConfig setNamespace(String namespace);
+
String getSQLSchema();
String getSchema();
SQLConfig setSchema(String schema);
From 2f5d947de21664ce77d16c20ec8851cd3d76e1dd Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sat, 1 Feb 2025 20:14:54 +0800
Subject: [PATCH 025/122] =?UTF-8?q?=E8=A7=A3=E5=86=B3=20SQL=20JOIN=20?=
=?UTF-8?q?=E5=9C=A8=E4=B8=80=E5=AF=B9=E5=A4=9A=E6=88=96=E5=A4=9A=E5=AF=B9?=
=?UTF-8?q?=E5=A4=9A=E6=97=B6=E8=BF=94=E5=9B=9E=E5=8D=95=E7=8B=AC=E6=9F=A5?=
=?UTF-8?q?=E8=AF=A2=E7=9A=84=E9=87=8D=E5=A4=8D=E5=89=AF=E8=A1=A8=E6=95=B0?=
=?UTF-8?q?=E6=8D=AE=EF=BC=8C=E8=80=8C=E4=B8=8D=E6=98=AF=20SQL=20=E7=BB=93?=
=?UTF-8?q?=E6=9E=9C=E9=9B=86=E9=87=8C=E7=9A=84=E5=89=AF=E8=A1=A8=E6=95=B0?=
=?UTF-8?q?=E6=8D=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../apijson/orm/AbstractObjectParser.java | 48 ++++++++++++++-----
.../main/java/apijson/orm/AbstractParser.java | 41 +++++++++-------
.../java/apijson/orm/AbstractSQLConfig.java | 4 +-
.../java/apijson/orm/AbstractSQLExecutor.java | 23 +++++++--
.../main/java/apijson/orm/ObjectParser.java | 8 +++-
.../src/main/java/apijson/orm/Parser.java | 4 +-
6 files changed, 91 insertions(+), 37 deletions(-)
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java
index 94e2020d0..8f6494c15 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java
@@ -123,6 +123,18 @@ public AbstractObjectParser setParentPath(String parentPath) {
return this;
}
+ protected JSONObject cache;
+ @Override
+ public JSONObject getCache() {
+ return cache;
+ }
+
+ @Override
+ public AbstractObjectParser setCache(JSONObject cache) {
+ this.cache = cache;
+ return this;
+ }
+
protected int position;
public int getPosition() {
return position;
@@ -243,6 +255,7 @@ public AbstractObjectParser parse(String name, boolean isReuse) throws Exception
int index = 0;
// hasOtherKeyNotFun = false;
+ JSONObject viceItem = null;
for (Entry entry : set) {
if (isBreakParse()) {
@@ -280,7 +293,14 @@ else if (value instanceof JSONObject) { // JSONObject,往下一级提取
childMap.put(key, (JSONObject)value);
}
else { // 直接解析并替换原来的,[]:{} 内必须直接解析,否则会因为丢掉count等属性,并且total@:"/[]/total"必须在[]:{} 后!
- response.put(key, onChildParse(index, key, (JSONObject)value));
+ JSON cache = index <= 0 || type != TYPE_ITEM || viceItem == null ? null : viceItem.getJSONObject(key);
+ JSON result = onChildParse(index, key, (JSONObject) value, cache);
+ if (index <= 0 && type == TYPE_ITEM) {
+ JSONObject mainItem = (JSONObject) result;
+ viceItem = result == null ? null : (JSONObject) mainItem.remove(AbstractSQLExecutor.KEY_VICE_ITEM);
+ }
+
+ response.put(key, result);
index ++;
}
}
@@ -368,7 +388,7 @@ public boolean onParse(@NotNull String key, @NotNull Object value) throws Except
+ JSONRequest.SUBQUERY_RANGE_ALL + ", " + JSONRequest.SUBQUERY_RANGE_ANY + "] 中的一个!");
}
- JSONArray arr = parser.onArrayParse(subquery, path, key, true);
+ JSONArray arr = parser.onArrayParse(subquery, path, key, true, null);
JSONObject obj = arr == null || arr.isEmpty() ? null : arr.getJSONObject(0);
if (obj == null) {
@@ -530,18 +550,19 @@ else if (isTable && key.startsWith("@") && JSONRequest.TABLE_KEY_LIST.contains(k
* @param index
* @param key
* @param value
+ * @param cache
* @return
* @throws Exception
*/
@Override
- public JSON onChildParse(int index, String key, JSONObject value) throws Exception {
+ public JSON onChildParse(int index, String key, JSONObject value, JSON cache) throws Exception {
boolean isFirst = index <= 0;
boolean isMain = isFirst && type == TYPE_ITEM;
JSON child;
boolean isEmpty;
- if (apijson.JSONObject.isArrayKey(key)) {//APIJSON Array
+ if (apijson.JSONObject.isArrayKey(key)) { // APIJSON Array
if (isMain) {
throw new IllegalArgumentException(parentPath + "/" + key + ":{} 不合法!"
+ "数组 []:{} 中第一个 key:{} 必须是主表 TableKey:{} !不能为 arrayKey[]:{} !");
@@ -557,7 +578,7 @@ public JSON onChildParse(int index, String key, JSONObject value) throws Excepti
}
String query = value.getString(KEY_QUERY);
- child = parser.onArrayParse(value, path, key, isSubquery);
+ child = parser.onArrayParse(value, path, key, isSubquery, cache instanceof JSONArray ? (JSONArray) cache : null);
isEmpty = child == null || ((JSONArray) child).isEmpty();
if ("2".equals(query) || "ALL".equals(query)) { // 不判断 isEmpty,因为分页数据可能只是某页没有
@@ -594,7 +615,8 @@ public JSON onChildParse(int index, String key, JSONObject value) throws Excepti
}
}
- child = parser.onObjectParse(value, path, key, isMain ? arrayConfig.setType(SQLConfig.TYPE_ITEM_CHILD_0) : null, isSubquery);
+ child = parser.onObjectParse(value, path, key, isMain ? arrayConfig.setType(SQLConfig.TYPE_ITEM_CHILD_0) : null
+ , isSubquery, cache instanceof JSONObject ? (JSONObject) cache : null);
isEmpty = child == null || ((JSONObject) child).isEmpty();
if (isFirst && isEmpty) {
@@ -776,7 +798,7 @@ public void onTableArrayParse(String key, JSONArray valueArray) throws Exception
req = parser.parseCorrectRequest(method, childKey, version, "", req, maxUpdateCount, parser);
}
//parser.getMaxSQLCount() ? 可能恶意调用接口,把数据库拖死
- result = (JSONObject) onChildParse(0, "" + i, req);
+ result = (JSONObject) onChildParse(0, "" + i, req, null);
}
catch (Exception e) {
if (allowPartialFailed == false) {
@@ -1080,7 +1102,7 @@ public void onChildResponse() throws Exception {
if (set != null) {
int index = 0;
for (Entry entry : set) {
- Object child = entry == null ? null : onChildParse(index, entry.getKey(), entry.getValue());
+ Object child = entry == null ? null : onChildParse(index, entry.getKey(), entry.getValue(), null);
if (child == null
|| (child instanceof JSONObject && ((JSONObject) child).isEmpty())
|| (child instanceof JSONArray && ((JSONArray) child).isEmpty())
@@ -1106,8 +1128,11 @@ public Object onReferenceParse(@NotNull String path) {
public JSONObject onSQLExecute() throws Exception {
int position = getPosition();
- JSONObject result;
- if (isArrayMainTable && position > 0) { // 数组主表使用专门的缓存数据
+ JSONObject result = getCache();
+ if (result != null) {
+ parser.putQueryResult(path, result);
+ }
+ else if (isArrayMainTable && position > 0) { // 数组主表使用专门的缓存数据
result = parser.getArrayMainCacheItem(parentPath.substring(0, parentPath.lastIndexOf("[]") + 2), position);
}
else {
@@ -1134,7 +1159,8 @@ public JSONObject onSQLExecute() throws Exception {
JSONObject obj = rawList.get(i);
if (obj != null) {
- parser.putQueryResult(arrayPath + "/" + i + "/" + name, obj); // 解决获取关联数据时requestObject里不存在需要的关联数据
+ // obj.remove(AbstractSQLExecutor.KEY_VICE_ITEM);
+ parser.putQueryResult(arrayPath + "/" + i + "/" + name, obj); // 解决获取关联数据时requestObject里不存在需要的关联数据
}
}
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
index 3a3822d25..22a984fa5 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
@@ -537,7 +537,7 @@ public JSONObject parseResponse(JSONObject request) {
queryDepth = 0;
executedSQLDuration = 0;
- requestObject = onObjectParse(request, null, null, null, false);
+ requestObject = onObjectParse(request, null, null, null, false, null);
onCommit();
}
@@ -1081,17 +1081,18 @@ public JSONObject getStructure(@NotNull String table, String method, String tag,
// protected SQLConfig itemConfig;
/**获取单个对象,该对象处于parentObject内
- * @param request parentObject 的 value
- * @param parentPath parentObject 的路径
- * @param name parentObject 的 key
- * @param arrayConfig config for array item
- * @param isSubquery 是否为子查询
- * @return
- * @throws Exception
- */
+ * @param request parentObject 的 value
+ * @param parentPath parentObject 的路径
+ * @param name parentObject 的 key
+ * @param arrayConfig config for array item
+ * @param isSubquery 是否为子查询
+ * @param cache SQL 结果缓存
+ * @return
+ * @throws Exception
+ */
@Override
- public JSONObject onObjectParse(final JSONObject request
- , String parentPath, String name, final SQLConfig arrayConfig, boolean isSubquery) throws Exception {
+ public JSONObject onObjectParse(final JSONObject request, String parentPath, String name
+ , final SQLConfig arrayConfig, boolean isSubquery, JSONObject cache) throws Exception {
if (Log.DEBUG) {
Log.i(TAG, "\ngetObject: parentPath = " + parentPath
@@ -1135,6 +1136,8 @@ public JSONObject onObjectParse(final JSONObject request
}
// 对象 - 设置 method
setOpMethod(request, op, name);
+
+ op.setCache(cache);
op = op.parse(name, isReuse);
JSONObject response = null;
@@ -1251,14 +1254,16 @@ public JSONObject onObjectParse(final JSONObject request
}
/**获取对象数组,该对象数组处于parentObject内
+ * @param request parentObject的value
* @param parentPath parentObject的路径
* @param name parentObject的key
- * @param request parentObject的value
+ * @param isSubquery 是否为子查询
+ * @param cache SQL 结果缓存
* @return
* @throws Exception
*/
@Override
- public JSONArray onArrayParse(JSONObject request, String parentPath, String name, boolean isSubquery) throws Exception {
+ public JSONArray onArrayParse(JSONObject request, String parentPath, String name, boolean isSubquery, JSONArray cache) throws Exception {
if (Log.DEBUG) {
Log.i(TAG, "\n\n\n onArrayParse parentPath = " + parentPath
+ "; name = " + name + "; request = " + JSON.toJSONString(request));
@@ -1355,7 +1360,8 @@ else if (childKeys.length == 1 && JSONRequest.isTableKey(childKeys[0])) { //
//Table<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
- response = new JSONArray();
+
+ List joinList = onJoinParse(join, request);
SQLConfig config = createSQLConfig()
.setMethod(requestMethod)
.setCount(size)
@@ -1363,15 +1369,16 @@ else if (childKeys.length == 1 && JSONRequest.isTableKey(childKeys[0])) { //
.setQuery(query2)
.setCompat(compat)
.setTable(arrTableKey)
- .setJoinList(onJoinParse(join, request));
+ .setJoinList(joinList);
JSONObject parent;
boolean isExtract = true;
+ response = new JSONArray();
//生成size个
for (int i = 0; i < (isSubquery ? 1 : size); i++) {
- parent = onObjectParse(request, isSubquery ? parentPath : path, isSubquery ? name : "" + i, config.setType(SQLConfig.TYPE_ITEM).setPosition(i), isSubquery);
+ parent = onObjectParse(request, isSubquery ? parentPath : path, isSubquery ? name : "" + i, config.setType(SQLConfig.TYPE_ITEM).setPosition(i), isSubquery, null);
if (parent == null || parent.isEmpty()) {
break;
}
@@ -1386,7 +1393,7 @@ else if (childKeys.length == 1 && JSONRequest.isTableKey(childKeys[0])) { //
@SuppressWarnings("unchecked")
List list = fo == null ? null : (List) fo.remove(AbstractSQLExecutor.KEY_RAW_LIST);
- if (list != null && list.isEmpty() == false) {
+ if (list != null && list.isEmpty() == false && (joinList == null || joinList.isEmpty())) {
isExtract = false;
list.set(0, fo); // 不知道为啥第 0 项也加了 @RAW@LIST
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
index 51b76e193..6c46d2059 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
@@ -4504,7 +4504,7 @@ public String getSetString(RequestMethod method, Map content, bo
if (setString.isEmpty()) {
throw new IllegalArgumentException("PUT 请求必须在Table内设置要修改的 key:value !");
}
- return (isClickHouse()?" ":" SET ") + setString;
+ return (isClickHouse() ? " " : " SET ") + setString;
}
/**SET key = concat(key, 'value')
@@ -6023,7 +6023,7 @@ public static String getRealKey(RequestMethod method, String originKey
return originKey;
}
- String key = new String(originKey);
+ String key = originKey;
if (key.endsWith("$")) {//搜索 LIKE,查询时处理
String k = key.substring(0, key.length() - 1);
// key%$:"a" -> key LIKE '%a%'; key?%$:"a" -> key LIKE 'a%'; key_?$:"a" -> key LIKE '_a'; key_%$:"a" -> key LIKE '_a%'
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java
index 36ef71ca9..fd708f9b8 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java
@@ -32,6 +32,7 @@ public abstract class AbstractSQLExecutor implements SQLExecut
//是否返回 值为null的字段
public static boolean ENABLE_OUTPUT_NULL_COLUMN = false;
public static String KEY_RAW_LIST = "@RAW@LIST"; // 避免和字段命名冲突,不用 $RAW@LIST$ 是因为 $ 会在 fastjson 内部转义,浪费性能
+ public static String KEY_VICE_ITEM = "@VICE@ITEM"; // 避免和字段命名冲突,不用 $VICE@LIST$ 是因为 $ 会在 fastjson 内部转义,浪费性能
private Parser parser;
@Override
@@ -406,6 +407,7 @@ public JSONObject execute(@NotNull SQLConfig config, boolean unknownType) thr
Log.d(TAG, "\n\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n execute while (rs.next()){ index = " + index + "\n\n");
JSONObject item = new JSONObject(true);
+ JSONObject viceItem = null;
JSONObject curItem = item;
boolean isMain = true;
@@ -537,6 +539,9 @@ else if (config.isClickHouse() && (sqlTable.startsWith("`") || sqlTable.startsWi
columnIndexAndJoinMap[i - 1] = curJoin;
}
+ //boolean isVice = false;
+ //String viceName = null;
+
// 如果是主表则直接用主表对应的 item,否则缓存副表数据到 childMap
Join prevJoin = columnIndexAndJoinMap == null || i < 2 ? null : columnIndexAndJoinMap[i - 2];
if (curJoin != prevJoin) { // 前后字段不在同一个表对象,即便后面出现 null,也不该是主表数据,而是逻辑 bug 导致
@@ -556,6 +561,7 @@ else if (config.isClickHouse() && (sqlTable.startsWith("`") || sqlTable.startsWi
}
}
}
+
String viceSql = viceConfig == null ? null : viceConfig.getSQL(false); //TODO 在 SQLConfig 缓存 SQL,减少大量的重复生成
if (StringUtil.isEmpty(viceSql, true)) {
@@ -568,10 +574,17 @@ else if (curJoin.isOuterJoin() || curJoin.isAntiJoin()) {
// 副表是按常规条件查询,缓存会导致其它同表同条件对象查询结果集为空 childMap.put(viceSql, new JSONObject()); // 缓存固定空数据,避免后续多余查询
}
else {
- curItem = childMap.get(viceSql);
+ //isVice = true;
+ String viceName = viceConfig.getTable() + (StringUtil.isEmpty(viceConfig.getAlias()) ? "" : ":" + StringUtil.isEmpty(viceConfig.getAlias()));
+ if (viceItem == null) {
+ viceItem = new JSONObject(true);
+ }
+ curItem = viceItem.getJSONObject(viceName);
+ //curItem = childMap.get(viceSql);
if (curItem == null) {
curItem = new JSONObject(true);
- childMap.put(viceSql, curItem);
+ //childMap.put(viceSql, curItem);
+ viceItem.put(viceName, curItem);
}
}
}
@@ -579,6 +592,10 @@ else if (curJoin.isOuterJoin() || curJoin.isAntiJoin()) {
curItem = onPutColumn(config, rs, rsmd, index, curItem, i, curJoin, childMap); // isExplain == false && hasJoin && i >= viceColumnStart ? childMap : null);
}
+ if (viceItem != null) {
+ item.put(KEY_VICE_ITEM, viceItem);
+ }
+
resultList = onPutTable(config, rs, rsmd, resultList, index, item);
Log.d(TAG, "execute while (rs.next()) { resultList.put( " + index + ", result); " + "\n >>>>>>>>>>>>>>>>>>>>>>>>>>> \n\n");
@@ -907,7 +924,7 @@ protected JSONObject onPutColumn(@NotNull SQLConfig config, @NotNull ResultSe
// 主表必须 put 至少一个 null 进去,否则全部字段为 null 都不 put 会导致中断后续正常返回值
if (value != null) {
table.put(label, value);
- } else{
+ } else {
if (join == null && table.isEmpty()) {
table.put(label, null);
} else if (ENABLE_OUTPUT_NULL_COLUMN) {
diff --git a/APIJSONORM/src/main/java/apijson/orm/ObjectParser.java b/APIJSONORM/src/main/java/apijson/orm/ObjectParser.java
index 6df050e0b..205126908 100755
--- a/APIJSONORM/src/main/java/apijson/orm/ObjectParser.java
+++ b/APIJSONORM/src/main/java/apijson/orm/ObjectParser.java
@@ -26,6 +26,10 @@ public interface ObjectParser {
String getParentPath();
ObjectParser setParentPath(String parentPath);
+ ObjectParser setCache(JSONObject cache);
+ JSONObject getCache();
+
+
/**解析成员
* response重新赋值
* @param name
@@ -67,10 +71,11 @@ public interface ObjectParser {
* @param index
* @param key
* @param value
+ * @param cache SQL 结果缓存
* @return
* @throws Exception
*/
- JSON onChildParse(int index, String key, JSONObject value) throws Exception;
+ JSON onChildParse(int index, String key, JSONObject value, JSON cache) throws Exception;
/**解析赋值引用
* @param path
@@ -164,5 +169,4 @@ public interface ObjectParser {
Map> getFunctionMap();
Map getChildMap();
-
}
diff --git a/APIJSONORM/src/main/java/apijson/orm/Parser.java b/APIJSONORM/src/main/java/apijson/orm/Parser.java
index 7ed0d1b1c..b2da33477 100755
--- a/APIJSONORM/src/main/java/apijson/orm/Parser.java
+++ b/APIJSONORM/src/main/java/apijson/orm/Parser.java
@@ -66,9 +66,9 @@ JSONObject parseCorrectRequest(RequestMethod method, String tag, int version, St
JSONObject getStructure(String table, String method, String tag, int version) throws Exception;
- JSONObject onObjectParse(JSONObject request, String parentPath, String name, SQLConfig arrayConfig, boolean isSubquery) throws Exception;
+ JSONObject onObjectParse(JSONObject request, String parentPath, String name, SQLConfig arrayConfig, boolean isSubquery, JSONObject cache) throws Exception;
- JSONArray onArrayParse(JSONObject request, String parentPath, String name, boolean isSubquery) throws Exception;
+ JSONArray onArrayParse(JSONObject request, String parentPath, String name, boolean isSubquery, JSONArray cache) throws Exception;
/**解析远程函数
* @param key
From e5261ec84c2a6ab1ccf8d666618cc799ebcefb37 Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sun, 2 Feb 2025 19:29:14 +0800
Subject: [PATCH 026/122] =?UTF-8?q?=E8=A7=A3=E5=86=B3=20SQL=20JOIN=20?=
=?UTF-8?q?=E5=90=8C=E5=90=8D=E5=89=AF=E8=A1=A8=E8=BF=94=E5=9B=9E=E6=95=B0?=
=?UTF-8?q?=E6=8D=AE=E9=94=99=E4=B9=B1=EF=BC=8C=E8=A7=A3=E5=86=B3=E6=9C=89?=
=?UTF-8?q?=E6=97=B6=20SELECT=20=E5=92=8C=20ON=20=E4=B8=AD=E7=9A=84?=
=?UTF-8?q?=E8=A1=A8=E5=88=AB=E5=90=8D=E5=AF=B9=E5=BA=94=E9=94=99=E8=AF=AF?=
=?UTF-8?q?=EF=BC=8C=E8=A7=A3=E5=86=B3=20Oracle=20=E6=9F=90=E4=BA=9B?=
=?UTF-8?q?=E6=83=85=E5=86=B5=E4=B8=8B=E7=94=A8=E4=BA=86=E4=B8=8D=E5=85=81?=
=?UTF-8?q?=E8=AE=B8=E7=9A=84=20AS=20=E5=88=AB=E5=90=8D=EF=BC=9B=E4=BC=98?=
=?UTF-8?q?=E5=8C=96=E4=BB=A3=E7=A0=81=20-=20JOIN=20=E5=89=AF=E8=A1=A8?=
=?UTF-8?q?=E6=9C=AA=E6=8C=87=E5=AE=9A=20@column=20=E4=BC=9A=E5=AF=BC?=
=?UTF-8?q?=E8=87=B4=E5=86=97=E4=BD=99=E6=9F=A5=E8=AF=A2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../apijson/orm/AbstractObjectParser.java | 4 +-
.../main/java/apijson/orm/AbstractParser.java | 3 +-
.../java/apijson/orm/AbstractSQLConfig.java | 236 ++++++++----------
.../java/apijson/orm/AbstractSQLExecutor.java | 80 ++++--
.../src/main/java/apijson/orm/Join.java | 9 +
.../src/main/java/apijson/orm/SQLConfig.java | 14 ++
6 files changed, 183 insertions(+), 163 deletions(-)
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java
index 8f6494c15..1ed3f1716 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java
@@ -290,7 +290,7 @@ public AbstractObjectParser parse(String name, boolean isReuse) throws Exception
}
else if (value instanceof JSONObject) { // JSONObject,往下一级提取
if (childMap != null) { // 添加到childMap,最后再解析
- childMap.put(key, (JSONObject)value);
+ childMap.put(key, (JSONObject) value);
}
else { // 直接解析并替换原来的,[]:{} 内必须直接解析,否则会因为丢掉count等属性,并且total@:"/[]/total"必须在[]:{} 后!
JSON cache = index <= 0 || type != TYPE_ITEM || viceItem == null ? null : viceItem.getJSONObject(key);
@@ -457,10 +457,10 @@ else if (value instanceof String) { // //key{}@ getRealKey, 引用赋值路径
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;");
+ // FIXME getCache() != null 时 return true,解决 RIGHT/OUTER/FOREIGN JOIN 主表无数据导致副表数据也不返回
return false; // 获取不到就不用再做无效的 query 了。不考虑 Table:{Table:{}} 嵌套
}
-
Log.d(TAG, "onParse isTable(table) == false >> return true;");
return true; // 舍去,对Table无影响
}
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
index 22a984fa5..54eafe97a 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
@@ -1734,7 +1734,7 @@ else if (join != null){
throw new IllegalArgumentException(e.getKey() + ":'/targetTable:targetAlias/targetKey' 中 targetAlias 值 " + targetAlias + " 不合法!必须满足英文单词变量名格式!");
}
- targetTable = targetTableKey; // 主表允许别名
+ //targetTable = targetTableKey; // 主表允许别名
if (StringUtil.isName(targetTable) == false) {
throw new IllegalArgumentException(e.getKey() + ":'/targetTable/targetKey' 中 targetTable 值 " + targetTable + " 不合法!必须满足大写字母开头的表对象英文单词 key 格式!");
}
@@ -1760,6 +1760,7 @@ else if (join != null){
on.setOriginKey(originKey);
on.setOriginValue((String) refEntry.getValue());
+ on.setTargetTableKey(targetTableKey);
on.setTargetTable(targetTable);
on.setTargetAlias(targetAlias);
on.setTargetKey(targetKey);
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
index 6c46d2059..5867b648c 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
@@ -9,15 +9,8 @@
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
import java.util.Map.Entry;
-import java.util.Set;
import java.util.regex.Pattern;
import apijson.JSON;
@@ -1431,10 +1424,6 @@ public String getSQLTable() {
return StringUtil.isEmpty(nt) ? ot : nt;
}
- @JSONField(serialize = false)
- public String getSQLTableWithAlias(String table,String alias) {
- return StringUtil.isEmpty(alias) ? table : table + ":" + alias; // 带上原表名,避免 alias 和其它表名/字段名冲突
- }
@JSONField(serialize = false)
@Override
@@ -1445,7 +1434,7 @@ public String getTablePath() {
String sqlTable = getSQLTable();
return (StringUtil.isEmpty(sch, true) ? "" : q + sch + q + ".") + q + sqlTable + q
- + ( isKeyPrefix() ? " AS " + getAliasWithQuote() : "");
+ + (isKeyPrefix() ? getAs() + q + getSQLAlias() + q : "");
}
@Override
public AbstractSQLConfig setTable(String table) { //Table已经在Parser中校验,所以这里不用防SQL注入
@@ -1453,6 +1442,10 @@ public AbstractSQLConfig setTable(String table) { //Table已经在Parser中校
return this;
}
+ public String getAs() {
+ return isOracle() ? " " : " AS ";
+ }
+
@Override
public String getAlias() {
return alias;
@@ -1462,11 +1455,8 @@ public AbstractSQLConfig setAlias(String alias) {
this.alias = alias;
return this;
}
- public String getAliasWithQuote() {
- String a = getAlias();
- if (StringUtil.isEmpty(a, true)) {
- a = getTable();
- }
+ public String getSQLAliasWithQuote() {
+ String a = getSQLAlias();
String q = getQuote();
// getTable 不能小写,因为Verifier用大小写敏感的名称判断权限
// 如果要强制小写,则可在子类重写这个方法再 toLowerCase
@@ -1502,9 +1492,9 @@ public String getGroupString(boolean hasPrefix) {
if (cfg != null) {
cfg.setMain(false).setKeyPrefix(true);
- if (StringUtil.isEmpty(cfg.getAlias(), true)) {
- cfg.setAlias(cfg.getTable());
- }
+ //if (StringUtil.isEmpty(cfg.getAlias(), true)) {
+ // cfg.setAlias(cfg.getTable());
+ //}
String c = ((AbstractSQLConfig) cfg).getGroupString(false);
if (StringUtil.isEmpty(c, true) == false) {
@@ -1579,9 +1569,9 @@ public String getHavingString(boolean hasPrefix) throws Exception {
if (cfg != null) {
cfg.setMain(false).setKeyPrefix(true);
- if (StringUtil.isEmpty(cfg.getAlias(), true)) {
- cfg.setAlias(cfg.getTable());
- }
+ //if (StringUtil.isEmpty(cfg.getAlias(), true)) {
+ // cfg.setAlias(cfg.getTable());
+ //}
String c = ((AbstractSQLConfig) cfg).getHavingString(false);
if (StringUtil.isEmpty(c, true) == false) {
@@ -1610,7 +1600,7 @@ public String getHavingString(boolean hasPrefix) throws Exception {
//fun0(arg0,arg1,...);fun1(arg0,arg1,...)
String havingString = parseCombineExpression(getMethod(), getQuote(), getTable()
- , getAliasWithQuote(), map, getHavingCombine(), true, containRaw, true);
+ , getAlias(), map, getHavingCombine(), true, containRaw, true);
return (hasPrefix ? " HAVING " : "") + StringUtil.concat(havingString, joinHaving, AND);
}
@@ -1693,9 +1683,9 @@ public String getOrderString(boolean hasPrefix) {
if (cfg != null) {
cfg.setMain(false).setKeyPrefix(true);
- if (StringUtil.isEmpty(cfg.getAlias(), true)) {
- cfg.setAlias(cfg.getTable());
- }
+ //if (StringUtil.isEmpty(cfg.getAlias(), true)) {
+ // cfg.setAlias(cfg.getTable());
+ //}
String c = ((AbstractSQLConfig) cfg).getOrderString(false);
if (StringUtil.isEmpty(c, true) == false) {
@@ -1890,6 +1880,8 @@ public String getColumnString() throws Exception {
@JSONField(serialize = false)
public String getColumnString(boolean inSQLJoin) throws Exception {
List column = getColumn();
+ String as = getAs();
+ String q = getQuote();
switch (getMethod()) {
case HEAD:
@@ -1950,25 +1942,24 @@ public String getColumnString(boolean inSQLJoin) throws Exception {
if (start > 0 && end > start) {
String fun = c0.substring(0, start);
- // Invalid use of group function SELECT count(max(`id`)) AS count FROM `sys`.`Comment`
+ // Invalid use of group function SELECT count(max(`id`)) AS count FROM `sys`.`Comment`
if (SQL_AGGREGATE_FUNCTION_MAP.containsKey(fun)) {
String group = getGroup(); // TODO 唯一 100% 兼容的可能只有 SELECT count(*) FROM (原语句) AS table
return StringUtil.isEmpty(group, true) ? "1" : "count(DISTINCT " + group + ")";
}
String[] args = start == end - 1 ? null : StringUtil.split(c0.substring(start + 1, end));
- if (args == null || args.length <= 0) {
- return SQL.count(c0);
+ if (args != null && args.length > 0) {
+ List raw = getRaw();
+ boolean containRaw = raw != null && raw.contains(KEY_COLUMN);
+ c0 = parseSQLExpression(KEY_COLUMN, c0, containRaw, false, null);
}
- List raw = getRaw();
- boolean containRaw = raw != null && raw.contains(KEY_COLUMN);
-
- return SQL.count(parseSQLExpression(KEY_COLUMN, c0, containRaw, false, null));
+ return "count(" + c0 + ")" + as + q + JSONResponse.KEY_COUNT + q;
}
}
- return SQL.count(onlyOne ? getKey(c0) : "*");
+ return "count(" + (onlyOne ? getKey(c0) : "*") + ")" + as + q + JSONResponse.KEY_COUNT + q;
// return SQL.count(onlyOne && StringUtil.isName(column.get(0)) ? getKey(column.get(0)) : "*");
case POST:
if (column == null || column.isEmpty()) {
@@ -1993,30 +1984,28 @@ public String getColumnString(boolean inSQLJoin) throws Exception {
String joinColumn = "";
if (joinList != null) {
boolean first = true;
- for (Join j : joinList) {
- if (j.isAppJoin()) {
+ for (Join join : joinList) {
+ if (join.isAppJoin()) {
continue;
}
- SQLConfig ocfg = j.getOuterConfig();
+ SQLConfig ocfg = join.getOuterConfig();
boolean isEmpty = ocfg == null || ocfg.getColumn() == null;
- boolean isLeftOrRightJoin = j.isLeftOrRightJoin();
+ boolean isLeftOrRightJoin = join.isLeftOrRightJoin();
if (isEmpty && isLeftOrRightJoin) {
// 改为 SELECT ViceTable.* 解决 SELECT sum(ViceTable.id)
// LEFT/RIGHT JOIN (SELECT sum(id) FROM ViceTable...) AS ViceTable
// 不仅导致 SQL 函数重复计算,还有时导致 SQL 报错或对应字段未返回
- String quote = getQuote();
- joinColumn += (first ? "" : ", ") + quote + (StringUtil.isEmpty(j.getAlias(), true)
- ? j.getTable() : j.getAlias()) + quote + ".*";
+ joinColumn += (first ? "" : ", ") + q + SQLConfig.getSQLAlias(join.getTable(), join.getAlias()) + q + ".*";
first = false;
} else {
- SQLConfig cfg = isLeftOrRightJoin == false && isEmpty ? j.getJoinConfig() : ocfg;
+ SQLConfig cfg = isLeftOrRightJoin == false && isEmpty ? join.getJoinConfig() : ocfg;
if (cfg != null) {
cfg.setMain(false).setKeyPrefix(true);
- if (StringUtil.isEmpty(cfg.getAlias(), true)) {
- cfg.setAlias(cfg.getTable());
- }
+ //if (StringUtil.isEmpty(cfg.getAlias(), true)) {
+ // cfg.setAlias(cfg.getTable());
+ //}
String c = ((AbstractSQLConfig) cfg).getColumnString(true);
if (StringUtil.isEmpty(c, true) == false) {
@@ -2030,9 +2019,8 @@ public String getColumnString(boolean inSQLJoin) throws Exception {
}
}
- String tableAlias = getAliasWithQuote();
-
- // String c = StringUtil.getString(column); //id,name;json_length(contactIdList):contactCount;...
+ String tableAlias = q + getSQLAlias() + q;
+ // String c = StringUtil.getString(column); //id,name;json_length(contactIdList):contactCount;...
String[] keys = column == null ? null : column.toArray(new String[]{}); //StringUtil.split(c, ";");
if (keys == null || keys.length <= 0) {
@@ -2043,7 +2031,6 @@ public String getColumnString(boolean inSQLJoin) throws Exception {
return StringUtil.concat(mc, joinColumn, ", ", true);
}
-
List raw = getRaw();
boolean containRaw = raw != null && raw.contains(KEY_COLUMN);
@@ -2062,7 +2049,7 @@ public String getColumnString(boolean inSQLJoin) throws Exception {
boolean hasAlias = StringUtil.isName(alias);
String pre = index > 0 && hasAlias ? expression.substring(0, index) : expression;
if (RAW_MAP.containsValue(pre) || "".equals(RAW_MAP.get(pre))) { // newSQLConfig 提前处理好的
- keys[i] = pre + (hasAlias ? " AS " + alias : "");
+ keys[i] = pre + (hasAlias ? getAs() + q + alias + q : "");
continue;
}
}
@@ -2197,7 +2184,7 @@ public String parseSQLExpression(String key, String expression, boolean containR
}
String origin = fun + "(" + (distinct ? PREFIX_DISTINCT : "") + StringUtil.getString(ckeys) + ")" + suffix;
- expression = origin + (StringUtil.isEmpty(alias, true) ? "" : " AS " + quote + alias + quote);
+ expression = origin + (StringUtil.isEmpty(alias, true) ? "" : getAs() + quote + alias + quote);
}
else {
//是窗口函数 fun(arg0,agr1) OVER (agr0 agr1 ...)
@@ -2255,7 +2242,7 @@ else if (SQL_FUNCTION_MAP.containsKey(fun) == false) {
String argsString2[] = parseArgsSplitWithComma(argString2, false, containRaw, allowAlias);
expression = fun + "(" + StringUtil.getString(agrsString1) + (containOver ? ") OVER (" : ") AGAINST (")
+ StringUtil.getString(argsString2) + ")" + suffix // 传参不传空格,拼接带空格
- + (StringUtil.isEmpty(alias, true) ? "" : " AS " + quote + alias + quote);
+ + (StringUtil.isEmpty(alias, true) ? "" : getAs() + quote + alias + quote);
}
}
@@ -2274,7 +2261,7 @@ private String[] parseArgsSplitWithComma(String param, boolean isColumn, boolean
// 以"," 分割参数
String quote = getQuote();
boolean isKeyPrefix = isKeyPrefix();
- String tableAlias = getAliasWithQuote();
+ String tableAlias = quote + getSQLAlias() + quote;
String ckeys[] = StringUtil.split(param); // 以","分割参数
if (ckeys != null && ckeys.length > 0) {
@@ -2385,7 +2372,7 @@ else if ("!=null".equals(ck)) {
}
if (isColumn && StringUtil.isEmpty(alias, true) == false) {
- origin += " AS " + quote + alias + quote;
+ origin += getAs() + quote + alias + quote;
}
}
}
@@ -2408,7 +2395,7 @@ else if ("!=null".equals(ck)) {
private String parseArgsSplitWithSpace(String mkes[]) {
String quote = getQuote();
boolean isKeyPrefix = isKeyPrefix();
- String tableAlias = getAliasWithQuote();
+ String tableAlias = quote + getSQLAlias() + quote;
// 包含空格的参数 肯定不包含别名 不用处理别名
if (mkes != null && mkes.length > 0) {
@@ -2988,8 +2975,7 @@ public String getWhereString(boolean hasPrefix) throws Exception {
@JSONField(serialize = false)
public String getWhereString(boolean hasPrefix, RequestMethod method, Map where
, String combine, List joinList, boolean verifyName) throws Exception {
-
- String whereString = parseCombineExpression(method, getQuote(), getTable(), getAliasWithQuote()
+ String whereString = parseCombineExpression(method, getQuote(), getTable(), getAlias()
, where, combine, verifyName, false, false);
whereString = concatJoinWhereString(whereString);
String result = StringUtil.isEmpty(whereString, true) ? "" : (hasPrefix ? " WHERE " : "") + whereString;
@@ -3680,7 +3666,7 @@ else if (isTest()) {
}
public String getSQLKey(String key) {
String q = getQuote();
- return (isKeyPrefix() ? getAliasWithQuote() + "." : "") + q + key + q;
+ return (isKeyPrefix() ? q + getSQLAlias() + q + "." : "") + q + key + q;
}
/**
@@ -4327,11 +4313,12 @@ private String withAsExpreSubqueryString(SQLConfig cfg, Subquery subquery) throw
}
String quote = getQuote();
+ String as = getAs();
String withAsExpreSql;
if (list != null) {
String withQuoteName = quote + subquery.getKey() + quote;
- list.add(" " + withQuoteName + " AS " + "(" + cfg.getSQL(isPrepared()) + ") ");
+ list.add(" " + withQuoteName + as + "(" + cfg.getSQL(isPrepared()) + ") ");
withAsExpreSql = " SELECT * FROM " + withQuoteName;
// 预编译参数 FIXME 这里重复添加了,导致子查询都报错参数超过 ? 数量 Parameter index out of range (5 > number of parameters, which is 4)
@@ -4350,7 +4337,7 @@ private String withAsExpreSubqueryString(SQLConfig cfg, Subquery subquery) throw
withAsExpreSql = cfg.getSQL(isPrepared());
// mysql 才存在这个问题, 主表和子表是一张表
if (isWithAsEnable && isMySQL() && StringUtil.equals(getTable(), subquery.getFrom())) {
- withAsExpreSql = " SELECT * FROM (" + withAsExpreSql + ") AS " + quote + subquery.getKey() + quote;
+ withAsExpreSql = " SELECT * FROM (" + withAsExpreSql + ")" + as + quote + subquery.getKey() + quote;
}
}
@@ -4629,7 +4616,7 @@ public static String getSQL(AbstractSQLConfig config) throws Exception {
if (config.isTest() && RequestMethod.isGetMethod(config.getMethod(), true)) { // FIXME 为啥是 code 而不是 count ?
String q = config.getQuote(); // 生成 SELECT ( (24 >=0 AND 24 <3) ) AS `code` LIMIT 1 OFFSET 0
return explain + "SELECT " + config.getWhereString(false)
- + " AS " + q + JSONResponse.KEY_COUNT + q + config.getLimitString();
+ + config.getAs() + q + JSONResponse.KEY_COUNT + q + config.getLimitString();
}
config.setPreparedValueList(new ArrayList());
@@ -4690,8 +4677,8 @@ protected String getOraclePageSql(String sql) {
return sql;
}
int offset = getOffset(getPage(), count);
- String alias = getAliasWithQuote();
String quote = getQuote();
+ String alias = quote + getSQLAlias() + quote;
return "SELECT * FROM (SELECT " + alias + ".*, ROWNUM "+ quote + "RN" + quote +" FROM (" + sql + ") " + alias
+ " WHERE ROWNUM <= " + (offset + count) + ") WHERE "+ quote + "RN" + quote +" > " + offset;
}
@@ -4705,7 +4692,7 @@ protected String getOraclePageSql(String sql) {
private static String getConditionString(String table, AbstractSQLConfig config) throws Exception {
Subquery from = config.getFrom();
if (from != null) {
- table = config.getSubqueryString(from) + " AS " + config.getAliasWithQuote() + " ";
+ table = config.getSubqueryString(from) + config.getAs() + config.getSQLAliasWithQuote() + " ";
}
String join = config.getJoinString();
@@ -4803,7 +4790,7 @@ public String getJoinString() throws Exception {
jc.setPrepared(isPrepared());
// 将关联表所属数据源配置为主表数据源
jc.setDatasource(this.getDatasource());
- String jt = StringUtil.isEmpty(jc.getAlias(), true) ? jc.getTable() : jc.getAlias();
+ String jt = jc.getSQLAlias();
List onList = j.getOnList();
//如果要强制小写,则可在子类重写这个方法再 toLowerCase
@@ -4824,7 +4811,7 @@ public String getJoinString() throws Exception {
case ">": // RIGHT JOIN
jc.setMain(true).setKeyPrefix(false);
sql = ( "<".equals(type) ? " LEFT" : (">".equals(type) ? " RIGHT" : " CROSS") )
- + " JOIN ( " + jc.getSQL(isPrepared()) + " ) AS " + quote + jt + quote;
+ + " JOIN ( " + jc.getSQL(isPrepared()) + " ) " + getAs() + quote + jt + quote;
sql = concatJoinOn(sql, quote, j, jt, onList);
jc.setMain(false).setKeyPrefix(true);
@@ -4844,9 +4831,10 @@ public String getJoinString() throws Exception {
sql = concatJoinOn(sql, quote, j, jt, onList);
break;
default:
+ String k = jc.getTableKey();
throw new UnsupportedOperationException(
- "join:value 中 value 里的 " + jt + "/" + j.getPath()
- + "错误!不支持 " + jt + " 等 [ @ APP, < LEFT, > RIGHT, * CROSS"
+ "join:value 中 value 里的 " + k + "/" + j.getPath()
+ + "错误!不支持 " + k + " 等 [ @ APP, < LEFT, > RIGHT, * CROSS"
+ ", & INNER, | FULL, ! OUTER, ^ SIDE, ( ANTI, ) FOREIGN ] 之外的 JOIN 类型 !"
);
}
@@ -4881,45 +4869,42 @@ public String getJoinString() throws Exception {
}
- protected String concatJoinOn(@NotNull String sql, @NotNull String quote, @NotNull Join j, @NotNull String jt, List onList) {
+ protected String concatJoinOn(@NotNull String sql, @NotNull String quote, @NotNull Join join, @NotNull String jt, List onList) {
if (onList != null) {
+ SQLConfig jc = join.getJoinConfig();
+ Map castMap = jc == null ? null : jc.getCast();
+
boolean first = true;
for (On on : onList) {
Logic logic = on.getLogic();
boolean isNot = logic == null ? false : logic.isNot();
if (isNot) {
- onJoinNotRelation(sql, quote, j, jt, onList, on);
+ onJoinNotRelation(sql, quote, join, jt, onList, on);
+ }
+
+ String lk = quote + jt + quote + "." + quote + on.getKey() + quote;
+ Object ct = castMap == null ? null : castMap.get(on.getOriginKey());
+ if (StringUtil.isNotEmpty(ct, false)) {
+ lk = "cast(" + lk + " AS " + ct + ")"; // 解决 JOIN ON 不支持 @cast 问题,CAST(expression AS TYPE) 中 AS 不能省略
}
String rt = on.getRelateType();
+
+ String rk = quote + SQLConfig.getSQLAlias(on.getTargetTable(), on.getTargetAlias()) + quote + "." + quote + on.getTargetKey() + quote;
+
if (StringUtil.isEmpty(rt, false)) {
- // 解决 JOIN ON 不支持 @cast 问题
- SQLConfig jc = j.getJoinConfig();
- Map castMap = jc == null ? null : jc.getCast();
- if (castMap == null || castMap.isEmpty()) {
- sql += (first ? ON : AND) + quote + jt + quote + "." + quote + on.getKey() + quote + (isNot ? " != " : " = ")
- + quote + on.getTargetTable() + quote + "." + quote + on.getTargetKey() + quote;
- } else {
- String leftTableRelationSql = quote + jt + quote + "." + quote + on.getKey() + quote;
- Object castValueType = castMap.get(on.getOriginKey());
- if (castValueType != null) {
- leftTableRelationSql = "CAST(" + leftTableRelationSql + " AS " + castValueType + ")";
- }
- sql += (first ? ON : AND) + leftTableRelationSql + (isNot ? " != " : " = ")
- + quote + on.getTargetTable() + quote + "." + quote + on.getTargetKey() + quote;
- }
+ sql += (first ? ON : AND) + lk + (isNot ? " != " : " = ") + rk;
}
else {
- onJoinComplexRelation(sql, quote, j, jt, onList, on);
+ onJoinComplexRelation(sql, quote, join, jt, onList, on);
if (">=".equals(rt) || "<=".equals(rt) || ">".equals(rt) || "<".equals(rt)) {
if (isNot) {
- throw new IllegalArgumentException("join:value 中 value 里的 " + jt + "/" + j.getPath()
+ throw new IllegalArgumentException("join:value 中 value 里的 " + jt + "/" + join.getPath()
+ " 中 JOIN ON 条件关联逻辑符 " + rt + " 不合法! >, <, >=, <= 不支持与或非逻辑符 & | ! !");
}
- sql += (first ? ON : AND) + quote + jt + quote + "." + quote + on.getKey() + quote + " " + rt + " "
- + quote + getSQLTableWithAlias(on.getTargetTable(), on.getTargetAlias()) + quote + "." + quote + on.getTargetKey() + quote;
+ sql += (first ? ON : AND) + lk + " " + rt + " " + rk;
}
else if (rt.endsWith("$")) {
String t = rt.substring(0, rt.length() - 1);
@@ -4964,52 +4949,38 @@ else if (l > 0 && StringUtil.isName(String.valueOf(l))) {
}
if (l <= 0 && r <= 0) {
- sql += (first ? ON : AND) + quote + jt + quote + "." + quote + on.getKey() + quote + (isNot ? NOT : "")
- + " LIKE " + quote + getSQLTableWithAlias(on.getTargetTable(), on.getTargetAlias()) + quote + "." + quote + on.getTargetKey() + quote;
+ sql += (first ? ON : AND) + lk + (isNot ? NOT : "") + " LIKE " + rk;
}
else {
- sql += (first ? ON : AND) + quote + jt + quote + "." + quote + on.getKey() + quote + (isNot ? NOT : "")
- + (l <= 0 ? " LIKE concat(" : " LIKE concat('" + l + "', ") + quote + getSQLTableWithAlias(on.getTargetTable(), on.getTargetAlias()) + quote
- + "." + quote + on.getTargetKey() + quote + (r <= 0 ? ")" : ", '" + r + "')");
+ sql += (first ? ON : AND) + lk + (isNot ? NOT : "")
+ + (l <= 0 ? " LIKE concat(" : " LIKE concat('" + l + "', ") + rk + (r <= 0 ? ")" : ", '" + r + "')");
}
}
else if (rt.endsWith("~")) {
boolean ignoreCase = "*~".equals(rt);
if (isPostgreSQL() || isInfluxDB()) {
- sql += (first ? ON : AND) + quote + jt + quote + "." + quote + on.getKey() + quote
- + (isNot ? NOT : "") + " ~" + (ignoreCase ? "* " : " ")
- + quote + getSQLTableWithAlias(on.getTargetTable(), on.getTargetAlias()) + quote + "." + quote + on.getTargetKey() + quote;
+ sql += (first ? ON : AND) + lk + (isNot ? NOT : "") + " ~" + (ignoreCase ? "* " : " ") + rk;
}
else if (isOracle() || isDameng() || isKingBase()) {
- sql += (first ? ON : AND) + "regexp_like(" + quote + jt + quote + "." + quote + on.getKey() + quote
- + ", " + quote + getSQLTableWithAlias(on.getTargetTable(), on.getTargetAlias()) + quote + "." + quote + on.getTargetKey() + quote
- + (ignoreCase ? ", 'i'" : ", 'c'") + ")";
+ sql += (first ? ON : AND) + "regexp_like(" + lk + ", " + rk + (ignoreCase ? ", 'i'" : ", 'c'") + ")";
}
else if (isPresto() || isTrino()) {
- sql += (first ? ON : AND) + "regexp_like(" + (ignoreCase ? "lower(" : "") + quote
- + jt + quote + "." + quote + on.getKey() + quote + (ignoreCase ? ")" : "")
- + ", " + (ignoreCase ? "lower(" : "") + quote + getSQLTableWithAlias(on.getTargetTable(), on.getTargetAlias())
- + quote + "." + quote + on.getTargetKey() + quote + (ignoreCase ? ")" : "") + ")";
+ sql += (first ? ON : AND) + "regexp_like(" + (ignoreCase ? "lower(" : "") + lk + (ignoreCase ? ")" : "")
+ + ", " + (ignoreCase ? "lower(" : "") + rk + (ignoreCase ? ")" : "") + ")";
}
else if (isClickHouse()) {
- sql += (first ? ON : AND) + "match(" + (ignoreCase ? "lower(" : "") + quote + jt
- + quote + "." + quote + on.getKey() + quote + (ignoreCase ? ")" : "")
- + ", " + (ignoreCase ? "lower(" : "") + quote + getSQLTableWithAlias(on.getTargetTable(), on.getTargetAlias())
- + quote + "." + quote + on.getTargetKey() + quote + (ignoreCase ? ")" : "") + ")";
+ sql += (first ? ON : AND) + "match(" + (ignoreCase ? "lower(" : "") + lk + (ignoreCase ? ")" : "")
+ + ", " + (ignoreCase ? "lower(" : "") + rk + (ignoreCase ? ")" : "") + ")";
}
else if (isElasticsearch()) {
- sql += (first ? ON : AND) + quote + jt + quote + "." + quote + on.getKey() + quote + (isNot ? NOT : "")
- + " RLIKE " + quote + getSQLTableWithAlias(on.getTargetTable(), on.getTargetAlias()) + quote + "." + quote + on.getTargetKey() + quote;
+ sql += (first ? ON : AND) + lk + (isNot ? NOT : "") + " RLIKE " + rk;
}
else if (isHive()) {
- sql += (first ? ON : AND) + (ignoreCase ? "lower(" : "") + quote + jt + quote + "." + quote + on.getKey() + quote + (ignoreCase ? ")" : "")
- + " REGEXP " + (ignoreCase ? "lower(" : "") + quote + getSQLTableWithAlias(on.getTargetTable(), on.getTargetAlias())
- + quote + "." + quote + on.getTargetKey() + quote + (ignoreCase ? ")" : "");
+ sql += (first ? ON : AND) + (ignoreCase ? "lower(" : "") + lk + (ignoreCase ? ")" : "")
+ + " REGEXP " + (ignoreCase ? "lower(" : "") + rk + (ignoreCase ? ")" : "");
}
else {
- sql += (first ? ON : AND) + quote + jt + quote + "." + quote + on.getKey() + quote + (isNot ? NOT : "")
- + " REGEXP " + (ignoreCase ? "" : "BINARY ")
- + quote + getSQLTableWithAlias(on.getTargetTable(), on.getTargetAlias()) + quote + "." + quote + on.getTargetKey() + quote;
+ sql += (first ? ON : AND) + lk + (isNot ? NOT : "") + " REGEXP " + (ignoreCase ? "" : "BINARY ") + rk;
}
}
else if ("{}".equals(rt) || "<>".equals(rt)) {
@@ -5017,13 +4988,13 @@ else if ("{}".equals(rt) || "<>".equals(rt)) {
String ta = on.getTargetAlias();
Map cast = null;
- if (tt.equals(getTable()) && ((ta == null && getAlias() == null) || ta.equals(getAlias()))) {
+ if (tt.equals(getTable()) && Objects.equals(ta, getAlias())) {
cast = getCast();
}
else {
boolean find = false;
for (Join jn : joinList) {
- if (tt.equals(jn.getTable()) && ((ta == null && jn.getAlias() == null) || ta.equals(jn.getAlias()))) {
+ if (tt.equals(jn.getTable()) && Objects.equals(ta, jn.getAlias())) {
cast = getCast();
find = true;
break;
@@ -5031,23 +5002,16 @@ else if ("{}".equals(rt) || "<>".equals(rt)) {
}
if (find == false) {
- throw new IllegalArgumentException("join:value 中 value 里的 " + jt + "/" + j.getPath()
+ throw new IllegalArgumentException("join:value 中 value 里的 " + jt + "/" + join.getPath()
+ " 中 JOIN ON 条件中找不到对应的 " + rt + " 不合法!只支持 =, {}, <> 这几种!");
}
}
boolean isBoolOrNum = SQL.isBooleanOrNumber(cast == null ? null : cast.get(on.getTargetKey()));
- String arrKeyPath;
- String itemKeyPath;
- if ("{}".equals(rt)) {
- arrKeyPath = quote + getSQLTableWithAlias(on.getTargetTable(),on.getTargetAlias()) + quote + "." + quote + on.getTargetKey() + quote;
- itemKeyPath = quote + jt + quote + "." + quote + on.getKey() + quote;
- }
- else {
- arrKeyPath = quote + jt + quote + "." + quote + on.getKey() + quote;
- itemKeyPath = quote + getSQLTableWithAlias(on.getTargetTable(),on.getTargetAlias()) + quote + "." + quote + on.getTargetKey() + quote;
- }
+ boolean isIn = "{}".equals(rt);
+ String arrKeyPath = isIn ? rk : lk;
+ String itemKeyPath = isIn ? lk : rk;
if (isPostgreSQL() || isInfluxDB()) { //operator does not exist: jsonb @> character varying "[" + c + "]");
sql += (first ? ON : AND) + (isNot ? "( " : "") + getCondition(isNot, arrKeyPath
@@ -5073,12 +5037,12 @@ else if (isClickHouse()) {
+ " IS NOT NULL AND json_contains(" + arrKeyPath
+ (isBoolOrNum ? ", cast(" + itemKeyPath + " AS CHAR), '$')"
: ", concat('\"', " + itemKeyPath + ", '\"'), '$')"
- )
- ) + (isNot ? ") " : "");
+ )
+ ) + (isNot ? ") " : "");
}
}
else {
- throw new IllegalArgumentException("join:value 中 value 里的 " + jt + "/" + j.getPath()
+ throw new IllegalArgumentException("join:value 中 value 里的 " + jt + "/" + join.getPath()
+ " 中 JOIN ON 条件关联类型 " + rt + " 不合法!只支持 =, >, <, >=, <=, !=, $, ~, {}, <> 这几种!");
}
}
@@ -5953,13 +5917,13 @@ else if (joinConfig.getDatabase().equals(config.getDatabase()) == false) {
joinConfig.setMain(false).setKeyPrefix(true);
if (j.getOuter() != null) {
- SQLConfig outterConfig = newSQLConfig(method, table, alias, j.getOuter(), null, false, callback);
- outterConfig.setMain(false)
+ SQLConfig outerConfig = newSQLConfig(method, table, alias, j.getOuter(), null, false, callback);
+ outerConfig.setMain(false)
.setKeyPrefix(true)
.setDatabase(joinConfig.getDatabase())
.setSchema(joinConfig.getSchema()); //解决主表 JOIN 副表,引号不一致
- j.setOuterConfig(outterConfig);
+ j.setOuterConfig(outerConfig);
}
}
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java
index fd708f9b8..84b30437e 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java
@@ -410,6 +410,7 @@ public JSONObject execute(@NotNull SQLConfig config, boolean unknownType) thr
JSONObject viceItem = null;
JSONObject curItem = item;
boolean isMain = true;
+ boolean reseted = false;
for (int i = 1; i <= length; i++) {
@@ -437,20 +438,31 @@ public JSONObject execute(@NotNull SQLConfig config, boolean unknownType) thr
if (toFindJoin) { // 在主表字段数量内的都归属主表
long startTime3 = System.currentTimeMillis();
sqlTable = rsmd.getTableName(i); // SQL 函数甚至部分字段都不返回表名,当然如果没传 @column 生成的 Table.* 则返回的所有字段都会带表名
- sqlResultDuration += System.currentTimeMillis() - startTime3;
- if (StringUtil.isEmpty(sqlTable, true)) {
- boolean isEmpty = curItem == null || curItem.isEmpty();
- String label = isEmpty ? null : getKey(config, rs, rsmd, index, curItem, i, childMap);
- if (isEmpty || curItem.containsKey(label) == false) { // 重复字段几乎肯定不是一张表的,尤其是主副表同名主键 id
- sqlTable = i <= 1 ? config.getSQLTable() : lastTableName; // Presto 等引擎 JDBC 返回 rsmd.getTableName(i) 为空,主表如果一个字段都没有会导致 APISJON 主副表所有字段都不返回
- }
- }
+ //if (StringUtil.isEmpty(sqlTable, true)) {
+ // boolean isEmpty = curItem == null || curItem.isEmpty();
+ String label = getKey(config, rs, rsmd, index, curItem, i, childMap);
+ if (i > 1 && ( (curItem != null && curItem.containsKey(label))
+ || (StringUtil.isNotEmpty(label) && StringUtil.equals(label, curConfig == null ? null : curConfig.getIdKey())))
+ ) { // Presto 等引擎 JDBC 返回 rsmd.getTableName(i) 为空,主表如果一个字段都没有会导致 APISJON 主副表所有字段都不返回
+ sqlTable = null;
+ if (reseted) {
+ lastViceTableStart ++;
+
+ SQLConfig lastCfg = lastJoin == null ? null : lastJoin.getCacheConfig();
+ List lastColumn = lastCfg == null ? null : lastCfg.getColumn();
+ lastViceColumnStart += lastColumn == null ? 1 : lastColumn.size();
+ }
+ reseted = true;
+ }
+ //}
+ sqlResultDuration += System.currentTimeMillis() - startTime3;
if (StringUtil.isEmpty(sqlTable, true)) { // hasJoin 已包含这个判断 && joinList != null) {
int nextViceColumnStart = lastViceColumnStart; // 主表没有 @column 时会偏小 lastViceColumnStart
- for (int j = lastViceTableStart; j < joinList.size(); j++) { // 查找副表 @column,定位字段所在表
+ int joinCount = joinList.size();
+ for (int j = lastViceTableStart; j < joinCount; j++) { // 查找副表 @column,定位字段所在表
Join join = joinList.get(j);
SQLConfig cfg = join == null || ! join.isSQLJoin() ? null : join.getJoinConfig();
List c = cfg == null ? null : cfg.getColumn();
@@ -461,7 +473,7 @@ public JSONObject execute(@NotNull SQLConfig config, boolean unknownType) thr
&& StringUtil.equals(sqlAlias, lastAliasName) ? 1 : 0
)
);
- if (i < nextViceColumnStart) {
+ if (i < nextViceColumnStart || j >= joinCount - 1) {
sqlTable = cfg.getSQLTable();
sqlAlias = cfg.getAlias();
lastViceTableStart = j; // 避免后面的空 @column 表内字段被放到之前的空 @column 表
@@ -539,17 +551,17 @@ else if (config.isClickHouse() && (sqlTable.startsWith("`") || sqlTable.startsWi
columnIndexAndJoinMap[i - 1] = curJoin;
}
- //boolean isVice = false;
- //String viceName = null;
-
// 如果是主表则直接用主表对应的 item,否则缓存副表数据到 childMap
Join prevJoin = columnIndexAndJoinMap == null || i < 2 ? null : columnIndexAndJoinMap[i - 2];
if (curJoin != prevJoin) { // 前后字段不在同一个表对象,即便后面出现 null,也不该是主表数据,而是逻辑 bug 导致
SQLConfig viceConfig = curJoin != null && curJoin.isSQLJoin() ? curJoin.getCacheConfig() : null;
+ boolean hasPK = false;
if (viceConfig != null) { //FIXME 只有和主表关联才能用 item,否则应该从 childMap 查其它副表数据
List onList = curJoin.getOnList();
int size = onList == null ? 0 : onList.size();
if (size > 0) {
+ String idKey = viceConfig.getIdKey();
+ String tblKey = config.getTableKey();
for (int j = size - 1; j >= 0; j--) {
On on = onList.get(j);
String ok = on == null ? null : on.getOriginKey();
@@ -557,34 +569,54 @@ else if (config.isClickHouse() && (sqlTable.startsWith("`") || sqlTable.startsWi
throw new NullPointerException("服务器内部错误,List 中 Join.onList[" + j + (on == null ? "] = null!" : ".getOriginKey() = null!"));
}
- viceConfig.putWhere(ok.substring(0, ok.length() - 1), item.get(on.getTargetKey()), true);
+ String k = ok.substring(0, ok.length() - 1);
+ String ttk = on.getTargetTableKey();
+
+ JSONObject target = StringUtil.equals(ttk, tblKey) ? item : (viceItem == null ? null : viceItem.getJSONObject(ttk));
+ Object v = target == null ? null : target.get(on.getTargetKey());
+ hasPK = hasPK || (k.equals(idKey) && v != null);
+
+ viceConfig.putWhere(k, v, true);
}
}
}
- String viceSql = viceConfig == null ? null : viceConfig.getSQL(false); //TODO 在 SQLConfig 缓存 SQL,减少大量的重复生成
-
- if (StringUtil.isEmpty(viceSql, true)) {
- Log.i(TAG, "execute StringUtil.isEmpty(viceSql, true) >> item = null; >> ");
+ if (viceConfig == null) { // StringUtil.isEmpty(viceSql, true)) {
+ Log.i(TAG, "execute viceConfig == null >> item = null; >> ");
curItem = null;
}
else if (curJoin.isOuterJoin() || curJoin.isAntiJoin()) {
Log.i(TAG, "execute curJoin.isOuterJoin() || curJoin.isAntiJoin() >> item = null; >> ");
curItem = null; // 肯定没有数据,缓存也无意义
- // 副表是按常规条件查询,缓存会导致其它同表同条件对象查询结果集为空 childMap.put(viceSql, new JSONObject()); // 缓存固定空数据,避免后续多余查询
+ // 副表是按常规条件查询,缓存会导致其它同表同条件对象查询结果集为空 childMap.put(viceSql, new JSONObject()); // 缓存固定空数据,避免后续多余查询
}
else {
- //isVice = true;
- String viceName = viceConfig.getTable() + (StringUtil.isEmpty(viceConfig.getAlias()) ? "" : ":" + StringUtil.isEmpty(viceConfig.getAlias()));
+ String viceName = viceConfig.getTableKey();
if (viceItem == null) {
viceItem = new JSONObject(true);
}
curItem = viceItem.getJSONObject(viceName);
- //curItem = childMap.get(viceSql);
- if (curItem == null) {
+
+ String viceSql = hasPK ? viceConfig.getSQL(false) : null; // TODO 在 SQLConfig 缓存 SQL,减少大量的重复生成
+ JSONObject curCache = hasPK ? childMap.get(viceSql) : null;
+
+ if (curItem == null || curItem.isEmpty()) {
+ // 导致前面判断重复 key 出错 curItem = curCache != null ? curCache : new JSONObject(true);
curItem = new JSONObject(true);
- //childMap.put(viceSql, curItem);
viceItem.put(viceName, curItem);
+ if (hasPK && curCache == null) {
+ childMap.put(viceSql, curItem);
+ }
+ }
+ else if (hasPK) {
+ if (curCache == null || curCache.isEmpty()) {
+ childMap.put(viceSql, curItem);
+ }
+ else {
+ curCache.putAll(curItem);
+ // 导致前面判断重复 key 出错 curItem = curCache;
+ // viceItem.put(viceName, curItem);
+ }
}
}
}
diff --git a/APIJSONORM/src/main/java/apijson/orm/Join.java b/APIJSONORM/src/main/java/apijson/orm/Join.java
index 68d7e8344..f648ff8bf 100644
--- a/APIJSONORM/src/main/java/apijson/orm/Join.java
+++ b/APIJSONORM/src/main/java/apijson/orm/Join.java
@@ -181,6 +181,7 @@ public static class On {
private Logic logic; // & | !
private String relateType; // "" - 一对一, "{}" - 一对多, "<>" - 多对一, > , <= , !=
private String key; // id
+ private String targetTableKey; // Moment:main
private String targetTable; // Moment
private String targetAlias; // main
private String targetKey; // userId
@@ -218,6 +219,14 @@ public String getKey() {
public void setKey(String key) {
this.key = key;
}
+
+ public void setTargetTableKey(String targetTableKey) {
+ this.targetTableKey = targetTableKey;
+ }
+ public String getTargetTableKey() {
+ return targetTableKey;
+ }
+
public void setTargetTable(String targetTable) {
this.targetTable = targetTable;
}
diff --git a/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
index 8e5755f89..641212708 100755
--- a/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
@@ -345,6 +345,19 @@ default int[] getDBVersionNums() {
SQLConfig setAlias(String alias);
+ default String getTableKey() {
+ String alias = getAlias();
+ return getTable() + (StringUtil.isEmpty(alias) ? "" : ":" + alias);
+ }
+
+ default String getSQLAlias() {
+ return getSQLAlias(getTable(), getAlias());
+ }
+ static String getSQLAlias(@NotNull String table, String alias) {
+ return StringUtil.isEmpty(alias) ? table : table + "_" + alias; // 带上原表名,避免 alias 和其它表名/字段名冲突
+ }
+
+
String getWhereString(boolean hasPrefix) throws Exception;
String getRawSQL(String key, Object value) throws Exception;
@@ -374,4 +387,5 @@ default int[] getDBVersionNums() {
boolean isFakeDelete();
Map onFakeDelete(Map map);
+
}
From 324fe328631077018078fa53c4934cfbd39d3ac5 Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sun, 2 Feb 2025 19:57:51 +0800
Subject: [PATCH 027/122] =?UTF-8?q?=E4=BC=98=E5=8C=96=20JOIN=20=E4=B8=AD?=
=?UTF-8?q?=E7=9A=84=E5=89=AF=E8=A1=A8=E5=88=AB=E5=90=8D=EF=BC=8C=E7=94=A8?=
=?UTF-8?q?=20=5F=5F=20=E5=8F=8C=E4=B8=8B=E5=88=92=E7=BA=BF=E6=9B=BF?=
=?UTF-8?q?=E4=BB=A3=E5=8E=9F=E6=9D=A5=E7=9A=84=20=5F=20=E5=8D=95=E4=B8=8B?=
=?UTF-8?q?=E5=88=92=E7=BA=BF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
APIJSONORM/src/main/java/apijson/orm/SQLConfig.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
index 641212708..60f2ddcdc 100755
--- a/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
@@ -354,7 +354,8 @@ default String getSQLAlias() {
return getSQLAlias(getTable(), getAlias());
}
static String getSQLAlias(@NotNull String table, String alias) {
- return StringUtil.isEmpty(alias) ? table : table + "_" + alias; // 带上原表名,避免 alias 和其它表名/字段名冲突
+ // 这里不用 : $ 等符号,因为部分数据库/引擎似乎不支持 `key`, "key", [key] 等避免关键词冲突的方式,只能使用符合变量命名的表别名
+ return StringUtil.isEmpty(alias) ? table : table + "__" + alias; // 带上原表名,避免 alias 和其它表名/字段名冲突
}
From 84edf9372bc3316a100d916146f819377d7ede23 Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sun, 2 Feb 2025 20:02:44 +0800
Subject: [PATCH 028/122] =?UTF-8?q?=E5=8D=87=E7=BA=A7=E7=89=88=E6=9C=AC?=
=?UTF-8?q?=E5=8F=B7?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
APIJSONORM/src/main/java/apijson/Log.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/APIJSONORM/src/main/java/apijson/Log.java b/APIJSONORM/src/main/java/apijson/Log.java
index 3484638cb..1c0b97a5d 100755
--- a/APIJSONORM/src/main/java/apijson/Log.java
+++ b/APIJSONORM/src/main/java/apijson/Log.java
@@ -14,7 +14,7 @@ public class Log {
public static boolean DEBUG = true;
- public static final String VERSION = "7.4.0";
+ public static final String VERSION = "7.4.2";
public static final String KEY_SYSTEM_INFO_DIVIDER = "\n---|-----APIJSON SYSTEM INFO-----|---\n";
public static final String OS_NAME;
From 448f31ddf77061ce62c984d5cca3d031648ad2bf Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sun, 9 Feb 2025 16:54:49 +0800
Subject: [PATCH 029/122] =?UTF-8?q?Maven=20pom.xml=20=E7=89=88=E6=9C=AC?=
=?UTF-8?q?=E6=94=B9=E4=B8=BA=207.4.2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
APIJSONORM/pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/APIJSONORM/pom.xml b/APIJSONORM/pom.xml
index b301c6d95..e19551a17 100644
--- a/APIJSONORM/pom.xml
+++ b/APIJSONORM/pom.xml
@@ -5,7 +5,7 @@
com.github.Tencent
APIJSON
- 7.4.0
+ 7.4.2
jar
APIJSONORM
From 31e8d7290378e6257fd48eb861a6126dff4d99dd Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sun, 9 Feb 2025 16:55:23 +0800
Subject: [PATCH 030/122] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81?=
=?UTF-8?q?=E5=8D=8E=E4=B8=BA=20openGauss-=E9=AB=98=E6=96=AF=E6=95=B0?=
=?UTF-8?q?=E6=8D=AE=E5=BA=93=E5=BC=80=E6=BA=90=E7=89=88=EF=BC=8C=E9=AB=98?=
=?UTF-8?q?=E5=8F=AF=E7=94=A8=E3=80=81=E9=AB=98=E6=80=A7=E8=83=BD=E3=80=81?=
=?UTF-8?q?=E9=AB=98=E5=AE=89=E5=85=A8=E3=80=81=E9=AB=98=E5=BC=B9=E6=80=A7?=
=?UTF-8?q?=E3=80=81=E9=AB=98=E6=99=BA=E8=83=BD=E3=80=81=E6=98=93=E9=83=A8?=
=?UTF-8?q?=E7=BD=B2=E3=80=81=E6=98=93=E8=BF=81=E7=A7=BB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
https://github.com/Tencent/APIJSON/issues/795
---
APIJSONORM/pom.xml | 2 +-
APIJSONORM/src/main/java/apijson/Log.java | 2 +-
.../src/main/java/apijson/orm/AbstractSQLConfig.java | 9 +++++++++
APIJSONORM/src/main/java/apijson/orm/SQLConfig.java | 2 ++
4 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/APIJSONORM/pom.xml b/APIJSONORM/pom.xml
index e19551a17..2f71df253 100644
--- a/APIJSONORM/pom.xml
+++ b/APIJSONORM/pom.xml
@@ -5,7 +5,7 @@
com.github.Tencent
APIJSON
- 7.4.2
+ 7.5.0
jar
APIJSONORM
diff --git a/APIJSONORM/src/main/java/apijson/Log.java b/APIJSONORM/src/main/java/apijson/Log.java
index 1c0b97a5d..e9315e224 100755
--- a/APIJSONORM/src/main/java/apijson/Log.java
+++ b/APIJSONORM/src/main/java/apijson/Log.java
@@ -14,7 +14,7 @@ public class Log {
public static boolean DEBUG = true;
- public static final String VERSION = "7.4.2";
+ public static final String VERSION = "7.5.0";
public static final String KEY_SYSTEM_INFO_DIVIDER = "\n---|-----APIJSON SYSTEM INFO-----|---\n";
public static final String OS_NAME;
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
index 5867b648c..573ee0b1e 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
@@ -200,6 +200,7 @@ public abstract class AbstractSQLConfig implements SQLConfig(); // 保证顺序,避免配置冲突等意外情况
@@ -1322,6 +1323,14 @@ public static boolean isSurrealDB(String db) {
return DATABASE_SURREALDB.equals(db);
}
+ @Override
+ public boolean isOpenGauss() {
+ return isOpenGauss(getSQLDatabase());
+ }
+ public static boolean isOpenGauss(String db) {
+ return DATABASE_OPENGAUSS.equals(db);
+ }
+
@Override
public String getQuote() { // MongoDB 同时支持 `tbl` 反引号 和 "col" 双引号
if(isElasticsearch() || isIoTDB() || isSurrealDB()) {
diff --git a/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
index 60f2ddcdc..61233313d 100755
--- a/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
@@ -45,6 +45,7 @@ public interface SQLConfig {
String DATABASE_SQLITE = "SQLITE"; // https://www.sqlite.org
String DATABASE_DUCKDB = "DUCKDB"; // https://duckdb.org
String DATABASE_SURREALDB = "SURREALDB"; // https://surrealdb.com
+ String DATABASE_OPENGAUSS = "OPENGAUSS"; // https://surrealdb.com
String DATABASE_MQ = "MQ"; //
@@ -101,6 +102,7 @@ public interface SQLConfig {
boolean isSQLite();
boolean isDuckDB();
boolean isSurrealDB();
+ boolean isOpenGauss();
// 暂时只兼容以上几种
From a1e4085407939ffb2872ff5ebdb8704ddf48aaf9 Mon Sep 17 00:00:00 2001
From: TommyLemon <1184482681@qq.com>
Date: Sun, 9 Feb 2025 17:32:48 +0800
Subject: [PATCH 031/122] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=8D=8E=E4=B8=BA=20?=
=?UTF-8?q?openGauss,=20=E6=B8=85=E5=8D=8E=20IoTDB,=20DuckDB,=20SurrealDB,?=
=?UTF-8?q?=20Kingbase=20=E7=9A=84=E6=94=AF=E6=8C=81=E7=89=88=E6=9C=AC?=
=?UTF-8?q?=E5=8F=8A=E5=BF=AB=E6=8D=B7=E5=85=A5=E5=8F=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
https://github.com/Tencent/APIJSON?tab=readme-ov-file#--apijson
---
README.md | 28 +++++++++++++++++-----------
1 file changed, 17 insertions(+), 11 deletions(-)
diff --git a/README.md b/README.md
index 5ccf60161..e373f91b5 100644
--- a/README.md
+++ b/README.md
@@ -20,25 +20,31 @@ This source code is licensed under the Apache License Version 2.0
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
From 7fe5c0701bd21ded3133a8c55cfa1b67e7dee64e Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sat, 15 Feb 2025 22:41:25 +0800
Subject: [PATCH 032/122] =?UTF-8?q?=E6=89=93=E5=8C=85=E7=94=A8=E7=9A=84=20?=
=?UTF-8?q?JDK=2017=20=E6=94=B9=E4=B8=BA=201.8=EF=BC=8C=E5=85=BC=E5=AE=B9?=
=?UTF-8?q?=E4=BD=8E=E7=89=88=E6=9C=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 1 +
APIJSONORM/jitpack.yml | 6 ------
APIJSONORM/pom.xml | 12 ++++++------
APIJSONORM/src/main/java/apijson/Log.java | 2 +-
.../src/main/java/apijson/orm/AbstractParser.java | 2 +-
5 files changed, 9 insertions(+), 14 deletions(-)
delete mode 100644 APIJSONORM/jitpack.yml
diff --git a/.gitignore b/.gitignore
index f4b1dd878..a06bbd0a8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,3 +35,4 @@ build/
### VS Code ###
.vscode/
APIJSONORM/bin
+*.DS_Store
diff --git a/APIJSONORM/jitpack.yml b/APIJSONORM/jitpack.yml
deleted file mode 100644
index 9e42c425a..000000000
--- a/APIJSONORM/jitpack.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-jdk:
- - openjdk17
-
-before_install:
- - sdk install java 17.0.6-open
- - sdk use java 17.0.6-open
diff --git a/APIJSONORM/pom.xml b/APIJSONORM/pom.xml
index 2f71df253..30a3f9444 100644
--- a/APIJSONORM/pom.xml
+++ b/APIJSONORM/pom.xml
@@ -5,7 +5,7 @@
com.github.Tencent
APIJSON
- 7.5.0
+ 7.5.5
jar
APIJSONORM
@@ -14,10 +14,10 @@
UTF-8
UTF-8
- 17
+ 1.8
UTF-8
- 17
- 17
+ 1.8
+ 1.8
@@ -35,8 +35,8 @@
maven-compiler-plugin
3.12.1
- 17
- 17
+ 1.8
+ 1.8
diff --git a/APIJSONORM/src/main/java/apijson/Log.java b/APIJSONORM/src/main/java/apijson/Log.java
index e9315e224..6183afea8 100755
--- a/APIJSONORM/src/main/java/apijson/Log.java
+++ b/APIJSONORM/src/main/java/apijson/Log.java
@@ -14,7 +14,7 @@ public class Log {
public static boolean DEBUG = true;
- public static final String VERSION = "7.5.0";
+ public static final String VERSION = "7.5.5";
public static final String KEY_SYSTEM_INFO_DIVIDER = "\n---|-----APIJSON SYSTEM INFO-----|---\n";
public static final String OS_NAME;
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
index 54eafe97a..277893eb9 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
@@ -1981,7 +1981,7 @@ public Object getValueByPath(String valuePath) {
*/
public static String getDecodedKey(String key) {
try {
- return URLDecoder.decode(key, StandardCharsets.UTF_8);
+ return URLDecoder.decode(key, StringUtil.UTF_8);
} catch (Throwable e) {
return key;
}
From f82c1de346e8da030d9f7a5cee262a20f0a81992 Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sat, 15 Feb 2025 22:54:03 +0800
Subject: [PATCH 033/122] =?UTF-8?q?=E7=A7=BB=E9=99=A4=E6=8C=87=E5=AE=9A=20?=
=?UTF-8?q?JDK=2017=20=E6=89=93=E5=8C=85=E7=9A=84=20jitpack.yml?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
jitpack.yml | 6 ------
1 file changed, 6 deletions(-)
delete mode 100644 jitpack.yml
diff --git a/jitpack.yml b/jitpack.yml
deleted file mode 100644
index 9e42c425a..000000000
--- a/jitpack.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-jdk:
- - openjdk17
-
-before_install:
- - sdk install java 17.0.6-open
- - sdk use java 17.0.6-open
From a4108de1a865765d2f4a5a269212c554bf6547d5 Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sat, 22 Feb 2025 01:19:36 +0800
Subject: [PATCH 034/122] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20@catalog=20?=
=?UTF-8?q?=E6=8C=87=E5=AE=9A=E6=95=B0=E6=8D=AE=E5=BA=93=E7=9B=AE=E5=BD=95?=
=?UTF-8?q?=EF=BC=8C=E5=AE=8C=E5=96=84=20@namespace=20=E5=92=8C=20@catalog?=
=?UTF-8?q?=20=E5=85=A8=E5=B1=80=E5=85=B3=E9=94=AE=E8=AF=8D=E5=8F=8A=20JOI?=
=?UTF-8?q?N=20=E5=A4=84=E7=90=86=EF=BC=8C=E4=BC=98=E5=8C=96=E4=BB=A3?=
=?UTF-8?q?=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
APIJSONORM/pom.xml | 2 +-
.../src/main/java/apijson/JSONObject.java | 13 +-
.../apijson/orm/AbstractObjectParser.java | 40 +++--
.../main/java/apijson/orm/AbstractParser.java | 56 +++++--
.../java/apijson/orm/AbstractSQLConfig.java | 139 ++++++++++--------
.../java/apijson/orm/AbstractSQLExecutor.java | 9 +-
.../src/main/java/apijson/orm/Parser.java | 4 +-
.../src/main/java/apijson/orm/SQLConfig.java | 102 +++++++------
8 files changed, 230 insertions(+), 135 deletions(-)
diff --git a/APIJSONORM/pom.xml b/APIJSONORM/pom.xml
index 30a3f9444..475e6ba91 100644
--- a/APIJSONORM/pom.xml
+++ b/APIJSONORM/pom.xml
@@ -5,7 +5,7 @@
com.github.Tencent
APIJSON
- 7.5.5
+ 7.5.6
jar
APIJSONORM
diff --git a/APIJSONORM/src/main/java/apijson/JSONObject.java b/APIJSONORM/src/main/java/apijson/JSONObject.java
index 68fb30c57..6f4359019 100755
--- a/APIJSONORM/src/main/java/apijson/JSONObject.java
+++ b/APIJSONORM/src/main/java/apijson/JSONObject.java
@@ -140,8 +140,9 @@ public JSONObject setUserIdIn(List list) {
public static final String KEY_ROLE = "@role"; //角色,拥有对某些数据的某些操作的权限
public static final String KEY_DATABASE = "@database"; //数据库类型,默认为MySQL
public static final String KEY_DATASOURCE = "@datasource"; //数据源
- public static final String KEY_NAMESPACE = "@namespace"; //命名空间,Table在非默认namespace内时需要声明
- public static final String KEY_SCHEMA = "@schema"; //数据库,Table在非默认schema内时需要声明
+ public static final String KEY_NAMESPACE = "@namespace"; //命名空间,Table 在非默认 namespace 内时需要声明
+ public static final String KEY_CATALOG = "@catalog"; //目录,Table 在非默认 catalog 内时需要声明
+ public static final String KEY_SCHEMA = "@schema"; //数据库,Table 在非默认 schema 内时需要声明
public static final String KEY_EXPLAIN = "@explain"; //分析 true/false
public static final String KEY_CACHE = "@cache"; //缓存 RAM/ROM/ALL
public static final String KEY_COLUMN = "@column"; //查询的Table字段或SQL函数
@@ -172,6 +173,7 @@ public JSONObject setUserIdIn(List list) {
TABLE_KEY_LIST.add(KEY_DATABASE);
TABLE_KEY_LIST.add(KEY_DATASOURCE);
TABLE_KEY_LIST.add(KEY_NAMESPACE);
+ TABLE_KEY_LIST.add(KEY_CATALOG);
TABLE_KEY_LIST.add(KEY_SCHEMA);
TABLE_KEY_LIST.add(KEY_EXPLAIN);
TABLE_KEY_LIST.add(KEY_CACHE);
@@ -269,6 +271,13 @@ public JSONObject setDatasource(String datasource) {
public JSONObject setNamespace(String namespace) {
return puts(KEY_NAMESPACE, namespace);
}
+ /**set catalog where table was puts
+ * @param catalog
+ * @return this
+ */
+ public JSONObject setCatalog(String catalog) {
+ return puts(KEY_CATALOG, catalog);
+ }
/**set schema where table was puts
* @param schema
* @return this
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java
index 1ed3f1716..0a35761cb 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java
@@ -328,22 +328,42 @@ else if (_method == PUT && value instanceof JSONArray && (whereList == null || w
}
if (isTable) {
- if (parser.getGlobalDatabase() != null && sqlRequest.get(JSONRequest.KEY_DATABASE) == null) {
- sqlRequest.put(JSONRequest.KEY_DATABASE, parser.getGlobalDatabase());
+ // parser.onVerifyRole 已处理 globalRole
+
+ String db = parser.getGlobalDatabase();
+ if (db != null) {
+ sqlRequest.putIfAbsent(JSONRequest.KEY_DATABASE, db);
+ }
+
+ String ds = parser.getGlobalDatasource();
+ if (ds != null) {
+ sqlRequest.putIfAbsent(JSONRequest.KEY_DATASOURCE, ds);
+ }
+
+ String ns = parser.getGlobalNamespace();
+ if (ns != null) {
+ sqlRequest.putIfAbsent(JSONRequest.KEY_NAMESPACE, ns);
}
- if (parser.getGlobalSchema() != null && sqlRequest.get(JSONRequest.KEY_SCHEMA) == null) {
- sqlRequest.put(JSONRequest.KEY_SCHEMA, parser.getGlobalSchema());
+
+ String cl = parser.getGlobalCatalog();
+ if (cl != null) {
+ sqlRequest.putIfAbsent(JSONRequest.KEY_CATALOG, cl);
}
- if (parser.getGlobalDatasource() != null && sqlRequest.get(JSONRequest.KEY_DATASOURCE) == null) {
- sqlRequest.put(JSONRequest.KEY_DATASOURCE, parser.getGlobalDatasource());
+
+ String sch = parser.getGlobalSchema();
+ if (sch != null) {
+ sqlRequest.putIfAbsent(JSONRequest.KEY_SCHEMA, sch);
}
if (isSubquery == false) { // 解决 SQL 语法报错,子查询不能 EXPLAIN
- if (parser.getGlobalExplain() != null && sqlRequest.get(JSONRequest.KEY_EXPLAIN) == null) {
- sqlRequest.put(JSONRequest.KEY_EXPLAIN, parser.getGlobalExplain());
+ Boolean exp = parser.getGlobalExplain();
+ if (sch != null) {
+ sqlRequest.putIfAbsent(JSONRequest.KEY_EXPLAIN, exp);
}
- if (parser.getGlobalCache() != null && sqlRequest.get(JSONRequest.KEY_CACHE) == null) {
- sqlRequest.put(JSONRequest.KEY_CACHE, parser.getGlobalCache());
+
+ String cache = parser.getGlobalCache();
+ if (cache != null) {
+ sqlRequest.putIfAbsent(JSONRequest.KEY_CACHE, cache);
}
}
}
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
index 277893eb9..624830374 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
@@ -320,15 +320,7 @@ public AbstractParser setGlobalDatabase(String globalDatabase) {
public String getGlobalDatabase() {
return globalDatabase;
}
- protected String globalSchema;
- public AbstractParser setGlobalSchema(String globalSchema) {
- this.globalSchema = globalSchema;
- return this;
- }
- @Override
- public String getGlobalSchema() {
- return globalSchema;
- }
+
protected String globalDatasource;
@Override
public String getGlobalDatasource() {
@@ -339,6 +331,36 @@ public AbstractParser setGlobalDatasource(String globalDatasource) {
return this;
}
+ protected String globalNamespace;
+ public AbstractParser setGlobalNamespace(String globalNamespace) {
+ this.globalNamespace = globalNamespace;
+ return this;
+ }
+ @Override
+ public String getGlobalNamespace() {
+ return globalNamespace;
+ }
+
+ protected String globalCatalog;
+ public AbstractParser setGlobalCatalog(String globalCatalog) {
+ this.globalCatalog = globalCatalog;
+ return this;
+ }
+ @Override
+ public String getGlobalCatalog() {
+ return globalCatalog;
+ }
+
+ protected String globalSchema;
+ public AbstractParser setGlobalSchema(String globalSchema) {
+ this.globalSchema = globalSchema;
+ return this;
+ }
+ @Override
+ public String getGlobalSchema() {
+ return globalSchema;
+ }
+
protected Boolean globalExplain;
public AbstractParser setGlobalExplain(Boolean globalExplain) {
this.globalExplain = globalExplain;
@@ -508,19 +530,25 @@ public JSONObject parseResponse(JSONObject request) {
}
try {
- setGlobalFormat(requestObject.getBoolean(JSONRequest.KEY_FORMAT));
setGlobalDatabase(requestObject.getString(JSONRequest.KEY_DATABASE));
- setGlobalSchema(requestObject.getString(JSONRequest.KEY_SCHEMA));
setGlobalDatasource(requestObject.getString(JSONRequest.KEY_DATASOURCE));
+ setGlobalNamespace(requestObject.getString(JSONRequest.KEY_NAMESPACE));
+ setGlobalCatalog(requestObject.getString(JSONRequest.KEY_CATALOG));
+ setGlobalSchema(requestObject.getString(JSONRequest.KEY_SCHEMA));
+
setGlobalExplain(requestObject.getBoolean(JSONRequest.KEY_EXPLAIN));
setGlobalCache(requestObject.getString(JSONRequest.KEY_CACHE));
+ setGlobalFormat(requestObject.getBoolean(JSONRequest.KEY_FORMAT));
- requestObject.remove(JSONRequest.KEY_FORMAT);
requestObject.remove(JSONRequest.KEY_DATABASE);
- requestObject.remove(JSONRequest.KEY_SCHEMA);
requestObject.remove(JSONRequest.KEY_DATASOURCE);
+ requestObject.remove(JSONRequest.KEY_NAMESPACE);
+ requestObject.remove(JSONRequest.KEY_CATALOG);
+ requestObject.remove(JSONRequest.KEY_SCHEMA);
+
requestObject.remove(JSONRequest.KEY_EXPLAIN);
requestObject.remove(JSONRequest.KEY_CACHE);
+ requestObject.remove(JSONRequest.KEY_FORMAT);
} catch (Exception e) {
return extendErrorResult(requestObject, e, requestMethod, getRequestURL(), isRoot);
}
@@ -1462,6 +1490,8 @@ else if (childKeys.length == 1 && JSONRequest.isTableKey(childKeys[0])) { //
JOIN_COPY_KEY_LIST = new ArrayList();
JOIN_COPY_KEY_LIST.add(JSONRequest.KEY_ROLE);
JOIN_COPY_KEY_LIST.add(JSONRequest.KEY_DATABASE);
+ JOIN_COPY_KEY_LIST.add(JSONRequest.KEY_NAMESPACE);
+ JOIN_COPY_KEY_LIST.add(JSONRequest.KEY_CATALOG);
JOIN_COPY_KEY_LIST.add(JSONRequest.KEY_SCHEMA);
JOIN_COPY_KEY_LIST.add(JSONRequest.KEY_DATASOURCE);
JOIN_COPY_KEY_LIST.add(JSONRequest.KEY_COLUMN);
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
index 573ee0b1e..aed2efb62 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
@@ -96,6 +96,7 @@ public abstract class AbstractSQLConfig implements SQLConfig setVersion(int version) {
this.version = version;
return this;
}
@@ -870,7 +871,7 @@ public String getTag() {
return tag;
}
@Override
- public AbstractSQLConfig setTag(String tag) {
+ public AbstractSQLConfig setTag(String tag) {
this.tag = tag;
return this;
}
@@ -927,6 +928,7 @@ public String getUserIdKey() {
private boolean distinct = false;
private String database; //表所在的数据库类型
private String namespace; //表所在的命名空间
+ private String catalog; //表所在的目录
private String schema; //表所在的数据库名
private String datasource; //数据源
private String table; //表名
@@ -964,7 +966,7 @@ public String getUserIdKey() {
private String procedure;
- public SQLConfig setProcedure(String procedure) {
+ public AbstractSQLConfig setProcedure(String procedure) {
this.procedure = procedure;
return this;
}
@@ -994,7 +996,7 @@ public RequestMethod getMethod() {
return method;
}
@Override
- public AbstractSQLConfig setMethod(RequestMethod method) {
+ public AbstractSQLConfig setMethod(RequestMethod method) {
this.method = method;
return this;
}
@@ -1003,7 +1005,7 @@ public boolean isPrepared() {
return prepared && ! isMongoDB(); // MongoDB JDBC 还不支持预编译;
}
@Override
- public AbstractSQLConfig setPrepared(boolean prepared) {
+ public AbstractSQLConfig setPrepared(boolean prepared) {
this.prepared = prepared;
return this;
}
@@ -1012,7 +1014,7 @@ public boolean isMain() {
return main;
}
@Override
- public AbstractSQLConfig setMain(boolean main) {
+ public AbstractSQLConfig setMain(boolean main) {
this.main = main;
return this;
}
@@ -1023,7 +1025,7 @@ public Object getId() {
return id;
}
@Override
- public AbstractSQLConfig setId(Object id) {
+ public AbstractSQLConfig setId(Object id) {
this.id = id;
return this;
}
@@ -1033,7 +1035,7 @@ public Object getIdIn() {
return idIn;
}
@Override
- public AbstractSQLConfig setIdIn(Object idIn) {
+ public AbstractSQLConfig setIdIn(Object idIn) {
this.idIn = idIn;
return this;
}
@@ -1044,7 +1046,7 @@ public Object getUserId() {
return userId;
}
@Override
- public AbstractSQLConfig setUserId(Object userId) {
+ public AbstractSQLConfig setUserId(Object userId) {
this.userId = userId;
return this;
}
@@ -1054,7 +1056,7 @@ public Object getUserIdIn() {
return userIdIn;
}
@Override
- public AbstractSQLConfig setUserIdIn(Object userIdIn) {
+ public AbstractSQLConfig setUserIdIn(Object userIdIn) {
this.userIdIn = userIdIn;
return this;
}
@@ -1065,7 +1067,7 @@ public String getRole() {
return role;
}
@Override
- public AbstractSQLConfig setRole(String role) {
+ public AbstractSQLConfig setRole(String role) {
this.role = role;
return this;
}
@@ -1075,7 +1077,7 @@ public boolean isDistinct() {
return distinct;
}
@Override
- public SQLConfig setDistinct(boolean distinct) {
+ public AbstractSQLConfig setDistinct(boolean distinct) {
this.distinct = distinct;
return this;
}
@@ -1085,7 +1087,7 @@ public String getDatabase() {
return database;
}
@Override
- public SQLConfig setDatabase(String database) {
+ public AbstractSQLConfig setDatabase(String database) {
this.database = database;
return this;
}
@@ -1344,26 +1346,39 @@ public String quote(String s) {
return q + s + q;
}
- @Override
- public String getNamespace() {
- return namespace;
- }
-
@Override
public String getSQLNamespace() {
String sch = getNamespace(); // 前端传参 @namespace 优先
return sch == null ? DEFAULT_NAMESPACE : sch; // 最后代码默认兜底配置
}
+ @Override
+ public String getNamespace() {
+ return namespace;
+ }
+
@Override
public AbstractSQLConfig setNamespace(String namespace) {
this.namespace = namespace;
return this;
}
+
@Override
- public String getSchema() {
- return schema;
+ public String getSQLCatalog() {
+ String catalog = getCatalog(); // 前端传参 @catalog 优先
+ return catalog == null ? DEFAULT_CATALOG : catalog; // 最后代码默认兜底配置
+ }
+
+ @Override
+ public String getCatalog() {
+ return catalog;
+ }
+
+ @Override
+ public AbstractSQLConfig setCatalog(String catalog) {
+ this.catalog = catalog;
+ return this;
}
@NotNull
@@ -1393,7 +1408,12 @@ public String getSQLSchema() {
}
@Override
- public AbstractSQLConfig setSchema(String schema) {
+ public String getSchema() {
+ return schema;
+ }
+
+ @Override
+ public AbstractSQLConfig setSchema(String schema) {
if (schema != null) {
AbstractFunctionParser.verifySchema(schema, getTable());
}
@@ -1406,7 +1426,7 @@ public String getDatasource() {
return datasource;
}
@Override
- public SQLConfig setDatasource(String datasource) {
+ public AbstractSQLConfig setDatasource(String datasource) {
this.datasource = datasource;
return this;
}
@@ -1446,7 +1466,7 @@ public String getTablePath() {
+ (isKeyPrefix() ? getAs() + q + getSQLAlias() + q : "");
}
@Override
- public AbstractSQLConfig setTable(String table) { //Table已经在Parser中校验,所以这里不用防SQL注入
+ public AbstractSQLConfig setTable(String table) { //Table已经在Parser中校验,所以这里不用防SQL注入
this.table = table;
return this;
}
@@ -1460,7 +1480,7 @@ public String getAlias() {
return alias;
}
@Override
- public AbstractSQLConfig setAlias(String alias) {
+ public AbstractSQLConfig setAlias(String alias) {
this.alias = alias;
return this;
}
@@ -1477,11 +1497,11 @@ public String getSQLAliasWithQuote() {
public String getGroup() {
return group;
}
- public AbstractSQLConfig setGroup(String... keys) {
+ public AbstractSQLConfig setGroup(String... keys) {
return setGroup(StringUtil.getString(keys));
}
@Override
- public AbstractSQLConfig setGroup(String group) {
+ public AbstractSQLConfig setGroup(String group) {
this.group = group;
return this;
}
@@ -1540,7 +1560,7 @@ public String getHavingCombine() {
return havingCombine;
}
@Override
- public SQLConfig setHavingCombine(String havingCombine) {
+ public AbstractSQLConfig setHavingCombine(String havingCombine) {
this.havingCombine = havingCombine;
return this;
}
@@ -1550,11 +1570,11 @@ public Map getHaving() {
return having;
}
@Override
- public SQLConfig setHaving(Map having) {
+ public AbstractSQLConfig setHaving(Map having) {
this.having = having;
return this;
}
- public AbstractSQLConfig setHaving(String... conditions) {
+ public AbstractSQLConfig setHaving(String... conditions) {
return setHaving(StringUtil.getString(conditions));
}
@@ -1668,11 +1688,11 @@ else if (SQL_FUNCTION_MAP.containsKey(method) == false) {
public String getOrder() {
return order;
}
- public AbstractSQLConfig setOrder(String... conditions) {
+ public AbstractSQLConfig setOrder(String... conditions) {
return setOrder(StringUtil.getString(conditions));
}
@Override
- public AbstractSQLConfig setOrder(String order) {
+ public AbstractSQLConfig setOrder(String order) {
this.order = order;
return this;
}
@@ -1787,7 +1807,7 @@ public Map getKeyMap() {
return keyMap;
}
@Override
- public AbstractSQLConfig setKeyMap(Map keyMap) {
+ public AbstractSQLConfig setKeyMap(Map keyMap) {
this.keyMap = keyMap;
return this;
}
@@ -1797,7 +1817,7 @@ public List getRaw() {
return raw;
}
@Override
- public AbstractSQLConfig setRaw(List raw) {
+ public AbstractSQLConfig setRaw(List raw) {
this.raw = raw;
return this;
}
@@ -1857,7 +1877,7 @@ public List getJson() {
return json;
}
@Override
- public AbstractSQLConfig setJson(List json) {
+ public AbstractSQLConfig setJson(List json) {
this.json = json;
return this;
}
@@ -1868,7 +1888,7 @@ public Subquery getFrom() {
return from;
}
@Override
- public AbstractSQLConfig setFrom(Subquery from) {
+ public AbstractSQLConfig setFrom(Subquery from) {
this.from = from;
return this;
}
@@ -1878,7 +1898,7 @@ public List getColumn() {
return column;
}
@Override
- public AbstractSQLConfig setColumn(List column) {
+ public AbstractSQLConfig setColumn(List column) {
this.column = column;
return this;
}
@@ -2517,7 +2537,7 @@ public String getValuesString() {
return s;
}
@Override
- public AbstractSQLConfig setValues(List> valuess) {
+ public AbstractSQLConfig setValues(List> valuess) {
this.values = valuess;
return this;
}
@@ -2527,7 +2547,7 @@ public Map getContent() {
return content;
}
@Override
- public AbstractSQLConfig setContent(Map content) {
+ public AbstractSQLConfig setContent(Map content) {
this.content = content;
return this;
}
@@ -2537,7 +2557,7 @@ public int getCount() {
return count;
}
@Override
- public AbstractSQLConfig setCount(int count) {
+ public AbstractSQLConfig setCount(int count) {
this.count = count;
return this;
}
@@ -2546,7 +2566,7 @@ public int getPage() {
return page;
}
@Override
- public AbstractSQLConfig setPage(int page) {
+ public AbstractSQLConfig setPage(int page) {
this.page = page;
return this;
}
@@ -2555,7 +2575,7 @@ public int getPosition() {
return position;
}
@Override
- public AbstractSQLConfig setPosition(int position) {
+ public AbstractSQLConfig setPosition(int position) {
this.position = position;
return this;
}
@@ -2565,7 +2585,7 @@ public int getQuery() {
return query;
}
@Override
- public AbstractSQLConfig setQuery(int query) {
+ public AbstractSQLConfig setQuery(int query) {
this.query = query;
return this;
}
@@ -2574,7 +2594,7 @@ public Boolean getCompat() {
return compat;
}
@Override
- public AbstractSQLConfig setCompat(Boolean compat) {
+ public AbstractSQLConfig setCompat(Boolean compat) {
this.compat = compat;
return this;
}
@@ -2584,7 +2604,7 @@ public int getType() {
return type;
}
@Override
- public AbstractSQLConfig setType(int type) {
+ public AbstractSQLConfig setType(int type) {
this.type = type;
return this;
}
@@ -2594,12 +2614,12 @@ public int getCache() {
return cache;
}
@Override
- public AbstractSQLConfig setCache(int cache) {
+ public AbstractSQLConfig setCache(int cache) {
this.cache = cache;
return this;
}
- public AbstractSQLConfig setCache(String cache) {
+ public AbstractSQLConfig setCache(String cache) {
return setCache(getCache(cache));
}
public static int getCache(String cache) {
@@ -2638,7 +2658,7 @@ public boolean isExplain() {
return explain;
}
@Override
- public AbstractSQLConfig setExplain(boolean explain) {
+ public AbstractSQLConfig setExplain(boolean explain) {
this.explain = explain;
return this;
}
@@ -2648,7 +2668,7 @@ public List getJoinList() {
return joinList;
}
@Override
- public SQLConfig setJoinList(List joinList) {
+ public AbstractSQLConfig setJoinList(List joinList) {
this.joinList = joinList;
return this;
}
@@ -2663,7 +2683,7 @@ public boolean isTest() {
return test;
}
@Override
- public AbstractSQLConfig setTest(boolean test) {
+ public AbstractSQLConfig setTest(boolean test) {
this.test = test;
return this;
}
@@ -2761,7 +2781,7 @@ public List getNull() {
return nulls;
}
@Override
- public SQLConfig setNull(List nulls) {
+ public AbstractSQLConfig setNull(List nulls) {
this.nulls = nulls;
return this;
}
@@ -2771,7 +2791,7 @@ public Map getCast() {
return cast;
}
@Override
- public SQLConfig setCast(Map cast) {
+ public AbstractSQLConfig setCast(Map cast) {
this.cast = cast;
return this;
}
@@ -2803,7 +2823,7 @@ public String getCombine() {
return combine;
}
@Override
- public AbstractSQLConfig setCombine(String combine) {
+ public AbstractSQLConfig setCombine(String combine) {
this.combine = combine;
return this;
}
@@ -2822,7 +2842,7 @@ public Map> getCombineMap() {
return combineMap;
}
@Override
- public AbstractSQLConfig setCombineMap(Map> combineMap) {
+ public AbstractSQLConfig setCombineMap(Map> combineMap) {
this.combineMap = combineMap;
return this;
}
@@ -2832,7 +2852,7 @@ public Map getWhere() {
return where;
}
@Override
- public AbstractSQLConfig setWhere(Map where) {
+ public AbstractSQLConfig setWhere(Map where) {
this.where = where;
return this;
}
@@ -2877,7 +2897,7 @@ public Object getWhere(String key, boolean exactMatch) {
return null;
}
@Override
- public AbstractSQLConfig putWhere(String key, Object value, boolean prior) {
+ public AbstractSQLConfig putWhere(String key, Object value, boolean prior) {
if (key != null) {
if (where == null) {
where = new LinkedHashMap();
@@ -3740,7 +3760,7 @@ public List getPreparedValueList() {
return preparedValueList;
}
@Override
- public AbstractSQLConfig setPreparedValueList(List preparedValueList) {
+ public AbstractSQLConfig setPreparedValueList(List preparedValueList) {
this.preparedValueList = preparedValueList;
return this;
}
@@ -4770,7 +4790,7 @@ public boolean isKeyPrefix() {
return keyPrefix;
}
@Override
- public AbstractSQLConfig setKeyPrefix(boolean keyPrefix) {
+ public AbstractSQLConfig setKeyPrefix(boolean keyPrefix) {
this.keyPrefix = keyPrefix;
return this;
}
@@ -5105,6 +5125,7 @@ public static SQLConfig newSQLConfig(RequestMethod method,
String datasource = request.getString(KEY_DATASOURCE);
String namespace = request.getString(KEY_NAMESPACE);
+ String catalog = request.getString(KEY_CATALOG);
String schema = request.getString(KEY_SCHEMA);
SQLConfig config = callback.getSQLConfig(method, database, schema, datasource, table);
@@ -5113,6 +5134,7 @@ public static SQLConfig newSQLConfig(RequestMethod method,
config.setDatabase(database); // 不删,后面表对象还要用的,必须放在 parseJoin 前
config.setDatasource(datasource); // 不删,后面表对象还要用的
config.setNamespace(namespace); // 不删,后面表对象还要用的
+ config.setCatalog(catalog); // 不删,后面表对象还要用的
config.setSchema(schema); // 不删,后面表对象还要用的
if (isProcedure) {
@@ -5274,6 +5296,7 @@ else if (userId instanceof Subquery) {}
request.remove(KEY_DATABASE);
request.remove(KEY_DATASOURCE);
request.remove(KEY_NAMESPACE);
+ request.remove(KEY_CATALOG);
request.remove(KEY_SCHEMA);
request.remove(KEY_FROM);
request.remove(KEY_COLUMN);
@@ -6233,7 +6256,7 @@ public List getWithAsExprPreparedValueList() {
}
@Override
- public AbstractSQLConfig setWithAsExprPreparedValueList(List list) {
+ public AbstractSQLConfig setWithAsExprPreparedValueList(List list) {
this.withAsExprPreparedValueList = list;
return this;
}
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java
index 84b30437e..9cddeb4e1 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java
@@ -1237,7 +1237,7 @@ public PreparedStatement setArgument(@NotNull SQLConfig config, @NotNull Prep
@NotNull
@Override
public Connection getConnection(@NotNull SQLConfig config) throws Exception {
- String connectionKey = config.getDatasource() + "-" + config.getDatabase();
+ String connectionKey = getConnectionKey(config);
connection = connectionMap.get(connectionKey);
if (connection == null || connection.isClosed()) {
Log.i(TAG, "select connection " + (connection == null ? " = null" : ("isClosed = " + connection.isClosed()))) ;
@@ -1255,6 +1255,13 @@ public Connection getConnection(@NotNull SQLConfig config) throws Exception {
return connection;
}
+ public String getConnectionKey(@NotNull SQLConfig config) {
+ return getConnectionKey(config.getNamespace(), config.getCatalog(), config.getDatasource(), config.getDatabase());
+ }
+ public String getConnectionKey(String database, String datasource, String namespace, String catalog) {
+ return database + "-" + datasource + "-" + namespace + "-" + catalog;
+ }
+
//事务处理 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
private int transactionIsolation;
@Override
diff --git a/APIJSONORM/src/main/java/apijson/orm/Parser.java b/APIJSONORM/src/main/java/apijson/orm/Parser.java
index b2da33477..a272fc27a 100755
--- a/APIJSONORM/src/main/java/apijson/orm/Parser.java
+++ b/APIJSONORM/src/main/java/apijson/orm/Parser.java
@@ -112,8 +112,10 @@ JSONObject parseCorrectRequest(RequestMethod method, String tag, int version, St
Boolean getGlobalFormat();
String getGlobalRole();
String getGlobalDatabase();
- String getGlobalSchema();
String getGlobalDatasource();
+ String getGlobalNamespace();
+ String getGlobalCatalog();
+ String getGlobalSchema();
Boolean getGlobalExplain();
String getGlobalCache();
diff --git a/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
index 61233313d..6252bc68a 100755
--- a/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
@@ -60,19 +60,19 @@ public interface SQLConfig {
Parser getParser();
- SQLConfig setParser(Parser parser);
+ SQLConfig setParser(Parser parser);
ObjectParser getObjectParser();
- SQLConfig setObjectParser(ObjectParser objectParser);
+ SQLConfig setObjectParser(ObjectParser objectParser);
int getVersion();
- SQLConfig setVersion(int version);
+ SQLConfig setVersion(int version);
String getTag();
- SQLConfig setTag(String tag);
+ SQLConfig setTag(String tag);
boolean isMySQL();
boolean isPostgreSQL();
@@ -182,72 +182,76 @@ default int[] getDBVersionNums() {
boolean isTest();
- SQLConfig setTest(boolean test);
+ SQLConfig setTest(boolean test);
int getType();
- SQLConfig setType(int type);
+ SQLConfig setType(int type);
int getCount();
- SQLConfig setCount(int count);
+ SQLConfig setCount(int count);
int getPage();
- SQLConfig setPage(int page);
+ SQLConfig setPage(int page);
int getQuery();
- SQLConfig setQuery(int query);
+ SQLConfig setQuery(int query);
Boolean getCompat();
- SQLConfig setCompat(Boolean compat);
+ SQLConfig setCompat(Boolean compat);
int getPosition();
- SQLConfig setPosition(int position);
+ SQLConfig setPosition(int position);
int getCache();
- SQLConfig setCache(int cache);
+ SQLConfig setCache(int cache);
boolean isExplain();
- SQLConfig setExplain(boolean explain);
+ SQLConfig setExplain(boolean explain);
RequestMethod getMethod();
- SQLConfig setMethod(RequestMethod method);
+ SQLConfig setMethod(RequestMethod method);
Object getId();
- SQLConfig setId(Object id);
+ SQLConfig setId(Object id);
Object getIdIn();
- SQLConfig setIdIn(Object idIn);
+ SQLConfig setIdIn(Object idIn);
Object getUserId();
- SQLConfig setUserId(Object userId);
+ SQLConfig setUserId(Object userId);
Object getUserIdIn();
- SQLConfig setUserIdIn(Object userIdIn);
+ SQLConfig setUserIdIn(Object userIdIn);
String getRole();
- SQLConfig setRole(String role);
+ SQLConfig setRole(String role);
public boolean isDistinct();
- public SQLConfig setDistinct(boolean distinct);
+ public SQLConfig setDistinct(boolean distinct);
String getDatabase();
- SQLConfig setDatabase(String database);
+ SQLConfig setDatabase(String database);
String getSQLNamespace();
String getNamespace();
SQLConfig setNamespace(String namespace);
+ String getSQLCatalog();
+ String getCatalog();
+ SQLConfig setCatalog(String catalog);
+
String getSQLSchema();
String getSchema();
- SQLConfig setSchema(String schema);
+ SQLConfig setSchema(String schema);
String getDatasource();
- SQLConfig setDatasource(String datasource);
+ SQLConfig setDatasource(String datasource);
String getQuote();
List getJson();
- SQLConfig setJson(List json);
+ SQLConfig setJson(List json);
/**请求传进来的Table名
* @return
@@ -255,7 +259,7 @@ default int[] getDBVersionNums() {
*/
String getTable();
- SQLConfig setTable(String table);
+ SQLConfig setTable(String table);
/**数据库里的真实Table名
* 通过 {@link AbstractSQLConfig.TABLE_KEY_MAP} 映射
@@ -266,49 +270,49 @@ default int[] getDBVersionNums() {
String getTablePath();
Map getKeyMap();
- SQLConfig setKeyMap(Map keyMap);
+ SQLConfig setKeyMap(Map keyMap);
List getRaw();
- SQLConfig setRaw(List raw);
+ SQLConfig setRaw(List raw);
Subquery getFrom();
- SQLConfig setFrom(Subquery from);
+ SQLConfig setFrom(Subquery from);
List getColumn();
- SQLConfig setColumn(List column);
+ SQLConfig setColumn(List column);
List> getValues();
- SQLConfig setValues(List> values);
+ SQLConfig setValues(List> values);
Map getContent();
- SQLConfig setContent(Map content);
+ SQLConfig setContent(Map content);
Map> getCombineMap();
- SQLConfig setCombineMap(Map> combineMap);
+ SQLConfig setCombineMap(Map> combineMap);
String getCombine();
- SQLConfig setCombine(String combine);
+ SQLConfig setCombine(String combine);
Map getCast();
- SQLConfig setCast(Map cast);
+ SQLConfig setCast(Map cast);
List getNull();
- SQLConfig setNull(List nulls);
+ SQLConfig setNull(List nulls);
Map getWhere();
- SQLConfig setWhere(Map where);
+ SQLConfig setWhere(Map where);
String getGroup();
- SQLConfig setGroup(String group);
+ SQLConfig setGroup(String group);
Map getHaving();
- SQLConfig setHaving(Map having);
+ SQLConfig setHaving(Map having);
String getHavingCombine();
- SQLConfig setHavingCombine(String havingCombine);
+ SQLConfig setHavingCombine(String havingCombine);
String getOrder();
- SQLConfig setOrder(String order);
+ SQLConfig setOrder(String order);
/**
* exactMatch = false
@@ -327,25 +331,25 @@ default int[] getDBVersionNums() {
* @param value
* @return
*/
- SQLConfig putWhere(String key, Object value, boolean prior);
+ SQLConfig putWhere(String key, Object value, boolean prior);
boolean isPrepared();
- SQLConfig setPrepared(boolean prepared);
+ SQLConfig setPrepared(boolean prepared);
boolean isMain();
- SQLConfig setMain(boolean main);
+ SQLConfig setMain(boolean main);
List getPreparedValueList();
- SQLConfig setPreparedValueList(List preparedValueList);
+ SQLConfig setPreparedValueList(List preparedValueList);
String getAlias();
- SQLConfig setAlias(String alias);
+ SQLConfig setAlias(String alias);
default String getTableKey() {
String alias = getAlias();
@@ -368,24 +372,24 @@ static String getSQLAlias(@NotNull String table, String alias) {
boolean isKeyPrefix();
- SQLConfig setKeyPrefix(boolean keyPrefix);
+ SQLConfig setKeyPrefix(boolean keyPrefix);
List getJoinList();
- SQLConfig setJoinList(List joinList);
+ SQLConfig setJoinList(List joinList);
boolean hasJoin();
String getSubqueryString(Subquery subquery) throws Exception;
- SQLConfig setProcedure(String procedure);
+ SQLConfig setProcedure(String procedure);
List getWithAsExprPreparedValueList();
- SQLConfig setWithAsExprPreparedValueList(List withAsExprePreparedValueList);
+ SQLConfig setWithAsExprPreparedValueList(List withAsExprePreparedValueList);
boolean isFakeDelete();
From 9b9086af8f3f5a9fc0288c015c357abbce4c617b Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sat, 1 Mar 2025 16:28:22 +0800
Subject: [PATCH 035/122] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81=20?=
=?UTF-8?q?CockroachDB-=E4=BA=91=E5=8E=9F=E7=94=9F=E5=88=86=E5=B8=83?=
=?UTF-8?q?=E5=BC=8F=E9=AB=98=E5=8F=AF=E7=94=A8=E8=BD=BB=E6=9D=BE=E6=89=A9?=
=?UTF-8?q?=E5=B1=95=E6=95=B0=E6=8D=AE=E5=BA=93?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
APIJSONORM/pom.xml | 2 +-
APIJSONORM/src/main/java/apijson/Log.java | 2 +-
.../java/apijson/orm/AbstractSQLConfig.java | 29 +++++---
.../java/apijson/orm/AbstractSQLExecutor.java | 2 +-
.../src/main/java/apijson/orm/SQLConfig.java | 16 +++--
.../orm/exception/CommonException.java | 71 +++++++++++++++++--
6 files changed, 100 insertions(+), 22 deletions(-)
diff --git a/APIJSONORM/pom.xml b/APIJSONORM/pom.xml
index 475e6ba91..f3c7bb589 100644
--- a/APIJSONORM/pom.xml
+++ b/APIJSONORM/pom.xml
@@ -5,7 +5,7 @@
com.github.Tencent
APIJSON
- 7.5.6
+ 7.6.0
jar
APIJSONORM
diff --git a/APIJSONORM/src/main/java/apijson/Log.java b/APIJSONORM/src/main/java/apijson/Log.java
index 6183afea8..12fe35cc4 100755
--- a/APIJSONORM/src/main/java/apijson/Log.java
+++ b/APIJSONORM/src/main/java/apijson/Log.java
@@ -14,7 +14,7 @@ public class Log {
public static boolean DEBUG = true;
- public static final String VERSION = "7.5.5";
+ public static final String VERSION = "7.6.0";
public static final String KEY_SYSTEM_INFO_DIVIDER = "\n---|-----APIJSON SYSTEM INFO-----|---\n";
public static final String OS_NAME;
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
index aed2efb62..53d8633ab 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
@@ -95,8 +95,8 @@ public abstract class AbstractSQLConfig implements SQLConfig implements SQLConfig setTable(String table) { //Table已经在Parser中校验,所以这里不用防SQL注入
@@ -3955,7 +3968,7 @@ public String getRegExpString(String key, String column, Object[] values, int ty
*/
@JSONField(serialize = false)
public String getRegExpString(String key, String column, String value, boolean ignoreCase) {
- if (isPostgreSQL() || isInfluxDB()) {
+ if (isPostgreSQL() || isCockroachDB() || isInfluxDB()) {
return getKey(column) + " ~" + (ignoreCase ? "* " : " ") + getValue(key, column, value);
}
if (isOracle() || isDameng() || isKingBase() || (isMySQL() && getDBVersionNums()[0] >= 8)) {
@@ -4281,7 +4294,7 @@ public String getContainString(String key, String column, Object[] childs, int t
}
condition += (i <= 0 ? "" : (Logic.isAnd(type) ? AND : OR));
- if (isPostgreSQL() || isInfluxDB()) {
+ if (isPostgreSQL() || isCockroachDB() || isInfluxDB()) {
condition += (getKey(column) + " @> " + getValue(key, column, newJSONArray(c)));
// operator does not exist: jsonb @> character varying "[" + c + "]");
}
@@ -4987,7 +5000,7 @@ else if (l > 0 && StringUtil.isName(String.valueOf(l))) {
}
else if (rt.endsWith("~")) {
boolean ignoreCase = "*~".equals(rt);
- if (isPostgreSQL() || isInfluxDB()) {
+ if (isPostgreSQL() || isCockroachDB() || isInfluxDB()) {
sql += (first ? ON : AND) + lk + (isNot ? NOT : "") + " ~" + (ignoreCase ? "* " : " ") + rk;
}
else if (isOracle() || isDameng() || isKingBase()) {
@@ -5042,7 +5055,7 @@ else if ("{}".equals(rt) || "<>".equals(rt)) {
String arrKeyPath = isIn ? rk : lk;
String itemKeyPath = isIn ? lk : rk;
- if (isPostgreSQL() || isInfluxDB()) { //operator does not exist: jsonb @> character varying "[" + c + "]");
+ if (isPostgreSQL() || isCockroachDB() || isInfluxDB()) { //operator does not exist: jsonb @> character varying "[" + c + "]");
sql += (first ? ON : AND) + (isNot ? "( " : "") + getCondition(isNot, arrKeyPath
+ " IS NOT NULL AND " + arrKeyPath + " @> " + itemKeyPath) + (isNot ? ") " : "");
}
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java
index 9cddeb4e1..9393f43be 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java
@@ -1190,7 +1190,7 @@ else if (RequestMethod.isGetMethod(config.getMethod(), true)) {
//} else {
// statement = getConnection(config).prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
//}
- if (config.isMySQL() || config.isPostgreSQL() || config.isOracle() || config.isSQLServer() || config.isDb2()) {
+ if (config.isMySQL() || config.isPostgreSQL() || config.isCockroachDB() || config.isOracle() || config.isSQLServer() || config.isDb2()) {
statement = getConnection(config).prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
} else {
statement = getConnection(config).prepareStatement(sql);
diff --git a/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
index 6252bc68a..d70de4b0e 100755
--- a/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
@@ -22,12 +22,13 @@ public interface SQLConfig {
String DATABASE_SQLSERVER = "SQLSERVER"; // https://www.microsoft.com/en-us/sql-server
String DATABASE_ORACLE = "ORACLE"; // https://www.oracle.com/database
String DATABASE_DB2 = "DB2"; // https://www.ibm.com/products/db2
- String DATABASE_MARIADB = "MARIADB"; // https://mariadb.org
- String DATABASE_TIDB = "TIDB"; // https://www.pingcap.com/tidb
- String DATABASE_DAMENG = "DAMENG"; // https://www.dameng.com
- String DATABASE_KINGBASE = "KINGBASE"; // https://www.kingbase.com.cn
- String DATABASE_ELASTICSEARCH = "ELASTICSEARCH"; // https://www.elastic.co/guide/en/elasticsearch/reference/7.4/xpack-sql.html
- String DATABASE_CLICKHOUSE = "CLICKHOUSE"; // https://clickhouse.com
+ String DATABASE_MARIADB = "MARIADB"; // https://mariadb.org
+ String DATABASE_TIDB = "TIDB"; // https://www.pingcap.com/tidb
+ String DATABASE_COCKROACHDB = "COCKROACHDB"; // https://www.cockroachlabs.com
+ String DATABASE_DAMENG = "DAMENG"; // https://www.dameng.com
+ String DATABASE_KINGBASE = "KINGBASE"; // https://www.kingbase.com.cn
+ String DATABASE_ELASTICSEARCH = "ELASTICSEARCH"; // https://www.elastic.co/guide/en/elasticsearch/reference/7.4/xpack-sql.html
+ String DATABASE_CLICKHOUSE = "CLICKHOUSE"; // https://clickhouse.com
String DATABASE_HIVE = "HIVE"; // https://hive.apache.org
String DATABASE_PRESTO = "PRESTO"; // Facebook PrestoDB https://prestodb.io
String DATABASE_TRINO = "TRINO"; // PrestoSQL https://trino.io
@@ -45,7 +46,7 @@ public interface SQLConfig {
String DATABASE_SQLITE = "SQLITE"; // https://www.sqlite.org
String DATABASE_DUCKDB = "DUCKDB"; // https://duckdb.org
String DATABASE_SURREALDB = "SURREALDB"; // https://surrealdb.com
- String DATABASE_OPENGAUSS = "OPENGAUSS"; // https://surrealdb.com
+ String DATABASE_OPENGAUSS = "OPENGAUSS"; // https://opengauss.org
String DATABASE_MQ = "MQ"; //
@@ -81,6 +82,7 @@ public interface SQLConfig {
boolean isDb2();
boolean isMariaDB();
boolean isTiDB();
+ boolean isCockroachDB();
boolean isDameng();
boolean isKingBase();
boolean isElasticsearch();
diff --git a/APIJSONORM/src/main/java/apijson/orm/exception/CommonException.java b/APIJSONORM/src/main/java/apijson/orm/exception/CommonException.java
index fe748b7a1..6dc15129c 100755
--- a/APIJSONORM/src/main/java/apijson/orm/exception/CommonException.java
+++ b/APIJSONORM/src/main/java/apijson/orm/exception/CommonException.java
@@ -147,7 +147,7 @@ public CommonException(Throwable t, String environment) {
}
- public static Exception wrap(Exception e, SQLConfig config) {
+ public static Exception wrap(Exception e, SQLConfig> config) {
if (Log.DEBUG == false && e instanceof SQLException) {
return new SQLException("数据库驱动执行异常SQLException,非 Log.DEBUG 模式下不显示详情,避免泄漏真实模式名、表名等隐私信息", e);
}
@@ -158,23 +158,32 @@ public static Exception wrap(Exception e, SQLConfig config) {
// msg != null && msg.contains(Log.KEY_SYSTEM_INFO_DIVIDER) == false) {
try {
String db = config == null ? AbstractSQLConfig.DEFAULT_DATABASE : (config instanceof AbstractSQLConfig
- ? ((AbstractSQLConfig) config).getSQLDatabase() : config.getDatabase()
+ ? ((AbstractSQLConfig>) config).getSQLDatabase() : config.getDatabase()
);
- String dbVersion = config.getDBVersion();
+ String dbVersion = config == null ? null : config.getDBVersion();
if (StringUtil.isEmpty(dbVersion)) {
dbVersion = "";
}
- if (db != null) {
+ if (db != null || config == null) {
db += " " + dbVersion;
}
else if (config.isMySQL()) {
db = SQLConfig.DATABASE_MYSQL + " " + dbVersion;
}
+ else if (config.isMariaDB()) {
+ db = SQLConfig.DATABASE_MARIADB + " " + dbVersion;
+ }
+ else if (config.isTiDB()) {
+ db = SQLConfig.DATABASE_TIDB + " " + dbVersion;
+ }
else if (config.isPostgreSQL()) {
db = SQLConfig.DATABASE_POSTGRESQL + " " + dbVersion;
}
+ else if (config.isCockroachDB()) {
+ db = SQLConfig.DATABASE_COCKROACHDB + " " + dbVersion;
+ }
else if (config.isSQLServer()) {
db = SQLConfig.DATABASE_SQLSERVER + " " + dbVersion;
}
@@ -184,15 +193,69 @@ else if (config.isOracle()) {
else if (config.isDb2()) {
db = SQLConfig.DATABASE_DB2 + " " + dbVersion;
}
+ else if (config.isDuckDB()) {
+ db = SQLConfig.DATABASE_DUCKDB + " " + dbVersion;
+ }
+ else if (config.isSurrealDB()) {
+ db = SQLConfig.DATABASE_SURREALDB + " " + dbVersion;
+ }
+ else if (config.isOpenGauss()) {
+ db = SQLConfig.DATABASE_OPENGAUSS + " " + dbVersion;
+ }
else if (config.isDameng()) {
db = SQLConfig.DATABASE_DAMENG + " " + dbVersion;
}
+ else if (config.isKingBase()) {
+ db = SQLConfig.DATABASE_KINGBASE + " " + dbVersion;
+ }
+ else if (config.isElasticsearch()) {
+ db = SQLConfig.DATABASE_ELASTICSEARCH + " " + dbVersion;
+ }
else if (config.isClickHouse()) {
db = SQLConfig.DATABASE_CLICKHOUSE + " " + dbVersion;
}
+ else if (config.isMilvus()) {
+ db = SQLConfig.DATABASE_MILVUS + " " + dbVersion;
+ }
+ else if (config.isInfluxDB()) {
+ db = SQLConfig.DATABASE_INFLUXDB + " " + dbVersion;
+ }
else if (config.isTDengine()) {
db = SQLConfig.DATABASE_TDENGINE + " " + dbVersion;
}
+ else if (config.isIoTDB()) {
+ db = SQLConfig.DATABASE_IOTDB + " " + dbVersion;
+ }
+ else if (config.isSQLite()) {
+ db = SQLConfig.DATABASE_SQLITE + " " + dbVersion;
+ }
+ else if (config.isHive()) {
+ db = SQLConfig.DATABASE_HIVE + " " + dbVersion;
+ }
+ else if (config.isPresto()) {
+ db = SQLConfig.DATABASE_PRESTO + " " + dbVersion;
+ }
+ else if (config.isTrino()) {
+ db = SQLConfig.DATABASE_TRINO + " " + dbVersion;
+ }
+ else if (config.isSnowflake()) {
+ db = SQLConfig.DATABASE_SNOWFLAKE + " " + dbVersion;
+ }
+ else if (config.isDatabricks()) {
+ db = SQLConfig.DATABASE_DATABRICKS + " " + dbVersion;
+ }
+ else if (config.isMongoDB()) {
+ db = SQLConfig.DATABASE_MONGODB + " " + dbVersion;
+ }
+ else if (config.isCassandra()) {
+ db = SQLConfig.DATABASE_CASSANDRA + " " + dbVersion;
+ }
+ else if (config.isRedis()) {
+ db = SQLConfig.DATABASE_REDIS + " " + dbVersion;
+ }
+ else if (config.isKafka()) {
+ db = SQLConfig.DATABASE_KAFKA + " " + dbVersion;
+ }
else {
db = "";
}
From bc1035fec2356feb6f0cd81a6bd8f2b98d6a63c8 Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sat, 1 Mar 2025 17:46:11 +0800
Subject: [PATCH 036/122] =?UTF-8?q?=E4=BC=98=E5=8C=96=20SQLConfig=20?=
=?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=BC=A9=E8=BF=9B=EF=BC=8C=E8=A7=A3=E5=86=B3?=
=?UTF-8?q?=E5=9C=A8=20GitHub=20=E4=B8=8A=E5=9B=A0=E4=B8=BA=20tab=20?=
=?UTF-8?q?=E7=BC=A9=E8=BF=9B=E5=92=8C=20IDEA=20=E4=B8=8D=E4=B8=80?=
=?UTF-8?q?=E8=87=B4=E5=AF=BC=E8=87=B4=E4=B8=8A=E4=B8=8B=E6=98=BE=E7=A4=BA?=
=?UTF-8?q?=E6=B2=A1=E5=AF=B9=E9=BD=90?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../src/main/java/apijson/orm/SQLConfig.java | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
index d70de4b0e..e63687976 100755
--- a/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
@@ -113,9 +113,9 @@ public interface SQLConfig {
// boolean isPLSQL();
// boolean isAnsiSQL();
- /**用来给 Table, Column 等系统属性表来绕过 MAX_SQL_COUNT 等限制
- * @return
- */
+ /**用来给 Table, Column 等系统属性表来绕过 MAX_SQL_COUNT 等限制
+ * @return
+ */
boolean limitSQLCount();
/**是否开启 WITH AS 表达式来简化 SQL 和提升性能
@@ -123,11 +123,11 @@ public interface SQLConfig {
*/
boolean isWithAsEnable();
/**允许增删改部分失败
- * @return
- */
- boolean allowPartialUpdateFailed();
+ * @return
+ */
+ boolean allowPartialUpdateFailed();
- @NotNull
+ @NotNull
String getIdKey();
@NotNull
String getUserIdKey();
From de742e729b38a47bfc35b5e811ce53a33b9e7fa0 Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sun, 2 Mar 2025 12:00:24 +0800
Subject: [PATCH 037/122] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81=20?=
=?UTF-8?q?ManticoreSearch-=E6=9B=BF=E4=BB=A3=20Elasticsearch=20=E7=9A=84?=
=?UTF-8?q?=E8=BD=BB=E9=87=8F=E7=BA=A7=E6=90=9C=E7=B4=A2=E5=BC=95=E6=93=8E?=
=?UTF-8?q?=EF=BC=8C=E5=85=BC=E5=AE=B9=20MySQL=20=E5=8D=8F=E8=AE=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
APIJSONORM/pom.xml | 2 +-
APIJSONORM/src/main/java/apijson/Log.java | 2 +-
.../src/main/java/apijson/orm/AbstractSQLConfig.java | 11 ++++++++++-
APIJSONORM/src/main/java/apijson/orm/SQLConfig.java | 2 ++
.../java/apijson/orm/exception/CommonException.java | 3 +++
5 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/APIJSONORM/pom.xml b/APIJSONORM/pom.xml
index f3c7bb589..179373256 100644
--- a/APIJSONORM/pom.xml
+++ b/APIJSONORM/pom.xml
@@ -5,7 +5,7 @@
com.github.Tencent
APIJSON
- 7.6.0
+ 7.7.0
jar
APIJSONORM
diff --git a/APIJSONORM/src/main/java/apijson/Log.java b/APIJSONORM/src/main/java/apijson/Log.java
index 12fe35cc4..6f9aa894c 100755
--- a/APIJSONORM/src/main/java/apijson/Log.java
+++ b/APIJSONORM/src/main/java/apijson/Log.java
@@ -14,7 +14,7 @@ public class Log {
public static boolean DEBUG = true;
- public static final String VERSION = "7.6.0";
+ public static final String VERSION = "7.7.0";
public static final String KEY_SYSTEM_INFO_DIVIDER = "\n---|-----APIJSON SYSTEM INFO-----|---\n";
public static final String OS_NAME;
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
index 53d8633ab..9b901e6cb 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
@@ -185,6 +185,7 @@ public abstract class AbstractSQLConfig implements SQLConfig {
String DATABASE_DAMENG = "DAMENG"; // https://www.dameng.com
String DATABASE_KINGBASE = "KINGBASE"; // https://www.kingbase.com.cn
String DATABASE_ELASTICSEARCH = "ELASTICSEARCH"; // https://www.elastic.co/guide/en/elasticsearch/reference/7.4/xpack-sql.html
+ String DATABASE_MANTICORE = "MANTICORE"; // https://manticoresearch.com
String DATABASE_CLICKHOUSE = "CLICKHOUSE"; // https://clickhouse.com
String DATABASE_HIVE = "HIVE"; // https://hive.apache.org
String DATABASE_PRESTO = "PRESTO"; // Facebook PrestoDB https://prestodb.io
@@ -86,6 +87,7 @@ public interface SQLConfig {
boolean isDameng();
boolean isKingBase();
boolean isElasticsearch();
+ boolean isManticore();
boolean isClickHouse();
boolean isHive();
boolean isPresto();
diff --git a/APIJSONORM/src/main/java/apijson/orm/exception/CommonException.java b/APIJSONORM/src/main/java/apijson/orm/exception/CommonException.java
index 6dc15129c..23055198c 100755
--- a/APIJSONORM/src/main/java/apijson/orm/exception/CommonException.java
+++ b/APIJSONORM/src/main/java/apijson/orm/exception/CommonException.java
@@ -211,6 +211,9 @@ else if (config.isKingBase()) {
else if (config.isElasticsearch()) {
db = SQLConfig.DATABASE_ELASTICSEARCH + " " + dbVersion;
}
+ else if (config.isManticore()) {
+ db = SQLConfig.DATABASE_MANTICORE + " " + dbVersion;
+ }
else if (config.isClickHouse()) {
db = SQLConfig.DATABASE_CLICKHOUSE + " " + dbVersion;
}
From 013441a045b5935bde59f6a54edc73340515f480 Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Mon, 3 Mar 2025 00:35:19 +0800
Subject: [PATCH 038/122] =?UTF-8?q?=E5=8E=BB=E6=8E=89=20ManticoreSearch=20?=
=?UTF-8?q?=E4=B8=8D=E6=94=AF=E6=8C=81=E7=9A=84=20SQL=20=E5=85=B3=E9=94=AE?=
=?UTF-8?q?=E8=AF=8D=20AS?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
index 9b901e6cb..1512a5529 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
@@ -1494,7 +1494,7 @@ public AbstractSQLConfig setTable(String table) { //Table已经在Parser中
}
public String getAs() {
- return isOracle() ? " " : " AS ";
+ return isOracle() || isManticore() ? " " : " AS ";
}
@Override
From 7ff081260e018f2217ba8f84693d4fad3b06601e Mon Sep 17 00:00:00 2001
From: TommyLemon <1184482681@qq.com>
Date: Mon, 3 Mar 2025 00:54:57 +0800
Subject: [PATCH 039/122] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20CockroachDB,=20Man?=
=?UTF-8?q?ticoreSearch,=20PosgGIS=20=E7=9A=84=E6=94=AF=E6=8C=81=E8=AF=B4?=
=?UTF-8?q?=E6=98=8E?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
https://github.com/Tencent/APIJSON#--apijson
---
README.md | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index e373f91b5..1f71bde90 100644
--- a/README.md
+++ b/README.md
@@ -22,6 +22,7 @@ This source code is licensed under the Apache License Version 2.0
+
@@ -30,6 +31,7 @@ This source code is licensed under the Apache License Version 2.0
+
@@ -43,7 +45,8 @@ This source code is licensed under the Apache License Version 2.0
-
+
+
From 54ecd56fc71412a8cf3e1742cbb0b97e122e5fb7 Mon Sep 17 00:00:00 2001
From: TommyLemon <1184482681@qq.com>
Date: Mon, 3 Mar 2025 00:57:12 +0800
Subject: [PATCH 040/122] =?UTF-8?q?=20=E6=96=B0=E5=A2=9E=20CockroachDB,=20?=
=?UTF-8?q?ManticoreSearch,=20PosgGIS=20=E7=9A=84=E6=94=AF=E6=8C=81?=
=?UTF-8?q?=E8=AF=B4=E6=98=8E?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
https://github.com/Tencent/APIJSON#--apijson
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index 1f71bde90..721e0adf6 100644
--- a/README.md
+++ b/README.md
@@ -30,6 +30,7 @@ This source code is licensed under the Apache License Version 2.0
+
From 69573d1d6dfd6101ccfc993b5e4ceb6d1e61de8f Mon Sep 17 00:00:00 2001
From: TommyLemon <1184482681@qq.com>
Date: Mon, 3 Mar 2025 00:59:27 +0800
Subject: [PATCH 041/122] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20CockroachDB,=20Man?=
=?UTF-8?q?ticoreSearch,=20PosgGIS=20=E7=9A=84=E6=94=AF=E6=8C=81=E8=AF=B4?=
=?UTF-8?q?=E6=98=8E?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
https://github.com/Tencent/APIJSON#--apijson
---
README.md | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 721e0adf6..57bed4104 100644
--- a/README.md
+++ b/README.md
@@ -38,6 +38,7 @@ This source code is licensed under the Apache License Version 2.0
+
@@ -47,8 +48,6 @@ This source code is licensed under the Apache License Version 2.0
-
-
From 86fd75a05ea581afac88d8a0bf20ef9453ce591b Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sun, 9 Mar 2025 22:12:51 +0800
Subject: [PATCH 042/122] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81=20?=
=?UTF-8?q?TimescaleDB-=E9=AB=98=E6=80=A7=E8=83=BD=E5=AE=9E=E6=97=B6?=
=?UTF-8?q?=E5=88=86=E6=9E=90=E6=97=B6=E5=BA=8F=E6=95=B0=E6=8D=AE=E5=BA=93?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
APIJSONORM/pom.xml | 2 +-
APIJSONORM/src/main/java/apijson/Log.java | 2 +-
.../src/main/java/apijson/orm/AbstractSQLConfig.java | 9 +++++++++
APIJSONORM/src/main/java/apijson/orm/SQLConfig.java | 2 ++
.../main/java/apijson/orm/exception/CommonException.java | 3 +++
5 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/APIJSONORM/pom.xml b/APIJSONORM/pom.xml
index 179373256..2d0768fff 100644
--- a/APIJSONORM/pom.xml
+++ b/APIJSONORM/pom.xml
@@ -5,7 +5,7 @@
com.github.Tencent
APIJSON
- 7.7.0
+ 7.8.0
jar
APIJSONORM
diff --git a/APIJSONORM/src/main/java/apijson/Log.java b/APIJSONORM/src/main/java/apijson/Log.java
index 6f9aa894c..86c2e61cc 100755
--- a/APIJSONORM/src/main/java/apijson/Log.java
+++ b/APIJSONORM/src/main/java/apijson/Log.java
@@ -14,7 +14,7 @@ public class Log {
public static boolean DEBUG = true;
- public static final String VERSION = "7.7.0";
+ public static final String VERSION = "7.8.0";
public static final String KEY_SYSTEM_INFO_DIVIDER = "\n---|-----APIJSON SYSTEM INFO-----|---\n";
public static final String OS_NAME;
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
index 1512a5529..19446e69e 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
@@ -193,6 +193,7 @@ public abstract class AbstractSQLConfig implements SQLConfig {
String DATABASE_MILVUS = "MILVUS"; // https://milvus.io
String DATABASE_INFLUXDB = "INFLUXDB"; // https://www.influxdata.com/products/influxdb-overview
String DATABASE_TDENGINE = "TDENGINE"; // https://tdengine.com
+ String DATABASE_TIMESCALEDB = "TIMESCALEDB"; // https://www.timescale.com
String DATABASE_IOTDB = "IOTDB"; // https://iotdb.apache.org/zh/UserGuide/latest/API/Programming-JDBC.html
String DATABASE_REDIS = "REDIS"; // https://redisql.com
@@ -98,6 +99,7 @@ public interface SQLConfig {
boolean isMilvus();
boolean isInfluxDB();
boolean isTDengine();
+ boolean isTimescaleDB();
boolean isIoTDB();
boolean isRedis();
boolean isMongoDB();
diff --git a/APIJSONORM/src/main/java/apijson/orm/exception/CommonException.java b/APIJSONORM/src/main/java/apijson/orm/exception/CommonException.java
index 23055198c..9dab4ea16 100755
--- a/APIJSONORM/src/main/java/apijson/orm/exception/CommonException.java
+++ b/APIJSONORM/src/main/java/apijson/orm/exception/CommonException.java
@@ -226,6 +226,9 @@ else if (config.isInfluxDB()) {
else if (config.isTDengine()) {
db = SQLConfig.DATABASE_TDENGINE + " " + dbVersion;
}
+ else if (config.isTimescaleDB()) {
+ db = SQLConfig.DATABASE_TIMESCALEDB + " " + dbVersion;
+ }
else if (config.isIoTDB()) {
db = SQLConfig.DATABASE_IOTDB + " " + dbVersion;
}
From f2f7fe660980b35b854dc196d0551547121b456b Mon Sep 17 00:00:00 2001
From: TommyLemon <1184482681@qq.com>
Date: Sun, 9 Mar 2025 22:36:36 +0800
Subject: [PATCH 043/122] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20TimescaleDB-?=
=?UTF-8?q?=E9=AB=98=E6=80=A7=E8=83=BD=E5=AE=9E=E6=97=B6=E5=88=86=E6=9E=90?=
=?UTF-8?q?=E6=97=B6=E5=BA=8F=E6=95=B0=E6=8D=AE=E5=BA=93=20=E7=9A=84?=
=?UTF-8?q?=E5=BF=AB=E6=8D=B7=E5=85=A5=E5=8F=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
https://github.com/Tencent/APIJSON#--apijson
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index 57bed4104..a5f474067 100644
--- a/README.md
+++ b/README.md
@@ -47,6 +47,7 @@ This source code is licensed under the Apache License Version 2.0
+
From ecb9bb729683e390332c45bd056a2a364451370c Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sat, 15 Mar 2025 20:52:55 +0800
Subject: [PATCH 044/122] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20=E4=BB=A3=E7=A0=81?=
=?UTF-8?q?=E5=AE=89=E5=85=A8=E6=89=AB=E6=8F=8F=E9=85=8D=E7=BD=AE=20yaml?=
=?UTF-8?q?=20=E6=96=87=E4=BB=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
github/Tencent/APIJSON.yml | 13 +++++++++++++
1 file changed, 13 insertions(+)
create mode 100644 github/Tencent/APIJSON.yml
diff --git a/github/Tencent/APIJSON.yml b/github/Tencent/APIJSON.yml
new file mode 100644
index 000000000..e9c40e3e0
--- /dev/null
+++ b/github/Tencent/APIJSON.yml
@@ -0,0 +1,13 @@
+tosr_no:
+
+account_mappings:
+ caohao-go: smallhowcao
+
+opensource_repository_information:
+ tencentopen_url: https://github.com/Tencent/APIJSON
+ tencentopen_name: APIJSON
+ status: ongoing
+ owner: smallhowcao
+ follower: smallhowcao
+ internal_id:
+ internal_url:
From 476f6e2a181fc3f110c92deb9d9f1bef6c6cbf3a Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sat, 15 Mar 2025 21:26:58 +0800
Subject: [PATCH 045/122] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Document-English.md | 28 ++++++++++++++--------------
Document.md | 30 +++++++++++++++---------------
2 files changed, 29 insertions(+), 29 deletions(-)
diff --git a/Document-English.md b/Document-English.md
index 8d1fab8a4..c9a4f2948 100644
--- a/Document-English.md
+++ b/Document-English.md
@@ -4,7 +4,7 @@
Request:
{
"User":{
- }
+ }
}
@@ -44,10 +44,10 @@ Response:
Request:
{
"[]":{
- "count":3, //just get 3 results
- "User":{
- "@column":"id,name" //just get ids and names
- }
+ "count":3, //just get 3 results
+ "User":{
+ "@column":"id,name" //just get ids and names
+ }
}
}
@@ -134,13 +134,13 @@ Response:
Request:
{
"[]":{ //get an array
- "page":0, //pagination
+ "page":0, //pagination
"count":2,
- "Moment":{ //get a Moment
- "content$":"%a%" //filter condition: content contains 'a'
+ "Moment":{ //get a Moment
+ "content$":"%a%" //filter condition: content contains 'a'
},
"User":{
- "id@":"/Moment/userId", //User.id = Moment.userId, short reference path,starts from grandparents path
+ "id@":"/Moment/userId", //User.id = Moment.userId, short reference path,starts from grandparents path
"@column":"id,name,head" //get specified keys with the written order
},
"Comment[]":{ //get a Comment array, and unwrap Comment object
@@ -163,7 +163,7 @@ Response:
"id":15,
"userId":70793,
"date":1486541171000,
- "content":"APIJSON is a JSON Transmission Structure Protocol…",
+ "content":"APIJSON is a JSON Transmission Protocol…",
"praiseUserIdList":[
82055,
82002,
@@ -288,14 +288,14 @@ Response:
### 1. Methods and API endpoints
- Methods | URL | Request | Response
+ Methods | URL | Request | Response
------------ | ------------ | ------------ | ------------
-**GET**: A general way to get data. You can use dev tools to make edits in a web browser. | base_url/get/ | { TableName:{ //Add contiditions here. } } Eg. To get a Moment with `id = 235`: { "Moment":{ "id":235 } } | { TableName:{ ... }, "code":200, "msg":"success" } Eg. { "Moment":{ "id":235, "userId":38710, "content":"APIJSON,let interfaces and documents go to hell !" }, "code":200, "msg":"success" }
+**GET**: A general way to get data. You can use dev tools to make edits in a web browser. | base_url/get/ | { TableName:{ //Add contiditions here. } } Eg. To get a Moment with `id = 235`: { "Moment":{ "id":235 } } | { TableName:{ ... }, "code":200, "msg":"success" } Eg. { "Moment":{ "id":235, "userId":38710, "content":"APIJSON is the real-time coding-free, powerful and secure ORM" }, "code":200, "msg":"success" }
**HEAD**: A general way to get counts. You can use dev tools to make edits in a web browser. | base_url/head/ | { TableName:{ … } } {…} are conditions. Eg. Get the number of Moments posted by the user with `id = 38710`: { "Moment":{ "userId":38710 } } | { TableName:{ "code":200, "msg":"success", "count":10 }, "code":200, "msg":"success" } Eg. { "Moment":{ "code":200, "msg":"success", "count":10 }, "code":200, "msg":"success" }
**GETS**: Get data with high security and confidentiality. Eg. bank accounts, birth date. | base_url/gets/ | You need to add `"tag":tag` with the same level of `Moment:{}`. Others are the same as **GET**. | Same as **GET**.
**HEADS**: Get counts of confidential data(eg. bank account).| base_url/heads/ | You need to add `"tag":tag` with the same level of `Moment:{}`. Others are the same as **HEAD**. | Same as **HEAD**.
-**POST**: Add new data. | base_url/post/ | { TableName:{ … }, "tag":tag } The id in {...} is generated automatically when table is built and can’t be set by the user. Eg. A user with `id = 38710` posts a new Moment: { "Moment":{ "userId":38710, "content":"APIJSON,let interfaces and documents go to hell !" }, "tag":"Moment" } | { TableName:{ "code":200, "msg":"success", "id":38710 }, "code":200, "msg":"success" } Eg. { "Moment":{ "code":200, "msg":"success", "id":120 }, "code":200, "msg":"success" }
-**PUT**: Make changes to a specific item. Only change the part sent to server. | base_url/put/ | { TableName:{ "id":id, … }, "tag":tag } You can also add multiple id as `id{}`. Eg. Make changes to Moment's content with id= 235: { "Moment":{ "id":235, "content":"APIJSON,let interfaces and documents go to hell !" }, "tag":"Moment" } | Same as **POST**.
+**POST**: Add new data. | base_url/post/ | { TableName:{ … }, "tag":tag } The id in {...} is generated automatically when table is built and can’t be set by the user. Eg. A user with `id = 38710` posts a new Moment: { "Moment":{ "userId":38710, "content":"APIJSON is the real-time coding-free, powerful and secure ORM" }, "tag":"Moment" } | { TableName:{ "code":200, "msg":"success", "id":38710 }, "code":200, "msg":"success" } Eg. { "Moment":{ "code":200, "msg":"success", "id":120 }, "code":200, "msg":"success" }
+**PUT**: Make changes to a specific item. Only change the part sent to server. | base_url/put/ | { TableName:{ "id":id, … }, "tag":tag } You can also add multiple id as `id{}`. Eg. Make changes to Moment's content with id= 235: { "Moment":{ "id":235, "content":"APIJSON is the real-time coding-free, powerful and secure ORM" }, "tag":"Moment" } | Same as **POST**.
**DELETE**: Delete data. | base_url/delete/ | { TableName:{ "id":id }, "tag":tag } You can also add multiple id as `id{}`. Or Delete contents with multiple id: { "Comment":{ "id{}":[100,110,120] }, "tag":"Comment[]" } | { TableName:{ "code":200, "msg":"success", "id[]":[100,110,120] "count":3 }, "code":200, "msg":"success" } Eg. { "Comment":{ "code":200, "msg":"success", "id[]":[100,110,120], "count":3 }, "code":200, "msg":"success" }
**Note**:
diff --git a/Document.md b/Document.md
index e20bfbb27..a97f7b823 100644
--- a/Document.md
+++ b/Document.md
@@ -30,7 +30,7 @@ https://github.com/Tencent/APIJSON
{
"User":{
"id":38710
- }
+ }
}
@@ -67,10 +67,10 @@ https://github.com/Tencent/APIJSON
请求:
{
"[]":{
- "count":3, //只要3个
- "User":{
- "@column":"id,name" //只要id,name这两个字段
- }
+ "count":3, //只要3个
+ "User":{
+ "@column":"id,name" //只要id,name这两个字段
+ }
}
}
@@ -156,14 +156,14 @@ https://github.com/Tencent/APIJSON
请求:
{
"[]":{ //请求一个数组
- "page":0, //数组条件
+ "page":0, //数组条件
"count":2,
- "Moment":{ //请求一个名为Moment的对象
- "content$":"%a%" //对象条件,搜索content中包含a的动态
+ "Moment":{ //请求一个名为Moment的对象
+ "content$":"%a%" //对象条件,搜索content中包含a的动态
},
"User":{
- "id@":"/Moment/userId", //User.id = Moment.userId 缺省引用赋值路径,从所处容器的父容器路径开始
- "@column":"id,name,head" //指定返回字段
+ "id@":"/Moment/userId", //User.id = Moment.userId 缺省引用赋值路径,从所处容器的父容器路径开始
+ "@column":"id,name,head" //指定返回字段
},
"Comment[]":{ //请求一个名为Comment的数组,并去除Comment包装
"count":2,
@@ -185,7 +185,7 @@ https://github.com/Tencent/APIJSON
"id":15,
"userId":70793,
"date":1486541171000,
- "content":"APIJSON is a JSON Transmission Structure Protocol…",
+ "content":"APIJSON is a JSON Transmission Protocol…",
"praiseUserIdList":[
82055,
82002,
@@ -378,14 +378,14 @@ https://github.com/Tencent/APIJSON
### 3.1 操作方法
- 方法及说明 | URL | Request | Response
+ 方法及说明 | URL | Request | Response
------------ | ------------ | ------------ | ------------
-GET: 普通获取数据, 可用浏览器调试 | base_url/get/ | { TableName:{ … } } {…}内为限制条件 例如获取一个 id = 235 的 Moment: [{ "Moment":{ "id":235 } }](http://apijson.cn/api/?url=http%3A%2F%2Fapijson.cn%3A8080%2Fget&type=JSON&json={"Moment"%3A{"id"%3A235}}) 后端校验通过后自动解析为 SQL 并执行: `SELECT * FROM Moment WHERE id=235 LIMIT 1` | { TableName:{ ... }, "code":200, "msg":"success" } 例如 { "Moment":{ "id":235, "userId":38710, "content":"APIJSON,let interfaces and documents go to hell !" }, "code":200, "msg":"success" }
+GET: 普通获取数据, 可用浏览器调试 | base_url/get/ | { TableName:{ … } } {…}内为限制条件 例如获取一个 id = 235 的 Moment: [{ "Moment":{ "id":235 } }](http://apijson.cn/api/?url=http%3A%2F%2Fapijson.cn%3A8080%2Fget&type=JSON&json={"Moment"%3A{"id"%3A235}}) 后端校验通过后自动解析为 SQL 并执行: `SELECT * FROM Moment WHERE id=235 LIMIT 1` | { TableName:{ ... }, "code":200, "msg":"success" } 例如 { "Moment":{ "id":235, "userId":38710, "content":"APIJSON is the real-time coding-free, powerful and secure ORM" }, "code":200, "msg":"success" }
HEAD: 普通获取数量, 可用浏览器调试 | base_url/head/ | { TableName:{ … } } {…}内为限制条件 例如获取一个 id = 38710 的 User 所发布的 Moment 总数: [{ "Moment":{ "userId":38710 } }](http://apijson.cn/api/?url=http%3A%2F%2Fapijson.cn%3A8080%2Fhead&type=JSON&json={"Moment"%3A{"userId"%3A38710}}) 后端校验通过后自动解析为 SQL 并执行: `SELECT count(*) FROM Moment WHERE userId=38710 LIMIT 1` | { TableName:{ "code":200, "msg":"success", "count":10 }, "code":200, "msg":"success" } 例如 { "Moment":{ "code":200, "msg":"success", "count":10 }, "code":200, "msg":"success" }
GETS: 安全/私密获取数据, 用于获取钱包等 对安全性要求高的数据 | base_url/gets/ | 最外层加一个 "tag":tag,例如 ["tag":"Privacy"](http://apijson.cn/api/?url=http%3A%2F%2Fapijson.cn%3A8080%2Fgets&type=JSON&json={"tag"%3A"Privacy","Privacy"%3A{"id"%3A82001}}),其它同GET | 同GET
HEADS: 安全/私密获取数量, 用于获取银行卡数量等 对安全性要求高的数据总数 | base_url/heads/ | 最外层加一个 "tag":tag,例如 ["tag":"Verify"](http://apijson.cn/api/?url=http%3A%2F%2Fapijson.cn%3A8080%2Fheads&type=JSON&json={"tag"%3A"Verify","Verify"%3A{"phone"%3A13000082001}}),其它同HEAD | 同HEAD
-POST: 新增数据 | base_url/post/ | 单个: { TableName:{ … }, "tag":tag } {…}中id由后端生成,不能传 例如当前登录用户 38710 发布一个新 Comment: [{ "Comment":{ "momentId":12, "content":"APIJSON,let interfaces and documents go to hell !" }, "tag":"Comment" }](http://apijson.cn/api?url=http%3A%2F%2Fapijson.cn%3A8080%2Fpost&type=JSON&json={"Comment":{"momentId":12,"content":"APIJSON,let%20interfaces%20and%20documents%20go%20to%20hell%20!"},"tag":"Comment"}) 后端校验通过后自动解析为 SQL 并执行: `INSERT INTO Comment(userId,momentId,content) VALUES(38710,12,'APIJSON,let interfaces and documents go to hell !')` 批量: { TableName\[]:\[{ … }, { … } … ], "tag":tag } {…}中id由后端生成,不能传 例如当前登录用户 82001 发布 2 个 Comment: [{ "Comment[]":[{ "momentId":12, "content":"APIJSON,let interfaces and documents go to hell !" }, { "momentId":15, "content":"APIJSON is a JSON transmision protocol." }], "tag":"Comment:[]" }](http://apijson.cn/api?url=http%3A%2F%2Fapijson.cn%3A8080%2Fpost&type=JSON&json={"Comment[]":[{"momentId":12,"content":"APIJSON,let%20interfaces%20and%20documents%20go%20to%20hell%20!"},{"momentId":15,"content":"APIJSON%20is%20a%20JSON%20transmision%20protocol."}],"tag":"Comment:[]"}) 后端校验通过后自动解析为 SQL 并执行: `INSERT INTO Comment(userId,momentId,content) VALUES(82001,12,'APIJSON,let interfaces and documents go to hell !');` `INSERT INTO Comment(userId,momentId,content) VALUES(82001,15,'APIJSON is a JSON transmision protocol.');` | 单个: { TableName:{ "code":200, "msg":"success", "id":38710 }, "code":200, "msg":"success" } 例如 { "Comment":{ "code":200, "msg":"success", "id":120 }, "code":200, "msg":"success" } 批量: { TableName:{ "code":200, "msg":"success", "count":5, "id[]":[1, 2, 3, 4, 5] }, "code":200, "msg":"success" } 例如 { "Comment":{ "code":200, "msg":"success", "count":2, "id[]":\[1, 2] }, "code":200, "msg":"success" }
-PUT: 修改数据, 只修改所传的字段 | base_url/put/ | { TableName:{ "id":id, … }, "tag":tag } {…} 中 id 或 id{} 至少传一个 例如当前登录用户 82001 修改 id = 235 的 Moment 的 content: [{ "Moment":{ "id":235, "content":"APIJSON,let interfaces and documents go to hell !" }, "tag":"Moment" }](http://apijson.cn/api?url=http%3A%2F%2Fapijson.cn%3A8080%2Fput&type=JSON&json={"Moment":{"id":235,"content":"APIJSON,let%20interfaces%20and%20documents%20go%20to%20hell%20!"},"tag":"Moment"}) 后端校验通过后自动解析为 SQL 并执行: `UPDATE Moment SET content='APIJSON,let interfaces and documents go to hell !' WHERE id=235 AND userId=82001 LIMIT 1` 批量除了 id{}:\[] 也可类似批量 POST,只是每个 {...} 里面都必须有 id。 "tag":"Comment[]" 对应对象 "Comment":{"id{}":[1,2,3]},表示指定记录全部统一设置; "tag":"Comment:[]" 多了冒号,对应数组 "Comment[]":[{"id":1},{"id":2},{"id":3}],表示每项单独设置 | 同POST
+POST: 新增数据 | base_url/post/ | 单个: { TableName:{ … }, "tag":tag } {…}中id由后端生成,不能传 例如当前登录用户 38710 发布一个新 Comment: [{ "Comment":{ "momentId":12, "content":"APIJSON is the real-time coding-free, powerful and secure ORM" }, "tag":"Comment" }](http://apijson.cn/api?url=http%3A%2F%2Fapijson.cn%3A8080%2Fpost&type=JSON&json={"Comment":{"momentId":12,"content":"APIJSON%20is%20the%20Real-Time%20coding-free,%20powerful%20and%20secure%20ORM."},"tag":"Comment"}) 后端校验通过后自动解析为 SQL 并执行: `INSERT INTO Comment(userId,momentId,content) VALUES(38710,12,'APIJSON is the real-time coding-free, powerful and secure ORM')` 批量: { TableName\[]:\[{ … }, { … } … ], "tag":tag } {…}中id由后端生成,不能传 例如当前登录用户 82001 发布 2 个 Comment: [{ "Comment[]":[{ "momentId":12, "content":"APIJSON is the real-time coding-free, powerful and secure ORM" }, { "momentId":15, "content":"APIJSON is a JSON transmision protocol." }], "tag":"Comment:[]" }](http://apijson.cn/api?url=http%3A%2F%2Fapijson.cn%3A8080%2Fpost&type=JSON&json={"Comment[]":[{"momentId":12,"content":"APIJSON%20is%20the%20Real-Time%20coding-free,%20powerful%20and%20secure%20ORM."},{"momentId":15,"content":"APIJSON%20is%20a%20JSON%20transmision%20protocol."}],"tag":"Comment:[]"}) 后端校验通过后自动解析为 SQL 并执行: `INSERT INTO Comment(userId,momentId,content) VALUES(82001,12,'APIJSON is the real-time coding-free, powerful and secure ORM');` `INSERT INTO Comment(userId,momentId,content) VALUES(82001,15,'APIJSON is a JSON transmision protocol.');` | 单个: { TableName:{ "code":200, "msg":"success", "id":38710 }, "code":200, "msg":"success" } 例如 { "Comment":{ "code":200, "msg":"success", "id":120 }, "code":200, "msg":"success" } 批量: { TableName:{ "code":200, "msg":"success", "count":5, "id[]":[1, 2, 3, 4, 5] }, "code":200, "msg":"success" } 例如 { "Comment":{ "code":200, "msg":"success", "count":2, "id[]":\[1, 2] }, "code":200, "msg":"success" }
+PUT: 修改数据, 只修改所传的字段 | base_url/put/ | { TableName:{ "id":id, … }, "tag":tag } {…} 中 id 或 id{} 至少传一个 例如当前登录用户 82001 修改 id = 235 的 Moment 的 content: [{ "Moment":{ "id":235, "content":"APIJSON is the real-time coding-free, powerful and secure ORM" }, "tag":"Moment" }](http://apijson.cn/api?url=http%3A%2F%2Fapijson.cn%3A8080%2Fput&type=JSON&json={"Moment":{"id":235,"content":"APIJSON%20is%20the%20Real-Time%20coding-free,%20powerful%20and%20secure%20ORM."},"tag":"Moment"}) 后端校验通过后自动解析为 SQL 并执行: `UPDATE Moment SET content='APIJSON is the real-time coding-free, powerful and secure ORM' WHERE id=235 AND userId=82001 LIMIT 1` 批量除了 id{}:\[] 也可类似批量 POST,只是每个 {...} 里面都必须有 id。 "tag":"Comment[]" 对应对象 "Comment":{"id{}":[1,2,3]},表示指定记录全部统一设置; "tag":"Comment:[]" 多了冒号,对应数组 "Comment[]":[{"id":1},{"id":2},{"id":3}],表示每项单独设置 | 同POST
DELETE: 删除数据 | base_url/delete/ | { TableName:{ "id":id }, "tag":tag } {…} 中 id 或 id{} 至少传一个,一般只传 id 或 id{} 例如当前登录用户 82001 批量删除 id = 100,110,120 的 Comment: [{ "Comment":{ "id{}":[100,110,120] }, "tag":"Comment[]" }](http://apijson.cn/api?url=http%3A%2F%2Fapijson.cn%3A8080%2Fdelete&type=JSON&json={"Comment":{"id{}":[100,110,120]},"tag":"Comment[]"}) 后端校验通过后自动解析为 SQL 并执行: `DELETE FROM Comment WHERE id IN(100,110,120) AND userId=82001 LIMIT 3` | { TableName:{ "code":200, "msg":"success", "id[]":[100,110,120] "count":3 }, "code":200, "msg":"success" } 例如 { "Comment":{ "code":200, "msg":"success", "id[]":[100,110,120], "count":3 }, "code":200, "msg":"success" }
以上接口的简单形式: base_url/{method}/{tag} | GET: 普通获取数据 base_url/get/{tag} HEAD: 普通获取数量 base_url/head/{tag} GETS: 安全/私密获取数据 base_url/gets/{tag} HEADS: 安全/私密获取数量 base_url/heads/{tag} POST: 新增数据 base_url/post/{tag} PUT: 修改数据 base_url/put/{tag} DELETE: 删除数据 base_url/delete/{tag} | 例如安全/私密获取一个 id = 82001 的 Privacy: [base_url/gets/Privacy/ {"id":82001}](http://apijson.cn/api/?url=http%3A%2F%2Fapijson.cn%3A8080%2Fgets%2FPrivacy&type=JSON&json={"id"%3A82001}) 相当于 [base_url/gets/ {"tag":"Privacy", "Privacy":{"id":82001}}](http://apijson.cn/api/?url=http%3A%2F%2Fapijson.cn%3A8080%2Fgets&type=JSON&json={"tag"%3A"Privacy","Privacy"%3A{"id"%3A82001}}) 例如批量修改 id = 114, 124 的 Comment 的 content: [base_url/put/Comemnt[]/ { "id{}":[114,124], "content":"test multi put" }](http://apijson.cn/api?url=http%3A%2F%2Fapijson.cn%3A8080%2Fput%2FComment[]&type=JSON&json={"id{}"%3A[114,124],"content"%3A"test%20multi%20put"}) 相当于 [base_url/put/ { "tag":"Comment[]", "Comment":{ "id{}":[114,124], "content":"test multi put" } }](http://apijson.cn/api?url=http%3A%2F%2Fapijson.cn%3A8080%2Fput&type=JSON&json={"tag"%3A"Comment[]","Comment"%3A{"id{}"%3A[114,124],"content"%3A"test%20multi%20put"}}) | 同以上对应的方法
From 41be0a8ddc4fee5f61bb6b0ccfe43341f23046e6 Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sat, 15 Mar 2025 21:38:11 +0800
Subject: [PATCH 046/122] Delete APIJSON.yml
---
github/Tencent/APIJSON.yml | 13 -------------
1 file changed, 13 deletions(-)
delete mode 100644 github/Tencent/APIJSON.yml
diff --git a/github/Tencent/APIJSON.yml b/github/Tencent/APIJSON.yml
deleted file mode 100644
index e9c40e3e0..000000000
--- a/github/Tencent/APIJSON.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-tosr_no:
-
-account_mappings:
- caohao-go: smallhowcao
-
-opensource_repository_information:
- tencentopen_url: https://github.com/Tencent/APIJSON
- tencentopen_name: APIJSON
- status: ongoing
- owner: smallhowcao
- follower: smallhowcao
- internal_id:
- internal_url:
From 632c806d630b481a8c33b703b32fa64b652f2c81 Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sat, 15 Mar 2025 22:00:26 +0800
Subject: [PATCH 047/122] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README-English.md | 20 ++++++++++----------
README.md | 34 +++++++++++++++++-----------------
2 files changed, 27 insertions(+), 27 deletions(-)
diff --git a/README-English.md b/README-English.md
index 9329faf0e..beea69d6c 100644
--- a/README-English.md
+++ b/README-English.md
@@ -17,8 +17,8 @@ This source code is licensed under the Apache License Version 2.0
-
-
+
+
@@ -42,21 +42,21 @@ This source code is licensed under the Apache License Version 2.0
-
-
-
+
+
+
-
-
+
+
-
-
+
+
@@ -179,7 +179,7 @@ See https://github.com/APIJSON/APIJSON-Demo/blob/master/APIJSON-Java-Server/READ
##
3. Frontend usage
You can skip this step and use [APIAuto](https://github.com/TommyLemon/APIAuto) or download App.
-See [Android](https://github.com/APIJSON/APIJSON-Demo/blob/master/APIJSON-Android/README-English.md), [iOS](https://github.com/APIJSON/APIJSON-Demo/blob/master/APIJSON-iOS/README-English.md) or [JavaScript](https://github.com/APIJSON/APIJSON-Demo/blob/master/APIJSON-JavaScript/README-English.md)
+See [Android](https://github.com/APIJSON/APIJSON-Demo/blob/master/APIJSON-Android/README-English.md), [iOS](https://github.com/APIJSON/APIJSON-Demo/blob/master/APIJSON-iOS/README-English.md) or [JavaScript](https://github.com/APIJSON/APIJSON-Demo/blob/master/APIJSON-JavaScript/README-English.md)
### Download App
diff --git a/README.md b/README.md
index a5f474067..67610d168 100644
--- a/README.md
+++ b/README.md
@@ -10,14 +10,14 @@ This source code is licensed under the Apache License Version 2.0
English
- 通用文档
+ 通用文档
视频教程
测试用例
-
-
+
+
@@ -54,22 +54,22 @@ This source code is licensed under the Apache License Version 2.0
-
-
-
+
+
+
-
-
-
+
+
+
-
-
+
+
@@ -189,16 +189,16 @@ https://github.com/Tencent/APIJSON/wiki
* **解决十大痛点** (可帮前后端开发大幅提振开发效率、强力杜绝联调扯皮、巧妙规避文档缺陷、非常节省流量带宽)
* **开发提速很大** (CRUD 零代码热更新全自动,APIJSONBoot 对比 SSM、SSH 等保守估计可提速 20 倍以上)
-* **腾讯官方开源** (使用 GitHub、Gitee、工蜂 等平台的官方账号开源,微信公众号、腾讯云+社区 等官方公告)
-* **社区影响力大** (GitHub 17K+ Star 在 400W Java 项目排名前 100,远超 FLAG, BAT 等国内外绝大部分开源项目)
+* **腾讯官方开源** (使用 GitHub、Gitee、工蜂 等平台的官方账号开源,微信公众号、腾讯云+社区 等官方公告)
+* **社区影响力大** (GitHub 17K+ Star 在 400W Java 项目排名前 100,远超 FLAG, BAT 等国内外绝大部分开源项目)
* **各项荣誉成就** (腾讯内外 5 个奖项、腾讯开源前六、腾讯后端 Star 第一、Trending 日周月榜大满贯 等)
* **多样用户案例** (腾讯内有互娱、音乐、微信、云与智慧,外部有华为、华能、百度、快手、中兴、圆通、传音等)
* **适用场景广泛** (社交聊天、阅读资讯、影音娱乐、办公学习 等各种 App、网站、小程序、公众号 等非金融类项目)
* **周边生态丰富** (Android, iOS, Web 等各种 Demo、继承 JSON 的海量生态、零代码 接口测试 和 单元测试 工具等)
-* **文档视频齐全** (项目介绍、快速上手、安装部署 等后端、前端、客户端的 图文解说、视频教程、代码注释 等)
+* **文档视频齐全** (项目介绍、快速上手、安装部署 等后端、前端、客户端的 图文解说、视频教程、代码注释 等)
* **功能丰富强大** (增删改查、分页排序、分组聚合、各种条件、各种 JOIN、各种子查询、跨库连表 等零代码实现)
* **使用安全简单** (自动增删改查、自动生成文档、自动管理版本、自动控制权限、自动校验参数、自动防 SQL 注入)
-* **灵活定制业务** (在后端编写 远程函数,可以拿到 session、version、当前 JSON 对象 等,然后自定义处理)
+* **灵活定制业务** (在后端编写 远程函数,可以拿到 session、version、当前 JSON 对象 等,然后自定义处理)
* **高质可靠代码** (代码严谨规范,蚂蚁集团源伞 Pinpoint 代码扫描分析报告平均每行代码 Bug 率低至 0.15%)
* **兼容各种项目** (协议不限 HTTP,与其它库无冲突,对各类 Web 框架集成友好且提供 SpringBoot, JFinal 的示例)
* **工程轻量小巧** (仅依赖 fastjson,Jar 仅 280KB,Java 文件仅 59 个共 13719 行代码,例如 APIJSONORM 4.3.1)
@@ -276,7 +276,7 @@ https://github.com/Tencent/APIJSON/issues/36
#### 2.前端上手
可以跳过这个步骤,直接使用 [APIAuto-机器学习HTTP接口工具](https://github.com/TommyLemon/APIAuto) 或 下载客户端App。
-见 [Android](https://github.com/APIJSON/APIJSON-Demo/tree/master/APIJSON-Android) 或 [iOS](https://github.com/APIJSON/APIJSON-Demo/tree/master/APIJSON-iOS) 或 [JavaScript](https://github.com/APIJSON/APIJSON-Demo/tree/master/APIJSON-JavaScript)
+见 [Android](https://github.com/APIJSON/APIJSON-Demo/tree/master/APIJSON-Android) 或 [iOS](https://github.com/APIJSON/APIJSON-Demo/tree/master/APIJSON-iOS) 或 [JavaScript](https://github.com/APIJSON/APIJSON-Demo/tree/master/APIJSON-JavaScript)
### 下载客户端 App
@@ -546,7 +546,7 @@ Issue/问卷 一般解答顺序:贡献者 > 帮助他人的用户 > 提供任
### 相关推荐
-[APIJSON, 让接口和文档见鬼去吧!](https://my.oschina.net/tommylemon/blog/805459)
+[APIJSON, 接口和文档的终结者!](https://my.oschina.net/tommylemon/blog/805459)
[腾讯业务百万数据 6s 响应,APIJSON 性能优化背后的故事](https://my.oschina.net/tommylemon/blog/5375645)
From a1caa259157632b981d7c274da7ab6859a53652f Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sun, 16 Mar 2025 00:31:08 +0800
Subject: [PATCH 048/122] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81=20?=
=?UTF-8?q?QuestDB=20=E5=B9=B6=E6=94=AF=E6=8C=81=20~=20ASOF=20JOIN?=
=?UTF-8?q?=EF=BC=8CSAMPLE=20BY,=20LATEST=20ON,=20PARTITION=20BY,=20FILL(L?=
=?UTF-8?q?INEAR)=20=E7=AD=89=E5=85=B3=E9=94=AE=E8=AF=8D=E5=8F=8A=E4=B8=8E?=
=?UTF-8?q?=E8=AF=AD=E6=B3=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
APIJSONORM/pom.xml | 2 +-
.../src/main/java/apijson/JSONObject.java | 68 ++++
APIJSONORM/src/main/java/apijson/Log.java | 2 +-
.../main/java/apijson/orm/AbstractParser.java | 4 +
.../java/apijson/orm/AbstractSQLConfig.java | 377 ++++++++++++++++--
.../java/apijson/orm/AbstractSQLExecutor.java | 12 +-
.../src/main/java/apijson/orm/Join.java | 5 +-
.../src/main/java/apijson/orm/SQLConfig.java | 18 +
.../orm/exception/CommonException.java | 3 +
9 files changed, 461 insertions(+), 30 deletions(-)
diff --git a/APIJSONORM/pom.xml b/APIJSONORM/pom.xml
index 2d0768fff..2cf436bd5 100644
--- a/APIJSONORM/pom.xml
+++ b/APIJSONORM/pom.xml
@@ -5,7 +5,7 @@
com.github.Tencent
APIJSON
- 7.8.0
+ 7.9.0
jar
APIJSONORM
diff --git a/APIJSONORM/src/main/java/apijson/JSONObject.java b/APIJSONORM/src/main/java/apijson/JSONObject.java
index 6f4359019..c69a03569 100755
--- a/APIJSONORM/src/main/java/apijson/JSONObject.java
+++ b/APIJSONORM/src/main/java/apijson/JSONObject.java
@@ -151,6 +151,10 @@ public JSONObject setUserIdIn(List list) {
public static final String KEY_GROUP = "@group"; //分组方式
public static final String KEY_HAVING = "@having"; //聚合函数条件,一般和@group一起用
public static final String KEY_HAVING_AND = "@having&"; //聚合函数条件,一般和@group一起用
+ public static final String KEY_SAMPLE = "@sample"; //取样方式
+ public static final String KEY_LATEST = "@latest"; //最近方式
+ public static final String KEY_PARTITION = "@partition"; //分区方式
+ public static final String KEY_FILL = "@fill"; //填充方式
public static final String KEY_ORDER = "@order"; //排序方式
public static final String KEY_KEY = "@key"; // key 映射,year:left(date,4);name_tag:(name,tag)
public static final String KEY_RAW = "@raw"; // 自定义原始 SQL 片段
@@ -185,6 +189,10 @@ public JSONObject setUserIdIn(List list) {
TABLE_KEY_LIST.add(KEY_GROUP);
TABLE_KEY_LIST.add(KEY_HAVING);
TABLE_KEY_LIST.add(KEY_HAVING_AND);
+ TABLE_KEY_LIST.add(KEY_SAMPLE);
+ TABLE_KEY_LIST.add(KEY_LATEST);
+ TABLE_KEY_LIST.add(KEY_PARTITION);
+ TABLE_KEY_LIST.add(KEY_FILL);
TABLE_KEY_LIST.add(KEY_ORDER);
TABLE_KEY_LIST.add(KEY_KEY);
TABLE_KEY_LIST.add(KEY_RAW);
@@ -410,6 +418,66 @@ public JSONObject setHaving(String keys, boolean isAnd) {
return puts(isAnd ? KEY_HAVING_AND : KEY_HAVING, keys);
}
+ /**set keys for sample by
+ * @param keys key0, key1, key2 ...
+ * @return {@link #setSample(String)}
+ */
+ public JSONObject setSample(String... keys) {
+ return setSample(StringUtil.getString(keys, true));
+ }
+ /**set keys for sample by
+ * @param keys "key0,key1,key2..."
+ * @return
+ */
+ public JSONObject setSample(String keys) {
+ return puts(KEY_SAMPLE, keys);
+ }
+
+ /**set keys for latest on
+ * @param keys key0, key1, key2 ...
+ * @return {@link #setLatest(String)}
+ */
+ public JSONObject setLatest(String... keys) {
+ return setLatest(StringUtil.getString(keys, true));
+ }
+ /**set keys for latest on
+ * @param keys "key0,key1,key2..."
+ * @return
+ */
+ public JSONObject setLatest(String keys) {
+ return puts(KEY_LATEST, keys);
+ }
+
+ /**set keys for partition by
+ * @param keys key0, key1, key2 ...
+ * @return {@link #setPartition(String)}
+ */
+ public JSONObject setPartition(String... keys) {
+ return setPartition(StringUtil.getString(keys, true));
+ }
+ /**set keys for partition by
+ * @param keys key0, key1, key2 ...
+ * @return
+ */
+ public JSONObject setPartition(String keys) {
+ return puts(KEY_PARTITION, keys);
+ }
+
+ /**set keys for fill(key): fill(null), fill(linear), fill(prev)
+ * @param keys key0, key1, key2 ...
+ * @return {@link #setFill(String)}
+ */
+ public JSONObject setFill(String... keys) {
+ return setFill(StringUtil.getString(keys, true));
+ }
+ /**set keys for fill(key): fill(null), fill(linear), fill(prev)
+ * @param keys key0, key1, key2 ...
+ * @return
+ */
+ public JSONObject setFill(String keys) {
+ return puts(KEY_FILL, keys);
+ }
+
/**set keys for order by
* @param keys key0, key1+, key2- ...
* @return {@link #setOrder(String)}
diff --git a/APIJSONORM/src/main/java/apijson/Log.java b/APIJSONORM/src/main/java/apijson/Log.java
index 86c2e61cc..0916af410 100755
--- a/APIJSONORM/src/main/java/apijson/Log.java
+++ b/APIJSONORM/src/main/java/apijson/Log.java
@@ -14,7 +14,7 @@ public class Log {
public static boolean DEBUG = true;
- public static final String VERSION = "7.8.0";
+ public static final String VERSION = "7.9.0";
public static final String KEY_SYSTEM_INFO_DIVIDER = "\n---|-----APIJSON SYSTEM INFO-----|---\n";
public static final String OS_NAME;
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
index 624830374..fd56b71b9 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
@@ -1501,6 +1501,10 @@ else if (childKeys.length == 1 && JSONRequest.isTableKey(childKeys[0])) { //
JOIN_COPY_KEY_LIST.add(JSONRequest.KEY_GROUP);
JOIN_COPY_KEY_LIST.add(JSONRequest.KEY_HAVING);
JOIN_COPY_KEY_LIST.add(JSONRequest.KEY_HAVING_AND);
+ JOIN_COPY_KEY_LIST.add(JSONRequest.KEY_SAMPLE);
+ JOIN_COPY_KEY_LIST.add(JSONRequest.KEY_LATEST);
+ JOIN_COPY_KEY_LIST.add(JSONRequest.KEY_PARTITION);
+ JOIN_COPY_KEY_LIST.add(JSONRequest.KEY_FILL);
JOIN_COPY_KEY_LIST.add(JSONRequest.KEY_ORDER);
JOIN_COPY_KEY_LIST.add(JSONRequest.KEY_KEY);
JOIN_COPY_KEY_LIST.add(JSONRequest.KEY_RAW);
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
index 19446e69e..e9b6c0a02 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
@@ -194,6 +194,7 @@ public abstract class AbstractSQLConfig implements SQLConfig having; //聚合函数的字符串数组,','分隔
+ private String sample; //取样方式的字符串数组,','分隔
+ private String latest; //最近方式的字符串数组,','分隔
+ private String partition; //分区方式的字符串数组,','分隔
+ private String fill; //填充方式的字符串数组,','分隔
private String order; //排序方式的字符串数组,','分隔
+
private Map keyMap; //字段名映射,支持 name_tag:(name,tag) 多字段 IN,year:left(date,4) 截取日期年份等
private List raw; //需要保留原始 SQL 的字段,','分隔
private List json; //需要转为 JSON 的字段,','分隔
@@ -1103,6 +1109,19 @@ public String getSQLDatabase() {
return db == null ? DEFAULT_DATABASE : db; // "" 表示已设置,不需要用全局默认的 StringUtil.isEmpty(db, false)) {
}
+ @Override
+ public boolean isTSQL() { // 兼容 TSQL 语法
+ return isOracle() || isSQLServer() || isDb2();
+ }
+ @Override
+ public boolean isMSQL() { // 兼容 MySQL 语法,但不一定可以使用它的 JDBC/ODBC
+ return isMySQL() || isTiDB() || isMariaDB() || isSQLite() || isTDengine();
+ }
+ @Override
+ public boolean isPSQL() { // 兼容 PostgreSQL 语法,但不一定可以使用它的 JDBC/ODBC
+ return isPostgreSQL() || isCockroachDB() || isOpenGauss() || isInfluxDB() || isTimescaleDB() || isQuestDB() || isDuckDB();
+ }
+
@Override
public boolean isMySQL() {
return isMySQL(getSQLDatabase());
@@ -1287,6 +1306,14 @@ public static boolean isTimescaleDB(String db) {
return DATABASE_TIMESCALEDB.equals(db);
}
+ @Override
+ public boolean isQuestDB() {
+ return isQuestDB(getSQLDatabase());
+ }
+ public static boolean isQuestDB(String db) {
+ return DATABASE_QUESTDB.equals(db);
+ }
+
public boolean isIoTDB() {
return isIoTDB(getDatabase());
@@ -1487,7 +1514,7 @@ public String getTablePath() {
String q = getQuote();
String ns = isSurrealDB() ? getSQLNamespace() : null;
- String cl = isPostgreSQL() || isCockroachDB() || isOpenGauss() || isDuckDB() ? getSQLCatalog() : null;
+ String cl = isPSQL() ? getSQLCatalog() : null;
String sch = getSQLSchema();
String sqlTable = getSQLTable();
@@ -1715,6 +1742,274 @@ else if (SQL_FUNCTION_MAP.containsKey(method) == false) {
return method + parseSQLExpression(KEY_HAVING, expression.substring(start), containRaw, false, null);
}
+ @Override
+ public String getSample() {
+ return sample;
+ }
+ public AbstractSQLConfig setSample(String... conditions) {
+ return setSample(StringUtil.getString(conditions));
+ }
+ @Override
+ public AbstractSQLConfig setSample(String sample) {
+ this.sample = sample;
+ return this;
+ }
+ @JSONField(serialize = false)
+ public String getSampleString(boolean hasPrefix) {
+ //加上子表的 sample
+ String joinSample = "";
+ if (joinList != null) {
+ boolean first = true;
+ for (Join j : joinList) {
+ if (j.isAppJoin()) {
+ continue;
+ }
+
+ SQLConfig ocfg = j.getOuterConfig();
+ SQLConfig cfg = (ocfg != null && ocfg.getSample() != null) || j.isLeftOrRightJoin() ? ocfg : j.getJoinConfig();
+
+ if (cfg != null) {
+ cfg.setMain(false).setKeyPrefix(true);
+ // if (StringUtil.isEmpty(cfg.getAlias(), true)) {
+ // cfg.setAlias(cfg.getTable());
+ // }
+ String c = ((AbstractSQLConfig) cfg).getSampleString(false);
+
+ if (StringUtil.isEmpty(c, true) == false) {
+ joinSample += (first ? "" : ", ") + c;
+ first = false;
+ }
+ }
+ }
+ }
+
+ String sample = StringUtil.getTrimedString(getSample());
+
+ String[] keys = StringUtil.split(sample);
+ if (keys == null || keys.length <= 0) {
+ return StringUtil.isEmpty(joinSample, true) ? "" : (hasPrefix ? " SAMPLE BY " : "") + joinSample;
+ }
+
+ for (int i = 0; i < keys.length; i++) {
+ String item = keys[i];
+ //if ("fill(null)".equals(item) || "fill(linear)".equals(item) || "fill(prev)".equals(item) || "fill(previous)".equals(item)) {
+ // continue;
+ //}
+
+ String origin = item;
+
+ if (isPrepared()) { //不能通过 ? 来代替,SELECT 'id','name' 返回的就是 id:"id", name:"name",而不是数据库里的值!
+ //这里既不对origin trim,也不对 ASC/DESC ignoreCase,希望前端严格传没有任何空格的字符串过来,减少传输数据量,节约服务器性能
+ if (StringUtil.isNumberOrAlpha(origin) == false) {
+ throw new IllegalArgumentException("预编译模式下 @sample:value 中 " + item + " 不合法! value 里面用 , 分割的"
+ + "每一项必须是 column 且其中 column 必须是 字母或数字组合!并且不要有多余的空格!");
+ }
+ }
+
+ keys[i] = getKey(origin);
+ }
+
+ return (hasPrefix ? " SAMPLE BY " : "") + StringUtil.concat(StringUtil.getString(keys), joinSample, ", ");
+ }
+
+ @Override
+ public String getLatest() {
+ return latest;
+ }
+ public AbstractSQLConfig setLatest(String... conditions) {
+ return setLatest(StringUtil.getString(conditions));
+ }
+ @Override
+ public AbstractSQLConfig setLatest(String latest) {
+ this.latest = latest;
+ return this;
+ }
+ @JSONField(serialize = false)
+ public String getLatestString(boolean hasPrefix) {
+ //加上子表的 latest
+ String joinLatest = "";
+ if (joinList != null) {
+ boolean first = true;
+ for (Join j : joinList) {
+ if (j.isAppJoin()) {
+ continue;
+ }
+
+ SQLConfig ocfg = j.getOuterConfig();
+ SQLConfig cfg = (ocfg != null && ocfg.getLatest() != null) || j.isLeftOrRightJoin() ? ocfg : j.getJoinConfig();
+
+ if (cfg != null) {
+ cfg.setMain(false).setKeyPrefix(true);
+ // if (StringUtil.isEmpty(cfg.getAlias(), true)) {
+ // cfg.setAlias(cfg.getTable());
+ // }
+ String c = ((AbstractSQLConfig) cfg).getLatestString(false);
+
+ if (StringUtil.isEmpty(c, true) == false) {
+ joinLatest += (first ? "" : ", ") + c;
+ first = false;
+ }
+ }
+ }
+ }
+
+ String latest = StringUtil.getTrimedString(getLatest());
+
+ String[] keys = StringUtil.split(latest);
+ if (keys == null || keys.length <= 0) {
+ return StringUtil.isEmpty(joinLatest, true) ? "" : (hasPrefix ? " LATEST ON " : "") + joinLatest;
+ }
+
+ for (int i = 0; i < keys.length; i++) {
+ String item = keys[i];
+ String origin = item;
+
+ if (isPrepared()) { //不能通过 ? 来代替,SELECT 'id','name' 返回的就是 id:"id", name:"name",而不是数据库里的值!
+ //这里既不对origin trim,也不对 ASC/DESC ignoreCase,希望前端严格传没有任何空格的字符串过来,减少传输数据量,节约服务器性能
+ if (StringUtil.isName(origin) == false) {
+ throw new IllegalArgumentException("预编译模式下 @latest:value 中 " + item + " 不合法! value 里面用 , 分割的"
+ + "每一项必须是 column 且其中 column 必须是 英语单词!并且不要有多余的空格!");
+ }
+ }
+
+ keys[i] = getKey(origin);
+ }
+
+ return (hasPrefix ? " LATEST ON " : "") + StringUtil.concat(StringUtil.getString(keys), joinLatest, ", ");
+ }
+
+ @Override
+ public String getPartition() {
+ return partition;
+ }
+ public AbstractSQLConfig setPartition(String... conditions) {
+ return setPartition(StringUtil.getString(conditions));
+ }
+ @Override
+ public AbstractSQLConfig setPartition(String partition) {
+ this.partition = partition;
+ return this;
+ }
+ @JSONField(serialize = false)
+ public String getPartitionString(boolean hasPrefix) {
+ //加上子表的 partition
+ String joinPartition = "";
+ if (joinList != null) {
+ boolean first = true;
+ for (Join j : joinList) {
+ if (j.isAppJoin()) {
+ continue;
+ }
+
+ SQLConfig ocfg = j.getOuterConfig();
+ SQLConfig cfg = (ocfg != null && ocfg.getPartition() != null) || j.isLeftOrRightJoin() ? ocfg : j.getJoinConfig();
+
+ if (cfg != null) {
+ cfg.setMain(false).setKeyPrefix(true);
+ // if (StringUtil.isEmpty(cfg.getAlias(), true)) {
+ // cfg.setAlias(cfg.getTable());
+ // }
+ String c = ((AbstractSQLConfig) cfg).getPartitionString(false);
+
+ if (StringUtil.isEmpty(c, true) == false) {
+ joinPartition += (first ? "" : ", ") + c;
+ first = false;
+ }
+ }
+ }
+ }
+
+ String partition = StringUtil.getTrimedString(getPartition());
+
+ String[] keys = StringUtil.split(partition);
+ if (keys == null || keys.length <= 0) {
+ return StringUtil.isEmpty(joinPartition, true) ? "" : (hasPrefix ? " PARTITION BY " : "") + joinPartition;
+ }
+
+ for (int i = 0; i < keys.length; i++) {
+ String item = keys[i];
+ String origin = item;
+
+ if (isPrepared()) { //不能通过 ? 来代替,SELECT 'id','name' 返回的就是 id:"id", name:"name",而不是数据库里的值!
+ //这里既不对origin trim,也不对 ASC/DESC ignoreCase,希望前端严格传没有任何空格的字符串过来,减少传输数据量,节约服务器性能
+ if (StringUtil.isName(origin) == false) {
+ throw new IllegalArgumentException("预编译模式下 @partition:value 中 " + item + " 不合法! value 里面用 , 分割的"
+ + "每一项必须是 column 且其中 column 必须是 英语单词!并且不要有多余的空格!");
+ }
+ }
+
+ keys[i] = getKey(origin);
+ }
+
+ return (hasPrefix ? " PARTITION BY " : "") + StringUtil.concat(StringUtil.getString(keys), joinPartition, ", ");
+ }
+
+ @Override
+ public String getFill() {
+ return fill;
+ }
+ public AbstractSQLConfig setFill(String... conditions) {
+ return setFill(StringUtil.getString(conditions));
+ }
+ @Override
+ public AbstractSQLConfig setFill(String fill) {
+ this.fill = fill;
+ return this;
+ }
+ @JSONField(serialize = false)
+ public String getFillString(boolean hasPrefix) {
+ //加上子表的 fill
+ String joinFill = "";
+ if (joinList != null) {
+ boolean first = true;
+ for (Join j : joinList) {
+ if (j.isAppJoin()) {
+ continue;
+ }
+
+ SQLConfig ocfg = j.getOuterConfig();
+ SQLConfig cfg = (ocfg != null && ocfg.getFill() != null) || j.isLeftOrRightJoin() ? ocfg : j.getJoinConfig();
+
+ if (cfg != null) {
+ cfg.setMain(false).setKeyPrefix(true);
+ // if (StringUtil.isEmpty(cfg.getAlias(), true)) {
+ // cfg.setAlias(cfg.getTable());
+ // }
+ String c = ((AbstractSQLConfig) cfg).getFillString(false);
+
+ if (StringUtil.isEmpty(c, true) == false) {
+ joinFill += (first ? "" : ", ") + c;
+ first = false;
+ }
+ }
+ }
+ }
+
+ String fill = StringUtil.getTrimedString(getFill());
+
+ String[] keys = StringUtil.split(fill);
+ if (keys == null || keys.length <= 0) {
+ return StringUtil.isEmpty(joinFill, true) ? "" : (hasPrefix ? " FILL(" : "") + joinFill + ")";
+ }
+
+ for (int i = 0; i < keys.length; i++) {
+ String item = keys[i];
+ String origin = item;
+
+ if (isPrepared()) { //不能通过 ? 来代替,SELECT 'id','name' 返回的就是 id:"id", name:"name",而不是数据库里的值!
+ //这里既不对origin trim,也不对 ASC/DESC ignoreCase,希望前端严格传没有任何空格的字符串过来,减少传输数据量,节约服务器性能
+ if (StringUtil.isName(origin) == false) {
+ throw new IllegalArgumentException("预编译模式下 @fill:value 中 " + item + " 不合法! value 里面用 , 分割的"
+ + "每一项必须是 column 且其中 column 必须是 英语单词!并且不要有多余的空格!");
+ }
+ }
+
+ keys[i] = getKey(origin);
+ }
+
+ return (hasPrefix ? " FILL(" : "") + StringUtil.concat(StringUtil.getString(keys), joinFill, ", ") + ")";
+ }
+
@Override
public String getOrder() {
return order;
@@ -2741,35 +3036,38 @@ public static int getOffset(int page, int count) {
public String getLimitString() {
int count = getCount();
- if (isMilvus()) {
+ boolean isSurrealDB = isSurrealDB();
+ boolean isQuestDB = isQuestDB();
+ if (isSurrealDB || isQuestDB || isMilvus()) {
if (count == 0) {
Parser parser = getParser();
count = parser == null ? AbstractParser.MAX_QUERY_COUNT : parser.getMaxQueryCount();
}
int offset = getOffset(getPage(), count);
- return " LIMIT " + offset + ", " + count; // 目前 moql-transx 的限制
- } else if (isSurrealDB()) {
- if (count == 0) {
- Parser parser = getParser();
- count = parser == null ? AbstractParser.MAX_QUERY_COUNT : parser.getMaxQueryCount();
+ if (isQuestDB()) {
+ return " LIMIT " + offset + ", " + (offset + count);
+ }
+ else if (isSurrealDB()) {
+ return " START " + offset + " LIMIT " + count;
+ }
+ else {
+ return " LIMIT " + offset + ", " + count; // 目前 moql-transx 的限制
}
-
- int offset = getOffset(getPage(), count);
- return " START " + offset + " LIMIT " + count;
}
if (count <= 0 || RequestMethod.isHeadMethod(getMethod(), true)) { // TODO HEAD 真的不需要 LIMIT ?
return "";
}
+ boolean isOracle = isOracle();
return getLimitString(
- getPage()
- , getCount()
- , isOracle() || isSQLServer() || isDb2()
- , isOracle() || isDameng() || isKingBase()
- , isPresto() || isTrino()
- );
+ getPage()
+ , count
+ , isTSQL()
+ , isOracle || isDameng() || isKingBase()
+ , isPresto() || isTrino()
+ );
}
/**获取限制数量及偏移量
* @param page
@@ -3462,6 +3760,7 @@ protected String concatJoinWhereString(String whereString) throws Exception {
case "^": // SIDE JOIN: ! (A & B)
case "(": // ANTI JOIN: A & ! B
case ")": // FOREIGN JOIN: B & ! A
+ case "~": // ASOF JOIN: B ~= A
jc = j.getJoinConfig();
boolean isMain = jc.isMain();
jc.setMain(false).setPrepared(isPrepared()).setPreparedValueList(new ArrayList());
@@ -3547,7 +3846,7 @@ else if (isSideJoin) { // ^ SIDE JOIN: ! (A & B)
throw new UnsupportedOperationException(
"join:value 中 value 里的 " + jt + "/" + j.getPath()
+ "错误!不支持 " + jt + " 等 [ @ APP, < LEFT, > RIGHT, * CROSS"
- + ", & INNER, | FULL, ! OUTER, ^ SIDE, ( ANTI, ) FOREIGN ] 之外的 JOIN 类型 !"
+ + ", & INNER, | FULL, ! OUTER, ^ SIDE, ( ANTI, ) FOREIGN, ~ ASOF ] 之外的 JOIN 类型 !"
);
}
}
@@ -3986,7 +4285,7 @@ public String getRegExpString(String key, String column, Object[] values, int ty
*/
@JSONField(serialize = false)
public String getRegExpString(String key, String column, String value, boolean ignoreCase) {
- if (isPostgreSQL() || isCockroachDB() || isInfluxDB()) {
+ if (isPSQL()) {
return getKey(column) + " ~" + (ignoreCase ? "* " : " ") + getValue(key, column, value);
}
if (isOracle() || isDameng() || isKingBase() || (isMySQL() && getDBVersionNums()[0] >= 8)) {
@@ -4312,7 +4611,7 @@ public String getContainString(String key, String column, Object[] childs, int t
}
condition += (i <= 0 ? "" : (Logic.isAnd(type) ? AND : OR));
- if (isPostgreSQL() || isCockroachDB() || isInfluxDB()) {
+ if (isPSQL()) {
condition += (getKey(column) + " @> " + getValue(key, column, newJSONArray(c)));
// operator does not exist: jsonb @> character varying "[" + c + "]");
}
@@ -4763,11 +5062,15 @@ private static String getConditionString(String table, AbstractSQLConfig config)
String aggregation;
if (RequestMethod.isGetMethod(config.getMethod(), true)) {
aggregation = config.getGroupString(true) + config.getHavingString(true)
+ + config.getSampleString(true) + config.getLatestString(true)
+ + config.getPartitionString(true) + config.getFillString(true)
+ config.getOrderString(true);
}
else if (RequestMethod.isHeadMethod(config.getMethod(), true)) {
// TODO 加参数 isPagenation 判断是 GET 内分页 query:2 查总数,不用加这些条件
- aggregation = config.getGroupString(true) + config.getHavingString(true) ;
+ aggregation = config.getGroupString(true) + config.getHavingString(true)
+ + config.getSampleString(true) + config.getLatestString(true)
+ + config.getPartitionString(true) + config.getFillString(true);
}
else if (config.getMethod() == PUT || config.getMethod() == DELETE) {
aggregation = config.getHavingString(true) ;
@@ -4890,12 +5193,16 @@ public String getJoinString() throws Exception {
sql = " INNER JOIN " + jc.getTablePath();
sql = concatJoinOn(sql, quote, j, jt, onList);
break;
+ case "~": // ASOF JOIN: B ~= A
+ sql = " ASOF JOIN " + jc.getTablePath();
+ sql = concatJoinOn(sql, quote, j, jt, onList);
+ break;
default:
String k = jc.getTableKey();
throw new UnsupportedOperationException(
"join:value 中 value 里的 " + k + "/" + j.getPath()
+ "错误!不支持 " + k + " 等 [ @ APP, < LEFT, > RIGHT, * CROSS"
- + ", & INNER, | FULL, ! OUTER, ^ SIDE, ( ANTI, ) FOREIGN ] 之外的 JOIN 类型 !"
+ + ", & INNER, | FULL, ! OUTER, ^ SIDE, ( ANTI, ) FOREIGN, ~ ASOF ] 之外的 JOIN 类型 !"
);
}
@@ -5018,7 +5325,7 @@ else if (l > 0 && StringUtil.isName(String.valueOf(l))) {
}
else if (rt.endsWith("~")) {
boolean ignoreCase = "*~".equals(rt);
- if (isPostgreSQL() || isCockroachDB() || isInfluxDB()) {
+ if (isPSQL()) {
sql += (first ? ON : AND) + lk + (isNot ? NOT : "") + " ~" + (ignoreCase ? "* " : " ") + rk;
}
else if (isOracle() || isDameng() || isKingBase()) {
@@ -5073,7 +5380,7 @@ else if ("{}".equals(rt) || "<>".equals(rt)) {
String arrKeyPath = isIn ? rk : lk;
String itemKeyPath = isIn ? lk : rk;
- if (isPostgreSQL() || isCockroachDB() || isInfluxDB()) { //operator does not exist: jsonb @> character varying "[" + c + "]");
+ if (isPSQL()) { //operator does not exist: jsonb @> character varying "[" + c + "]");
sql += (first ? ON : AND) + (isNot ? "( " : "") + getCondition(isNot, arrKeyPath
+ " IS NOT NULL AND " + arrKeyPath + " @> " + itemKeyPath) + (isNot ? ") " : "");
}
@@ -5308,6 +5615,10 @@ else if (userId instanceof Subquery) {}
String group = request.getString(KEY_GROUP);
Object having = request.get(KEY_HAVING);
String havingAnd = request.getString(KEY_HAVING_AND);
+ String sample = request.getString(KEY_SAMPLE);
+ String latest = request.getString(KEY_LATEST);
+ String partition = request.getString(KEY_PARTITION);
+ String fill = request.getString(KEY_FILL);
String order = request.getString(KEY_ORDER);
Object keyMap = request.get(KEY_KEY);
String raw = request.getString(KEY_RAW);
@@ -5337,6 +5648,10 @@ else if (userId instanceof Subquery) {}
request.remove(KEY_GROUP);
request.remove(KEY_HAVING);
request.remove(KEY_HAVING_AND);
+ request.remove(KEY_SAMPLE);
+ request.remove(KEY_LATEST);
+ request.remove(KEY_PARTITION);
+ request.remove(KEY_FILL);
request.remove(KEY_ORDER);
request.remove(KEY_KEY);
request.remove(KEY_RAW);
@@ -5841,6 +6156,10 @@ else if (keyMap != null) {
config.setGroup(group);
config.setHaving(havingMap);
config.setHavingCombine(havingCombine);
+ config.setSample(sample);
+ config.setLatest(latest);
+ config.setPartition(partition);
+ config.setFill(fill);
config.setOrder(order);
String[] jsons = StringUtil.split(json);
@@ -5905,6 +6224,18 @@ else if (keyMap != null) {
if (havingAnd != null) {
request.put(KEY_HAVING_AND, havingAnd);
}
+ if (sample != null) {
+ request.put(KEY_SAMPLE, sample);
+ }
+ if (latest != null) {
+ request.put(KEY_LATEST, latest);
+ }
+ if (partition != null) {
+ request.put(KEY_PARTITION, partition);
+ }
+ if (fill != null) {
+ request.put(KEY_FILL, fill);
+ }
if (order != null) {
request.put(KEY_ORDER, order);
}
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java
index 9393f43be..2f0482091 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java
@@ -1185,12 +1185,16 @@ public PreparedStatement getStatement(@NotNull SQLConfig config, String sql)
}
}
else if (RequestMethod.isGetMethod(config.getMethod(), true)) {
- //if (config.isPresto() || config.isTrino()) {
+ // if (config.isPresto() || config.isTrino()) {
// statement = getConnection(config).prepareStatement(sql); // , ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
- //} else {
+ // } else {
// statement = getConnection(config).prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
- //}
- if (config.isMySQL() || config.isPostgreSQL() || config.isCockroachDB() || config.isOracle() || config.isSQLServer() || config.isDb2()) {
+ // }
+
+ // TODO 补充各种支持 TYPE_SCROLL_SENSITIVE 和 CONCUR_UPDATABLE 的数据库
+ if (config.isMySQL() || config.isTiDB() || config.isMariaDB() || config.isOracle() || config.isSQLServer() || config.isDb2()
+ || config.isPostgreSQL() || config.isCockroachDB() || config.isOpenGauss() || config.isTimescaleDB() || config.isQuestDB()
+ ) {
statement = getConnection(config).prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
} else {
statement = getConnection(config).prepareStatement(sql);
diff --git a/APIJSONORM/src/main/java/apijson/orm/Join.java b/APIJSONORM/src/main/java/apijson/orm/Join.java
index f648ff8bf..449208bd9 100644
--- a/APIJSONORM/src/main/java/apijson/orm/Join.java
+++ b/APIJSONORM/src/main/java/apijson/orm/Join.java
@@ -19,7 +19,7 @@ public class Join {
private String path; // /User/id@
- private String joinType; // "@" - APP, "<" - LEFT, ">" - RIGHT, "*" - CROSS, "&" - INNER, "|" - FULL, "!" - OUTER, "^" - SIDE, "(" - ANTI, ")" - FOREIGN
+ private String joinType; // "@" - APP, "<" - LEFT, ">" - RIGHT, "*" - CROSS, "&" - INNER, "|" - FULL, "!" - OUTER, "^" - SIDE, "(" - ANTI, ")" - FOREIGN, "~" ASOF
private String table; // User
private String alias; // owner
private int count = 1; // 当app join子表,需要返回子表的行数,默认1行;
@@ -143,6 +143,9 @@ public boolean isAntiJoin() {
public boolean isForeignJoin() {
return ")".equals(getJoinType());
}
+ public boolean isAsofJoin() {
+ return "~".equals(getJoinType());
+ }
public boolean isLeftOrRightJoin() {
String jt = getJoinType();
diff --git a/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
index 64e6273ee..ac541c8da 100755
--- a/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
@@ -40,6 +40,7 @@ public interface SQLConfig {
String DATABASE_INFLUXDB = "INFLUXDB"; // https://www.influxdata.com/products/influxdb-overview
String DATABASE_TDENGINE = "TDENGINE"; // https://tdengine.com
String DATABASE_TIMESCALEDB = "TIMESCALEDB"; // https://www.timescale.com
+ String DATABASE_QUESTDB = "QUESTDB"; // https://questdb.com
String DATABASE_IOTDB = "IOTDB"; // https://iotdb.apache.org/zh/UserGuide/latest/API/Programming-JDBC.html
String DATABASE_REDIS = "REDIS"; // https://redisql.com
@@ -77,6 +78,10 @@ public interface SQLConfig {
SQLConfig setTag(String tag);
+ boolean isTSQL();
+ boolean isMSQL();
+ boolean isPSQL();
+
boolean isMySQL();
boolean isPostgreSQL();
boolean isSQLServer();
@@ -100,6 +105,7 @@ public interface SQLConfig {
boolean isInfluxDB();
boolean isTDengine();
boolean isTimescaleDB();
+ boolean isQuestDB();
boolean isIoTDB();
boolean isRedis();
boolean isMongoDB();
@@ -317,6 +323,18 @@ default int[] getDBVersionNums() {
String getHavingCombine();
SQLConfig setHavingCombine(String havingCombine);
+ String getSample();
+ SQLConfig setSample(String order);
+
+ String getLatest();
+ SQLConfig setLatest(String latest);
+
+ String getPartition();
+ SQLConfig setPartition(String partition);
+
+ String getFill();
+ SQLConfig setFill(String fill);
+
String getOrder();
SQLConfig setOrder(String order);
diff --git a/APIJSONORM/src/main/java/apijson/orm/exception/CommonException.java b/APIJSONORM/src/main/java/apijson/orm/exception/CommonException.java
index 9dab4ea16..0acced3be 100755
--- a/APIJSONORM/src/main/java/apijson/orm/exception/CommonException.java
+++ b/APIJSONORM/src/main/java/apijson/orm/exception/CommonException.java
@@ -229,6 +229,9 @@ else if (config.isTDengine()) {
else if (config.isTimescaleDB()) {
db = SQLConfig.DATABASE_TIMESCALEDB + " " + dbVersion;
}
+ else if (config.isQuestDB()) {
+ db = SQLConfig.DATABASE_QUESTDB + " " + dbVersion;
+ }
else if (config.isIoTDB()) {
db = SQLConfig.DATABASE_IOTDB + " " + dbVersion;
}
From d8b8e5783fc632043b25d89b818aaf25f24c4d24 Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sun, 16 Mar 2025 15:45:08 +0800
Subject: [PATCH 049/122] =?UTF-8?q?QuestDB:=20=E8=A7=A3=E5=86=B3=20JOIN=20?=
=?UTF-8?q?=E8=BF=94=E5=9B=9E=E4=B8=BB=E8=A1=A8=E7=A9=BA=E5=AF=B9=E8=B1=A1?=
=?UTF-8?q?=E5=B9=B6=E6=9C=AA=E8=BF=94=E5=9B=9E=E5=89=AF=E8=A1=A8=EF=BC=8C?=
=?UTF-8?q?=E8=A7=A3=E5=86=B3=20QuestDB=20=E8=87=AA=E5=8A=A8=E6=8A=8A?=
=?UTF-8?q?=E5=89=AF=E8=A1=A8=20id=20=E7=AD=89=E4=B8=8E=E4=B8=BB=E8=A1=A8?=
=?UTF-8?q?=E9=87=8D=E5=90=8D=E5=AD=97=E6=AE=B5=E6=94=B9=E6=88=90=20id1=20?=
=?UTF-8?q?=E5=AF=BC=E8=87=B4=E7=9A=84=E8=A7=A3=E6=9E=90=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../java/apijson/orm/AbstractSQLExecutor.java | 235 ++++++++++--------
1 file changed, 137 insertions(+), 98 deletions(-)
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java
index 2f0482091..49f51438e 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java
@@ -198,6 +198,7 @@ public JSONObject execute(@NotNull SQLConfig config, boolean unknownType) thr
ResultSet rs = null;
List resultList = null;
Map childMap = null;
+ Map keyMap = null;
try {
if (unknownType) {
@@ -393,6 +394,8 @@ public JSONObject execute(@NotNull SQLConfig config, boolean unknownType) thr
// 直接用数组存取更快 Map columnIndexAndJoinMap = isExplain || ! hasJoin ? null : new HashMap<>(length);
Join[] columnIndexAndJoinMap = isExplain || ! hasJoin ? null : new Join[length];
+ Map repeatMap = columnIndexAndJoinMap == null || ! config.isQuestDB() ? null : new HashMap<>();
+ keyMap = repeatMap == null ? null : new HashMap<>();
// int viceColumnStart = length + 1; //第一个副表字段的index
@@ -431,34 +434,69 @@ public JSONObject execute(@NotNull SQLConfig config, boolean unknownType) thr
List column = config.getColumn();
int mainColumnSize = column == null ? 0 : column.size();
- // FIXME 主副表同名导致主表数据当成副表数据 { "[]": { "join": "": 0 }, "Comment:to": { "@column": "id,content", "id@": "/Comment/toId" } }, "@explain": true }
boolean toFindJoin = mainColumnSize <= 0 || i > mainColumnSize; // 主表就不用找 JOIN 配置
if (StringUtil.isEmpty(sqlTable, true)) {
+ //sqlTable = null;
+
if (toFindJoin) { // 在主表字段数量内的都归属主表
long startTime3 = System.currentTimeMillis();
sqlTable = rsmd.getTableName(i); // SQL 函数甚至部分字段都不返回表名,当然如果没传 @column 生成的 Table.* 则返回的所有字段都会带表名
//if (StringUtil.isEmpty(sqlTable, true)) {
- // boolean isEmpty = curItem == null || curItem.isEmpty();
- String label = getKey(config, rs, rsmd, index, curItem, i, childMap);
- if (i > 1 && ( (curItem != null && curItem.containsKey(label))
- || (StringUtil.isNotEmpty(label) && StringUtil.equals(label, curConfig == null ? null : curConfig.getIdKey())))
+ // boolean isEmpty = curItem == null || curItem.isEmpty();
+ String key = getKey(config, rs, rsmd, index, curItem, i, childMap, keyMap);
+ char last = repeatMap == null ? 0 : key.charAt(key.length() - 1);
+ String repeatKey = last < '0' || last > '9' ? null : key.substring(0, key.length() - 1);
+ Integer repeatCount = repeatKey == null ? null : repeatMap.get(repeatKey);
+ int nc = repeatCount == null ? 1 : repeatCount + 1;
+ if (last == nc + '0') {
+ keyMap.put(key, repeatKey);
+ repeatMap.put(repeatKey, nc);
+ key = repeatKey; // QuestDB 会自动把副表与主表同名的字段重命名,例如 id 改为 id1, date 改为 date1
+ }
+
+ if (i > 1 && ( (curItem != null && curItem.containsKey(key))
+ || (StringUtil.isNotEmpty(key) && StringUtil.equals(key, curConfig == null ? null : curConfig.getIdKey())))
) { // Presto 等引擎 JDBC 返回 rsmd.getTableName(i) 为空,主表如果一个字段都没有会导致 APISJON 主副表所有字段都不返回
sqlTable = null;
if (reseted) {
- lastViceTableStart ++;
-
SQLConfig lastCfg = lastJoin == null ? null : lastJoin.getCacheConfig();
List lastColumn = lastCfg == null ? null : lastCfg.getColumn();
+
+ lastViceTableStart ++;
lastViceColumnStart += lastColumn == null ? 1 : lastColumn.size();
}
+ else if (isMain) {
+ for (int j = 0; j < joinList.size(); j++) {
+ Join join = joinList.get(j);
+ SQLConfig cfg = join == null || ! join.isSQLJoin() ? null : join.getJoinConfig();
+ List c = cfg == null ? null : cfg.getColumn();
+
+ if (cfg != null) {
+ sqlTable = cfg.getSQLTable();
+ sqlAlias = cfg.getAlias();
+ lastViceTableStart = j; // 避免后面的空 @column 表内字段被放到之前的空 @column 表
+ lastViceColumnStart = i + 1;
+
+ curJoin = join;
+ curConfig = cfg;
+ curColumn = c;
+
+ toFindJoin = false;
+ isMain = false;
+ break;
+ }
+ }
+ }
+
reseted = true;
}
//}
sqlResultDuration += System.currentTimeMillis() - startTime3;
- if (StringUtil.isEmpty(sqlTable, true)) { // hasJoin 已包含这个判断 && joinList != null) {
+ if (toFindJoin && StringUtil.isEmpty(sqlTable, true)) { // hasJoin 已包含这个判断 && joinList != null) {
+ //sqlTable = null; // QuestDB 等 rsmd.getTableName(i) 返回 "" 导致以下 StringUtil.equalsIgnoreCase 对比失败
int nextViceColumnStart = lastViceColumnStart; // 主表没有 @column 时会偏小 lastViceColumnStart
int joinCount = joinList.size();
@@ -469,11 +507,11 @@ public JSONObject execute(@NotNull SQLConfig config, boolean unknownType) thr
nextViceColumnStart += (c != null && ! c.isEmpty() ?
c.size() : (
- StringUtil.equalsIgnoreCase(sqlTable, lastTableName)
+ StringUtil.equalsIgnoreCase(sqlTable, lastTableName)
&& StringUtil.equals(sqlAlias, lastAliasName) ? 1 : 0
- )
- );
- if (i < nextViceColumnStart || j >= joinCount - 1) {
+ )
+ );
+ if (i < nextViceColumnStart) { // 导致只 JOIN 一张副表时主表数据放到副表 || j >= joinCount - 1) {
sqlTable = cfg.getSQLTable();
sqlAlias = cfg.getAlias();
lastViceTableStart = j; // 避免后面的空 @column 表内字段被放到之前的空 @column 表
@@ -496,8 +534,7 @@ public JSONObject execute(@NotNull SQLConfig config, boolean unknownType) thr
toFindJoin = false;
}
}
- }
- else if (config.isClickHouse() && (sqlTable.startsWith("`") || sqlTable.startsWith("\""))){
+ } else if (config.isClickHouse() && (sqlTable.startsWith("`") || sqlTable.startsWith("\""))){
sqlTable = sqlTable.substring(1, sqlTable.length() - 1);
}
@@ -512,7 +549,7 @@ else if (config.isClickHouse() && (sqlTable.startsWith("`") || sqlTable.startsWi
SQLConfig cfg = join == null || ! join.isSQLJoin() ? null : join.getJoinConfig();
if (cfg != null && StringUtil.equalsIgnoreCase(sqlTable, cfg.getSQLTable())
- ) { // FIXME 导致副表字段错放到主表 && StringUtil.equals(sqlAlias, cfg.getAlias())) {
+ ) { // FIXME 导致副表字段错放到主表 && StringUtil.equals(sqlAlias, cfg.getAlias())) {
lastViceTableStart = j; // 避免后面的空 @column 表内字段被放到之前的空 @column 表
curJoin = join;
@@ -621,7 +658,7 @@ else if (hasPK) {
}
}
- curItem = onPutColumn(config, rs, rsmd, index, curItem, i, curJoin, childMap); // isExplain == false && hasJoin && i >= viceColumnStart ? childMap : null);
+ curItem = onPutColumn(config, rs, rsmd, index, curItem, i, curJoin, childMap, keyMap); // isExplain == false && hasJoin && i >= viceColumnStart ? childMap : null);
}
if (viceItem != null) {
@@ -671,7 +708,7 @@ else if (hasPK) {
// @ APP JOIN 查询副表并缓存到 childMap <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Map> appJoinChildMap = new HashMap<>();
childMap.forEach((viceSql, item) -> appJoinChildMap.put(viceSql, Arrays.asList(item)));
- executeAppJoin(config, resultList, appJoinChildMap);
+ executeAppJoin(config, resultList, appJoinChildMap, keyMap);
// @ APP JOIN 查询副表并缓存到 childMap >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
@@ -713,7 +750,7 @@ else if (hasPK) {
* @param childMap
* @throws Exception
*/
- protected void executeAppJoin(SQLConfig config, List resultList, Map> childMap) throws Exception {
+ protected void executeAppJoin(SQLConfig config, List resultList, Map> childMap, Map keyMap) throws Exception {
List joinList = config.getJoinList();
if (joinList != null) {
@@ -737,27 +774,27 @@ protected void executeAppJoin(SQLConfig config, List resultList,
On on = onList == null || onList.isEmpty() ? null : onList.get(0); // APP JOIN 应该有且只有一个 ON 条件
String originKey = on == null ? null : on.getOriginKey();
if (originKey == null) {
- throw new NullPointerException("服务器内部错误,List 中 Join.onList[0" + (on == null ? "] = null!" : ".getOriginKey() = null!"));
+ throw new NullPointerException("服务器内部错误,List 中 Join.onList[0" + (on == null ? "] = null!" : ".getOriginKey() = null!"));
}
String key = on.getKey();
if (key == null) {
- throw new NullPointerException("服务器内部错误,List 中 Join.onList[0" + (on == null ? "] = null!" : ".getKey() = null!"));
+ throw new NullPointerException("服务器内部错误,List 中 Join.onList[0" + (on == null ? "] = null!" : ".getKey() = null!"));
}
// 取出 "id@": "@/User/userId" 中所有 userId 的值
List targetValueList = new ArrayList<>();
for (int i = 0; i < resultList.size(); i++) {
- JSONObject mainTable = resultList.get(i);
- Object targetValue = mainTable == null ? null : mainTable.get(on.getTargetKey());
+ JSONObject mainTable = resultList.get(i);
+ Object targetValue = mainTable == null ? null : mainTable.get(on.getTargetKey());
- if (targetValue != null && targetValueList.contains(targetValue) == false) {
- targetValueList.add(targetValue);
- }
+ if (targetValue != null && targetValueList.contains(targetValue) == false) {
+ targetValueList.add(targetValue);
+ }
}
if (targetValueList.isEmpty() && config.isExplain() == false) {
- throw new NotExistException("targetValueList.isEmpty() && config.isExplain() == false");
+ throw new NotExistException("targetValueList.isEmpty() && config.isExplain() == false");
}
// 替换为 "id{}": [userId1, userId2, userId3...]
@@ -796,38 +833,38 @@ protected void executeAppJoin(SQLConfig config, List resultList,
String sql2 = null;
if (childCount > 0 && isOne2Many && (jc.isMySQL() == false || jc.getDBVersionNums()[0] >= 8)) {
- // 加 row_number 字段并不会导致 count 等聚合函数统计出错,结果偏大,SQL JOIN 才会,之前没发现是因为缓存失效 bug
- // boolean noAggrFun = true;
- // List column = jc.getColumn();
- // if (column != null) {
- // for (String c : column) {
- // int start = c == null ? -1 : c.indexOf("(");
- // int end = start <= 0 ? -1 : c.lastIndexOf(")");
- // if (start > 0 && end > start) {
- // String fun = c.substring(0, start);
- // if (AbstractSQLConfig.SQL_AGGREGATE_FUNCTION_MAP.containsKey(fun)) {
- // noAggrFun = false;
- // break;
- // }
- // }
- // }
- // }
- //
- // if (noAggrFun) { // 加 row_number 字段会导致 count 等聚合函数统计出错,结果偏大?
- String q = jc.getQuote();
- sql2 = prepared && jc.isTDengine() == false ? jc.getSQL(true) : sql;
-
- String prefix = "SELECT * FROM(";
- String rnStr = ", row_number() OVER (PARTITION BY " + q + key + q + ((AbstractSQLConfig) jc).getOrderString(true) + ") _row_num_ FROM ";
- String suffix = ") _t WHERE ( (_row_num_ <= " + childCount + ") )" + (allChildCount > 0 ? " LIMIT " + allChildCount : "");
-
- sql2 = prefix
- // 放一块逻辑更清晰,也避免解析 * 等不支持或性能开销 + sql
- + sql2.replaceFirst(" FROM ", rnStr) // * 居然只能放在 row_number() 前面,放后面就报错 "SELECT ", rnStr)
- + suffix;
-
- sql = prepared ? (prefix + sql.replaceFirst(" FROM ", rnStr) + suffix) : sql2;
- // }
+ // 加 row_number 字段并不会导致 count 等聚合函数统计出错,结果偏大,SQL JOIN 才会,之前没发现是因为缓存失效 bug
+ // boolean noAggrFun = true;
+ // List column = jc.getColumn();
+ // if (column != null) {
+ // for (String c : column) {
+ // int start = c == null ? -1 : c.indexOf("(");
+ // int end = start <= 0 ? -1 : c.lastIndexOf(")");
+ // if (start > 0 && end > start) {
+ // String fun = c.substring(0, start);
+ // if (AbstractSQLConfig.SQL_AGGREGATE_FUNCTION_MAP.containsKey(fun)) {
+ // noAggrFun = false;
+ // break;
+ // }
+ // }
+ // }
+ // }
+ //
+ // if (noAggrFun) { // 加 row_number 字段会导致 count 等聚合函数统计出错,结果偏大?
+ String q = jc.getQuote();
+ sql2 = prepared && jc.isTDengine() == false ? jc.getSQL(true) : sql;
+
+ String prefix = "SELECT * FROM(";
+ String rnStr = ", row_number() OVER (PARTITION BY " + q + key + q + ((AbstractSQLConfig) jc).getOrderString(true) + ") _row_num_ FROM ";
+ String suffix = ") _t WHERE ( (_row_num_ <= " + childCount + ") )" + (allChildCount > 0 ? " LIMIT " + allChildCount : "");
+
+ sql2 = prefix
+ // 放一块逻辑更清晰,也避免解析 * 等不支持或性能开销 + sql
+ + sql2.replaceFirst(" FROM ", rnStr) // * 居然只能放在 row_number() 前面,放后面就报错 "SELECT ", rnStr)
+ + suffix;
+
+ sql = prepared ? (prefix + sql.replaceFirst(" FROM ", rnStr) + suffix) : sql2;
+ // }
}
boolean isExplain = jc.isExplain();
@@ -846,12 +883,12 @@ protected void executeAppJoin(SQLConfig config, List resultList,
try {
long executedSQLStartTime = 0;
if (isExplain == false) { //只有 SELECT 才能 EXPLAIN
- executedSQLCount ++;
- executedSQLStartTime = System.currentTimeMillis();
+ executedSQLCount ++;
+ executedSQLStartTime = System.currentTimeMillis();
}
rs = executeQuery(jc, sql2);
if (isExplain == false) {
- executedSQLDuration += System.currentTimeMillis() - executedSQLStartTime;
+ executedSQLDuration += System.currentTimeMillis() - executedSQLStartTime;
}
int count = 0;
@@ -876,7 +913,7 @@ protected void executeAppJoin(SQLConfig config, List resultList,
JSONObject result = new JSONObject(true);
for (int i = 1; i <= length; i++) {
- result = onPutColumn(jc, rs, rsmd, index, result, i, null, null);
+ result = onPutColumn(jc, rs, rsmd, index, result, i, null, null, keyMap);
}
//每个 result 都要用新的 SQL 来存 childResultMap = onPutTable(config, rs, rsmd, childResultMap, index, result);
@@ -890,21 +927,19 @@ protected void executeAppJoin(SQLConfig config, List resultList,
List results = childMap.get(cacheSql);
if (results == null || skipMap.get(cacheSql) == null) { // 避免添加重复数据
- results = new ArrayList<>(childCount);
- childMap.put(cacheSql, results);
- skipMap.put(cacheSql, Boolean.TRUE);
+ results = new ArrayList<>(childCount);
+ childMap.put(cacheSql, results);
+ skipMap.put(cacheSql, Boolean.TRUE);
}
if (childCount <= 0 || results.size() < childCount) { // 避免超过子数组每页数量
- // if (count == 1 && results.isEmpty() == false) { // 避免添加重复数据
- // results.clear();
- // }
- results.add(result); //缓存到 childMap
- count ++;
- Log.d(TAG, ">>> executeAppJoin childMap.put('" + cacheSql + "', result); childMap.size() = " + childMap.size());
+ // if (count == 1 && results.isEmpty() == false) { // 避免添加重复数据
+ // results.clear();
+ // }
+ results.add(result); //缓存到 childMap
+ count ++;
+ Log.d(TAG, ">>> executeAppJoin childMap.put('" + cacheSql + "', result); childMap.size() = " + childMap.size());
}
- }
- }
finally {
if (rs != null) {
try {
@@ -939,29 +974,24 @@ protected void executeAppJoin(SQLConfig config, List resultList,
* @throws Exception
*/
protected JSONObject onPutColumn(@NotNull SQLConfig config, @NotNull ResultSet rs, @NotNull ResultSetMetaData rsmd
- , final int tablePosition, @NotNull JSONObject table, final int columnIndex, Join join, Map childMap) throws Exception {
+ , final int row, @NotNull JSONObject table, final int columnIndex, Join join, Map childMap
+ , Map keyMap) throws Exception {
if (table == null) { // 对应副表 viceSql 不能生成正常 SQL, 或者是 ! - Outer, ( - ANTI JOIN 的副表这种不需要缓存及返回的数据
Log.i(TAG, "onPutColumn table == null >> return table;");
return table;
}
- if (isHideColumn(config, rs, rsmd, tablePosition, table, columnIndex, childMap)) {
- Log.i(TAG, "onPutColumn isHideColumn(config, rs, rsmd, tablePosition, table, columnIndex, childMap) >> return table;");
+ if (isHideColumn(config, rs, rsmd, row, table, columnIndex, childMap, keyMap)) {
+ Log.i(TAG, "onPutColumn isHideColumn(config, rs, rsmd, row, table, columnIndex, childMap) >> return table;");
return table;
}
- String label = getKey(config, rs, rsmd, tablePosition, table, columnIndex, childMap);
- Object value = getValue(config, rs, rsmd, tablePosition, table, columnIndex, label, childMap);
+ String label = getKey(config, rs, rsmd, row, table, columnIndex, childMap, keyMap);
+ Object value = getValue(config, rs, rsmd, row, table, columnIndex, label, childMap, keyMap);
// 主表必须 put 至少一个 null 进去,否则全部字段为 null 都不 put 会导致中断后续正常返回值
- if (value != null) {
+ if (value != null || ENABLE_OUTPUT_NULL_COLUMN || (join == null && table.isEmpty())) {
table.put(label, value);
- } else {
- if (join == null && table.isEmpty()) {
- table.put(label, null);
- } else if (ENABLE_OUTPUT_NULL_COLUMN) {
- table.put(label, null);
- }
}
return table;
@@ -971,7 +1001,7 @@ protected JSONObject onPutColumn(@NotNull SQLConfig config, @NotNull ResultSe
* @param config
* @param rs
* @param rsmd
- * @param tablePosition
+ * @param row
* @param table
* @param columnIndex
* @param childMap
@@ -979,7 +1009,8 @@ protected JSONObject onPutColumn(@NotNull SQLConfig config, @NotNull ResultSe
* @throws SQLException
*/
protected boolean isHideColumn(@NotNull SQLConfig config, @NotNull ResultSet rs, @NotNull ResultSetMetaData rsmd
- , final int tablePosition, @NotNull JSONObject table, final int columnIndex, Map childMap) throws SQLException {
+ , final int row, @NotNull JSONObject table, final int columnIndex, Map childMap
+ , Map keyMap) throws SQLException {
return rsmd.getColumnName(columnIndex).startsWith("_");
}
@@ -999,12 +1030,11 @@ protected List onPutTable(@NotNull SQLConfig config, @NotNull Res
return resultList;
}
-
-
protected String getKey(@NotNull SQLConfig config, @NotNull ResultSet rs, @NotNull ResultSetMetaData rsmd
- , final int tablePosition, @NotNull JSONObject table, final int columnIndex, Map childMap) throws Exception {
+ , final int row, @NotNull JSONObject table, final int columnIndex, Map childMap
+ , Map keyMap) throws Exception {
long startTime = System.currentTimeMillis();
- String key = rsmd.getColumnLabel(columnIndex); // dotIndex < 0 ? lable : lable.substring(dotIndex + 1);
+ String key = rsmd.getColumnLabel(columnIndex); // dotIndex < 0 ? label : label.substring(dotIndex + 1);
sqlResultDuration += System.currentTimeMillis() - startTime;
if (config.isHive()) {
@@ -1018,18 +1048,26 @@ protected String getKey(@NotNull SQLConfig config, @NotNull ResultSet rs, @No
}
}
+ if (keyMap != null && ! keyMap.isEmpty()) {
+ String nk = keyMap.get(key);
+ if (StringUtil.isNotEmpty(nk, true)) {
+ key = nk; // QuestDB 会自动把副表与主表同名的字段重命名,例如 id 改为 id1, date 改为 date1
+ }
+ }
+
return key;
}
protected Object getValue(@NotNull SQLConfig config, @NotNull ResultSet rs, @NotNull ResultSetMetaData rsmd
- , final int tablePosition, @NotNull JSONObject table, final int columnIndex, String lable, Map childMap) throws Exception {
+ , final int row, @NotNull JSONObject table, final int columnIndex, String label
+ , Map childMap, Map keyMap) throws Exception {
long startTime = System.currentTimeMillis();
Object value = rs.getObject(columnIndex);
sqlResultDuration += System.currentTimeMillis() - startTime;
// Log.d(TAG, "name:" + rsmd.getColumnName(i));
- // Log.d(TAG, "lable:" + rsmd.getColumnLabel(i));
+ // Log.d(TAG, "label:" + rsmd.getColumnLabel(i));
// Log.d(TAG, "type:" + rsmd.getColumnType(i));
// Log.d(TAG, "typeName:" + rsmd.getColumnTypeName(i));
@@ -1093,6 +1131,7 @@ else if (value instanceof Clob) { //SQL Server TEXT 类型 居然走这个
if (castToJson == false) {
List json = config.getJson();
castToJson = json != null && json.contains(lable);
+ castToJson = json != null && json.contains(label);
}
if (castToJson) {
try {
@@ -1133,13 +1172,13 @@ public Object getNumVal(Number value) {
/**判断是否为JSON类型
* @param config
- * @param lable
+ * @param label
* @param rsmd
* @param position
* @return
*/
@Override
- public boolean isJSONType(@NotNull SQLConfig config, ResultSetMetaData rsmd, int position, String lable) {
+ public boolean isJSONType(@NotNull SQLConfig config, ResultSetMetaData rsmd, int position, String label) {
try {
long startTime = System.currentTimeMillis();
String column = rsmd.getColumnTypeName(position);
@@ -1158,16 +1197,16 @@ public boolean isJSONType(@NotNull SQLConfig config, ResultSetMetaData rsmd,
e.printStackTrace();
}
// List json = config.getJson();
- // return json != null && json.contains(lable);
+ // return json != null && json.contains(label);
return false;
}
-
@Override // 重写是为了返回类型从 Statement 改为 PreparedStatement,避免其它方法出错
public PreparedStatement getStatement(@NotNull SQLConfig config) throws Exception {
return getStatement(config, null);
}
+
@Override
public PreparedStatement getStatement(@NotNull SQLConfig config, String sql) throws Exception {
if (StringUtil.isEmpty(sql)) {
@@ -1193,7 +1232,7 @@ else if (RequestMethod.isGetMethod(config.getMethod(), true)) {
// TODO 补充各种支持 TYPE_SCROLL_SENSITIVE 和 CONCUR_UPDATABLE 的数据库
if (config.isMySQL() || config.isTiDB() || config.isMariaDB() || config.isOracle() || config.isSQLServer() || config.isDb2()
- || config.isPostgreSQL() || config.isCockroachDB() || config.isOpenGauss() || config.isTimescaleDB() || config.isQuestDB()
+ || config.isPostgreSQL() || config.isCockroachDB() || config.isOpenGauss() || config.isTimescaleDB() || config.isQuestDB()
) {
statement = getConnection(config).prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
} else {
From 9a45d3381e9e27095baf6367078283d7f7d98a85 Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sun, 16 Mar 2025 15:46:50 +0800
Subject: [PATCH 050/122] =?UTF-8?q?QuestDB:=20=E8=A7=A3=E5=86=B3=20JOIN=20?=
=?UTF-8?q?=E8=BF=94=E5=9B=9E=E4=B8=BB=E8=A1=A8=E7=A9=BA=E5=AF=B9=E8=B1=A1?=
=?UTF-8?q?=E5=B9=B6=E6=9C=AA=E8=BF=94=E5=9B=9E=E5=89=AF=E8=A1=A8=EF=BC=8C?=
=?UTF-8?q?=E8=A7=A3=E5=86=B3=20QuestDB=20=E8=87=AA=E5=8A=A8=E6=8A=8A?=
=?UTF-8?q?=E5=89=AF=E8=A1=A8=20id=20=E7=AD=89=E4=B8=8E=E4=B8=BB=E8=A1=A8?=
=?UTF-8?q?=E9=87=8D=E5=90=8D=E5=AD=97=E6=AE=B5=E6=94=B9=E6=88=90=20id1=20?=
=?UTF-8?q?=E5=AF=BC=E8=87=B4=E7=9A=84=E8=A7=A3=E6=9E=90=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../src/main/java/apijson/orm/AbstractSQLExecutor.java | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java
index 49f51438e..35d1efda2 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java
@@ -940,6 +940,8 @@ protected void executeAppJoin(SQLConfig config, List resultList,
count ++;
Log.d(TAG, ">>> executeAppJoin childMap.put('" + cacheSql + "', result); childMap.size() = " + childMap.size());
}
+ }
+ }
finally {
if (rs != null) {
try {
@@ -1101,7 +1103,7 @@ else if (value instanceof Month) {
else if (value instanceof DayOfWeek) {
value = ((DayOfWeek) value).getValue();
}
- else if (value instanceof String && isJSONType(config, rsmd, columnIndex, lable)) { //json String
+ else if (value instanceof String && isJSONType(config, rsmd, columnIndex, label)) { //json String
castToJson = true;
}
else if (value instanceof Blob) { //FIXME 存的是 abcde,取出来直接就是 [97, 98, 99, 100, 101] 这种 byte[] 类型,没有经过以下处理,但最终序列化后又变成了字符串 YWJjZGU=
@@ -1130,7 +1132,7 @@ else if (value instanceof Clob) { //SQL Server TEXT 类型 居然走这个
if (castToJson == false) {
List json = config.getJson();
- castToJson = json != null && json.contains(lable);
+ castToJson = json != null && json.contains(label);
castToJson = json != null && json.contains(label);
}
if (castToJson) {
From 58404703b09c8a123a5018d31d66b2b49256cb35 Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sun, 16 Mar 2025 16:18:39 +0800
Subject: [PATCH 051/122] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E8=AF=AF=E5=9C=A8?=
=?UTF-8?q?=E5=AD=90=E6=9F=A5=E8=AF=A2=E6=8B=BC=E6=8E=A5=20LIMIT=EF=BC=9B?=
=?UTF-8?q?=E8=A7=A3=E5=86=B3=20@sample=20SAMPLE=20BY=20@fill=20FILL=20?=
=?UTF-8?q?=E7=9A=84=20SQL=20=E6=8B=BC=E6=8E=A5=20bug?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../src/main/java/apijson/StringUtil.java | 15 ++++++
.../java/apijson/orm/AbstractSQLConfig.java | 47 ++++++++++---------
2 files changed, 41 insertions(+), 21 deletions(-)
diff --git a/APIJSONORM/src/main/java/apijson/StringUtil.java b/APIJSONORM/src/main/java/apijson/StringUtil.java
index c6caf21e7..49c72677a 100755
--- a/APIJSONORM/src/main/java/apijson/StringUtil.java
+++ b/APIJSONORM/src/main/java/apijson/StringUtil.java
@@ -343,6 +343,7 @@ public static boolean isNotEmpty(String s, boolean trim) {
public static final Pattern PATTERN_PHONE;
public static final Pattern PATTERN_EMAIL;
public static final Pattern PATTERN_ID_CARD;
+ public static final Pattern PATTERN_NUM_OR_ALPHA;
public static final Pattern PATTERN_ALPHA;
public static final Pattern PATTERN_PASSWORD; //TODO
public static final Pattern PATTERN_NAME;
@@ -351,6 +352,7 @@ public static boolean isNotEmpty(String s, boolean trim) {
public static final Pattern PATTERN_BRANCH_URL;
static {
PATTERN_NUMBER = Pattern.compile("^[0-9]+$");
+ PATTERN_NUM_OR_ALPHA = Pattern.compile("^[0-9a-zA-Z_.:]+$");
PATTERN_ALPHA = Pattern.compile("^[a-zA-Z]+$");
PATTERN_ALPHA_BIG = Pattern.compile("^[A-Z]+$");
PATTERN_ALPHA_SMALL = Pattern.compile("^[a-z]+$");
@@ -442,6 +444,19 @@ public static boolean isNumberOrAlpha(String s) {
return isNumer(s) || isAlpha(s);
}
+ /**判断是否全是数字或字母
+ * @param s
+ * @return
+ */
+ public static boolean isCombineOfNumOrAlpha(String s) {
+ if (isEmpty(s, true)) {
+ return false;
+ }
+
+ currentString = s;
+ return PATTERN_NUM_OR_ALPHA.matcher(s).matches();
+ }
+
/**判断是否为代码名称,只能包含字母,数字或下划线
* @param s
* @return
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
index e9b6c0a02..45383553e 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
@@ -1792,17 +1792,18 @@ public String getSampleString(boolean hasPrefix) {
for (int i = 0; i < keys.length; i++) {
String item = keys[i];
- //if ("fill(null)".equals(item) || "fill(linear)".equals(item) || "fill(prev)".equals(item) || "fill(previous)".equals(item)) {
- // continue;
- //}
String origin = item;
if (isPrepared()) { //不能通过 ? 来代替,SELECT 'id','name' 返回的就是 id:"id", name:"name",而不是数据库里的值!
//这里既不对origin trim,也不对 ASC/DESC ignoreCase,希望前端严格传没有任何空格的字符串过来,减少传输数据量,节约服务器性能
- if (StringUtil.isNumberOrAlpha(origin) == false) {
+ if (StringUtil.isName(origin)) {}
+ else if (StringUtil.isCombineOfNumOrAlpha(origin)) {
+ continue;
+ }
+ else {
throw new IllegalArgumentException("预编译模式下 @sample:value 中 " + item + " 不合法! value 里面用 , 分割的"
- + "每一项必须是 column 且其中 column 必须是 字母或数字组合!并且不要有多余的空格!");
+ + "每一项必须是 column 且其中 column 必须是 数字或英语字母组合!并且不要有多余的空格!");
}
}
@@ -1994,13 +1995,21 @@ public String getFillString(boolean hasPrefix) {
for (int i = 0; i < keys.length; i++) {
String item = keys[i];
+ if ("NULL".equals(item) || "LINEAR".equals(item) || "PREV".equals(item) || "PREVIOUS".equals(item)) {
+ continue;
+ }
+
String origin = item;
if (isPrepared()) { //不能通过 ? 来代替,SELECT 'id','name' 返回的就是 id:"id", name:"name",而不是数据库里的值!
//这里既不对origin trim,也不对 ASC/DESC ignoreCase,希望前端严格传没有任何空格的字符串过来,减少传输数据量,节约服务器性能
- if (StringUtil.isName(origin) == false) {
+ if (StringUtil.isName(origin)) {}
+ else if (StringUtil.isCombineOfNumOrAlpha(origin)) {
+ continue;
+ }
+ else {
throw new IllegalArgumentException("预编译模式下 @fill:value 中 " + item + " 不合法! value 里面用 , 分割的"
- + "每一项必须是 column 且其中 column 必须是 英语单词!并且不要有多余的空格!");
+ + "每一项必须是 column 且其中 column 必须是 数字或英语字母组合!并且不要有多余的空格!");
}
}
@@ -3035,20 +3044,26 @@ public static int getOffset(int page, int count) {
@JSONField(serialize = false)
public String getLimitString() {
int count = getCount();
+ int page = getPage();
+
+ boolean isMilvus = isMilvus();
+ if ((count <= 0 && ! (isMilvus && isMain())) || RequestMethod.isHeadMethod(getMethod(), true)) { // TODO HEAD 真的不需要 LIMIT ?
+ return "";
+ }
boolean isSurrealDB = isSurrealDB();
boolean isQuestDB = isQuestDB();
- if (isSurrealDB || isQuestDB || isMilvus()) {
+ if (isSurrealDB || isQuestDB || isMilvus) {
if (count == 0) {
Parser parser = getParser();
count = parser == null ? AbstractParser.MAX_QUERY_COUNT : parser.getMaxQueryCount();
}
- int offset = getOffset(getPage(), count);
+ int offset = getOffset(page, count);
if (isQuestDB()) {
return " LIMIT " + offset + ", " + (offset + count);
}
- else if (isSurrealDB()) {
+ else if (isSurrealDB()) {
return " START " + offset + " LIMIT " + count;
}
else {
@@ -3056,18 +3071,8 @@ else if (isSurrealDB()) {
}
}
- if (count <= 0 || RequestMethod.isHeadMethod(getMethod(), true)) { // TODO HEAD 真的不需要 LIMIT ?
- return "";
- }
-
boolean isOracle = isOracle();
- return getLimitString(
- getPage()
- , count
- , isTSQL()
- , isOracle || isDameng() || isKingBase()
- , isPresto() || isTrino()
- );
+ return getLimitString(page, count, isTSQL(), isOracle || isDameng() || isKingBase(), isPresto() || isTrino());
}
/**获取限制数量及偏移量
* @param page
From 02d90c7499b0e88a3e72d1e3df57426341aee438 Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sun, 16 Mar 2025 16:28:40 +0800
Subject: [PATCH 052/122] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?=
=?UTF-8?q?=E6=8B=BC=E5=86=99=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
APIJSONORM/src/main/java/apijson/StringUtil.java | 14 +++++++-------
.../main/java/apijson/orm/AbstractSQLConfig.java | 4 ++--
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/APIJSONORM/src/main/java/apijson/StringUtil.java b/APIJSONORM/src/main/java/apijson/StringUtil.java
index 49c72677a..b357f5279 100755
--- a/APIJSONORM/src/main/java/apijson/StringUtil.java
+++ b/APIJSONORM/src/main/java/apijson/StringUtil.java
@@ -389,7 +389,7 @@ public static boolean isPassword(String s) {
* @return
*/
public static boolean isNumberPassword(String s) {
- return getLength(s, false) == 6 && isNumer(s);
+ return getLength(s, false) == 6 && isNumber(s);
}
/**判断email格式是否正确
* @param email
@@ -410,13 +410,13 @@ public static boolean isEmail(String email) {
* @return
*/
public static boolean isVerify(String s) {
- return getLength(s, false) >= 4 && isNumer(s);
+ return getLength(s, false) >= 4 && isNumber(s);
}
/**判断是否全是数字
* @param s
* @return
*/
- public static boolean isNumer(String s) {
+ public static boolean isNumber(String s) {
if (isNotEmpty(s, true) == false) {
return false;
}
@@ -441,7 +441,7 @@ public static boolean isAlpha(String s) {
* @return
*/
public static boolean isNumberOrAlpha(String s) {
- return isNumer(s) || isAlpha(s);
+ return isNumber(s) || isAlpha(s);
}
/**判断是否全是数字或字母
@@ -500,7 +500,7 @@ public static boolean isSmallName(String s) {
* @return
*/
public static boolean isIDCard(String number) {
- if (isNumberOrAlpha(number) == false) {
+ if (isCombineOfNumOrAlpha(number) == false) {
return false;
}
number = getString(number);
@@ -627,7 +627,7 @@ public static String getNumber(String s, boolean onlyStart) {
String single;
for (int i = 0; i < s.length(); i++) {
single = s.substring(i, i + 1);
- if (isNumer(single)) {
+ if (isNumber(single)) {
numberString.append(single);
} else {
if (onlyStart) {
@@ -732,7 +732,7 @@ public static String getPrice(String price, int formatType) {
String s;
for (int i = 0; i < price.length(); i++) {
s = price.substring(i, i + 1);
- if (".".equals(s) || isNumer(s)) {
+ if (".".equals(s) || isNumber(s)) {
correctPriceBuilder.append(s);
}
}
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
index 45383553e..a2882f463 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
@@ -2707,7 +2707,7 @@ else if ("!=null".equals(ck)) {
if (mk.length() > 0) {
origin = mk;
}
- } else if (StringUtil.isNumer(origin)) {
+ } else if (StringUtil.isNumber(origin)) {
//do nothing
} else {
String[] keys = origin.split("[.]");
@@ -2809,7 +2809,7 @@ else if (ck.contains("`") || ck.contains("'") || origin.startsWith("_") || origi
+ " 且不包含连续减号 -- !DISTINCT 必须全大写,且后面必须有且只有 1 个空格!其它情况不允许空格!");
}
- if (StringUtil.isNumer(origin)) {
+ if (StringUtil.isNumber(origin)) {
//do nothing
} else {
String[] keys = origin.split("[.]");
From 8cdca093659a9afb9a8908cdbfb31028ce96338a Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sun, 16 Mar 2025 16:29:54 +0800
Subject: [PATCH 053/122] =?UTF-8?q?=E5=88=A0=E9=99=A4=E5=A4=9A=E4=BD=99?=
=?UTF-8?q?=E7=9A=84=E4=BB=A3=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
APIJSONORM/src/main/java/apijson/StringUtil.java | 2 --
1 file changed, 2 deletions(-)
diff --git a/APIJSONORM/src/main/java/apijson/StringUtil.java b/APIJSONORM/src/main/java/apijson/StringUtil.java
index b357f5279..caac16d25 100755
--- a/APIJSONORM/src/main/java/apijson/StringUtil.java
+++ b/APIJSONORM/src/main/java/apijson/StringUtil.java
@@ -520,8 +520,6 @@ public static boolean isIDCard(String number) {
public static final String HTTP = "http";
public static final String URL_PREFIX = "http://";
public static final String URL_PREFIXs = "https://";
- public static final String URL_STAFFIX = URL_PREFIX;
- public static final String URL_STAFFIXs = URL_PREFIXs;
/**判断字符类型是否是网址
* @param url
* @return
From c9b124d7a1a8cfd48ee1f591d1d4a2ef989cf92f Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sun, 16 Mar 2025 17:17:38 +0800
Subject: [PATCH 054/122] =?UTF-8?q?=E7=AE=80=E5=8C=96=20StringUtil=20?=
=?UTF-8?q?=E4=B8=AD=E5=90=84=E7=A7=8D=E5=AD=97=E7=AC=A6=E4=B8=B2=E7=9B=B8?=
=?UTF-8?q?=E5=85=B3=E6=96=B9=E6=B3=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
APIJSONORM/src/main/java/apijson/JSON.java | 2 +-
.../src/main/java/apijson/JSONObject.java | 24 +-
.../src/main/java/apijson/JSONRequest.java | 4 +-
APIJSONORM/src/main/java/apijson/SQL.java | 2 +-
.../src/main/java/apijson/StringUtil.java | 300 +++++++++++++-----
.../main/java/apijson/orm/AbstractParser.java | 11 +-
.../java/apijson/orm/AbstractSQLConfig.java | 56 ++--
.../java/apijson/orm/AbstractSQLExecutor.java | 4 +-
.../java/apijson/orm/AbstractVerifier.java | 23 +-
.../src/main/java/apijson/orm/Logic.java | 2 +-
.../src/main/java/apijson/orm/Pair.java | 6 +-
.../src/main/java/apijson/orm/SQLConfig.java | 2 +-
12 files changed, 289 insertions(+), 147 deletions(-)
diff --git a/APIJSONORM/src/main/java/apijson/JSON.java b/APIJSONORM/src/main/java/apijson/JSON.java
index d7854aae1..0a1f901b7 100755
--- a/APIJSONORM/src/main/java/apijson/JSON.java
+++ b/APIJSONORM/src/main/java/apijson/JSON.java
@@ -48,7 +48,7 @@ public static String getCorrectJson(String s) {
* @return
*/
public static String getCorrectJson(String s, boolean isArray) {
- s = StringUtil.getTrimedString(s);
+ s = StringUtil.trim(s);
// if (isArray) {
// while (s.startsWith("\"")) {
// s = s.substring(1);
diff --git a/APIJSONORM/src/main/java/apijson/JSONObject.java b/APIJSONORM/src/main/java/apijson/JSONObject.java
index c69a03569..0adf18365 100755
--- a/APIJSONORM/src/main/java/apijson/JSONObject.java
+++ b/APIJSONORM/src/main/java/apijson/JSONObject.java
@@ -326,7 +326,7 @@ public JSONObject setCache(String cache) {
* @return {@link #setColumn(String)}
*/
public JSONObject setColumn(String... keys) {
- return setColumn(StringUtil.getString(keys, true));
+ return setColumn(StringUtil.get(keys, true));
}
/**set keys need to be returned
* @param keys "key0,key1,key2..."
@@ -341,7 +341,7 @@ public JSONObject setColumn(String keys) {
* @return {@link #setNull(String)}
*/
public JSONObject setNull(String... keys) {
- return setNull(StringUtil.getString(keys, true));
+ return setNull(StringUtil.get(keys, true));
}
/**set keys whose value is null
* @param keys "key0,key1,key2..."
@@ -356,7 +356,7 @@ public JSONObject setNull(String keys) {
* @return {@link #setCast(String)}
*/
public JSONObject setCast(String... keyTypes) {
- return setCast(StringUtil.getString(keyTypes, true));
+ return setCast(StringUtil.get(keyTypes, true));
}
/**set keys and types whose value should be cast to type, cast(value AS DATE)
* @param keyTypes "key0:type0,key1:type1,key2:type2..."
@@ -371,7 +371,7 @@ public JSONObject setCast(String keyTypes) {
* @return {@link #setColumn(String)}
*/
public JSONObject setCombine(String... keys) {
- return setCombine(StringUtil.getString(keys, true));
+ return setCombine(StringUtil.get(keys, true));
}
/**set combination of keys for conditions
* @param keys key0,&key1,|key2,!key3 ... TODO or key0> | (key1{} & !key2)...
@@ -386,7 +386,7 @@ public JSONObject setCombine(String keys) {
* @return {@link #setGroup(String)}
*/
public JSONObject setGroup(String... keys) {
- return setGroup(StringUtil.getString(keys, true));
+ return setGroup(StringUtil.get(keys, true));
}
/**set keys for group by
* @param keys "key0,key1,key2..."
@@ -401,7 +401,7 @@ public JSONObject setGroup(String keys) {
* @return {@link #setHaving(String)}
*/
public JSONObject setHaving(String... keys) {
- return setHaving(StringUtil.getString(keys, true));
+ return setHaving(StringUtil.get(keys, true));
}
/**set keys for having
* @param keys "key0,key1,key2..."
@@ -423,7 +423,7 @@ public JSONObject setHaving(String keys, boolean isAnd) {
* @return {@link #setSample(String)}
*/
public JSONObject setSample(String... keys) {
- return setSample(StringUtil.getString(keys, true));
+ return setSample(StringUtil.get(keys, true));
}
/**set keys for sample by
* @param keys "key0,key1,key2..."
@@ -438,7 +438,7 @@ public JSONObject setSample(String keys) {
* @return {@link #setLatest(String)}
*/
public JSONObject setLatest(String... keys) {
- return setLatest(StringUtil.getString(keys, true));
+ return setLatest(StringUtil.get(keys, true));
}
/**set keys for latest on
* @param keys "key0,key1,key2..."
@@ -453,7 +453,7 @@ public JSONObject setLatest(String keys) {
* @return {@link #setPartition(String)}
*/
public JSONObject setPartition(String... keys) {
- return setPartition(StringUtil.getString(keys, true));
+ return setPartition(StringUtil.get(keys, true));
}
/**set keys for partition by
* @param keys key0, key1, key2 ...
@@ -468,7 +468,7 @@ public JSONObject setPartition(String keys) {
* @return {@link #setFill(String)}
*/
public JSONObject setFill(String... keys) {
- return setFill(StringUtil.getString(keys, true));
+ return setFill(StringUtil.get(keys, true));
}
/**set keys for fill(key): fill(null), fill(linear), fill(prev)
* @param keys key0, key1, key2 ...
@@ -483,7 +483,7 @@ public JSONObject setFill(String keys) {
* @return {@link #setOrder(String)}
*/
public JSONObject setOrder(String... keys) {
- return setOrder(StringUtil.getString(keys, true));
+ return setOrder(StringUtil.get(keys, true));
}
/**set keys for order by
* @param keys "key0,key1+,key2-..."
@@ -530,7 +530,7 @@ public JSONObject setJson(String keys) {
* @return {@link #puts(String, Object)}
*/
public JSONObject putsPath(String key, String... keys) {
- return puts(key+"@", StringUtil.getString(keys, "/"));
+ return puts(key+"@", StringUtil.get(keys, "/"));
}
/**
diff --git a/APIJSONORM/src/main/java/apijson/JSONRequest.java b/APIJSONORM/src/main/java/apijson/JSONRequest.java
index 62d724199..ae5e19950 100755
--- a/APIJSONORM/src/main/java/apijson/JSONRequest.java
+++ b/APIJSONORM/src/main/java/apijson/JSONRequest.java
@@ -138,7 +138,7 @@ public JSONRequest setPage(int page) {
* @return
*/
public JSONRequest setJoin(String... joins) {
- return puts(KEY_JOIN, StringUtil.getString(joins));
+ return puts(KEY_JOIN, StringUtil.get(joins));
}
/**set range for Subquery
@@ -178,7 +178,7 @@ public JSONRequest toArray(int count, int page) {
* @return {name+KEY_ARRAY : this}. if needs to be put, use {@link #putsAll(Map extends String, ? extends Object>)} instead
*/
public JSONRequest toArray(int count, int page, String name) {
- return new JSONRequest(StringUtil.getString(name) + KEY_ARRAY, this.setCount(count).setPage(page));
+ return new JSONRequest(StringUtil.get(name) + KEY_ARRAY, this.setCount(count).setPage(page));
}
diff --git a/APIJSONORM/src/main/java/apijson/SQL.java b/APIJSONORM/src/main/java/apijson/SQL.java
index 6cec79bd2..110ae3d47 100755
--- a/APIJSONORM/src/main/java/apijson/SQL.java
+++ b/APIJSONORM/src/main/java/apijson/SQL.java
@@ -242,7 +242,7 @@ public static String toLowerCase(String s) {
* @return column.isEmpty() ? "*" : column;
*/
public static String column(String column) {
- column = StringUtil.getTrimedString(column);
+ column = StringUtil.trim(column);
return column.isEmpty() ? "*" : column;
}
/**有别名的字段
diff --git a/APIJSONORM/src/main/java/apijson/StringUtil.java b/APIJSONORM/src/main/java/apijson/StringUtil.java
index caac16d25..13b0ff214 100755
--- a/APIJSONORM/src/main/java/apijson/StringUtil.java
+++ b/APIJSONORM/src/main/java/apijson/StringUtil.java
@@ -53,171 +53,317 @@ public StringUtil() {
public static final String YUAN = "元";
- private static String currentString = "";
- /**获取刚传入处理后的string
+ private static String current = "";
+ /**获取刚传入处理后的 string
+ * @must 上个影响 current 的方法 和 这个方法都应该在同一线程中,否则返回值可能不对
+ * @return
+ */
+ public static String cur() {
+ return get(current);
+ }
+
+ /**FIXME 改用 cur
* @must 上个影响currentString的方法 和 这个方法都应该在同一线程中,否则返回值可能不对
* @return
*/
+ @Deprecated
public static String getCurrentString() {
- return currentString == null ? "" : currentString;
+ return cur();
}
//获取string,为null时返回"" <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
/**获取string,为null则返回""
+ * @param obj
+ * @return
+ */
+ public static String get(Object obj) {
+ return obj == null ? "" : obj.toString();
+ }
+ /**获取string,为null则返回""
+ * @param s
+ * @return
+ */
+ public static String get(String s) {
+ return s == null ? "" : s;
+ }
+ /**获取string,为null则返回""
+ * ignoreEmptyItem = false;
+ * split = ","
+ * @param arr
+ * @return {@link #get(Object[], boolean)}
+ */
+ public static String get(Object[] arr) {
+ return get(arr, false);
+ }
+ /**获取string,为null则返回""
+ * split = ","
+ * @param arr
+ * @param ignoreEmptyItem
+ * @return {@link #get(Object[], boolean)}
+ */
+ public static String get(Object[] arr, boolean ignoreEmptyItem) {
+ return get(arr, null, ignoreEmptyItem);
+ }
+ /**获取string,为null则返回""
+ * ignoreEmptyItem = false;
+ * @param arr
+ * @param split
+ * @return {@link #get(Object[], String, boolean)}
+ */
+ public static String get(Object[] arr, String split) {
+ return get(arr, split, false);
+ }
+ //CS304 Issue link: https://github.com/Tencent/APIJSON/issues/182
+ /**获取string,为null则返回""
+ * @param arr -the str arr given
+ * @param split -the token used to split
+ * @param ignoreEmptyItem -whether to ignore empty item or not
+ * @return {@link #get(Object[], String, boolean)}
+ * Here we replace the simple "+" way of concatenating with Stringbuilder 's append
+ */
+ public static String get(Object[] arr, String split, boolean ignoreEmptyItem) {
+ StringBuilder s = new StringBuilder("");
+ if (arr != null) {
+ if (split == null) {
+ split = ",";
+ }
+ for (int i = 0; i < arr.length; i++) {
+ if (ignoreEmptyItem && isEmpty(arr[i], true)) {
+ continue;
+ }
+ s.append(((i > 0 ? split : "") + arr[i]));
+ }
+ }
+ return get(s.toString());
+ }
+
+ /**FIXME 用 get 替代
* @param object
* @return
*/
+ @Deprecated
public static String getString(Object object) {
return object == null ? "" : object.toString();
}
- /**获取string,为null则返回""
+ /**FIXME 用 get 替代
* @param cs
* @return
*/
+ @Deprecated
public static String getString(CharSequence cs) {
return cs == null ? "" : cs.toString();
}
- /**获取string,为null则返回""
+ /**FIXME 用 get 替代
* @param s
* @return
*/
+ @Deprecated
public static String getString(String s) {
return s == null ? "" : s;
}
- /**获取string,为null则返回""
+ /**FIXME 用 get 替代
* ignoreEmptyItem = false;
* split = ","
* @param array
- * @return {@link #getString(Object[], boolean)}
+ * @return {@link #get(Object[], boolean)}
*/
+ @Deprecated
public static String getString(Object[] array) {
- return getString(array, false);
+ return get(array, false);
}
- /**获取string,为null则返回""
+ /**FIXME 用 get 替代
* split = ","
* @param array
* @param ignoreEmptyItem
- * @return {@link #getString(Object[], boolean)}
+ * @return {@link #get(Object[], boolean)}
*/
+ @Deprecated
public static String getString(Object[] array, boolean ignoreEmptyItem) {
- return getString(array, null, ignoreEmptyItem);
+ return get(array, null, ignoreEmptyItem);
}
- /**获取string,为null则返回""
+ /**FIXME 用 get 替代
* ignoreEmptyItem = false;
* @param array
* @param split
- * @return {@link #getString(Object[], String, boolean)}
+ * @return {@link #get(Object[], String, boolean)}
*/
+ @Deprecated
public static String getString(Object[] array, String split) {
- return getString(array, split, false);
+ return get(array, split, false);
}
//CS304 Issue link: https://github.com/Tencent/APIJSON/issues/182
- /**获取string,为null则返回""
+ /**FIXME 用 get 替代
* @param array -the str array given
* @param split -the token used to split
* @param ignoreEmptyItem -whether to ignore empty item or not
- * @return {@link #getString(Object[], String, boolean)}
+ * @return {@link #get(Object[], String, boolean)}
* Here we replace the simple "+" way of concatenating with Stringbuilder 's append
*/
+ @Deprecated
public static String getString(Object[] array, String split, boolean ignoreEmptyItem) {
- StringBuilder s = new StringBuilder("");
- if (array != null) {
- if (split == null) {
- split = ",";
- }
- for (int i = 0; i < array.length; i++) {
- if (ignoreEmptyItem && isEmpty(array[i], true)) {
- continue;
- }
- s.append(((i > 0 ? split : "") + array[i]));
- }
- }
- return getString(s.toString());
+ return get(array, split, ignoreEmptyItem);
}
//获取string,为null时返回"" >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//获取去掉前后空格后的string<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
-
/**获取去掉前后空格后的string,为null则返回""
+ * @param obj
+ * @return
+ */
+ public static String trim(Object obj) {
+ return trim(get(obj));
+ }
+ /**获取去掉前后空格后的string,为null则返回""
+ * @param cs
+ * @return
+ */
+ public static String trim(CharSequence cs) {
+ return trim(get(cs));
+ }
+ /**获取去掉前后空格后的string,为null则返回""
+ * @param s
+ * @return
+ */
+ public static String trim(String s) {
+ return get(s).trim();
+ }
+
+
+ /**FIXME 用 trim 替代
* @param object
* @return
*/
+ @Deprecated
public static String getTrimedString(Object object) {
- return getTrimedString(getString(object));
+ return trim(object);
}
- /**获取去掉前后空格后的string,为null则返回""
+ /**FIXME 用 trim 替代
* @param cs
* @return
*/
+ @Deprecated
public static String getTrimedString(CharSequence cs) {
- return getTrimedString(getString(cs));
+ return trim(cs);
}
- /**获取去掉前后空格后的string,为null则返回""
+ /**FIXME 用 trim 替代
* @param s
* @return
*/
+ @Deprecated
public static String getTrimedString(String s) {
- return getString(s).trim();
+ return trim(s);
}
//获取去掉前后空格后的string>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//获取去掉所有空格后的string <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
-
/**获取去掉所有空格后的string,为null则返回""
+ * @param obj
+ * @return
+ */
+ public static String noBlank(Object obj) {
+ return noBlank(get(obj));
+ }
+ /**获取去掉所有空格后的string,为null则返回""
+ * @param cs
+ * @return
+ */
+ public static String noBlank(CharSequence cs) {
+ return noBlank(get(cs));
+ }
+ /**获取去掉所有空格后的string,为null则返回""
+ * @param s
+ * @return
+ */
+ public static String noBlank(String s) {
+ return get(s).replaceAll("\\s", "");
+ }
+
+ /**FIXME 用 noBlank 替代
* @param object
* @return
*/
+ @Deprecated
public static String getNoBlankString(Object object) {
- return getNoBlankString(getString(object));
+ return noBlank(object);
}
- /**获取去掉所有空格后的string,为null则返回""
+ /**FIXME 用 noBlank 替代
* @param cs
* @return
*/
+ @Deprecated
public static String getNoBlankString(CharSequence cs) {
- return getNoBlankString(getString(cs));
+ return noBlank(cs);
}
- /**获取去掉所有空格后的string,为null则返回""
+ /**FIXME 用 noBlank 替代
* @param s
* @return
*/
+ @Deprecated
public static String getNoBlankString(String s) {
- return getString(s).replaceAll("\\s", "");
+ return noBlank(s);
}
//获取去掉所有空格后的string >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//获取string的长度<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
-
/**获取string的长度,为null则返回0
* @param object
* @param trim
* @return
*/
- public static int getLength(Object object, boolean trim) {
- return getLength(getString(object), trim);
+ public static int length(Object object, boolean trim) {
+ return length(get(object), trim);
}
/**获取string的长度,为null则返回0
* @param cs
* @param trim
* @return
*/
- public static int getLength(CharSequence cs, boolean trim) {
- return getLength(getString(cs), trim);
+ public static int length(CharSequence cs, boolean trim) {
+ return length(get(cs), trim);
}
/**获取string的长度,为null则返回0
* @param s
* @param trim
* @return
*/
+ public static int length(String s, boolean trim) {
+ s = trim ? trim(s) : s;
+ return get(s).length();
+ }
+
+
+ /**FIXME 用 length 替代
+ * @param object
+ * @param trim
+ * @return
+ */
+ @Deprecated
+ public static int getLength(Object object, boolean trim) {
+ return length(object, trim);
+ }
+ /**FIXME 用 length 替代
+ * @param cs
+ * @param trim
+ * @return
+ */
+ @Deprecated
+ public static int getLength(CharSequence cs, boolean trim) {
+ return length(cs, trim);
+ }
+ /**FIXME 用 length 替代
+ * @param s
+ * @param trim
+ * @return
+ */
+ @Deprecated
public static int getLength(String s, boolean trim) {
- s = trim ? getTrimedString(s) : s;
- return getString(s).length();
+ return length(s, trim);
}
//获取string的长度>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
@@ -238,7 +384,7 @@ public static boolean isEmpty(Object obj) {
* @return
*/
public static boolean isEmpty(Object obj, boolean trim) {
- return isEmpty(getString(obj), trim);
+ return isEmpty(get(obj), trim);
}
/**判断字符是否为空 trim = true
* @param cs
@@ -253,7 +399,7 @@ public static boolean isEmpty(CharSequence cs) {
* @return
*/
public static boolean isEmpty(CharSequence cs, boolean trim) {
- return isEmpty(getString(cs), trim);
+ return isEmpty(get(cs), trim);
}
/**判断字符是否为空 trim = true
* @param s
@@ -268,7 +414,7 @@ public static boolean isEmpty(String s) {
* @return
*/
public static boolean isEmpty(String s, boolean trim) {
- // Log.i(TAG, "getTrimedString s = " + s);
+ // Log.i(TAG, "isEmpty s = " + s);
if (s == null) {
return true;
}
@@ -279,7 +425,7 @@ public static boolean isEmpty(String s, boolean trim) {
return true;
}
- currentString = s;
+ current = s;
return false;
}
@@ -289,7 +435,7 @@ public static boolean isEmpty(String s, boolean trim) {
//判断字符是否非空 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
/**判断字符是否非空 trim = true
- * @param object
+ * @param obj
* @return
*/
public static boolean isNotEmpty(Object obj) {
@@ -374,7 +520,7 @@ public static boolean isPhone(String phone) {
return false;
}
- currentString = phone;
+ current = phone;
return PATTERN_PHONE.matcher(phone).matches();
}
/**判断手机格式是否正确
@@ -382,14 +528,14 @@ public static boolean isPhone(String phone) {
* @return
*/
public static boolean isPassword(String s) {
- return getLength(s, false) >= 6 && PATTERN_PASSWORD.matcher(s).matches();
+ return length(s, false) >= 6 && PATTERN_PASSWORD.matcher(s).matches();
}
/**判断是否全是数字密码
* @param s
* @return
*/
public static boolean isNumberPassword(String s) {
- return getLength(s, false) == 6 && isNumber(s);
+ return length(s, false) == 6 && isNumber(s);
}
/**判断email格式是否正确
* @param email
@@ -400,7 +546,7 @@ public static boolean isEmail(String email) {
return false;
}
- currentString = email;
+ current = email;
return PATTERN_EMAIL.matcher(email).matches();
}
@@ -410,18 +556,18 @@ public static boolean isEmail(String email) {
* @return
*/
public static boolean isVerify(String s) {
- return getLength(s, false) >= 4 && isNumber(s);
+ return length(s, false) >= 4 && isNumber(s);
}
/**判断是否全是数字
* @param s
* @return
*/
public static boolean isNumber(String s) {
- if (isNotEmpty(s, true) == false) {
+ if (isEmpty(s, true)) {
return false;
}
- currentString = s;
+ current = s;
return PATTERN_NUMBER.matcher(s).matches();
}
/**判断是否全是字母
@@ -433,7 +579,7 @@ public static boolean isAlpha(String s) {
return false;
}
- currentString = s;
+ current = s;
return PATTERN_ALPHA.matcher(s).matches();
}
/**判断是否全是数字或字母
@@ -453,7 +599,7 @@ public static boolean isCombineOfNumOrAlpha(String s) {
return false;
}
- currentString = s;
+ current = s;
return PATTERN_NUM_OR_ALPHA.matcher(s).matches();
}
@@ -503,14 +649,14 @@ public static boolean isIDCard(String number) {
if (isCombineOfNumOrAlpha(number) == false) {
return false;
}
- number = getString(number);
+ number = get(number);
if (number.length() == 15) {
Log.i(TAG, "isIDCard number.length() == 15 old IDCard");
- currentString = number;
+ current = number;
return true;
}
if (number.length() == 18) {
- currentString = number;
+ current = number;
return true;
}
@@ -532,7 +678,7 @@ public static boolean isUrl(String url) {
return false;
}
- currentString = url;
+ current = url;
return true;
}
@@ -577,7 +723,7 @@ public static boolean isFilePath(String path) {
return false;
}
- currentString = path;
+ current = path;
return true;
}
@@ -592,14 +738,14 @@ public static boolean isFilePath(String path) {
* @return
*/
public static String getNumber(Object object) {
- return getNumber(getString(object));
+ return getNumber(get(object));
}
/**去掉string内所有非数字类型字符
* @param cs
* @return
*/
public static String getNumber(CharSequence cs) {
- return getNumber(getString(cs));
+ return getNumber(get(cs));
}
/**去掉string内所有非数字类型字符
* @param s
@@ -617,7 +763,7 @@ public static String getNumber(String s) {
* Here we replace the simple "+" way of concatenating with Stringbuilder 's append
*/
public static String getNumber(String s, boolean onlyStart) {
- if (isNotEmpty(s, true) == false) {
+ if (isEmpty(s, true)) {
return "";
}
@@ -669,7 +815,7 @@ public static String getCorrectPhone(String phone) {
return "";
}
- phone = getNoBlankString(phone);
+ phone = noBlank(phone);
phone = phone.replaceAll("-", "");
if (phone.startsWith("+86")) {
phone = phone.substring(3);
@@ -687,7 +833,7 @@ public static String getCorrectEmail(String email) {
return "";
}
- email = getNoBlankString(email);
+ email = noBlank(email);
if (isEmail(email) == false && ! email.endsWith(".com")) {
email += ".com";
}
@@ -857,7 +1003,7 @@ public static String[] split(String s, boolean trim) {
* @return
*/
public static String[] split(String s, String split, boolean trim) {
- s = getString(s);
+ s = get(s);
if (s.isEmpty()) {
return null;
}
@@ -881,7 +1027,7 @@ public static String[] split(String s, String split, boolean trim) {
* @return key + suffix,第一个字母小写
*/
public static String addSuffix(String key, String suffix) {
- key = getNoBlankString(key);
+ key = noBlank(key);
if (key.isEmpty()) {
return firstCase(suffix);
}
@@ -899,7 +1045,7 @@ public static String firstCase(String key) {
* @return
*/
public static String firstCase(String key, boolean upper) {
- key = getString(key);
+ key = get(key);
if (key.isEmpty()) {
return "";
}
@@ -923,7 +1069,7 @@ public static String toUpperCase(String s) {
* @return
*/
public static String toUpperCase(String s, boolean trim) {
- s = trim ? getTrimedString(s) : getString(s);
+ s = trim ? trim(s) : get(s);
return s.toUpperCase();
}
/**全部小写
@@ -938,7 +1084,7 @@ public static String toLowerCase(String s) {
* @return
*/
public static String toLowerCase(String s, boolean trim) {
- s = trim ? getTrimedString(s) : getString(s);
+ s = trim ? trim(s) : get(s);
return s.toLowerCase();
}
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
index fd56b71b9..061e32d11 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
@@ -14,7 +14,6 @@
import java.net.InetAddress;
import java.net.URLDecoder;
import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Savepoint;
@@ -819,9 +818,9 @@ public static JSONObject extendResult(JSONObject object, int code, String msg, S
object.put(JSONResponse.KEY_CODE, code);
}
- String m = StringUtil.getString(object.getString(JSONResponse.KEY_MSG));
+ String m = StringUtil.get(object.getString(JSONResponse.KEY_MSG));
if (m.isEmpty() == false) {
- msg = m + " ;\n " + StringUtil.getString(msg);
+ msg = m + " ;\n " + StringUtil.get(msg);
}
object.put(JSONResponse.KEY_MSG, msg);
@@ -1875,8 +1874,8 @@ public static String getValuePath(String parentPath, String valuePath) {
*/
public static String getAbsPath(String path, String name) {
Log.i(TAG, "getPath path = " + path + "; name = " + name + " <<<<<<<<<<<<<");
- path = StringUtil.getString(path);
- name = StringUtil.getString(name);
+ path = StringUtil.get(path);
+ name = StringUtil.get(name);
if (StringUtil.isNotEmpty(path, false)) {
if (StringUtil.isNotEmpty(name, false)) {
path += ((name.startsWith("/") ? "" : "/") + name);
@@ -1917,7 +1916,7 @@ public static String replaceArrayChildPath(String parentPath, String valuePath)
vs[i+1] = pos + "/" + vs[i+1];
}
}
- return StringUtil.getString(vs, "]/");
+ return StringUtil.get(vs, "]/");
}
}
return valuePath;
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
index a2882f463..4dd665edf 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
@@ -1556,7 +1556,7 @@ public String getGroup() {
return group;
}
public AbstractSQLConfig setGroup(String... keys) {
- return setGroup(StringUtil.getString(keys));
+ return setGroup(StringUtil.get(keys));
}
@Override
public AbstractSQLConfig setGroup(String group) {
@@ -1593,7 +1593,7 @@ public String getGroupString(boolean hasPrefix) {
}
- group = StringUtil.getTrimedString(group);
+ group = StringUtil.trim(group);
String[] keys = StringUtil.split(group);
if (keys == null || keys.length <= 0) {
return StringUtil.isEmpty(joinGroup, true) ? "" : (hasPrefix ? " GROUP BY " : "") + joinGroup;
@@ -1610,7 +1610,7 @@ public String getGroupString(boolean hasPrefix) {
keys[i] = getKey(keys[i]);
}
- return (hasPrefix ? " GROUP BY " : "") + StringUtil.concat(StringUtil.getString(keys), joinGroup, ", ");
+ return (hasPrefix ? " GROUP BY " : "") + StringUtil.concat(StringUtil.get(keys), joinGroup, ", ");
}
@Override
@@ -1633,7 +1633,7 @@ public AbstractSQLConfig setHaving(Map having) {
return this;
}
public AbstractSQLConfig setHaving(String... conditions) {
- return setHaving(StringUtil.getString(conditions));
+ return setHaving(StringUtil.get(conditions));
}
/**TODO @having 改为默认 | 或连接,且支持 @having: { "key1>": 1, "key{}": "length(key2)>0", "@combine": "key1,key2" }
@@ -1747,7 +1747,7 @@ public String getSample() {
return sample;
}
public AbstractSQLConfig setSample(String... conditions) {
- return setSample(StringUtil.getString(conditions));
+ return setSample(StringUtil.get(conditions));
}
@Override
public AbstractSQLConfig setSample(String sample) {
@@ -1783,7 +1783,7 @@ public String getSampleString(boolean hasPrefix) {
}
}
- String sample = StringUtil.getTrimedString(getSample());
+ String sample = StringUtil.trim(getSample());
String[] keys = StringUtil.split(sample);
if (keys == null || keys.length <= 0) {
@@ -1810,7 +1810,7 @@ else if (StringUtil.isCombineOfNumOrAlpha(origin)) {
keys[i] = getKey(origin);
}
- return (hasPrefix ? " SAMPLE BY " : "") + StringUtil.concat(StringUtil.getString(keys), joinSample, ", ");
+ return (hasPrefix ? " SAMPLE BY " : "") + StringUtil.concat(StringUtil.get(keys), joinSample, ", ");
}
@Override
@@ -1818,7 +1818,7 @@ public String getLatest() {
return latest;
}
public AbstractSQLConfig setLatest(String... conditions) {
- return setLatest(StringUtil.getString(conditions));
+ return setLatest(StringUtil.get(conditions));
}
@Override
public AbstractSQLConfig setLatest(String latest) {
@@ -1854,7 +1854,7 @@ public String getLatestString(boolean hasPrefix) {
}
}
- String latest = StringUtil.getTrimedString(getLatest());
+ String latest = StringUtil.trim(getLatest());
String[] keys = StringUtil.split(latest);
if (keys == null || keys.length <= 0) {
@@ -1876,7 +1876,7 @@ public String getLatestString(boolean hasPrefix) {
keys[i] = getKey(origin);
}
- return (hasPrefix ? " LATEST ON " : "") + StringUtil.concat(StringUtil.getString(keys), joinLatest, ", ");
+ return (hasPrefix ? " LATEST ON " : "") + StringUtil.concat(StringUtil.get(keys), joinLatest, ", ");
}
@Override
@@ -1884,7 +1884,7 @@ public String getPartition() {
return partition;
}
public AbstractSQLConfig setPartition(String... conditions) {
- return setPartition(StringUtil.getString(conditions));
+ return setPartition(StringUtil.get(conditions));
}
@Override
public AbstractSQLConfig setPartition(String partition) {
@@ -1920,7 +1920,7 @@ public String getPartitionString(boolean hasPrefix) {
}
}
- String partition = StringUtil.getTrimedString(getPartition());
+ String partition = StringUtil.trim(getPartition());
String[] keys = StringUtil.split(partition);
if (keys == null || keys.length <= 0) {
@@ -1942,7 +1942,7 @@ public String getPartitionString(boolean hasPrefix) {
keys[i] = getKey(origin);
}
- return (hasPrefix ? " PARTITION BY " : "") + StringUtil.concat(StringUtil.getString(keys), joinPartition, ", ");
+ return (hasPrefix ? " PARTITION BY " : "") + StringUtil.concat(StringUtil.get(keys), joinPartition, ", ");
}
@Override
@@ -1950,7 +1950,7 @@ public String getFill() {
return fill;
}
public AbstractSQLConfig setFill(String... conditions) {
- return setFill(StringUtil.getString(conditions));
+ return setFill(StringUtil.get(conditions));
}
@Override
public AbstractSQLConfig setFill(String fill) {
@@ -1986,7 +1986,7 @@ public String getFillString(boolean hasPrefix) {
}
}
- String fill = StringUtil.getTrimedString(getFill());
+ String fill = StringUtil.trim(getFill());
String[] keys = StringUtil.split(fill);
if (keys == null || keys.length <= 0) {
@@ -2016,7 +2016,7 @@ else if (StringUtil.isCombineOfNumOrAlpha(origin)) {
keys[i] = getKey(origin);
}
- return (hasPrefix ? " FILL(" : "") + StringUtil.concat(StringUtil.getString(keys), joinFill, ", ") + ")";
+ return (hasPrefix ? " FILL(" : "") + StringUtil.concat(StringUtil.get(keys), joinFill, ", ") + ")";
}
@Override
@@ -2024,7 +2024,7 @@ public String getOrder() {
return order;
}
public AbstractSQLConfig setOrder(String... conditions) {
- return setOrder(StringUtil.getString(conditions));
+ return setOrder(StringUtil.get(conditions));
}
@Override
public AbstractSQLConfig setOrder(String order) {
@@ -2061,7 +2061,7 @@ public String getOrderString(boolean hasPrefix) {
}
- String order = StringUtil.getTrimedString(getOrder());
+ String order = StringUtil.trim(getOrder());
// SELECT * FROM sys.Moment ORDER BY userId ASC, rand(); 前面的 userId ASC 和后面的 rand() 都有效
// if ("rand()".equals(order)) {
// return (hasPrefix ? " ORDER BY " : "") + StringUtil.concat(order, joinOrder, ", ");
@@ -2134,7 +2134,7 @@ public String getOrderString(boolean hasPrefix) {
keys[i] = getKey(origin) + sort;
}
- return (hasPrefix ? " ORDER BY " : "") + StringUtil.concat(StringUtil.getString(keys), joinOrder, ", ");
+ return (hasPrefix ? " ORDER BY " : "") + StringUtil.concat(StringUtil.get(keys), joinOrder, ", ");
}
@Override
@@ -2426,7 +2426,7 @@ public String getColumnString(boolean inSQLJoin) throws Exception {
, "@column:\"column0,column1:alias1;function0(arg0,arg1,...);function1(...):alias2...\"");
}
- String c = StringUtil.getString(keys);
+ String c = StringUtil.get(keys);
c = c + (StringUtil.isEmpty(joinColumn, true) ? "" : ", " + joinColumn);//不能在这里改,后续还要用到:
return isMain() && isDistinct() ? PREFIX_DISTINCT + c : c;
default:
@@ -2471,7 +2471,7 @@ public String parseSQLExpression(String key, String expression, boolean containR
if (start < 0) {
//没有函数 ,可能是字段,也可能是 DISTINCT xx
String[] cks = parseArgsSplitWithComma(expression, true, containRaw, allowAlias);
- expression = StringUtil.getString(cks);
+ expression = StringUtil.get(cks);
} else { // FIXME 用括号断开? 如果少的话,用关键词加括号断开,例如 )OVER( 和 )AGAINST(
// 窗口函数 rank() OVER (PARTITION BY id ORDER BY userId ASC)
// 全文索引 math(name,tag) AGAINST ('a b +c -d' IN NATURALE LANGUAGE MODE) // IN BOOLEAN MODE
@@ -2547,7 +2547,7 @@ public String parseSQLExpression(String key, String expression, boolean containR
+ " 中 ?value 必须符合正则表达式 " + PATTERN_RANGE + " 且不包含连续减号 -- 或注释符 /* !不允许多余的空格!");
}
- String origin = fun + "(" + (distinct ? PREFIX_DISTINCT : "") + StringUtil.getString(ckeys) + ")" + suffix;
+ String origin = fun + "(" + (distinct ? PREFIX_DISTINCT : "") + StringUtil.get(ckeys) + ")" + suffix;
expression = origin + (StringUtil.isEmpty(alias, true) ? "" : getAs() + quote + alias + quote);
}
else {
@@ -2604,8 +2604,8 @@ else if (SQL_FUNCTION_MAP.containsKey(fun) == false) {
// 获取后半部分的参数解析 (agr0 agr1 ...)
String argsString2[] = parseArgsSplitWithComma(argString2, false, containRaw, allowAlias);
- expression = fun + "(" + StringUtil.getString(agrsString1) + (containOver ? ") OVER (" : ") AGAINST (")
- + StringUtil.getString(argsString2) + ")" + suffix // 传参不传空格,拼接带空格
+ expression = fun + "(" + StringUtil.get(agrsString1) + (containOver ? ") OVER (" : ") AGAINST (")
+ + StringUtil.get(argsString2) + ")" + suffix // 传参不传空格,拼接带空格
+ (StringUtil.isEmpty(alias, true) ? "" : getAs() + quote + alias + quote);
}
}
@@ -2867,7 +2867,7 @@ public String getValuesString() {
}
items[i] += ")";
}
- s = StringUtil.getString(items);
+ s = StringUtil.get(items);
}
return s;
}
@@ -3367,7 +3367,7 @@ protected String parseCombineExpression(RequestMethod method, String quote, Stri
, Map conditionMap, String combine, boolean verifyName, boolean containRaw, boolean isHaving) throws Exception {
String errPrefix = table + (isHaving ? ":{ @having:{ " : ":{ ") + "@combine:'" + combine + (isHaving ? "' } }" : "' }");
- String s = StringUtil.getString(combine);
+ String s = StringUtil.get(combine);
if (s.startsWith(" ") || s.endsWith(" ") ) {
throw new IllegalArgumentException(errPrefix + " 中字符 '" + s
+ "' 不合法!不允许首尾有空格,也不允许连续空格!空格不能多也不能少!"
@@ -5463,7 +5463,7 @@ public static SQLConfig newSQLConfig(RequestMethod method,
String database = request.getString(KEY_DATABASE);
if (StringUtil.isEmpty(database, false) == false && DATABASE_LIST.contains(database) == false) {
throw new UnsupportedDataTypeException("@database:value 中 value 错误,只能是 ["
- + StringUtil.getString(DATABASE_LIST.toArray()) + "] 中的一种!");
+ + StringUtil.get(DATABASE_LIST.toArray()) + "] 中的一种!");
}
String datasource = request.getString(KEY_DATASOURCE);
@@ -5748,7 +5748,7 @@ else if (userId instanceof Subquery) {}
}
column = (id == null ? "" : idKey + ",") + (userId == null ? "" : userIdKey + ",")
- + StringUtil.getString(columns); //set已经判断过不为空
+ + StringUtil.get(columns); //set已经判断过不为空
int idCount = id == null ? (userId == null ? 0 : 1) : (userId == null ? 1 : 2);
int size = idCount + columns.length; // 以 key 数量为准
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java
index 35d1efda2..838f5a8a8 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java
@@ -190,8 +190,8 @@ public JSONObject execute(@NotNull SQLConfig config, boolean unknownType) thr
Log.d(TAG, "\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
+ "\n已生成 " + generatedSQLCount + " 条 SQL"
+ "\nexecute startTime = " + startTime
- + "\ndatabase = " + StringUtil.getString(config.getDatabase())
- + "; schema = " + StringUtil.getString(config.getSchema())
+ + "\ndatabase = " + StringUtil.get(config.getDatabase())
+ + "; schema = " + StringUtil.get(config.getSchema())
+ "; sql = \n" + sql
+ "\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractVerifier.java b/APIJSONORM/src/main/java/apijson/orm/AbstractVerifier.java
index b2eca8bc8..e4fb2526f 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractVerifier.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractVerifier.java
@@ -34,8 +34,6 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import apijson.orm.script.JavaScriptExecutor;
-import apijson.orm.script.ScriptExecutor;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
@@ -69,7 +67,6 @@
import apijson.orm.model.TestRecord;
import javax.script.ScriptEngine;
-import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;
/**校验器(权限、请求参数、返回结果等)
@@ -295,7 +292,7 @@ public boolean verifyAccess(SQLConfig config) throws Exception {
if (ROLE_MAP.containsKey(role) == false) {
Set NAMES = ROLE_MAP.keySet();
throw new IllegalArgumentException("角色 " + role + " 不存在!" +
- "只能是[" + StringUtil.getString(NAMES.toArray()) + "]中的一种!");
+ "只能是[" + StringUtil.get(NAMES.toArray()) + "]中的一种!");
}
if (role.equals(UNKNOWN) == false) { //未登录的角色
@@ -435,7 +432,7 @@ else if (id instanceof String) {
Object oid;
for (List ovl : ovs) {
oid = ovl == null || index >= ovl.size() ? null : ovl.get(index);
- if (oid == null || StringUtil.getString(oid).equals("" + visitorId) == false) {
+ if (oid == null || StringUtil.get(oid).equals("" + visitorId) == false) {
throw new IllegalAccessException(visitorIdKey + " = " + oid + " 的 " + table
+ " 不允许 " + role + " 用户的 " + method.name() + " 请求!");
}
@@ -459,7 +456,7 @@ else if (id instanceof String) {
}
else {
requestId = config.getWhere(visitorIdKey, true);//JSON里数值不能保证是Long,可能是Integer
- if (requestId != null && StringUtil.getString(requestId).equals(StringUtil.getString(visitorId)) == false) {
+ if (requestId != null && StringUtil.get(requestId).equals(StringUtil.get(visitorId)) == false) {
throw new IllegalAccessException(visitorIdKey + " = " + requestId + " 的 " + table
+ " 不允许 " + role + " 用户的 " + method.name() + " 请求!");
}
@@ -934,11 +931,11 @@ public static JSONObject parse(@NotNull final RequestMethod m
JSONObject update = target.getJSONObject(UPDATE.name());
JSONObject replace = target.getJSONObject(REPLACE.name());
- String exist = StringUtil.getString(target.getString(EXIST.name()));
- String unique = StringUtil.getString(target.getString(UNIQUE.name()));
- String remove = StringUtil.getString(target.getString(REMOVE.name()));
- String must = StringUtil.getString(target.getString(MUST.name()));
- String refuse = StringUtil.getString(target.getString(REFUSE.name()));
+ String exist = StringUtil.get(target.getString(EXIST.name()));
+ String unique = StringUtil.get(target.getString(UNIQUE.name()));
+ String remove = StringUtil.get(target.getString(REMOVE.name()));
+ String must = StringUtil.get(target.getString(MUST.name()));
+ String refuse = StringUtil.get(target.getString(REFUSE.name()));
Object _if = target.get(IF.name());
boolean ifIsStr = _if instanceof String && StringUtil.isNotEmpty(_if, true);
@@ -952,7 +949,7 @@ public static JSONObject parse(@NotNull final RequestMethod m
// Object code = target.get(CODE.name());
- String allowPartialUpdateFail = StringUtil.getString(target.getString(ALLOW_PARTIAL_UPDATE_FAIL.name()));
+ String allowPartialUpdateFail = StringUtil.get(target.getString(ALLOW_PARTIAL_UPDATE_FAIL.name()));
// 移除字段<<<<<<<<<<<<<<<<<<<
@@ -1097,7 +1094,7 @@ public static JSONObject parse(@NotNull final RequestMethod m
for (String rk : rkset) {
if (refuseSet.contains(rk)) { // 不允许的字段
throw new IllegalArgumentException(method + "请求," + name
- + " 里面不允许传 " + rk + " 等" + StringUtil.getString(refuseSet) + "内的任何字段!");
+ + " 里面不允许传 " + rk + " 等" + StringUtil.get(refuseSet) + "内的任何字段!");
}
if (rk == null) { // 无效的key
diff --git a/APIJSONORM/src/main/java/apijson/orm/Logic.java b/APIJSONORM/src/main/java/apijson/orm/Logic.java
index cfc08d016..bb8e806e6 100755
--- a/APIJSONORM/src/main/java/apijson/orm/Logic.java
+++ b/APIJSONORM/src/main/java/apijson/orm/Logic.java
@@ -42,7 +42,7 @@ public Logic(int type) {
}
public Logic(String key) {
this.originKey = key;
- key = StringUtil.getString(key);
+ key = StringUtil.get(key);
int type = getType(key.isEmpty() ? "" : key.substring(key.length() - 1));
diff --git a/APIJSONORM/src/main/java/apijson/orm/Pair.java b/APIJSONORM/src/main/java/apijson/orm/Pair.java
index a1f471c42..71ed7eb2c 100755
--- a/APIJSONORM/src/main/java/apijson/orm/Pair.java
+++ b/APIJSONORM/src/main/java/apijson/orm/Pair.java
@@ -79,7 +79,7 @@ public static String toPairString(String typeKey, String valueKey) {
* @return
*/
public static String toPairString(Class> type, Object value) {
- return toPairString(type == null ? null : type.getSimpleName(), StringUtil.getString(value));
+ return toPairString(type == null ? null : type.getSimpleName(), StringUtil.get(value));
}
/**
@@ -109,7 +109,7 @@ public static Entry parseEntry(String pair, boolean isRightValue
* @return @NonNull
*/
public static Entry parseEntry(String pair, boolean isRightValueDefault, String defaultValue) {
- pair = StringUtil.getString(pair);//让客户端去掉所有空格 getNoBlankString(pair);
+ pair = StringUtil.get(pair);//让客户端去掉所有空格 getNoBlankString(pair);
Entry entry = new Entry();
if (pair.isEmpty() == false) {
int index = pair.indexOf(":");
@@ -137,7 +137,7 @@ public static Entry parseVariableEntry(String pair) {
* @return
*/
public static Entry, Object> parseVariableEntry(String pair, Map valueMap) {
- pair = StringUtil.getString(pair);//让客户端去掉所有空格 getNoBlankString(pair);
+ pair = StringUtil.get(pair);//让客户端去掉所有空格 getNoBlankString(pair);
Entry, Object> entry = new Entry, Object>();
if (pair.isEmpty() == false) {
int index = pair.contains(":") ? pair.indexOf(":") : -1;
diff --git a/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
index ac541c8da..e86fd0fc0 100755
--- a/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
+++ b/APIJSONORM/src/main/java/apijson/orm/SQLConfig.java
@@ -151,7 +151,7 @@ public interface SQLConfig {
@NotNull
default int[] getDBVersionNums() {
- String dbVersion = StringUtil.getNoBlankString(getDBVersion());
+ String dbVersion = StringUtil.noBlank(getDBVersion());
if (dbVersion.isEmpty()) {
return new int[]{0};
}
From 970aee59fed8de155a92dae77af8ff82b06c42c3 Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sun, 16 Mar 2025 17:54:09 +0800
Subject: [PATCH 055/122] =?UTF-8?q?=E5=88=A0=E9=99=A4=E5=A4=9A=E4=BD=99?=
=?UTF-8?q?=E7=9A=84=E4=BB=A3=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java | 1 -
1 file changed, 1 deletion(-)
diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java
index 838f5a8a8..2165c3b05 100755
--- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java
+++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java
@@ -1133,7 +1133,6 @@ else if (value instanceof Clob) { //SQL Server TEXT 类型 居然走这个
if (castToJson == false) {
List json = config.getJson();
castToJson = json != null && json.contains(label);
- castToJson = json != null && json.contains(label);
}
if (castToJson) {
try {
From dd374314a0fd5a82d9c8170f11c028f4a57fd103 Mon Sep 17 00:00:00 2001
From: TommyLemon <1184482681@qq.com>
Date: Sun, 23 Mar 2025 23:05:10 +0800
Subject: [PATCH 056/122] =?UTF-8?q?APIJSON=20=E2=80=93=20The=20No-Code=20A?=
=?UTF-8?q?PI=20Revolution=20That=20Puts=20Developers=20in=20the=20Fast=20?=
=?UTF-8?q?Lane?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
thank you, [Hazem Abbas](https://medevel.com/author/hazem/), for posting this article ~
https://medevel.com/apijson
---
README.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/README.md b/README.md
index 67610d168..4dc10db9e 100644
--- a/README.md
+++ b/README.md
@@ -622,6 +622,8 @@ Issue/问卷 一般解答顺序:贡献者 > 帮助他人的用户 > 提供任
[wend看源码-ORM-APIJSON](https://itwend.blog.csdn.net/article/details/143980281)
+[APIJSON – The No-Code API Revolution That Puts Developers in the Fast Lane](https://medevel.com/apijson)
+
### 生态项目
[APIJSON-Demo](https://github.com/APIJSON/APIJSON-Demo) APIJSON 各种语言、各种框架 的 使用示例项目、上手文档、测试数据 SQL 文件 等
From 6712e9602cd1a2db95667a3c7cbd29e35233ef66 Mon Sep 17 00:00:00 2001
From: TommyLemon
Date: Sun, 30 Mar 2025 05:16:12 +0800
Subject: [PATCH 057/122] =?UTF-8?q?=E5=8E=BB=E9=99=A4=20fastjson=EF=BC=8CJ?=
=?UTF-8?q?SONObject=20=E7=94=A8=20M=20extends=20Map=20?=
=?UTF-8?q?=E6=9B=BF=E4=BB=A3=EF=BC=8CJSONArray=20=E7=94=A8=20L=20extends?=
=?UTF-8?q?=20List=20=E6=9B=BF=E4=BB=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
APIJSONORM/pom.xml | 5 -
APIJSONORM/src/main/java/apijson/JSON.java | 670 +++++++++++++-----
.../src/main/java/apijson/JSONArray.java | 221 ++++++
.../src/main/java/apijson/JSONCreator.java | 43 ++
.../src/main/java/apijson/JSONField.java | 5 +
.../src/main/java/apijson/JSONObject.java | 145 +++-
.../src/main/java/apijson/JSONParser.java | 27 +
.../src/main/java/apijson/JSONResponse.java | 155 ++--
.../apijson/orm/AbstractFunctionParser.java | 309 +++++---
.../apijson/orm/AbstractObjectParser.java | 273 ++++---
.../main/java/apijson/orm/AbstractParser.java | 438 ++++++------
.../java/apijson/orm/AbstractSQLConfig.java | 412 +++++------
.../java/apijson/orm/AbstractSQLExecutor.java | 171 +++--
.../java/apijson/orm/AbstractVerifier.java | 322 ++++-----
.../main/java/apijson/orm/FunctionParser.java | 33 +-
.../main/java/apijson/orm/JSONRequest.java | 11 +-
.../src/main/java/apijson/orm/Join.java | 35 +-
.../main/java/apijson/orm/ObjectParser.java | 56 +-
.../java/apijson/orm/OnParseCallback.java | 10 +-
.../src/main/java/apijson/orm/Pair.java | 11 +-
.../src/main/java/apijson/orm/Parser.java | 68 +-
.../main/java/apijson/orm/ParserCreator.java | 9 +-
.../src/main/java/apijson/orm/SQLConfig.java | 118 +--
.../src/main/java/apijson/orm/SQLCreator.java | 9 +-
.../main/java/apijson/orm/SQLExecutor.java | 37 +-
.../src/main/java/apijson/orm/Subquery.java | 35 +-
.../src/main/java/apijson/orm/Verifier.java | 25 +-
.../java/apijson/orm/VerifierCreator.java | 7 +-
.../orm/exception/CommonException.java | 4 +-
.../orm/script/JSR223ScriptExecutor.java | 11 +-
.../orm/script/JavaScriptExecutor.java | 7 +-
.../apijson/orm/script/ScriptExecutor.java | 9 +-
32 files changed, 2273 insertions(+), 1418 deletions(-)
create mode 100644 APIJSONORM/src/main/java/apijson/JSONArray.java
create mode 100755 APIJSONORM/src/main/java/apijson/JSONCreator.java
create mode 100644 APIJSONORM/src/main/java/apijson/JSONField.java
create mode 100755 APIJSONORM/src/main/java/apijson/JSONParser.java
diff --git a/APIJSONORM/pom.xml b/APIJSONORM/pom.xml
index 2cf436bd5..b4a860789 100644
--- a/APIJSONORM/pom.xml
+++ b/APIJSONORM/pom.xml
@@ -21,11 +21,6 @@
-
- com.alibaba
- fastjson
- 1.2.83
-
diff --git a/APIJSONORM/src/main/java/apijson/JSON.java b/APIJSONORM/src/main/java/apijson/JSON.java
index 0a1f901b7..c6573a650 100755
--- a/APIJSONORM/src/main/java/apijson/JSON.java
+++ b/APIJSONORM/src/main/java/apijson/JSON.java
@@ -4,269 +4,575 @@
package apijson;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
-import com.alibaba.fastjson.parser.Feature;
-import com.alibaba.fastjson.serializer.SerializerFeature;
-
import java.util.List;
+import java.util.Map;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+
+import apijson.orm.exception.UnsupportedDataTypeException;
+import apijson.Log;
+import apijson.StringUtil;
-/**阿里FastJSON封装类 防止解析时异常
+/**JSON工具类 防止解析时异常
* @author Lemon
*/
-public class JSON {
- private static final String TAG = "JSON";
+public interface JSON {
+ static final String TAG = "JSON";
- /**判断json格式是否正确
- * @param s
- * @return
- */
- public static boolean isJsonCorrect(String s) {
- //太长 Log.i(TAG, "isJsonCorrect <<<< " + s + " >>>>>>>");
- if (s == null
- // || s.equals("[]")
- // || s.equals("{}")
- || s.equals("")
- || s.equals("[null]")
- || s.equals("{null}")
- || s.equals("null")) {
- return false;
+ JSONParser extends Map, ? extends List> DEFAULT_JSON_PARSER = new JSONParser<>() {
+
+ @Override
+ public Map parseJSON(Object json) {
+ return Map.of();
}
- return true;
- }
- /**获取有效的json
- * @param s
- * @return
- */
- public static String getCorrectJson(String s) {
- return getCorrectJson(s, false);
- }
- /**获取有效的json
- * @param s
- * @param isArray
- * @return
- */
- public static String getCorrectJson(String s, boolean isArray) {
- s = StringUtil.trim(s);
- // if (isArray) {
- // while (s.startsWith("\"")) {
- // s = s.substring(1);
- // }
- // while (s.endsWith("\"")) {
- // s = s.substring(0, s.length() - 1);
- // }
- // }
- return s;//isJsonCorrect(s) ? s : null;
+ @Override
+ public Map parseObject(Object json) {
+ return Map.of();
+ }
+
+ @Override
+ public T parseObject(Object json, Class clazz) {
+ return null;
+ }
+
+ @Override
+ public List parseArray(Object json) {
+ return List.of();
+ }
+
+ @Override
+ public List parseArray(Object json, Class clazz) {
+ return List.of();
+ }
+
+ //
+ @Override
+ public String toJSONString(Object obj) {
+ return JSON.toJSONString(obj);
+ }
+
+ @Override
+ public Map createJSONObject() {
+ return new LinkedHashMap<>();
+ }
+
+ @Override
+ public List createJSONArray() {
+ return new ArrayList<>();
+ }
+ };
+
+ public static JSONCreator extends Map, ? extends List> DEFAULT_JSON_CREATOR = DEFAULT_JSON_PARSER;
+
+
+ public static Object parseJSON(Object json) throws Exception {
+ if (json instanceof Boolean || json instanceof Number || json instanceof Enum>) {
+ return json;
+ }
+
+ String s = StringUtil.trim(toJSONString(json));
+ if (s.startsWith("{")) {
+ return parseObject(json, DEFAULT_JSON_PARSER);
+ }
+
+ if (s.startsWith("[")) {
+ return parseArray(json, DEFAULT_JSON_PARSER);
+ }
+
+ throw new UnsupportedDataTypeException("JSON 格式错误!" + s);
}
/**
* @param json
* @return
*/
- private static final Feature[] DEFAULT_FASTJSON_FEATURES = {Feature.OrderedField, Feature.UseBigDecimal};
- public static Object parse(Object obj) {
+ public static Map parseObject(Object json) {
+ return parseObject(json, DEFAULT_JSON_PARSER);
+ }
+ public static , L extends List> M parseObject(Object json, JSONParser parser) {
+ String s = toJSONString(json);
+ if (StringUtil.isEmpty(s, true)) {
+ return null;
+ }
+
try {
- return com.alibaba.fastjson.JSON.parse(obj instanceof String ? (String) obj : toJSONString(obj), DEFAULT_FASTJSON_FEATURES);
+ M obj = parser.parseObject(s);
+ return obj;
} catch (Exception e) {
- Log.i(TAG, "parse catch \n" + e.getMessage());
+ Log.i(TAG, "parseObject catch \n" + e.getMessage());
}
return null;
}
+ public static , L extends List> T parseObject(Object json, Class clazz, JSONParser parser) {
+ String s = toJSONString(json);
+ if (StringUtil.isEmpty(s, true)) {
+ return null;
+ }
- /**obj转JSONObject
- * @param obj
- * @return
- */
- public static JSONObject parseObject(Object obj) {
- if (obj instanceof JSONObject) {
- return (JSONObject) obj;
+ try {
+ T obj = parser.parseObject(s, clazz);
+ return obj;
+ } catch (Exception e) {
+ Log.i(TAG, "parseObject catch \n" + e.getMessage());
}
- return parseObject(toJSONString(obj));
+ return null;
}
- /**json转JSONObject
+
+ /**
* @param json
* @return
*/
- public static JSONObject parseObject(String json) {
- return parseObject(json, JSONObject.class);
+ public static List parseArray(Object json) {
+ return parseArray(json, DEFAULT_JSON_PARSER);
}
- /**json转实体类
- * @param json
- * @param clazz
+
+ public static , L extends List> L parseArray(Object json, JSONParser parser) {
+ String s = toJSONString(json);
+ if (StringUtil.isEmpty(s, true)) {
+ return null;
+ }
+
+ try {
+ L arr = parser.parseArray(s);
+ return arr;
+ } catch (Exception e) {
+ Log.i(TAG, "parseArray catch \n" + e.getMessage());
+ }
+ return null;
+ }
+
+// public static > List parseArray(Object json, Class clazz) {
+// return parseArray(json, clazz, DEFAULT_JSON_PARSER);
+// }
+ public static > List parseArray(Object json, Class clazz, JSONParser> parser) {
+ String s = toJSONString(json);
+ if (StringUtil.isEmpty(s, true)) {
+ return null;
+ }
+
+ try {
+ List arr = parser.parseArray(s, clazz);
+ return arr;
+ } catch (Exception e) {
+ Log.i(TAG, "parseArray catch \n" + e.getMessage());
+ }
+ return null;
+ }
+
+ /**
+ * @param obj
* @return
*/
- public static T parseObject(String json, Class clazz) {
- if (clazz == null || StringUtil.isEmpty(json, true)) {
- Log.e(TAG, "parseObject clazz == null || StringUtil.isEmpty(json, true) >> return null;");
- } else {
- try {
- return com.alibaba.fastjson.JSON.parseObject(getCorrectJson(json), clazz, DEFAULT_FASTJSON_FEATURES);
- } catch (Exception e) {
- Log.i(TAG, "parseObject catch \n" + e.getMessage());
+ public static String toJSONString(Object obj) {
+ if (obj == null) {
+ return null;
+ }
+
+ // In a real implementation, you would use a JSON parser library
+ // Here we're just providing a basic implementation to replace fastjson
+ try {
+ // For now, this is a placeholder. In a real implementation,
+ // you would convert the object to a JSON string
+ if (obj instanceof String) {
+ return (String) obj;
+ }
+
+ if (obj instanceof Map) {
+ // Simple JSON object format
+ StringBuilder sb = new StringBuilder("{");
+ @SuppressWarnings("unchecked")
+ Map map = (Map) obj;
+ boolean first = true;
+ for (Map.Entry entry : map.entrySet()) {
+ if (! first) {
+ sb.append(",");
+ }
+ first = false;
+ sb.append("\"").append(entry.getKey()).append("\":");
+ Object value = entry.getValue();
+ if (value instanceof String) {
+ sb.append("\"").append(value).append("\"");
+ } else {
+ sb.append(toJSONString(value));
+ }
+ }
+ sb.append("}");
+ return sb.toString();
}
+
+ if (obj instanceof List) {
+ // Simple JSON array format
+ StringBuilder sb = new StringBuilder("[");
+ @SuppressWarnings("unchecked")
+ List list = (List) obj;
+ boolean first = true;
+ for (Object item : list) {
+ if (! first) {
+ sb.append(",");
+ }
+ first = false;
+ if (item instanceof String) {
+ sb.append("\"").append(item).append("\"");
+ } else {
+ sb.append(toJSONString(item));
+ }
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
+ return obj.toString();
+ }
+ catch (Exception e) {
+ Log.i(TAG, "toJSONString catch \n" + e.getMessage());
}
return null;
}
- /**list转JSONArray
- * @param list
+
+ /**判断是否为JSONObject或JSONArray的isXxx方法名
+ * @param key
* @return
*/
- public static JSONArray parseArray(List list) {
- return new JSONArray(list);
+ public static boolean isJSONType(String key) {
+ return key != null && key.startsWith("is") && key.length() > 2 && key.contains("JSON");
}
- /**obj转JSONArray
- * @param obj
- * @return
+
+ public static boolean isBooleanOrNumberOrString(Object obj) {
+ return obj instanceof Boolean || obj instanceof Number || obj instanceof String;
+ }
+
+ /**
+ * Get a value from a Map and convert to the specified type
+ * @param map Source map
+ * @param key The key
+ * @param Target type
+ * @return The converted value
*/
- public static JSONArray parseArray(Object obj) {
- if (obj instanceof JSONArray) {
- return (JSONArray) obj;
- }
- return parseArray(toJSONString(obj));
+ @SuppressWarnings("unchecked")
+ public static T get(Map map, String key) {
+ return map == null || key == null ? null : (T) map.get(key);
}
- /**json转JSONArray
- * @param json
- * @return
+
+ /**
+ * Get a value from a Map and convert to the specified type
+ * @param list Source map
+ * @param index The key
+ * @param Target type
+ * @return The converted value
*/
- public static JSONArray parseArray(String json) {
- if (StringUtil.isEmpty(json, true)) {
- Log.e(TAG, "parseArray StringUtil.isEmpty(json, true) >> return null;");
- } else {
- try {
- return com.alibaba.fastjson.JSON.parseArray(getCorrectJson(json, true));
- } catch (Exception e) {
- Log.i(TAG, "parseArray catch \n" + e.getMessage());
- }
+ @SuppressWarnings("unchecked")
+ public static T get(List list, int index) {
+ return list == null || index < 0 || index >= list.size() ? null : (T) list.get(index);
+ }
+// /**
+// * Get a value from a Map and convert to the specified type
+// * @param map Source map
+// * @param key The key
+// * @param Target type
+// * @return The converted value
+// */
+// @SuppressWarnings("unchecked")
+// public static T get(List list, int index) {
+// return list == null || index < 0 || index >= list.size() ? null : list.get(index);
+// }
+
+ /**
+ * Get a Map value from a Map
+ * @param map Source map
+ * @param key The key
+ * @return The Map value
+ * @throws UnsupportedDataTypeException If value is not a Map and cannot be converted
+ */
+ @SuppressWarnings("unchecked")
+ public static Map getMap(Map map, String key) throws UnsupportedDataTypeException {
+ Object value = map == null || key == null ? null : map.get(key);
+ if (value == null) {
+ return null;
}
- return null;
+
+ if (value instanceof Map) {
+ return (Map) value;
+ }
+
+ throw new UnsupportedDataTypeException("Value for key '" + key + "' is not a Map: " + value.getClass().getName());
}
- /**JSONArray转实体类列表
- * @param array
- * @param clazz
- * @return
+
+ /**
+ * Get a List value from a Map
+ * @param map Source map
+ * @param key The key
+ * @return The List value
+ * @throws UnsupportedDataTypeException If value is not a List and cannot be converted
*/
- public static List parseArray(JSONArray array, Class clazz) {
- return parseArray(toJSONString(array), clazz);
+ @SuppressWarnings("unchecked")
+ public static List getList(Map map, String key) throws UnsupportedDataTypeException {
+ Object value = map == null || key == null ? null : map.get(key);
+ if (value == null) {
+ return null;
+ }
+
+ if (value instanceof List) {
+ return (List) value;
+ }
+
+ throw new UnsupportedDataTypeException("Value for key '" + key + "' is not a List: " + value.getClass().getName());
}
- /**json转实体类列表
- * @param json
- * @param clazz
- * @return
+
+ /**
+ * Get an int value from a Map
+ * @param map Source map
+ * @param key The key
+ * @return The int value
+ * @throws UnsupportedDataTypeException If value cannot be converted to int
*/
- public static List parseArray(String json, Class clazz) {
- if (clazz == null || StringUtil.isEmpty(json, true)) {
- Log.e(TAG, "parseArray clazz == null || StringUtil.isEmpty(json, true) >> return null;");
- } else {
+ public static Integer getInteger(Map map, String key) throws UnsupportedDataTypeException {
+ Object value = map == null || key == null ? null : map.get(key);
+ if (value == null) {
+ return null;
+ }
+
+ if (value instanceof Number) {
+ return ((Number) value).intValue();
+ }
+
+ if (value instanceof String) {
try {
- return com.alibaba.fastjson.JSON.parseArray(getCorrectJson(json, true), clazz);
- } catch (Exception e) {
- Log.i(TAG, "parseArray catch \n" + e.getMessage());
+ return Integer.parseInt((String) value);
+ } catch (NumberFormatException e) {
+ throw new UnsupportedDataTypeException("Cannot convert String value '" + value + "' to int: " + e.getMessage());
}
}
- return null;
+
+ throw new UnsupportedDataTypeException("Cannot convert value of type " + value.getClass().getName() + " to int");
}
- /**实体类转json
- * @param obj
- * @return
+ /**
+ * Get an int value from a Map
+ * @param map Source map
+ * @param key The key
+ * @return The int value
+ * @throws UnsupportedDataTypeException If value cannot be converted to int
*/
- public static String toJSONString(Object obj) {
- if (obj == null) {
- return null;
+ public static int getIntValue(Map map, String key) throws UnsupportedDataTypeException {
+ Object value = map == null || key == null ? null : map.get(key);
+ if (value == null) {
+ return 0;
}
- if (obj instanceof String) {
- return (String) obj;
+
+ if (value instanceof Number) {
+ return ((Number) value).intValue();
}
- try {
- return com.alibaba.fastjson.JSON.toJSONString(obj);
- } catch (Exception e) {
- Log.e(TAG, "toJSONString catch \n" + e.getMessage());
+
+ if (value instanceof String) {
+ try {
+ return Integer.parseInt((String) value);
+ } catch (NumberFormatException e) {
+ throw new UnsupportedDataTypeException("Cannot convert String value '" + value + "' to int: " + e.getMessage());
+ }
}
- return null;
+
+ throw new UnsupportedDataTypeException("Cannot convert value of type " + value.getClass().getName() + " to int");
}
- /**实体类转json
- * @param obj
- * @param features
- * @return
+ /**
+ * Get an int value from a Map
+ * @param map Source map
+ * @param key The key
+ * @return The int value
+ * @throws UnsupportedDataTypeException If value cannot be converted to int
*/
- public static String toJSONString(Object obj, SerializerFeature... features) {
- if (obj == null) {
+ public static Long getLong(Map map, String key) throws UnsupportedDataTypeException {
+ Object value = map == null || key == null ? null : map.get(key);
+ if (value == null) {
return null;
}
- if (obj instanceof String) {
- return (String) obj;
+
+ if (value instanceof Number) {
+ return ((Number) value).longValue();
}
- try {
- return com.alibaba.fastjson.JSON.toJSONString(obj, features);
- } catch (Exception e) {
- Log.e(TAG, "toJSONString catch \n" + e.getMessage());
+
+ if (value instanceof String) {
+ try {
+ return Long.parseLong((String) value);
+ } catch (NumberFormatException e) {
+ throw new UnsupportedDataTypeException("Cannot convert String value '" + value + "' to int: " + e.getMessage());
+ }
}
- return null;
+
+ throw new UnsupportedDataTypeException("Cannot convert value of type " + value.getClass().getName() + " to int");
}
- /**格式化,显示更好看
- * @param json
- * @return
+ /**
+ * Get a long value from a Map
+ * @param map Source map
+ * @param key The key
+ * @return The long value
+ * @throws UnsupportedDataTypeException If value cannot be converted to long
*/
- public static String format(String json) {
- return format(parse(json));
+ public static long getLongValue(Map map, String key) throws UnsupportedDataTypeException {
+ Object value = map == null || key == null ? null : map.get(key);
+ if (value == null) {
+ return 0;
+ }
+
+ if (value instanceof Number) {
+ return ((Number) value).longValue();
+ }
+
+ if (value instanceof String) {
+ try {
+ return Long.parseLong((String) value);
+ } catch (NumberFormatException e) {
+ throw new UnsupportedDataTypeException("Cannot convert String value '" + value + "' to long: " + e.getMessage());
+ }
+ }
+
+ throw new UnsupportedDataTypeException("Cannot convert value of type " + value.getClass().getName() + " to long");
}
- /**格式化,显示更好看
- * @param object
- * @return
+
+ /**
+ * Get a double value from a Map
+ * @param map Source map
+ * @param key The key
+ * @return The double value
+ * @throws UnsupportedDataTypeException If value cannot be converted to double
*/
- public static String format(Object object) {
- return toJSONString(object, SerializerFeature.PrettyFormat);
+ public static Double getDouble(Map map, String key) throws UnsupportedDataTypeException {
+ Object value = map == null || key == null ? null : map.get(key);
+ if (value == null) {
+ return null;
+ }
+
+ if (value instanceof Number) {
+ return ((Number) value).doubleValue();
+ }
+
+ if (value instanceof String) {
+ try {
+ return Double.parseDouble((String) value);
+ } catch (NumberFormatException e) {
+ throw new UnsupportedDataTypeException("Cannot convert String value '" + value + "' to double: " + e.getMessage());
+ }
+ }
+
+ throw new UnsupportedDataTypeException("Cannot convert value of type " + value.getClass().getName() + " to double");
}
- /**判断是否为JSONObject
- * @param obj instanceof String ? parseObject
- * @return
+ /**
+ * Get a double value from a Map
+ * @param map Source map
+ * @param key The key
+ * @return The double value
+ * @throws UnsupportedDataTypeException If value cannot be converted to double
*/
- public static boolean isJSONObject(Object obj) {
- if (obj instanceof JSONObject) {
- return true;
+ public static double getDoubleValue(Map map, String key) throws UnsupportedDataTypeException {
+ Object value = map == null || key == null ? null : map.get(key);
+ if (value == null) {
+ return 0;
+ }
+
+ if (value instanceof Number) {
+ return ((Number) value).doubleValue();
}
- if (obj instanceof String) {
+
+ if (value instanceof String) {
try {
- JSONObject json = parseObject((String) obj);
- return json != null && json.isEmpty() == false;
- } catch (Exception e) {
- Log.e(TAG, "isJSONObject catch \n" + e.getMessage());
+ return Double.parseDouble((String) value);
+ } catch (NumberFormatException e) {
+ throw new UnsupportedDataTypeException("Cannot convert String value '" + value + "' to double: " + e.getMessage());
}
}
- return false;
+ throw new UnsupportedDataTypeException("Cannot convert value of type " + value.getClass().getName() + " to double");
}
- /**判断是否为JSONArray
- * @param obj instanceof String ? parseArray
- * @return
+
+
+ /**
+ * Get a boolean value from a Map
+ * @param map Source map
+ * @param key The key
+ * @return The boolean value
+ * @throws UnsupportedDataTypeException If value cannot be converted to boolean
*/
- public static boolean isJSONArray(Object obj) {
- if (obj instanceof JSONArray) {
- return true;
+ public static Boolean getBoolean(Map map, String key) throws UnsupportedDataTypeException {
+ Object value = map == null || key == null ? null : map.get(key);
+ if (value == null) {
+ return null;
}
- if (obj instanceof String) {
- try {
- JSONArray json = parseArray((String) obj);
- return json != null && json.isEmpty() == false;
- } catch (Exception e) {
- Log.e(TAG, "isJSONArray catch \n" + e.getMessage());
+
+ if (value instanceof Boolean) {
+ return (Boolean) value;
+ }
+
+ if (value instanceof String) {
+ String str = ((String) value).toLowerCase();
+ if (str.equals("true") || str.equals("false")) {
+ return Boolean.parseBoolean(str);
+ }
+ throw new UnsupportedDataTypeException("Cannot convert String value '" + value + "' to boolean");
+ }
+
+ if (value instanceof Number) {
+ int intValue = ((Number) value).intValue();
+ if (intValue == 0 || intValue == 1) {
+ return intValue != 0;
}
+ throw new UnsupportedDataTypeException("Cannot convert Number value '" + value + "' to boolean. Only 0 and 1 are supported.");
}
- return false;
+ throw new UnsupportedDataTypeException("Cannot convert value of type " + value.getClass().getName() + " to boolean");
}
- /**判断是否为 Boolean,Number,String 中的一种
- * @param obj
- * @return
+ /**
+ * Get a boolean value from a Map
+ * @param map Source map
+ * @param key The key
+ * @return The boolean value
+ * @throws UnsupportedDataTypeException If value cannot be converted to boolean
*/
- public static boolean isBooleanOrNumberOrString(Object obj) {
- return obj instanceof Boolean || obj instanceof Number || obj instanceof String;
+ public static boolean getBooleanValue(Map map, String key) throws UnsupportedDataTypeException {
+ Object value = map == null || key == null ? null : map.get(key);
+ if (value == null) {
+ return false;
+ }
+
+ if (value instanceof Boolean) {
+ return (Boolean) value;
+ }
+
+ if (value instanceof String) {
+ String str = ((String) value).toLowerCase();
+ if (str.equals("true") || str.equals("false")) {
+ return Boolean.parseBoolean(str);
+ }
+ throw new UnsupportedDataTypeException("Cannot convert String value '" + value + "' to boolean");
+ }
+
+ if (value instanceof Number) {
+ int intValue = ((Number) value).intValue();
+ if (intValue == 0 || intValue == 1) {
+ return intValue != 0;
+ }
+ throw new UnsupportedDataTypeException("Cannot convert Number value '" + value + "' to boolean. Only 0 and 1 are supported.");
+ }
+
+ throw new UnsupportedDataTypeException("Cannot convert value of type " + value.getClass().getName() + " to boolean");
}
+ /**
+ * Get a string value from a Map
+ * @param map Source map
+ * @param key The key
+ * @return The string value
+ */
+ public static String getString(Map map, String key) {
+ Object value = map == null || key == null ? null : map.get(key);
+ if (value == null) {
+ return null;
+ }
+
+ return value.toString();
+ }
}
diff --git a/APIJSONORM/src/main/java/apijson/JSONArray.java b/APIJSONORM/src/main/java/apijson/JSONArray.java
new file mode 100644
index 000000000..7760f6567
--- /dev/null
+++ b/APIJSONORM/src/main/java/apijson/JSONArray.java
@@ -0,0 +1,221 @@
+/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
+
+This source code is licensed under the Apache License Version 2.0.*/
+
+package apijson;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import apijson.orm.exception.UnsupportedDataTypeException;
+
+/**
+ * Custom JSONArray implementation based on ArrayList to replace com.alibaba.fastjson.JSONArray
+ * Maintains same API as fastjson but uses standard Java List implementation
+ * @author Lemon
+ */
+public class JSONArray extends ArrayList implements JSON {
+ private static final long serialVersionUID = 1L;
+ private static final String TAG = "JSONArray";
+
+ /**
+ * Create an empty JSONArray
+ */
+ public JSONArray() {
+ super();
+ }
+
+ /**
+ * Create a JSONArray with initial capacity
+ * @param initialCapacity the initial capacity
+ */
+ public JSONArray(int initialCapacity) {
+ super(initialCapacity);
+ }
+
+ /**
+ * Create a JSONArray from a Collection
+ * @param collection the collection to copy from
+ */
+ public JSONArray(Collection> collection) {
+ super();
+ if (collection != null) {
+ addAll(collection);
+ }
+ }
+
+ /**
+ * Create a JSONArray from a JSON string
+ * @param json JSON string
+ */
+ public JSONArray(String json) {
+ this();
+ List list = JSON.parseArray(json);
+ if (list != null) {
+ addAll(list);
+ }
+ }
+
+ /**
+ * Get a JSONObject at the specified index
+ * @param index the index
+ * @return the JSONObject or null if not a JSONObject
+ */
+ public JSONObject getJSONObject(int index) {
+ if (index < 0 || index >= size()) {
+ return null;
+ }
+
+ Object obj = get(index);
+ if (obj instanceof Map) {
+ @SuppressWarnings("unchecked")
+ Map map = (Map) obj;
+ return new JSONObject(map);
+ } else if (obj instanceof JSONObject) {
+ return (JSONObject) obj;
+ }
+ return null;
+ }
+
+ /**
+ * Get a JSONArray at the specified index
+ * @param index the index
+ * @return the JSONArray or null if not a JSONArray
+ */
+ public JSONArray getJSONArray(int index) {
+ if (index < 0 || index >= size()) {
+ return null;
+ }
+
+ Object obj = get(index);
+ if (obj instanceof List) {
+ @SuppressWarnings("unchecked")
+ List list = (List) obj;
+ return new JSONArray(list);
+ } else if (obj instanceof List>) {
+ return (JSONArray) obj;
+ }
+ return null;
+ }
+
+ /**
+ * Get a boolean value at the specified index
+ * @param index the index
+ * @return the boolean value or false if not found
+ */
+ public boolean getBooleanValue(int index) {
+ if (index < 0 || index >= size()) {
+ return false;
+ }
+
+ Object obj = get(index);
+ if (obj instanceof Boolean) {
+ return (Boolean) obj;
+ } else if (obj instanceof Number) {
+ return ((Number) obj).intValue() != 0;
+ } else if (obj instanceof String) {
+ return Boolean.parseBoolean((String) obj);
+ }
+ return false;
+ }
+
+ /**
+ * Get an integer value at the specified index
+ * @param index the index
+ * @return the integer value or 0 if not found
+ */
+ public int getIntValue(int index) {
+ if (index < 0 || index >= size()) {
+ return 0;
+ }
+
+ Object obj = get(index);
+ if (obj instanceof Number) {
+ return ((Number) obj).intValue();
+ } else if (obj instanceof String) {
+ try {
+ return Integer.parseInt((String) obj);
+ } catch (NumberFormatException e) {
+ // Ignore
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Get a long value at the specified index
+ * @param index the index
+ * @return the long value or 0 if not found
+ */
+ public long getLongValue(int index) {
+ if (index < 0 || index >= size()) {
+ return 0L;
+ }
+
+ Object obj = get(index);
+ if (obj instanceof Number) {
+ return ((Number) obj).longValue();
+ } else if (obj instanceof String) {
+ try {
+ return Long.parseLong((String) obj);
+ } catch (NumberFormatException e) {
+ // Ignore
+ }
+ }
+ return 0L;
+ }
+
+ /**
+ * Get a double value at the specified index
+ * @param index the index
+ * @return the double value or 0 if not found
+ */
+ public double getDoubleValue(int index) {
+ if (index < 0 || index >= size()) {
+ return 0.0;
+ }
+
+ Object obj = get(index);
+ if (obj instanceof Number) {
+ return ((Number) obj).doubleValue();
+ } else if (obj instanceof String) {
+ try {
+ return Double.parseDouble((String) obj);
+ } catch (NumberFormatException e) {
+ // Ignore
+ }
+ }
+ return 0.0;
+ }
+
+ /**
+ * Get a string value at the specified index
+ * @param index the index
+ * @return the string value or null if not found
+ */
+ public String getString(int index) {
+ if (index < 0 || index >= size()) {
+ return null;
+ }
+
+ Object obj = get(index);
+ return obj != null ? obj.toString() : null;
+ }
+
+ /**
+ * Add a value to the JSONArray
+ * @param obj the value to add
+ * @return this JSONArray
+ */
+ public JSONArray fluentAdd(Object obj) {
+ add(obj);
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return JSON.toJSONString(this);
+ }
+}
\ No newline at end of file
diff --git a/APIJSONORM/src/main/java/apijson/JSONCreator.java b/APIJSONORM/src/main/java/apijson/JSONCreator.java
new file mode 100755
index 000000000..fbd9da20d
--- /dev/null
+++ b/APIJSONORM/src/main/java/apijson/JSONCreator.java
@@ -0,0 +1,43 @@
+/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
+
+This source code is licensed under the Apache License Version 2.0.*/
+
+
+package apijson;
+
+import apijson.orm.SQLConfig;
+import apijson.orm.SQLExecutor;
+
+import java.util.List;
+import java.util.Map;
+
+/**SQL相关创建器
+ * @author Lemon
+ */
+public interface JSONCreator, L extends List> {
+
+ @NotNull
+ M createJSONObject();
+
+// @NotNull
+// M createJSONObject(String json);
+
+ @NotNull
+ default M createJSONObject(Map m) {
+ M obj = createJSONObject();
+ obj.putAll(m);
+ return obj;
+ }
+
+ @NotNull
+ L createJSONArray();
+// @NotNull
+// L createJSONArray(String json);
+
+ @NotNull
+ default L createJSONArray(List l){
+ L arr = createJSONArray();
+ arr.addAll(l);
+ return arr;
+ }
+}
diff --git a/APIJSONORM/src/main/java/apijson/JSONField.java b/APIJSONORM/src/main/java/apijson/JSONField.java
new file mode 100644
index 000000000..11a5cc309
--- /dev/null
+++ b/APIJSONORM/src/main/java/apijson/JSONField.java
@@ -0,0 +1,5 @@
+package apijson;
+
+public @interface JSONField {
+ boolean serialize() default true;
+}
diff --git a/APIJSONORM/src/main/java/apijson/JSONObject.java b/APIJSONORM/src/main/java/apijson/JSONObject.java
index 0adf18365..ee6828279 100755
--- a/APIJSONORM/src/main/java/apijson/JSONObject.java
+++ b/APIJSONORM/src/main/java/apijson/JSONObject.java
@@ -9,6 +9,10 @@
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+import apijson.orm.exception.UnsupportedDataTypeException;
/**use this class instead of com.alibaba.fastjson.JSONObject
* @author Lemon
@@ -16,7 +20,7 @@
* @see #puts
* @see #putsAll
*/
-public class JSONObject extends com.alibaba.fastjson.JSONObject {
+public class JSONObject extends LinkedHashMap implements JSON {
private static final long serialVersionUID = 1L;
private static final String TAG = "JSONObject";
@@ -25,27 +29,44 @@ public class JSONObject extends com.alibaba.fastjson.JSONObject {
/**ordered
*/
public JSONObject() {
- super(true);
+ super();
}
/**transfer Object to JSONObject
* @param object
* @see {@link #JSONObject(Object)}
*/
public JSONObject(Object object) {
- this(toJSONString(object));
+ this();
+ if (object instanceof Map) {
+ @SuppressWarnings("unchecked")
+ Map map = (Map) object;
+ putAll(map);
+ } else if (object != null) {
+ String json = JSON.toJSONString(object);
+ if (json != null) {
+ Map map = JSON.parseObject(json);
+ if (map != null) {
+ putAll(map);
+ }
+ }
+ }
}
/**parse JSONObject with JSON String
* @param json
* @see {@link #JSONObject(String)}
*/
public JSONObject(String json) {
- this(parseObject(json));
+ this();
+ Map map = JSON.parseObject(json);
+ if (map != null) {
+ putAll(map);
+ }
}
/**transfer com.alibaba.fastjson.JSONObject to JSONObject
* @param object
* @see {@link #putsAll(Map extends String, ? extends Object>)}
*/
- public JSONObject(com.alibaba.fastjson.JSONObject object) {
+ public JSONObject(Map object) {
this();
putsAll(object);
}
@@ -682,6 +703,116 @@ public Object put(String key, Object value) {
return super.put(key, value);
}
-
-
+ /**
+ * Get a boolean value from the JSONObject
+ * @param key the key
+ * @return the boolean value or false if not found
+ */
+ public boolean getBooleanValue(String key) {
+ try {
+ return JSON.getBooleanValue(this, key);
+ } catch (UnsupportedDataTypeException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Get an integer value from the JSONObject
+ * @param key the key
+ * @return the integer value or 0 if not found
+ */
+ public int getIntValue(String key) {
+ try {
+ return JSON.getIntValue(this, key);
+ } catch (UnsupportedDataTypeException e) {
+ return 0;
+ }
+ }
+
+ /**
+ * Get a long value from the JSONObject
+ * @param key the key
+ * @return the long value or 0 if not found
+ */
+ public long getLongValue(String key) {
+ try {
+ return JSON.getLongValue(this, key);
+ } catch (UnsupportedDataTypeException e) {
+ return 0L;
+ }
+ }
+
+ /**
+ * Get a double value from the JSONObject
+ * @param key the key
+ * @return the double value or 0 if not found
+ */
+ public double getDoubleValue(String key) {
+ try {
+ return JSON.getDoubleValue(this, key);
+ } catch (UnsupportedDataTypeException e) {
+ return 0.0;
+ }
+ }
+
+ /**
+ * Get a string value from the JSONObject
+ * @param key the key
+ * @return the string value or null if not found
+ */
+ public String getString(String key) {
+ Object value = get(key);
+ return value != null ? value.toString() : null;
+ }
+
+ /**
+ * Get a JSONObject value from the JSONObject
+ * @param key the key
+ * @return the JSONObject value or null if not found
+ */
+ public JSONObject getJSONObject(String key) {
+ try {
+ Map map = JSON.getMap(this, key);
+ return map != null ? new JSONObject(map) : null;
+ } catch (UnsupportedDataTypeException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Get a JSONArray value from the JSONObject
+ * @param key the key
+ * @return the JSONArray value or null if not found
+ */
+ public JSONArray getJSONArray(String key) {
+ try {
+ List list = JSON.getList(this, key);
+ return list != null ? new JSONArray(list) : null;
+ } catch (UnsupportedDataTypeException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Check if the JSONObject is empty or has no values other than null
+ * @return true if empty
+ */
+ public boolean isEmpty() {
+ if (super.isEmpty()) {
+ return true;
+ }
+
+ Set> set = entrySet();
+ for (Entry entry : set) {
+ if (entry.getValue() != null) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return JSON.toJSONString(this);
+ }
}
diff --git a/APIJSONORM/src/main/java/apijson/JSONParser.java b/APIJSONORM/src/main/java/apijson/JSONParser.java
new file mode 100755
index 000000000..1199ef5d5
--- /dev/null
+++ b/APIJSONORM/src/main/java/apijson/JSONParser.java
@@ -0,0 +1,27 @@
+/*Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
+
+This source code is licensed under the Apache License Version 2.0.*/
+
+
+package apijson;
+
+import java.util.List;
+import java.util.Map;
+
+/**SQL相关创建器
+ * @author Lemon
+ */
+public interface JSONParser, L extends List> extends JSONCreator {
+
+ M parseJSON(Object json);
+
+ M parseObject(Object json);
+
+ T parseObject(Object json, Class clazz);
+
+ L parseArray(Object json);
+
+ List parseArray(Object json, Class clazz);
+
+ String toJSONString(Object obj);
+}
diff --git a/APIJSONORM/src/main/java/apijson/JSONResponse.java b/APIJSONORM/src/main/java/apijson/JSONResponse.java
index 21f3fe8f6..7ee4f9f41 100755
--- a/APIJSONORM/src/main/java/apijson/JSONResponse.java
+++ b/APIJSONORM/src/main/java/apijson/JSONResponse.java
@@ -5,11 +5,11 @@
package apijson;
-import com.alibaba.fastjson.JSONArray;
-import com.alibaba.fastjson.JSONObject;
+import apijson.orm.exception.UnsupportedDataTypeException;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
+
+import static apijson.JSON.parseObject;
/**parser for response
* @author Lemon
@@ -19,7 +19,7 @@
*