feat:support Serializable

This commit is contained in:
SwallowGG
2024-03-15 14:07:51 +08:00
parent 3ae6f88247
commit 0fe586d263
33 changed files with 207 additions and 239 deletions

View File

@ -250,6 +250,10 @@ export const dataSourceFormConfigs: IConnectionConfig[] = [
{ {
"key": "zeroDateTimeBehavior", "key": "zeroDateTimeBehavior",
"value": "convertToNull" "value": "convertToNull"
},
{
"key": "useInformationSchema",
"value": "true"
} }
], ],
type: DatabaseTypeCode.MYSQL, type: DatabaseTypeCode.MYSQL,

View File

@ -11,7 +11,7 @@ import ai.chat2db.spi.model.TableIndex;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
public class ClickHouseSqlBuilder extends DefaultSqlBuilder implements SqlBuilder { public class ClickHouseSqlBuilder extends DefaultSqlBuilder {
@Override @Override
public String buildCreateTableSql(Table table) { public String buildCreateTableSql(Table table) {
StringBuilder script = new StringBuilder(); StringBuilder script = new StringBuilder();

View File

@ -5,7 +5,7 @@ import ai.chat2db.spi.jdbc.DefaultSqlBuilder;
import ai.chat2db.spi.model.Schema; import ai.chat2db.spi.model.Schema;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
public class H2SqlBuilder extends DefaultSqlBuilder implements SqlBuilder { public class H2SqlBuilder extends DefaultSqlBuilder {
@Override @Override
public String buildCreateSchemaSql(Schema schema) { public String buildCreateSchemaSql(Schema schema) {

View File

@ -14,7 +14,7 @@ import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class KingBaseSqlBuilder extends DefaultSqlBuilder implements SqlBuilder { public class KingBaseSqlBuilder extends DefaultSqlBuilder {
@Override @Override
public String buildCreateTableSql(Table table) { public String buildCreateTableSql(Table table) {
StringBuilder script = new StringBuilder(); StringBuilder script = new StringBuilder();

View File

@ -0,0 +1,17 @@
package ai.chat2db.plugin.mongodb;
import ai.chat2db.spi.model.Command;
import ai.chat2db.spi.model.ExecuteResult;
import ai.chat2db.spi.sql.SQLExecutor;
import java.util.List;
public class MongodbCommandExecutor extends SQLExecutor {
@Override
public List<ExecuteResult> executeSelectTable(Command command) {
String sql = "db." + command.getTableName() + ".find()";
command.setScript(sql);
return execute(command);
}
}

View File

@ -1,9 +1,9 @@
package ai.chat2db.plugin.mongodb; package ai.chat2db.plugin.mongodb;
import ai.chat2db.spi.CommandExecutor;
import ai.chat2db.spi.MetaData; import ai.chat2db.spi.MetaData;
import ai.chat2db.spi.jdbc.DefaultMetaService; import ai.chat2db.spi.jdbc.DefaultMetaService;
import ai.chat2db.spi.model.Database; import ai.chat2db.spi.model.Database;
import ai.chat2db.spi.sql.SQLExecutor;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import java.sql.Connection; import java.sql.Connection;
@ -17,4 +17,9 @@ public class MongodbMetaData extends DefaultMetaService implements MetaData {
public List<Database> databases(Connection connection) { public List<Database> databases(Connection connection) {
return Lists.newArrayList(); return Lists.newArrayList();
} }
@Override
public CommandExecutor getCommandExecutor() {
return new MongodbCommandExecutor();
}
} }

View File

@ -14,7 +14,7 @@ import org.apache.commons.lang3.StringUtils;
import java.util.*; import java.util.*;
public class MysqlSqlBuilder extends DefaultSqlBuilder implements SqlBuilder { public class MysqlSqlBuilder extends DefaultSqlBuilder {
@Override @Override
public String buildCreateTableSql(Table table) { public String buildCreateTableSql(Table table) {
StringBuilder script = new StringBuilder(); StringBuilder script = new StringBuilder();

View File

@ -2,14 +2,13 @@ package ai.chat2db.plugin.oracle.builder;
import ai.chat2db.plugin.oracle.type.OracleColumnTypeEnum; import ai.chat2db.plugin.oracle.type.OracleColumnTypeEnum;
import ai.chat2db.plugin.oracle.type.OracleIndexTypeEnum; import ai.chat2db.plugin.oracle.type.OracleIndexTypeEnum;
import ai.chat2db.spi.SqlBuilder;
import ai.chat2db.spi.jdbc.DefaultSqlBuilder; import ai.chat2db.spi.jdbc.DefaultSqlBuilder;
import ai.chat2db.spi.model.Table; import ai.chat2db.spi.model.Table;
import ai.chat2db.spi.model.TableColumn; import ai.chat2db.spi.model.TableColumn;
import ai.chat2db.spi.model.TableIndex; import ai.chat2db.spi.model.TableIndex;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
public class OracleSqlBuilder extends DefaultSqlBuilder implements SqlBuilder { public class OracleSqlBuilder extends DefaultSqlBuilder {
@Override @Override
public String buildCreateTableSql(Table table) { public String buildCreateTableSql(Table table) {
StringBuilder script = new StringBuilder(); StringBuilder script = new StringBuilder();

View File

@ -2,7 +2,6 @@ package ai.chat2db.plugin.postgresql.builder;
import ai.chat2db.plugin.postgresql.type.PostgreSQLColumnTypeEnum; import ai.chat2db.plugin.postgresql.type.PostgreSQLColumnTypeEnum;
import ai.chat2db.plugin.postgresql.type.PostgreSQLIndexTypeEnum; import ai.chat2db.plugin.postgresql.type.PostgreSQLIndexTypeEnum;
import ai.chat2db.spi.SqlBuilder;
import ai.chat2db.spi.jdbc.DefaultSqlBuilder; import ai.chat2db.spi.jdbc.DefaultSqlBuilder;
import ai.chat2db.spi.model.*; import ai.chat2db.spi.model.*;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
@ -14,7 +13,7 @@ import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class PostgreSQLSqlBuilder extends DefaultSqlBuilder implements SqlBuilder { public class PostgreSQLSqlBuilder extends DefaultSqlBuilder {
@Override @Override
public String buildCreateTableSql(Table table) { public String buildCreateTableSql(Table table) {
StringBuilder script = new StringBuilder(); StringBuilder script = new StringBuilder();

View File

@ -1,34 +0,0 @@
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>ai.chat2db</groupId>
<artifactId>chat2db-plugins</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>ai.chat2db</groupId>
<artifactId>chat2db-spi</artifactId>
</dependency>
</dependencies>
<artifactId>chat2db-redis</artifactId>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<!--The properties configuration file will be placed together with the compiled class file-->
<include>**/*.json</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
</build>
</project>

View File

@ -1,8 +0,0 @@
package ai.chat2db.plugin.redis;
import ai.chat2db.spi.DBManage;
import ai.chat2db.spi.jdbc.DefaultDBManage;
public class RedisDBManage extends DefaultDBManage implements DBManage {
}

View File

@ -1,57 +0,0 @@
package ai.chat2db.plugin.redis;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import ai.chat2db.spi.MetaData;
import ai.chat2db.spi.jdbc.DefaultMetaService;
import ai.chat2db.spi.model.Database;
import ai.chat2db.spi.model.Table;
import ai.chat2db.spi.sql.SQLExecutor;
import org.apache.commons.lang3.StringUtils;
public class RedisMetaData extends DefaultMetaService implements MetaData {
@Override
public List<Database> databases(Connection connection) {
List<Database> databases = new ArrayList<>();
return SQLExecutor.getInstance().execute(connection,"config get databases", resultSet -> {
try {
if (resultSet.next()) {
Object count = resultSet.getObject(2);
if(StringUtils.isNotBlank(count.toString())) {
for (int i = 0; i < Integer.parseInt(count.toString()); i++) {
Database database = Database.builder().name(String.valueOf(i)).build();
databases.add(database);
}
}
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
return databases;
});
}
@Override
public List<Table> tables(Connection connection, String databaseName, String schemaName, String tableName) {
return SQLExecutor.getInstance().execute(connection,"scan 0 MATCH * COUNT 1000", resultSet -> {
List<Table> tables = new ArrayList<>();
try {
while (resultSet.next()) {
ArrayList list = (ArrayList)resultSet.getObject(2);
for (Object object : list) {
Table table = new Table();
table.setName(object.toString());
tables.add(table);
}
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
return tables;
});
}
}

View File

@ -1,27 +0,0 @@
package ai.chat2db.plugin.redis;
import ai.chat2db.spi.DBManage;
import ai.chat2db.spi.MetaData;
import ai.chat2db.spi.Plugin;
import ai.chat2db.spi.config.DBConfig;
import ai.chat2db.spi.util.FileUtils;
public class RedisPlugin implements Plugin {
@Override
public DBConfig getDBConfig() {
return FileUtils.readJsonValue(this.getClass(),"redis.json", DBConfig.class);
}
@Override
public MetaData getMetaData() {
return new RedisMetaData();
}
@Override
public DBManage getDBManage() {
return new RedisDBManage();
}
}

View File

@ -1,18 +0,0 @@
{
"dbType": "REDIS",
"supportDatabase": false,
"supportSchema": false,
"driverConfigList": [
{
"url": "jdbc:redis://127.0.0.1:6379/0",
"custom": false,
"defaultDriver": true,
"downloadJdbcDriverUrls": [
"https://oss.sqlgpt.cn/lib/redis-jdbc-driver-1.3.jar"
],
"jdbcDriver": "redis-jdbc-driver-1.3.jar",
"jdbcDriverClass": "jdbc.RedisDriver"
}
],
"name": "Redis"
}

View File

@ -10,7 +10,7 @@ import ai.chat2db.spi.model.TableIndex;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
public class SqliteBuilder extends DefaultSqlBuilder implements SqlBuilder { public class SqliteBuilder extends DefaultSqlBuilder {
@Override @Override
public String buildCreateTableSql(Table table) { public String buildCreateTableSql(Table table) {
StringBuilder script = new StringBuilder(); StringBuilder script = new StringBuilder();

View File

@ -8,7 +8,7 @@ import ai.chat2db.spi.model.*;
import ai.chat2db.spi.sql.Chat2DBContext; import ai.chat2db.spi.sql.Chat2DBContext;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
public class SqlServerSqlBuilder extends DefaultSqlBuilder implements SqlBuilder { public class SqlServerSqlBuilder extends DefaultSqlBuilder {
@Override @Override
public String buildCreateTableSql(Table table) { public String buildCreateTableSql(Table table) {
StringBuilder script = new StringBuilder(); StringBuilder script = new StringBuilder();

View File

@ -28,7 +28,6 @@
<module>chat2db-mongodb</module> <module>chat2db-mongodb</module>
<module>chat2db-presto</module> <module>chat2db-presto</module>
<module>chat2db-hive</module> <module>chat2db-hive</module>
<module>chat2db-redis</module>
<module>chat2db-kingbase</module> <module>chat2db-kingbase</module>
</modules> </modules>

View File

@ -37,6 +37,9 @@ public class DlExecuteParam {
private String databaseName; private String databaseName;
private String tableName;
/** /**
* schema name * schema name
*/ */

View File

@ -27,6 +27,14 @@ public interface DlTemplateService {
ListResult<ExecuteResult> execute(DlExecuteParam param); ListResult<ExecuteResult> execute(DlExecuteParam param);
/**
*
* @param param
* @return
*/
ListResult<ExecuteResult> executeSelectTable(DlExecuteParam param);
/** /**
* Data source execution update * Data source execution update
* *

View File

@ -111,11 +111,6 @@
<artifactId>chat2db-presto</artifactId> <artifactId>chat2db-presto</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<dependency>
<groupId>ai.chat2db</groupId>
<artifactId>chat2db-redis</artifactId>
<version>${revision}</version>
</dependency>
<dependency> <dependency>
<groupId>ai.chat2db</groupId> <groupId>ai.chat2db</groupId>
<artifactId>chat2db-sqlite</artifactId> <artifactId>chat2db-sqlite</artifactId>

View File

@ -17,7 +17,6 @@ import ai.chat2db.spi.ValueHandler;
import ai.chat2db.spi.model.*; import ai.chat2db.spi.model.*;
import ai.chat2db.spi.sql.Chat2DBContext; import ai.chat2db.spi.sql.Chat2DBContext;
import ai.chat2db.spi.sql.ConnectInfo; import ai.chat2db.spi.sql.ConnectInfo;
import ai.chat2db.spi.sql.SQLExecutor;
import ai.chat2db.spi.util.JdbcUtils; import ai.chat2db.spi.util.JdbcUtils;
import ai.chat2db.spi.util.SqlUtils; import ai.chat2db.spi.util.SqlUtils;
import com.alibaba.druid.DbType; import com.alibaba.druid.DbType;
@ -28,6 +27,7 @@ import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -61,12 +61,15 @@ public class DlTemplateServiceImpl implements DlTemplateService {
CommandExecutor executor = Chat2DBContext.getMetaData().getCommandExecutor(); CommandExecutor executor = Chat2DBContext.getMetaData().getCommandExecutor();
Command command = commandConverter.param2model(param); Command command = commandConverter.param2model(param);
List<ExecuteResult> results = executor.execute(command); List<ExecuteResult> results = executor.execute(command);
return reBuildHeader(results,param.getSchemaName(),param.getDatabaseName());
}
private ListResult<ExecuteResult> reBuildHeader(List<ExecuteResult> results,String schemaName,String databaseName){
ListResult<ExecuteResult> listResult = ListResult.of(results); ListResult<ExecuteResult> listResult = ListResult.of(results);
for (ExecuteResult executeResult : results) { for (ExecuteResult executeResult : results) {
List<Header> headers = executeResult.getHeaderList(); List<Header> headers = executeResult.getHeaderList();
if (executeResult.getSuccess() && executeResult.isCanEdit() && CollectionUtils.isNotEmpty(headers)) { if (executeResult.getSuccess() && executeResult.isCanEdit() && CollectionUtils.isNotEmpty(headers)) {
headers = setColumnInfo(headers, executeResult.getTableName(), param.getSchemaName(), headers = setColumnInfo(headers, executeResult.getTableName(), schemaName, databaseName);
param.getDatabaseName());
executeResult.setHeaderList(headers); executeResult.setHeaderList(headers);
} }
if (!executeResult.getSuccess()) { if (!executeResult.getSuccess()) {
@ -77,12 +80,13 @@ public class DlTemplateServiceImpl implements DlTemplateService {
addOperationLog(executeResult); addOperationLog(executeResult);
} }
return listResult; return listResult;
}
// if ("SQLSERVER".equalsIgnoreCase(type)) { @Override
// RemoveSpecialGO(param); public ListResult<ExecuteResult> executeSelectTable(DlExecuteParam param) {
// } Command command = commandConverter.param2model(param);
List<ExecuteResult> results = Chat2DBContext.getMetaData().getCommandExecutor().executeSelectTable(command);
return reBuildHeader(results,param.getSchemaName(),param.getDatabaseName());
} }
@Override @Override
@ -159,8 +163,9 @@ public class DlTemplateServiceImpl implements DlTemplateService {
@Override @Override
public DataResult<String> updateSelectResult(UpdateSelectResultParam param) { public DataResult<String> updateSelectResult(UpdateSelectResultParam param) {
SqlBuilder sqlBuilder = Chat2DBContext.getSqlBuilder(); SqlBuilder sqlBuilder = Chat2DBContext.getSqlBuilder();
String sql = sqlBuilder.generateSqlBasedOnResults(param.getTableName(), param.getHeaderList(), QueryResult queryResult = new QueryResult();
param.getOperations()); BeanUtils.copyProperties(param, queryResult);
String sql = sqlBuilder.buildSqlByQuery(queryResult);
return DataResult.of(sql); return DataResult.of(sql);
} }

View File

@ -97,18 +97,7 @@ public class RdbDmlController {
@RequestMapping(value = "/execute_table", method = {RequestMethod.POST, RequestMethod.PUT}) @RequestMapping(value = "/execute_table", method = {RequestMethod.POST, RequestMethod.PUT})
public ListResult<ExecuteResultVO> executeTable(@RequestBody DmlTableRequest request) { public ListResult<ExecuteResultVO> executeTable(@RequestBody DmlTableRequest request) {
DlExecuteParam param = rdbWebConverter.request2param(request); DlExecuteParam param = rdbWebConverter.request2param(request);
// parse sql return dlTemplateService.executeSelectTable(param)
String type = Chat2DBContext.getConnectInfo().getDbType();
MetaData metaData = Chat2DBContext.getMetaData();
if (DataSourceTypeEnum.MONGODB.getCode().equals(type)) {
param.setSql("db." + request.getTableName() + ".find()");
} else if (DataSourceTypeEnum.SQLSERVER.getCode().equals(type)){
param.setSql("select * from" + metaData.getMetaDataName(request.getSchemaName()) + "." + metaData.getMetaDataName(request.getTableName()));
}else {
// Splice `tableName` to avoid the problem of keywords being occupied
param.setSql("select * from " + metaData.getMetaDataName(request.getTableName()));
}
return dlTemplateService.execute(param)
.map(rdbWebConverter::dto2vo); .map(rdbWebConverter::dto2vo);
} }

View File

@ -86,4 +86,21 @@
<artifactId>bson</artifactId> <artifactId>bson</artifactId>
</dependency> </dependency>
</dependencies> </dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version> <!-- 使用最新版本 -->
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal> <!-- 打包源代码成jar -->
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project> </project>

View File

@ -27,6 +27,12 @@ public interface CommandExecutor {
ExecuteResult executeUpdate(String sql, Connection connection, int n)throws SQLException; ExecuteResult executeUpdate(String sql, Connection connection, int n)throws SQLException;
/**
* Execute command
*/
List<ExecuteResult> executeSelectTable(Command command);
/** /**
* *
* *

View File

@ -3,7 +3,9 @@ package ai.chat2db.spi;
import java.sql.Connection; import java.sql.Connection;
import java.util.List; import java.util.List;
import ai.chat2db.server.tools.base.wrapper.result.PageResult;
import ai.chat2db.spi.model.*; import ai.chat2db.spi.model.*;
import cn.hutool.db.Page;
import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotEmpty;
/** /**
@ -52,6 +54,19 @@ public interface MetaData {
*/ */
List<Table> tables(Connection connection, @NotEmpty String databaseName, String schemaName, String tableName); List<Table> tables(Connection connection, @NotEmpty String databaseName, String schemaName, String tableName);
/**
* Querying all table under a schema.
*
* @param connection
* @param databaseName
* @param schemaName
* @param tableNamePattern
* @param pageNo
* @param pageSize
* @return
*/
PageResult<Table> tables(Connection connection, String databaseName, String schemaName, String tableNamePattern, int pageNo, int pageSize);
/** /**
* Querying view information. * Querying view information.
* *

View File

@ -4,7 +4,7 @@ import ai.chat2db.spi.model.*;
import java.util.List; import java.util.List;
public interface SqlBuilder { public interface SqlBuilder<T> {
/** /**
* Generate create table sql * Generate create table sql
@ -12,7 +12,7 @@ public interface SqlBuilder {
* @param table * @param table
* @return * @return
*/ */
String buildCreateTableSql(Table table); String buildCreateTableSql(T table);
/** /**
@ -22,7 +22,7 @@ public interface SqlBuilder {
* @param oldTable * @param oldTable
* @return * @return
*/ */
String buildModifyTaleSql(Table oldTable, Table newTable); String buildModifyTaleSql(T oldTable, T newTable);
/** /**
@ -79,7 +79,7 @@ public interface SqlBuilder {
/** /**
* generate sql based on results * generate sql based on results
*/ */
String generateSqlBasedOnResults(String tableName, List<Header> headerList, List<ResultOperation> operations); String buildSqlByQuery(QueryResult queryResult);
/** /**
* DML SQL * DML SQL
@ -87,5 +87,5 @@ public interface SqlBuilder {
* @param type * @param type
* @return * @return
*/ */
String getTableDmlSql(Table table,String type); String getTableDmlSql(T table,String type);
} }

View File

@ -3,9 +3,9 @@ package ai.chat2db.spi.jdbc;
import java.sql.Connection; import java.sql.Connection;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import ai.chat2db.server.tools.base.wrapper.result.PageResult;
import ai.chat2db.spi.CommandExecutor; import ai.chat2db.spi.CommandExecutor;
import ai.chat2db.spi.MetaData; import ai.chat2db.spi.MetaData;
import ai.chat2db.spi.SqlBuilder; import ai.chat2db.spi.SqlBuilder;
@ -48,6 +48,16 @@ public class DefaultMetaService implements MetaData {
return SQLExecutor.getInstance().tables(connection, StringUtils.isEmpty(databaseName) ? null : databaseName, StringUtils.isEmpty(schemaName) ? null : schemaName, tableName, new String[]{"TABLE","SYSTEM TABLE"}); return SQLExecutor.getInstance().tables(connection, StringUtils.isEmpty(databaseName) ? null : databaseName, StringUtils.isEmpty(schemaName) ? null : schemaName, tableName, new String[]{"TABLE","SYSTEM TABLE"});
} }
@Override
public PageResult<Table> tables(Connection connection, String databaseName, String schemaName, String tableNamePattern, int pageNo, int pageSize) {
List<Table> tables = tables(connection, databaseName, schemaName, tableNamePattern);
if(CollectionUtils.isEmpty(tables)){
return PageResult.of(tables,0L,pageNo, pageSize);
}
List result = tables.stream().skip((pageNo - 1) * pageSize).limit(pageSize).collect(Collectors.toList());
return PageResult.of(result, (long) tables.size(), pageNo, pageSize);
}
@Override @Override
public Table view(Connection connection, String databaseName, String schemaName, String viewName) { public Table view(Connection connection, String databaseName, String schemaName, String viewName) {
return null; return null;

View File

@ -19,7 +19,7 @@ import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class DefaultSqlBuilder implements SqlBuilder { public class DefaultSqlBuilder implements SqlBuilder<Table> {
@Override @Override
@ -90,8 +90,10 @@ public class DefaultSqlBuilder implements SqlBuilder {
} }
@Override @Override
public String generateSqlBasedOnResults(String tableName, List<Header> headerList, List<ResultOperation> operations) { public String buildSqlByQuery(QueryResult queryResult) {
List<Header> headerList = queryResult.getHeaderList();
List<ResultOperation> operations = queryResult.getOperations();
String tableName = queryResult.getTableName();
StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder = new StringBuilder();
MetaData metaSchema = Chat2DBContext.getMetaData(); MetaData metaSchema = Chat2DBContext.getMetaData();
List<String> keyColumns = getPrimaryColumns(headerList); List<String> keyColumns = getPrimaryColumns(headerList);

View File

@ -38,6 +38,11 @@ public class Command implements Serializable {
*/ */
private String schemaName; private String schemaName;
/**
*
*/
private String tableName;
/** /**
*Page coding *Page coding
* Only available for select statements * Only available for select statements

View File

@ -2,6 +2,7 @@ package ai.chat2db.spi.model;
import java.io.Serializable; import java.io.Serializable;
import java.util.List; import java.util.List;
import java.util.Map;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
@ -104,7 +105,12 @@ public class ExecuteResult implements Serializable {
private boolean canEdit; private boolean canEdit;
/** /**
* Table Name * Table Name for the result
*/ */
private String tableName; private String tableName;
/**
* Extra information that can be used by the plugin
*/
private Map<String,Object> extra;
} }

View File

@ -0,0 +1,16 @@
package ai.chat2db.spi.model;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
@Data
public class QueryResult implements Serializable {
private String tableName;
private List<Header> headerList;
private List<ResultOperation> operations;
private Map<String, Object> extra;
}

View File

@ -16,6 +16,7 @@ import ai.chat2db.server.tools.base.excption.BusinessException;
import ai.chat2db.server.tools.common.util.EasyCollectionUtils; import ai.chat2db.server.tools.common.util.EasyCollectionUtils;
import ai.chat2db.server.tools.common.util.I18nUtils; import ai.chat2db.server.tools.common.util.I18nUtils;
import ai.chat2db.spi.CommandExecutor; import ai.chat2db.spi.CommandExecutor;
import ai.chat2db.spi.MetaData;
import ai.chat2db.spi.ValueHandler; import ai.chat2db.spi.ValueHandler;
import ai.chat2db.spi.enums.DataTypeEnum; import ai.chat2db.spi.enums.DataTypeEnum;
import ai.chat2db.spi.enums.SqlTypeEnum; import ai.chat2db.spi.enums.SqlTypeEnum;
@ -39,7 +40,7 @@ import org.bson.Document;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
* Dbhub unified database connection management * Dbhub unified database connection management
* *
* @author jipengfei * @author jipengfei
*/ */
@ -74,6 +75,7 @@ public class SQLExecutor implements CommandExecutor {
} }
return null; return null;
} }
public void execute(Connection connection, String sql, ResultSetConsumer consumer) { public void execute(Connection connection, String sql, ResultSetConsumer consumer) {
log.info("execute:{}", sql); log.info("execute:{}", sql);
try (Statement stmt = connection.createStatement()) { try (Statement stmt = connection.createStatement()) {
@ -113,10 +115,10 @@ public class SQLExecutor implements CommandExecutor {
List<Header> headerList = Lists.newArrayListWithExpectedSize(col); List<Header> headerList = Lists.newArrayListWithExpectedSize(col);
for (int i = 1; i <= col; i++) { for (int i = 1; i <= col; i++) {
headerList.add(Header.builder() headerList.add(Header.builder()
.dataType(JdbcUtils.resolveDataType( .dataType(JdbcUtils.resolveDataType(
resultSetMetaData.getColumnTypeName(i), resultSetMetaData.getColumnType(i)).getCode()) resultSetMetaData.getColumnTypeName(i), resultSetMetaData.getColumnType(i)).getCode())
.name(ResultSetUtils.getColumnName(resultSetMetaData, i)) .name(ResultSetUtils.getColumnName(resultSetMetaData, i))
.build()); .build());
} }
headerConsumer.accept(headerList); headerConsumer.accept(headerList);
@ -144,13 +146,13 @@ public class SQLExecutor implements CommandExecutor {
* @throws SQLException * @throws SQLException
*/ */
public ExecuteResult execute(final String sql, Connection connection, ValueHandler valueHandler) public ExecuteResult execute(final String sql, Connection connection, ValueHandler valueHandler)
throws SQLException { throws SQLException {
return execute(sql, connection, true, null, null, valueHandler); return execute(sql, connection, true, null, null, valueHandler);
} }
@Override @Override
public ExecuteResult executeUpdate(String sql, Connection connection, int n) public ExecuteResult executeUpdate(String sql, Connection connection, int n)
throws SQLException { throws SQLException {
Assert.notNull(sql, "SQL must not be null"); Assert.notNull(sql, "SQL must not be null");
log.info("execute:{}", sql); log.info("execute:{}", sql);
// connection.setAutoCommit(false); // connection.setAutoCommit(false);
@ -160,29 +162,40 @@ public class SQLExecutor implements CommandExecutor {
if (affectedRows != n) { if (affectedRows != n) {
executeResult.setSuccess(false); executeResult.setSuccess(false);
executeResult.setMessage("Update error " + sql + " update affectedRows = " + affectedRows executeResult.setMessage("Update error " + sql + " update affectedRows = " + affectedRows
+ ", Each SQL statement should update no more than one record. Please use a unique key for " + ", Each SQL statement should update no more than one record. Please use a unique key for "
+ "updates."); + "updates.");
// connection.rollback(); // connection.rollback();
} }
} }
return executeResult; return executeResult;
} }
@Override
public List<ExecuteResult> executeSelectTable(Command command) {
MetaData metaData = Chat2DBContext.getMetaData();
String tableName = metaData.getMetaDataName(command.getDatabaseName(), command.getSchemaName(),
command.getTableName());
String sql = "select * from " + tableName;
command.setScript(sql);
return execute(command);
}
/** /**
* Executes the given SQL query using the provided connection. * Executes the given SQL query using the provided connection.
* @param sql The SQL query to be executed. *
* @param connection The database connection to use for the query. * @param sql The SQL query to be executed.
* @param connection The database connection to use for the query.
* @param limitRowSize Flag to indicate if row size should be limited. * @param limitRowSize Flag to indicate if row size should be limited.
* @param offset The starting point of rows to fetch in the result set. * @param offset The starting point of rows to fetch in the result set.
* @param count The number of rows to fetch from the result set. * @param count The number of rows to fetch from the result set.
* @param valueHandler Handles the processing of the result set values. * @param valueHandler Handles the processing of the result set values.
* @return ExecuteResult containing the result of the execution. * @return ExecuteResult containing the result of the execution.
* @throws SQLException If there is any SQL related error. * @throws SQLException If there is any SQL related error.
*/ */
public ExecuteResult execute(final String sql, Connection connection, boolean limitRowSize, Integer offset, public ExecuteResult execute(final String sql, Connection connection, boolean limitRowSize, Integer offset,
Integer count, ValueHandler valueHandler) Integer count, ValueHandler valueHandler)
throws SQLException { throws SQLException {
Assert.notNull(sql, "SQL must not be null"); Assert.notNull(sql, "SQL must not be null");
log.info("execute:{}", sql); log.info("execute:{}", sql);
@ -227,11 +240,11 @@ public class SQLExecutor implements CommandExecutor {
continue; continue;
} }
String dataType = JdbcUtils.resolveDataType( String dataType = JdbcUtils.resolveDataType(
resultSetMetaData.getColumnTypeName(i), resultSetMetaData.getColumnType(i)).getCode(); resultSetMetaData.getColumnTypeName(i), resultSetMetaData.getColumnType(i)).getCode();
headerList.add(Header.builder() headerList.add(Header.builder()
.dataType(dataType) .dataType(dataType)
.name(name) .name(name)
.build()); .build());
} }
// Get data information // Get data information
@ -271,16 +284,16 @@ public class SQLExecutor implements CommandExecutor {
if (o instanceof Document document) { if (o instanceof Document document) {
for (String string : document.keySet()) { for (String string : document.keySet()) {
headerListMap.computeIfAbsent(string, k -> Header.builder() headerListMap.computeIfAbsent(string, k -> Header.builder()
.dataType("string") .dataType("string")
.name(string) .name(string)
.build()); .build());
row.put(string, Objects.toString(document.get(string))); row.put(string, Objects.toString(document.get(string)));
} }
} else { } else {
headerListMap.computeIfAbsent("_unknown", k -> Header.builder() headerListMap.computeIfAbsent("_unknown", k -> Header.builder()
.dataType("string") .dataType("string")
.name("_unknown") .name("_unknown")
.build()); .build());
row.put("_unknown", Objects.toString(o)); row.put("_unknown", Objects.toString(o));
} }
} }
@ -393,12 +406,12 @@ public class SQLExecutor implements CommandExecutor {
* @return * @return
*/ */
public List<Table> tables(Connection connection, String databaseName, String schemaName, String tableName, public List<Table> tables(Connection connection, String databaseName, String schemaName, String tableName,
String types[]) { String types[]) {
try { try {
DatabaseMetaData metadata = connection.getMetaData(); DatabaseMetaData metadata = connection.getMetaData();
ResultSet resultSet = metadata.getTables(databaseName, schemaName, tableName, ResultSet resultSet = metadata.getTables(databaseName, schemaName, tableName,
types); types);
// If connection is mysql // If connection is mysql
if ("MySQL".equalsIgnoreCase(metadata.getDatabaseProductName())) { if ("MySQL".equalsIgnoreCase(metadata.getDatabaseProductName())) {
// Get the comment of mysql table // Get the comment of mysql table
@ -438,10 +451,10 @@ public class SQLExecutor implements CommandExecutor {
* @return * @return
*/ */
public List<TableColumn> columns(Connection connection, String databaseName, String schemaName, String public List<TableColumn> columns(Connection connection, String databaseName, String schemaName, String
tableName, tableName,
String columnName) { String columnName) {
try (ResultSet resultSet = connection.getMetaData().getColumns(databaseName, schemaName, tableName, try (ResultSet resultSet = connection.getMetaData().getColumns(databaseName, schemaName, tableName,
columnName)) { columnName)) {
return ResultSetUtils.toObjectList(resultSet, TableColumn.class); return ResultSetUtils.toObjectList(resultSet, TableColumn.class);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
@ -460,22 +473,22 @@ public class SQLExecutor implements CommandExecutor {
public List<TableIndex> indexes(Connection connection, String databaseName, String schemaName, String tableName) { public List<TableIndex> indexes(Connection connection, String databaseName, String schemaName, String tableName) {
List<TableIndex> tableIndices = Lists.newArrayList(); List<TableIndex> tableIndices = Lists.newArrayList();
try (ResultSet resultSet = connection.getMetaData().getIndexInfo(databaseName, schemaName, tableName, try (ResultSet resultSet = connection.getMetaData().getIndexInfo(databaseName, schemaName, tableName,
false, false,
false)) { false)) {
List<TableIndexColumn> tableIndexColumns = ResultSetUtils.toObjectList(resultSet, TableIndexColumn.class); List<TableIndexColumn> tableIndexColumns = ResultSetUtils.toObjectList(resultSet, TableIndexColumn.class);
tableIndexColumns.stream().filter(c -> c.getIndexName() != null).collect( tableIndexColumns.stream().filter(c -> c.getIndexName() != null).collect(
Collectors.groupingBy(TableIndexColumn::getIndexName)).entrySet() Collectors.groupingBy(TableIndexColumn::getIndexName)).entrySet()
.stream().forEach(entry -> { .stream().forEach(entry -> {
TableIndex tableIndex = new TableIndex(); TableIndex tableIndex = new TableIndex();
TableIndexColumn column = entry.getValue().get(0); TableIndexColumn column = entry.getValue().get(0);
tableIndex.setName(entry.getKey()); tableIndex.setName(entry.getKey());
tableIndex.setTableName(column.getTableName()); tableIndex.setTableName(column.getTableName());
tableIndex.setSchemaName(column.getSchemaName()); tableIndex.setSchemaName(column.getSchemaName());
tableIndex.setDatabaseName(column.getDatabaseName()); tableIndex.setDatabaseName(column.getDatabaseName());
tableIndex.setUnique(!column.getNonUnique()); tableIndex.setUnique(!column.getNonUnique());
tableIndex.setColumnList(entry.getValue()); tableIndex.setColumnList(entry.getValue());
tableIndices.add(tableIndex); tableIndices.add(tableIndex);
}); });
} catch (SQLException e) { } catch (SQLException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -491,7 +504,7 @@ public class SQLExecutor implements CommandExecutor {
* @return List<Function> * @return List<Function>
*/ */
public List<ai.chat2db.spi.model.Function> functions(Connection connection, String databaseName, public List<ai.chat2db.spi.model.Function> functions(Connection connection, String databaseName,
String schemaName) { String schemaName) {
try (ResultSet resultSet = connection.getMetaData().getFunctions(databaseName, schemaName, null);) { try (ResultSet resultSet = connection.getMetaData().getFunctions(databaseName, schemaName, null);) {
return ResultSetUtils.toObjectList(resultSet, ai.chat2db.spi.model.Function.class); return ResultSetUtils.toObjectList(resultSet, ai.chat2db.spi.model.Function.class);
} catch (Exception e) { } catch (Exception e) {