Browse Source

add sqlite

bble 1 năm trước cách đây
mục cha
commit
fa84e34638

+ 42 - 0
dbsyncer-connector/dbsyncer-connector-sqlite/pom.xml

@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>dbsyncer-connector</artifactId>
+        <groupId>org.ghi</groupId>
+        <version>2.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>dbsyncer-connector-sqlite</artifactId>
+
+    <dependencies>
+        <!-- sdk -->
+        <dependency>
+            <groupId>org.ghi</groupId>
+            <artifactId>dbsyncer-sdk</artifactId>
+            <version>${project.parent.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <!-- SQLite-driver -->
+        <dependency>
+            <groupId>org.xerial</groupId>
+            <artifactId>sqlite-jdbc</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-log4j2</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+    </dependencies>
+</project>

+ 64 - 0
dbsyncer-connector/dbsyncer-connector-sqlite/src/main/java/org/dbsyncer/connector/sqlite/DqlSQLiteConnector.java

@@ -0,0 +1,64 @@
+/**
+ * DBSyncer Copyright 2020-2023 All Rights Reserved.
+ */
+
+package org.dbsyncer.connector.sqlite;
+
+import org.dbsyncer.common.util.StringUtil;
+import org.dbsyncer.connector.sqlite.validator.DqlSQLiteConfigValidator;
+import org.dbsyncer.sdk.config.ReaderConfig;
+import org.dbsyncer.sdk.connector.ConfigValidator;
+import org.dbsyncer.sdk.connector.database.AbstractDQLConnector;
+import org.dbsyncer.sdk.constant.DatabaseConstant;
+import org.dbsyncer.sdk.enums.ListenerTypeEnum;
+import org.dbsyncer.sdk.listener.DatabaseQuartzListener;
+import org.dbsyncer.sdk.listener.Listener;
+import org.dbsyncer.sdk.model.PageSql;
+
+import java.util.List;
+
+/**
+ * DQLSQLite连接器实现
+ *
+ * @Author bble
+ * @Version 1.0.0
+ * @Date 2023-11-28 16:22
+ */
+public final class DqlSQLiteConnector extends AbstractDQLConnector {
+
+    private final String TYPE = "DqlSQLite";
+
+    private final DqlSQLiteConfigValidator configValidator = new DqlSQLiteConfigValidator();
+
+    @Override
+    public String getConnectorType() {
+        return TYPE;
+    }
+
+    @Override
+    public ConfigValidator getConfigValidator() {
+        return configValidator;
+    }
+
+    @Override
+    public Listener getListener(String listenerType) {
+        if (ListenerTypeEnum.isTiming(listenerType)) {
+            return new DatabaseQuartzListener();
+        }
+        return null;
+    }
+
+    @Override
+    public String getPageSql(PageSql config) {
+        List<String> primaryKeys = config.getPrimaryKeys();
+        String orderBy = StringUtil.join(primaryKeys, ",");
+        return String.format(DatabaseConstant.SQLITE_PAGE_SQL, orderBy, config.getQuerySql());
+    }
+
+    @Override
+    public Object[] getPageArgs(ReaderConfig config) {
+        int pageSize = config.getPageSize();
+        int pageIndex = config.getPageIndex();
+        return new Object[] {(pageIndex - 1) * pageSize + 1, pageIndex * pageSize};
+    }
+}

+ 118 - 0
dbsyncer-connector/dbsyncer-connector-sqlite/src/main/java/org/dbsyncer/connector/sqlite/SQLiteConnector.java

@@ -0,0 +1,118 @@
+/**
+ * DBSyncer Copyright 2020-2023 All Rights Reserved.
+ */
+package org.dbsyncer.connector.sqlite;
+
+import org.dbsyncer.common.util.CollectionUtils;
+import org.dbsyncer.common.util.StringUtil;
+import org.dbsyncer.connector.sqlite.validator.SQLiteConfigValidator;
+import org.dbsyncer.sdk.config.CommandConfig;
+import org.dbsyncer.sdk.config.DatabaseConfig;
+import org.dbsyncer.sdk.config.ReaderConfig;
+import org.dbsyncer.sdk.connector.ConfigValidator;
+import org.dbsyncer.sdk.connector.database.AbstractDatabaseConnector;
+import org.dbsyncer.sdk.connector.database.DatabaseConnectorInstance;
+import org.dbsyncer.sdk.constant.DatabaseConstant;
+import org.dbsyncer.sdk.enums.ListenerTypeEnum;
+import org.dbsyncer.sdk.enums.TableTypeEnum;
+import org.dbsyncer.sdk.listener.DatabaseQuartzListener;
+import org.dbsyncer.sdk.listener.Listener;
+import org.dbsyncer.sdk.model.Field;
+import org.dbsyncer.sdk.model.PageSql;
+import org.dbsyncer.sdk.model.Table;
+import org.dbsyncer.sdk.util.PrimaryKeyUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+
+/**
+ * SQLite连接器实现
+ * @Author bble
+ * @Version 1.0.0
+ * @Date 2023-11-28 16:22
+ */
+public final class SQLiteConnector extends AbstractDatabaseConnector {
+
+    private final String QUERY_VIEW = "SELECT name FROM sqlite_master WHERE type = 'view'";
+    private final String QUERY_TABLE = "SELECT name FROM sqlite_master WHERE type='table'";
+
+    private final String TYPE = "SQLite";
+    private final SQLiteConfigValidator configValidator = new SQLiteConfigValidator();
+
+    @Override
+    public String getConnectorType() {
+        return TYPE;
+    }
+
+    @Override
+    public ConfigValidator getConfigValidator() {
+        return configValidator;
+    }
+
+    @Override
+    public List<Table> getTable(DatabaseConnectorInstance connectorInstance) {
+        DatabaseConfig config = connectorInstance.getConfig();
+        List<Table> tables = getTables(connectorInstance, String.format(QUERY_TABLE, config.getSchema()), TableTypeEnum.TABLE);
+        tables.addAll(getTables(connectorInstance, QUERY_VIEW, TableTypeEnum.VIEW));
+        return tables;
+    }
+
+    @Override
+    public Listener getListener(String listenerType) {
+        if (ListenerTypeEnum.isTiming(listenerType)) {
+            return new DatabaseQuartzListener();
+        }
+        return null;
+    }
+
+    @Override
+    public String getPageSql(PageSql config) {
+        // select * from "my_user" where "id" > ? and "uid" > ? order by "id","uid" limit ? OFFSET ?
+        StringBuilder sql = new StringBuilder(config.getQuerySql());
+        if (PrimaryKeyUtil.isSupportedCursor(config.getFields())) {
+            appendOrderByPk(config, sql);
+        }
+        sql.append(DatabaseConstant.SQLITE_PAGE_SQL);
+        return sql.toString();
+    }
+
+    @Override
+    public Object[] getPageArgs(ReaderConfig config) {
+        int pageIndex = config.getPageIndex();
+        int pageSize = config.getPageSize();
+        return new Object[]{pageSize, (pageIndex - 1) * pageSize};
+    }
+
+    @Override
+    public String buildTableName(String tableName) {
+        return convertKey(tableName);
+    }
+
+    @Override
+    public String buildFieldName(Field field) {
+        return convertKey(field.getName());
+    }
+
+    @Override
+    public List<String> buildPrimaryKeys(List<String> primaryKeys) {
+        if (CollectionUtils.isEmpty(primaryKeys)) {
+            return primaryKeys;
+        }
+        return primaryKeys.stream().map(pk -> convertKey(pk)).collect(Collectors.toList());
+    }
+
+    private List<Table> getTables(DatabaseConnectorInstance connectorInstance, String sql, TableTypeEnum type) {
+        List<String> tableNames = connectorInstance.execute(databaseTemplate -> databaseTemplate.queryForList(sql, String.class));
+        if (!CollectionUtils.isEmpty(tableNames)) {
+            return tableNames.stream().map(name -> new Table(name, type.getCode())).collect(Collectors.toList());
+        }
+        return new ArrayList<>();
+    }
+
+    private String convertKey(String key) {
+        return new StringBuilder("\"").append(key).append("\"").toString();
+    }
+
+}

+ 30 - 0
dbsyncer-connector/dbsyncer-connector-sqlite/src/main/java/org/dbsyncer/connector/sqlite/SQLiteException.java

@@ -0,0 +1,30 @@
+/**
+ * DBSyncer Copyright 2020-2023 All Rights Reserved.
+ */
+package org.dbsyncer.connector.sqlite;
+
+/**
+ * @Author bble
+ * @Version 1.0.0
+ * @Date 2023-11-28 16:22
+ */
+public class SQLiteException extends RuntimeException {
+
+	private static final long serialVersionUID = 1L;
+
+	public SQLiteException(String message) {
+        super(message);
+    }
+
+    public SQLiteException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public SQLiteException(Throwable cause) {
+        super(cause);
+    }
+
+    protected SQLiteException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+}

+ 27 - 0
dbsyncer-connector/dbsyncer-connector-sqlite/src/main/java/org/dbsyncer/connector/sqlite/validator/DqlSQLiteConfigValidator.java

@@ -0,0 +1,27 @@
+/**
+ * DBSyncer Copyright 2020-2023 All Rights Reserved.
+ */
+
+package org.dbsyncer.connector.sqlite.validator;
+
+import org.dbsyncer.sdk.config.DatabaseConfig;
+import org.dbsyncer.sdk.connector.AbstractDataBaseConfigValidator;
+
+import java.util.Map;
+
+/**
+ * SQLite连接配置校验器实现
+ *
+ * @Author bble
+ * @Version 1.0.0
+ * @Date 2023-11-28 16:22
+ */
+public class DqlSQLiteConfigValidator extends AbstractDataBaseConfigValidator {
+
+    @Override
+    public void modify(DatabaseConfig connectorConfig, Map<String, String> params) {
+        super.modify(connectorConfig, params);
+        super.modifyDql(connectorConfig, params);
+        super.modifySchema(connectorConfig, params);
+    }
+}

+ 24 - 0
dbsyncer-connector/dbsyncer-connector-sqlite/src/main/java/org/dbsyncer/connector/sqlite/validator/SQLiteConfigValidator.java

@@ -0,0 +1,24 @@
+/**
+ * DBSyncer Copyright 2020-2023 All Rights Reserved.
+ */
+package org.dbsyncer.connector.sqlite.validator;
+
+import org.dbsyncer.sdk.config.DatabaseConfig;
+import org.dbsyncer.sdk.connector.AbstractDataBaseConfigValidator;
+
+import java.util.Map;
+
+/**
+ * SQLite连接配置校验器实现
+ *
+ * @Author bble
+ * @Version 1.0.0
+ * @Date 2023-11-28 16:22
+ */
+public class SQLiteConfigValidator extends AbstractDataBaseConfigValidator {
+    @Override
+    public void modify(DatabaseConfig connectorConfig, Map<String, String> params) {
+        super.modify(connectorConfig, params);
+        super.modifySchema(connectorConfig, params);
+    }
+}

+ 2 - 0
dbsyncer-connector/dbsyncer-connector-sqlite/src/main/resources/META-INF/services/org.dbsyncer.sdk.spi.ConnectorService

@@ -0,0 +1,2 @@
+org.dbsyncer.connector.sqlite.SQLiteConnector
+org.dbsyncer.connector.sqlite.DqlSQLiteConnector

+ 46 - 0
dbsyncer-connector/dbsyncer-connector-sqlite/src/main/resources/public/connector/addDqlSQLite.html

@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:th="http://www.thymeleaf.org" lang="zh-CN">
+
+<div th:fragment="content">
+    <div class="form-group">
+        <input class="form-control" name="username" type="hidden" maxlength="32" dbsyncer-valid="require" value="NONE"/>
+        <input class="form-control" name="password" type="hidden" maxlength="32" dbsyncer-valid="require" value="NONE"/>
+        <label class="col-sm-2 control-label">架构名 <strong class="driverVerifcateRequired">*</strong></label>
+        <div class="col-sm-10">
+            <input class="form-control" name="schema" type="text" maxlength="32" dbsyncer-valid="require" placeholder="main" th:value="${connector?.config?.schema} ?: 'main'"/>
+        </div>
+    </div>
+
+    <div class="form-group">
+        <label class="col-sm-2 control-label">URL <strong class="driverVerifcateRequired">*</strong></label>
+        <div class="col-sm-10">
+            <textarea name="url" class="form-control dbsyncer_textarea_resize_none" maxlength="8192" dbsyncer-valid="require" rows="5" th:text="${connector?.config?.url} ?: 'jdbc:sqlite:test.db'"></textarea>
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="col-sm-2 control-label">驱动 </label>
+        <div class="col-sm-10">
+            <input class="form-control" readonly="true" name="driverClassName" type="text" th:value="${connector?.config?.driverClassName} ?: 'org.sqlite.JDBC'" />
+        </div>
+    </div>
+
+    <!-- SQL配置 -->
+    <div th:replace="connector/addSQL :: content"></div>
+
+    <div class="form-group">
+        <label class="col-sm-2 control-label">SQL</label>
+        <div class="col-sm-10">
+            <textarea id="sql" name="sql" class="sql form-control dbsyncer_textarea_resize_none" maxlength="8192" rows="10">SELECT T1.* FROM USER T1</textarea>
+        </div>
+    </div>
+
+    <script type="text/javascript">
+        $(function () {
+            // 初始化select插件
+            initSelectIndex($(".select-control"), 1);
+        })
+    </script>
+</div>
+
+</html>

+ 29 - 0
dbsyncer-connector/dbsyncer-connector-sqlite/src/main/resources/public/connector/addSQLite.html

@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:th="http://www.thymeleaf.org" lang="zh-CN">
+
+<div th:fragment="content">
+    <div class="form-group">
+            <input class="form-control" name="username" type="hidden" maxlength="32" dbsyncer-valid="require" value="NONE"/>
+            <input class="form-control" name="password" type="hidden" maxlength="32" dbsyncer-valid="require" value="NONE"/>
+        <label class="col-sm-2 control-label">架构名 <strong class="driverVerifcateRequired">*</strong></label>
+        <div class="col-sm-10">
+            <input class="form-control" name="schema" type="text" maxlength="32" dbsyncer-valid="require" placeholder="main" th:value="${connector?.config?.schema} ?: 'main'"/>
+        </div>
+    </div>
+
+    <div class="form-group">
+        <label class="col-sm-2 control-label">URL <strong class="driverVerifcateRequired">*</strong></label>
+        <div class="col-sm-10">
+            <textarea name="url" class="form-control dbsyncer_textarea_resize_none" maxlength="1024" dbsyncer-valid="require" rows="5" th:text="${connector?.config?.url} ?: 'jdbc:sqlite:test.db'"></textarea>
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="col-sm-2 control-label">驱动 </label>
+        <div class="col-sm-10">
+            <input class="form-control" readonly="true" name="driverClassName" type="text" th:value="${connector?.config?.driverClassName} ?: 'org.sqlite.JDBC'" />
+        </div>
+    </div>
+</div>
+
+</html>

BIN
dbsyncer-connector/dbsyncer-connector-sqlite/src/main/resources/static/img/sqlite.png


+ 6 - 0
dbsyncer-sdk/src/main/java/org/dbsyncer/sdk/constant/DatabaseConstant.java

@@ -35,4 +35,10 @@ public class DatabaseConstant {
      * PostgreSQL分页语句
      */
     public static final String POSTGRESQL_PAGE_SQL = " limit ? OFFSET ?";
+
+    //*********************************** SQLite **************************************//
+    /**
+     * SQLite分页语句
+     */
+    public static final String SQLITE_PAGE_SQL = " limit ? OFFSET ?";
 }