diff --git a/.gitignore b/.gitignore
index 524f096..30b7352 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,24 +1,6 @@
-# Compiled class file
-*.class
-
-# Log file
-*.log
-
-# BlueJ files
-*.ctxt
-
-# Mobile Tools for Java (J2ME)
-.mtj.tmp/
-
-# Package Files #
-*.jar
-*.war
-*.nar
-*.ear
-*.zip
-*.tar.gz
-*.rar
-
-# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
-hs_err_pid*
-replay_pid*
+/target/
+.classpath
+.project
+.settings
+.idea
+*.iml
diff --git a/LICENSE b/LICENSE
index 261eeb9..4da1e40 100644
--- a/LICENSE
+++ b/LICENSE
@@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
- Copyright [yyyy] [name of copyright owner]
+ Copyright ©2021 APIJSON(https://github.com/APIJSON)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/README.md b/README.md
new file mode 100755
index 0000000..6646927
--- /dev/null
+++ b/README.md
@@ -0,0 +1,111 @@
+# apijson-iotdb [![](https://jitpack.io/v/APIJSON/apijson-iotdb.svg)](https://jitpack.io/#APIJSON/apijson-iotdb)
+腾讯 [APIJSON](https://github.com/Tencent/APIJSON) 7.0.3+ 的 IoTDB 数据库插件,可通过 Maven, Gradle 等远程依赖。
+An IoTDB plugin for Tencent [APIJSON](https://github.com/Tencent/APIJSON) 7.0.3+
+
+![image](https://private-user-images.githubusercontent.com/5738175/397984593-6d088d9c-86d9-40a9-b9fa-b49c679e19a6.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzQ4NzQ5NzQsIm5iZiI6MTczNDg3NDY3NCwicGF0aCI6Ii81NzM4MTc1LzM5Nzk4NDU5My02ZDA4OGQ5Yy04NmQ5LTQwYTktYjlmYS1iNDljNjc5ZTE5YTYucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MTIyMiUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDEyMjJUMTMzNzU0WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9OWM2OTBmYmM4MmRiYzIwNjg4ZDAzZDkxYjkwMjE4ZDM4NWY1NDFkYTFjNTMyMWQ0MzFlMzkxODhlNDIxNDYyMCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.POonQKkSUjGuF1fRF4vbT61mI1wKGmamLTL5Ld7GmxA)
+![image](https://github.com/user-attachments/assets/920dd1ea-5490-4c1e-8132-7e1f6324f156)
+
+## 添加依赖
+## Add Dependency
+
+### Maven
+#### 1. 在 pom.xml 中添加 JitPack 仓库
+#### 1. Add the JitPack repository to pom.xml
+```xml
+
+
+ jitpack.io
+ https://jitpack.io
+
+
+```
+
+![image](https://user-images.githubusercontent.com/5738175/167261814-d75d8fff-0e64-4534-a840-60ef628a8873.png)
+
+
+
+#### 2. 在 pom.xml 中添加 apijson-iotdb 依赖
+#### 2. Add the apijson-iotdb dependency to pom.xml
+```xml
+
+ com.github.APIJSON
+ apijson-iotdb
+ LATEST
+
+```
+
+
+
+https://github.com/APIJSON/APIJSON-Demo/blob/master/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/pom.xml
+
+
+
+
+### Gradle
+#### 1. 在项目根目录 build.gradle 中最后添加 JitPack 仓库
+#### 1. Add the JitPack repository in your root build.gradle at the end of repositories
+```gradle
+ allprojects {
+ repositories {
+ maven { url 'https://jitpack.io' }
+ }
+ }
+```
+
+
+#### 2. 在项目某个 module 目录(例如 `app`) build.gradle 中添加 apijson-iotdb 依赖
+#### 2. Add the apijson-iotdb dependency in one of your modules(such as `app`)
+```gradle
+ dependencies {
+ implementation 'com.github.APIJSON:apijson-iotdb:latest'
+ }
+```
+
+
+
+
+
+## 使用
+## Usage
+
+在你项目继承 AbstractSQLExecutor 的子类重写方法 execute
+Override execute in your SQLExecutor extends AbstractSQLExecutor
+
+```java
+ @Override
+ public JSONObject execute(@NotNull SQLConfig config, boolean unknownType) throws Exception {
+ if (config.isIoTDB()) {
+ return InfluxdbUtil.execute(config, null, unknownType);
+ }
+
+ return super.execute(config, unknownType);
+ }
+```
+
+
+在你项目继承 AbstractSQLConfig 的子类重写方法 execute
+Override execute in your SQLConfig extends AbstractSQLConfig
+
+```java
+ @Override
+ public String getTablePath() {
+ return IoTDBUtil.getTablePath(super.getTablePath(), isIoTDB());
+ }
+```
+
+#### 见 [IoTDBUtil](/src/main/java/apijson/iotdb/IoTDBUtil.java) 的注释及 [APIJSONBoot-MultiDataSource](https://github.com/APIJSON/APIJSON-Demo/blob/master/APIJSON-Java-Server/APIJSONBoot-MultiDataSource) 的 [DemoSQLExecutor](https://github.com/APIJSON/APIJSON-Demo/blob/master/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/demo/DemoSQLExecutor.java)
+
+#### See document in [IoTDBUtil](/src/main/java/apijson/iotdb/IoTDBUtil.java) and [DemoSQLExecutor](https://github.com/APIJSON/APIJSON-Demo/blob/master/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/demo/DemoSQLExecutor.java) in [APIJSONBoot-MultiDataSource](https://github.com/APIJSON/APIJSON-Demo/blob/master/APIJSON-Java-Server/APIJSONBoot-MultiDataSource)
+
+
+
+
+
+有问题可以去 Tencent/APIJSON 提 issue
+https://github.com/Tencent/APIJSON/issues/36
+
+
+
+#### 点右上角 ⭐Star 支持一下,谢谢 ^_^
+#### Please ⭐Star this project ^_^
+https://github.com/APIJSON/apijson-iotdb
diff --git a/pom.xml b/pom.xml
new file mode 100755
index 0000000..3f114a8
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,65 @@
+
+
+ 4.0.0
+
+ apijson.iotdb
+ apijson-iotdb
+ 1.0.0
+ jar
+
+ apijson-iotdb
+ A IoTDB plugin for Tencent APIJSON
+
+
+ UTF-8
+ UTF-8
+ 1.8
+
+
+
+
+
+ com.alibaba
+ fastjson
+ 1.2.83
+
+
+ com.github.Tencent
+ APIJSON
+ 7.0.3
+
+
+ org.apache.iotdb
+ iotdb-session
+ 1.3.1
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.1
+
+
+ 1.8
+
+
+
+
+
+
+
+
+ jitpack.io
+ https://jitpack.io
+
+ true
+
+
+
+
+
diff --git a/src/main/java/apijson/iotdb/IoTDBUtil.java b/src/main/java/apijson/iotdb/IoTDBUtil.java
new file mode 100644
index 0000000..7f2fb52
--- /dev/null
+++ b/src/main/java/apijson/iotdb/IoTDBUtil.java
@@ -0,0 +1,299 @@
+/*Copyright ©2024 APIJSON(https://github.com/APIJSON)
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.*/
+
+package apijson.iotdb;
+
+import apijson.JSONResponse;
+import apijson.NotNull;
+import apijson.RequestMethod;
+import apijson.StringUtil;
+import apijson.orm.AbstractParser;
+import apijson.orm.SQLConfig;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.iotdb.isession.SessionDataSet;
+import org.apache.iotdb.rpc.IoTDBConnectionException;
+import org.apache.iotdb.session.Session;
+import org.apache.iotdb.tsfile.read.common.Field;
+import org.apache.iotdb.tsfile.read.common.RowRecord;
+
+import java.util.*;
+
+import static apijson.orm.AbstractSQLExecutor.KEY_RAW_LIST;
+
+
+/**
+ * @author Lemon
+ * @see DemoSQLExecutor 重写 execute 方法:
+ * \@Override
+ * public JSONObject execute(@NotNull SQLConfig config, boolean unknownType) throws Exception {
+ * if (config.isIoTDB()) {
+ * return IoTDBUtil.execute(config, null, unknownType);
+ * }
+ *
+ * return super.execute(config, unknownType);
+ * }
+ *
+ * DemoSQLConfig 重写方法 getSchema, getSQLSchema 方法
+ * \@Override
+ * public String getSchema() {
+ * return IoTDBUtil.getSchema(super.getSchema(), DEFAULT_SCHEMA, isIoTDB());
+ * }
+ *
+ * \@Override
+ * public String getSQLSchema() {
+ * return IoTDBUtil.getSQLSchema(super.getSQLSchema(), isIoTDB());
+ * }
+ */
+public class IoTDBUtil {
+ public static final String TAG = "IoTDBUtil";
+
+ public static String getSchema(String schema, String defaultSchema) {
+ return getSchema(schema, defaultSchema, true);
+ }
+ public static String getSchema(String schema, String defaultSchema, boolean isIoTDB) {
+ if (StringUtil.isEmpty(schema) && isIoTDB) {
+ schema = defaultSchema;
+ }
+ return schema;
+ }
+
+ public static String getSQLSchema(String schema) {
+ return getSQLSchema(schema, true);
+ }
+ public static String getSQLSchema(String schema, boolean isIoTDB) {
+ return schema;
+ }
+
+ public static String getTablePath(String path) {
+ return getTablePath(path, true);
+ }
+ public static String getTablePath(String path, boolean isIoTDB) {
+ if (isIoTDB) {
+ String[] ks = path == null || path.trim().isEmpty() ? null : path.trim().split("\\.");
+ int len = ks == null ? 0 : ks.length;
+ return len <= 0 ? "**" : (len >= 3 ? path : path + ".**");
+ }
+
+ return path;
+ }
+
+ public static String getSessionKey(@NotNull SQLConfig config) {
+ String uri = config.getDBUri();
+ return uri + (uri.contains("?") ? "&" : "?") + "username=" + config.getDBAccount();
+ }
+
+ public static final Map CLIENT_MAP = new LinkedHashMap<>();
+ public static Session getSession(@NotNull SQLConfig config) throws IoTDBConnectionException {
+ return getSession(config, true);
+ }
+ public static Session getSession(@NotNull SQLConfig config, boolean autoNew) throws IoTDBConnectionException {
+ String key = getSessionKey(config);
+
+ Session session = CLIENT_MAP.get(key);
+ if (autoNew && session == null) {
+ String uri = config.getDBUri();
+ int ind = uri.indexOf("://");
+ String host = ind < 0 ? uri : uri.substring(ind + 3);
+ int ind2 = host.indexOf("?");
+ host = ind2 < 0 ? host : host.substring(0, ind2);
+ int ind3 = host.indexOf(":");
+ String portStr = ind < 0 ? null : host.substring(ind3 + 1);
+ host = ind3 < 0 ? host : host.substring(0, ind3);
+ int port = portStr == null || portStr.trim().isEmpty() ? 6667 : Integer.valueOf(portStr);
+
+ session = new Session.Builder()
+ .host(host)
+ .port(port)
+ .username(config.getDBAccount())
+ .password(config.getDBPassword())
+ .build();
+ session.open();
+
+ Session finalSession = session;
+ Runtime.getRuntime().addShutdownHook(new Thread(() -> {
+ try {
+ finalSession.close();
+ } catch (IoTDBConnectionException e) {
+ e.printStackTrace(); // throw new RuntimeException(e);
+ }
+ }));
+
+ CLIENT_MAP.put(key, session);
+ }
+
+ return session;
+ }
+
+ public static void closeSession(@NotNull SQLConfig config) {
+ try {
+ Session session = getSession(config, false);
+ if (session != null) {
+ String key = getSessionKey(config);
+ CLIENT_MAP.remove(key);
+
+ try {
+ session.close();
+ }
+ catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void closeAllSession() {
+ Collection cs = CLIENT_MAP.values();
+ for (Session c : cs) {
+ try {
+ c.close();
+ }
+ catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+
+ CLIENT_MAP.clear();
+ }
+
+
+ public static JSONObject execute(@NotNull SQLConfig config, String sql, boolean unknownType) throws Exception {
+ if (RequestMethod.isQueryMethod(config.getMethod())) {
+ List list = executeQuery(config, sql, unknownType);
+ JSONObject result = list == null || list.isEmpty() ? null : list.get(0);
+ if (result == null) {
+ result = new JSONObject(true);
+ }
+
+ if (list != null && list.size() > 1) {
+ result.put(KEY_RAW_LIST, list);
+ }
+
+ return result;
+ }
+
+ return executeUpdate(config, sql);
+ }
+
+ public static int execUpdate(SQLConfig config, String sql) throws Exception {
+ JSONObject result = executeUpdate(config, sql);
+ return result.getIntValue(JSONResponse.KEY_COUNT);
+ }
+
+ public static JSONObject executeUpdate(SQLConfig config, String sql) throws Exception {
+ return executeUpdate(null, config, sql);
+ }
+ public static JSONObject executeUpdate(Session session, SQLConfig config, String sql) throws Exception {
+ if (session == null) {
+ session = getSession(config);
+ }
+
+ session.executeNonQueryStatement(sql);
+
+ JSONObject result = AbstractParser.newSuccessResult();
+
+ RequestMethod method = config.getMethod();
+ if (method == RequestMethod.POST) {
+ List> values = config.getValues();
+ result.put(JSONResponse.KEY_COUNT, values == null ? 0 : values.size());
+ } else {
+ String idKey = config.getIdKey();
+ Object id = config.getId();
+ Object idIn = config.getIdIn();
+ if (id != null) {
+ result.put(idKey, id);
+ }
+ if (idIn != null) {
+ result.put(idKey + "[]", idIn);
+ }
+
+ if (method == RequestMethod.PUT) {
+ Map content = config.getContent();
+ result.put(JSONResponse.KEY_COUNT, content == null ? 0 : content.size());
+ } else {
+ result.put(JSONResponse.KEY_COUNT, id == null && idIn instanceof Collection ? ((Collection>) idIn).size() : 1); // FIXME 直接 SQLAuto 传 Flux/InfluxQL INSERT 如何取数量?
+ }
+ }
+
+ return result;
+ }
+
+
+ public static JSONObject execQuery(@NotNull SQLConfig config, String sql, boolean unknownType) throws Exception {
+ List list = executeQuery(config, sql, unknownType);
+ JSONObject result = list == null || list.isEmpty() ? null : list.get(0);
+ if (result == null) {
+ result = new JSONObject(true);
+ }
+
+ if (list != null && list.size() > 1) {
+ result.put(KEY_RAW_LIST, list);
+ }
+
+ return result;
+ }
+
+ public static List executeQuery(@NotNull SQLConfig config, String sql, boolean unknownType) throws Exception {
+ return executeQuery(null, config, sql, unknownType);
+ }
+ public static List executeQuery(Session session, @NotNull SQLConfig config, String sql, boolean unknownType) throws Exception {
+ if (session == null) {
+ session = getSession(config);
+ }
+
+// session.setDatabase(config.getSchema());
+
+ SessionDataSet ds = session.executeQueryStatement(sql);
+ List ns = ds == null ? null : ds.getColumnNames();
+ List nameList = ns == null || ns.isEmpty() ? null : new ArrayList<>(ns.size());
+
+ if (nameList != null) {
+ String prefix = config.getSQLSchema() + "." + config.getSQLTable() + ".";
+
+ for (String name : ns) {
+ if (name.startsWith(prefix)) {
+ name = name.substring(prefix.length());
+ }
+
+ nameList.add(name);
+ }
+ }
+
+ if (nameList == null || nameList.isEmpty()) {
+ return null;
+ }
+
+ List resultList = new ArrayList<>(ds.getFetchSize());
+
+ while (ds.hasNext()) {
+ RowRecord row = ds.next();
+ List fs = row.getFields();
+
+ JSONObject obj = new JSONObject(true);
+ obj.put(nameList.get(0), row.getTimestamp());
+ for (int i = 0; i < fs.size(); i++) {
+ Field f = fs.get(i);
+ Object v = f == null ? null : f.getObjectValue(f.getDataType());
+ obj.put(nameList.get(i + 1), v);
+ }
+
+ resultList.add(obj);
+ }
+
+ return resultList;
+ }
+
+}