feat(PostgreSQL): delete the PostgreSQL sequences

This commit is contained in:
Sylphy
2025-04-12 01:59:47 +08:00
parent 5968485f51
commit b4cc48bdb9
15 changed files with 116 additions and 23 deletions

View File

@ -22,6 +22,9 @@ import java.util.stream.Collectors;
import static ai.chat2db.plugin.postgresql.consts.SequenceCommonConst.*; import static ai.chat2db.plugin.postgresql.consts.SequenceCommonConst.*;
import static ai.chat2db.plugin.postgresql.consts.SQLConst.*; import static ai.chat2db.plugin.postgresql.consts.SQLConst.*;
import static ai.chat2db.server.tools.base.constant.SymbolConstant.*;
import static ai.chat2db.server.tools.base.constant.SymbolConstant.DOT;
import static ai.chat2db.server.tools.base.constant.SymbolConstant.SEMICOLON;
import static ai.chat2db.spi.util.SortUtils.sortDatabase; import static ai.chat2db.spi.util.SortUtils.sortDatabase;
public class PostgreSQLMetaData extends DefaultMetaService implements MetaData { public class PostgreSQLMetaData extends DefaultMetaService implements MetaData {
@ -369,7 +372,7 @@ public class PostgreSQLMetaData extends DefaultMetaService implements MetaData {
Optional.ofNullable(comment).ifPresent(v -> stringBuilder.append(COMMENT_ON_SEQUENCE) Optional.ofNullable(comment).ifPresent(v -> stringBuilder.append(COMMENT_ON_SEQUENCE)
.append(nspname).append(DOT).append(relname) .append(nspname).append(DOT).append(relname)
.append(IS).append(SINGLE_QUOTE).append(comment).append(SINGLE_QUOTE).append(SEMICOLON).append(BLANK_LINE)); .append(IS).append(SQUOT).append(comment).append(SQUOT).append(SEMICOLON).append(BLANK_LINE));
Optional.ofNullable(rolname).ifPresent(v -> stringBuilder.append(ALTER_SEQUENCE) Optional.ofNullable(rolname).ifPresent(v -> stringBuilder.append(ALTER_SEQUENCE)
.append(nspname).append(DOT).append(relname) .append(nspname).append(DOT).append(relname)

View File

@ -17,6 +17,10 @@ import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static ai.chat2db.plugin.postgresql.consts.SequenceCommonConst.*; import static ai.chat2db.plugin.postgresql.consts.SequenceCommonConst.*;
import static ai.chat2db.server.tools.base.constant.SymbolConstant.BLANK_LINE;
import static ai.chat2db.server.tools.base.constant.SymbolConstant.SQUOT;
import static ai.chat2db.server.tools.base.constant.SymbolConstant.DOT;
import static ai.chat2db.server.tools.base.constant.SymbolConstant.SEMICOLON;
public class PostgreSQLSqlBuilder extends DefaultSqlBuilder { public class PostgreSQLSqlBuilder extends DefaultSqlBuilder {
@ -282,7 +286,7 @@ public class PostgreSQLSqlBuilder extends DefaultSqlBuilder {
sqlBuilder.append(ALTER_SEQUENCE).append(oldSequence.getNspname()).append(DOT).append(oldSequence.getRelname()).append(RENAME_TO).append(newSequence.getRelname()).append(SEMICOLON).append(BLANK_LINE); sqlBuilder.append(ALTER_SEQUENCE).append(oldSequence.getNspname()).append(DOT).append(oldSequence.getRelname()).append(RENAME_TO).append(newSequence.getRelname()).append(SEMICOLON).append(BLANK_LINE);
} }
if (!StringUtils.equals(oldSequence.getComment(), newSequence.getComment())) { if (!StringUtils.equals(oldSequence.getComment(), newSequence.getComment())) {
sqlBuilder.append(COMMENT_ON_SEQUENCE).append(newSequence.getNspname()).append(DOT).append(newSequence.getRelname()).append(IS).append(SINGLE_QUOTE).append(newSequence.getComment()).append(SINGLE_QUOTE).append(SEMICOLON).append(BLANK_LINE); sqlBuilder.append(COMMENT_ON_SEQUENCE).append(newSequence.getNspname()).append(DOT).append(newSequence.getRelname()).append(IS).append(SQUOT).append(newSequence.getComment()).append(SQUOT).append(SEMICOLON).append(BLANK_LINE);
} }
if (!StringUtils.equals(oldSequence.getSeqcache(), newSequence.getSeqcache())) { if (!StringUtils.equals(oldSequence.getSeqcache(), newSequence.getSeqcache())) {
sqlBuilder.append(ALTER_SEQUENCE).append(newSequence.getNspname()).append(DOT).append(newSequence.getRelname()).append(CACHE).append(newSequence.getSeqcache()).append(SEMICOLON).append(BLANK_LINE); sqlBuilder.append(ALTER_SEQUENCE).append(newSequence.getNspname()).append(DOT).append(newSequence.getRelname()).append(CACHE).append(newSequence.getSeqcache()).append(SEMICOLON).append(BLANK_LINE);

View File

@ -27,9 +27,4 @@ public class SequenceCommonConst {
public static final String OWNED_BY = " OWNED BY "; public static final String OWNED_BY = " OWNED BY ";
public static final String IS = " IS "; public static final String IS = " IS ";
public static final String AS = " AS "; public static final String AS = " AS ";
public static final String BLANK_LINE = "\n\n";
public static final String NEW_LINE = "\n";
public static final String SEMICOLON = ";";
public static final String DOT = ".";
public static final String SINGLE_QUOTE = "'";
} }

View File

@ -30,12 +30,12 @@ public class DropParam {
private String databaseName; private String databaseName;
/** /**
* Table Name * Name
*/ */
private String tableName; private String name;
/** /**
* schema * schema
*/ */
private String tableSchema; private String schema;
} }

View File

@ -1,7 +1,9 @@
package ai.chat2db.server.domain.api.service; package ai.chat2db.server.domain.api.service;
import ai.chat2db.server.domain.api.param.DropParam;
import ai.chat2db.server.domain.api.param.SequencePageQueryParam; import ai.chat2db.server.domain.api.param.SequencePageQueryParam;
import ai.chat2db.server.domain.api.param.ShowCreateSequenceParam; import ai.chat2db.server.domain.api.param.ShowCreateSequenceParam;
import ai.chat2db.server.tools.base.wrapper.result.ActionResult;
import ai.chat2db.server.tools.base.wrapper.result.DataResult; import ai.chat2db.server.tools.base.wrapper.result.DataResult;
import ai.chat2db.server.tools.base.wrapper.result.ListResult; import ai.chat2db.server.tools.base.wrapper.result.ListResult;
import ai.chat2db.spi.model.Sequence; import ai.chat2db.spi.model.Sequence;
@ -19,4 +21,6 @@ public interface SequenceService {
ListResult<SimpleSequence> pageQuery(SequencePageQueryParam request); ListResult<SimpleSequence> pageQuery(SequencePageQueryParam request);
ListResult<Sql> buildSql(Sequence oldSequence, Sequence newSequence); ListResult<Sql> buildSql(Sequence oldSequence, Sequence newSequence);
ActionResult drop(DropParam dropParam);
} }

View File

@ -1,11 +1,14 @@
package ai.chat2db.server.domain.core.impl; package ai.chat2db.server.domain.core.impl;
import ai.chat2db.server.domain.api.param.DropParam;
import ai.chat2db.server.domain.api.param.SequencePageQueryParam; import ai.chat2db.server.domain.api.param.SequencePageQueryParam;
import ai.chat2db.server.domain.api.param.ShowCreateSequenceParam; import ai.chat2db.server.domain.api.param.ShowCreateSequenceParam;
import ai.chat2db.server.domain.api.service.SequenceService; import ai.chat2db.server.domain.api.service.SequenceService;
import ai.chat2db.server.tools.base.wrapper.result.ActionResult;
import ai.chat2db.server.tools.base.wrapper.result.DataResult; import ai.chat2db.server.tools.base.wrapper.result.DataResult;
import ai.chat2db.server.tools.base.wrapper.result.ListResult; import ai.chat2db.server.tools.base.wrapper.result.ListResult;
import ai.chat2db.spi.DBManage;
import ai.chat2db.spi.MetaData; import ai.chat2db.spi.MetaData;
import ai.chat2db.spi.SqlBuilder; import ai.chat2db.spi.SqlBuilder;
import ai.chat2db.spi.model.*; import ai.chat2db.spi.model.*;
@ -32,12 +35,14 @@ public class SequenceServiceImpl implements SequenceService {
return DataResult.of(ddl); return DataResult.of(ddl);
} }
@Override
public ListResult<SimpleSequence> pageQuery(SequencePageQueryParam request) { public ListResult<SimpleSequence> pageQuery(SequencePageQueryParam request) {
MetaData metaSchema = Chat2DBContext.getMetaData(); MetaData metaSchema = Chat2DBContext.getMetaData();
List<SimpleSequence> sequences = metaSchema.sequences(Chat2DBContext.getConnection(), request.getDatabaseName(), request.getSchemaName()); List<SimpleSequence> sequences = metaSchema.sequences(Chat2DBContext.getConnection(), request.getDatabaseName(), request.getSchemaName());
return ListResult.of(sequences); return ListResult.of(sequences);
} }
@Override
public ListResult<Sql> buildSql(Sequence oldSequence, Sequence newSequence) { public ListResult<Sql> buildSql(Sequence oldSequence, Sequence newSequence) {
SqlBuilder sqlBuilder = Chat2DBContext.getSqlBuilder(); SqlBuilder sqlBuilder = Chat2DBContext.getSqlBuilder();
List<Sql> sqls = new ArrayList<>(); List<Sql> sqls = new ArrayList<>();
@ -48,4 +53,11 @@ public class SequenceServiceImpl implements SequenceService {
} }
return ListResult.of(sqls); return ListResult.of(sqls);
} }
@Override
public ActionResult drop(DropParam param) {
DBManage metaSchema = Chat2DBContext.getDBManage();
metaSchema.dropSequence(Chat2DBContext.getConnection(), param.getDatabaseName(), param.getSchema(), param.getName());
return ActionResult.isSuccess();
}
} }

View File

@ -88,7 +88,7 @@ public class TableServiceImpl implements TableService {
@Override @Override
public ActionResult drop(DropParam param) { public ActionResult drop(DropParam param) {
DBManage metaSchema = Chat2DBContext.getDBManage(); DBManage metaSchema = Chat2DBContext.getDBManage();
metaSchema.dropTable(Chat2DBContext.getConnection(), param.getDatabaseName(), param.getTableSchema(), param.getTableName()); metaSchema.dropTable(Chat2DBContext.getConnection(), param.getDatabaseName(), param.getSchema(), param.getName());
return ActionResult.isSuccess(); return ActionResult.isSuccess();
} }

View File

@ -89,32 +89,32 @@ public class TableServiceTest extends TestApplication {
if (Objects.equals(dialectProperties.getDbType(), "MYSQL")) { if (Objects.equals(dialectProperties.getDbType(), "MYSQL")) {
DropParam param = new DropParam(); DropParam param = new DropParam();
param.setDatabaseName(dialectProperties.getDatabaseName()); param.setDatabaseName(dialectProperties.getDatabaseName());
param.setTableSchema(""); param.setSchema("");
param.setTableName("employee_details"); param.setName("employee_details");
ActionResult result = tableService.drop(param); ActionResult result = tableService.drop(param);
Assertions.assertTrue(result.success(), result.errorMessage()); Assertions.assertTrue(result.success(), result.errorMessage());
} else if (Objects.equals(dialectProperties.getDbType(), "ORACLE")) { } else if (Objects.equals(dialectProperties.getDbType(), "ORACLE")) {
DropParam param = new DropParam(); DropParam param = new DropParam();
param.setDatabaseName(dialectProperties.getDatabaseName()); param.setDatabaseName(dialectProperties.getDatabaseName());
param.setTableSchema("TEST_USER"); param.setSchema("TEST_USER");
param.setTableName("TEST_USER.DEMO"); param.setName("TEST_USER.DEMO");
ActionResult result = tableService.drop(param); ActionResult result = tableService.drop(param);
Assertions.assertTrue(result.success(), result.errorMessage()); Assertions.assertTrue(result.success(), result.errorMessage());
} else if (Objects.equals(dialectProperties.getDbType(), "MARIADB")) { } else if (Objects.equals(dialectProperties.getDbType(), "MARIADB")) {
DropParam param = new DropParam(); DropParam param = new DropParam();
param.setDatabaseName(dialectProperties.getDatabaseName()); param.setDatabaseName(dialectProperties.getDatabaseName());
param.setTableSchema(""); param.setSchema("");
param.setTableName("test_data"); param.setName("test_data");
ActionResult result = tableService.drop(param); ActionResult result = tableService.drop(param);
Assertions.assertTrue(result.success(), result.errorMessage()); Assertions.assertTrue(result.success(), result.errorMessage());
} else if (Objects.equals(dialectProperties.getDbType(), "POSTGRESQL")) { } else if (Objects.equals(dialectProperties.getDbType(), "POSTGRESQL")) {
DropParam param = new DropParam(); DropParam param = new DropParam();
param.setDatabaseName(dialectProperties.getDatabaseName()); param.setDatabaseName(dialectProperties.getDatabaseName());
param.setTableSchema("test"); param.setSchema("test");
param.setTableName("test.categories_2"); param.setName("test.categories_2");
ActionResult result = tableService.drop(param); ActionResult result = tableService.drop(param);
Assertions.assertTrue(result.success(), result.errorMessage()); Assertions.assertTrue(result.success(), result.errorMessage());

View File

@ -182,7 +182,7 @@ public class TableOperationsTest extends BaseTest {
DropParam dropParam = DropParam.builder() DropParam dropParam = DropParam.builder()
.dataSourceId(dataSourceId) .dataSourceId(dataSourceId)
.databaseName(dialectProperties.getDatabaseName()) .databaseName(dialectProperties.getDatabaseName())
.tableName(dialectProperties.toCase(TABLE_NAME)) .name(dialectProperties.toCase(TABLE_NAME))
.build(); .build();
tableService.drop(dropParam); tableService.drop(dropParam);
// Query table structure // Query table structure
@ -389,7 +389,7 @@ public class TableOperationsTest extends BaseTest {
DropParam dropParam = DropParam.builder() DropParam dropParam = DropParam.builder()
.dataSourceId(dataSourceId) .dataSourceId(dataSourceId)
.databaseName(dialectProperties.getDatabaseName()) .databaseName(dialectProperties.getDatabaseName())
.tableName(dialectProperties.toCase(tableName)) .name(dialectProperties.toCase(tableName))
.build(); .build();
tableService.drop(dropParam); tableService.drop(dropParam);
// Query table structure // Query table structure

View File

@ -54,5 +54,13 @@ public class SymbolConstant {
* colon ":" * colon ":"
*/ */
public static final String COLON = ":"; public static final String COLON = ":";
/**
* blank line "\n\n"
*/
public static final String BLANK_LINE = "\n\n";
/**
* new line "\n"
*/
public static final String NEW_LINE = "\n";
} }

View File

@ -1,16 +1,18 @@
package ai.chat2db.server.web.api.controller.rdb; package ai.chat2db.server.web.api.controller.rdb;
import ai.chat2db.server.domain.api.param.DropParam;
import ai.chat2db.server.domain.api.param.SequencePageQueryParam; import ai.chat2db.server.domain.api.param.SequencePageQueryParam;
import ai.chat2db.server.domain.api.param.ShowCreateSequenceParam; import ai.chat2db.server.domain.api.param.ShowCreateSequenceParam;
import ai.chat2db.server.domain.api.service.DatabaseService;
import ai.chat2db.server.domain.api.service.SequenceService; import ai.chat2db.server.domain.api.service.SequenceService;
import ai.chat2db.server.tools.base.wrapper.result.ActionResult;
import ai.chat2db.server.tools.base.wrapper.result.DataResult; import ai.chat2db.server.tools.base.wrapper.result.DataResult;
import ai.chat2db.server.tools.base.wrapper.result.ListResult; import ai.chat2db.server.tools.base.wrapper.result.ListResult;
import ai.chat2db.server.web.api.aspect.ConnectionInfoAspect; import ai.chat2db.server.web.api.aspect.ConnectionInfoAspect;
import ai.chat2db.server.web.api.controller.rdb.converter.RdbWebConverter; import ai.chat2db.server.web.api.controller.rdb.converter.RdbWebConverter;
import ai.chat2db.server.web.api.controller.rdb.request.DdlExportRequest; import ai.chat2db.server.web.api.controller.rdb.request.DdlExportRequest;
import ai.chat2db.server.web.api.controller.rdb.request.SequenceBriefQueryRequest; import ai.chat2db.server.web.api.controller.rdb.request.SequenceBriefQueryRequest;
import ai.chat2db.server.web.api.controller.rdb.request.SequenceDeleteRequest;
import ai.chat2db.server.web.api.controller.rdb.request.SequenceModifySqlRequest; import ai.chat2db.server.web.api.controller.rdb.request.SequenceModifySqlRequest;
import ai.chat2db.server.web.api.controller.rdb.vo.SqlVO; import ai.chat2db.server.web.api.controller.rdb.vo.SqlVO;
import ai.chat2db.spi.model.*; import ai.chat2db.spi.model.*;
@ -31,7 +33,6 @@ import org.springframework.web.bind.annotation.*;
@RequestMapping("/api/rdb/sequence") @RequestMapping("/api/rdb/sequence")
public class SequenceController { public class SequenceController {
private final RdbWebConverter rdbWebConverter; private final RdbWebConverter rdbWebConverter;
private final DatabaseService databaseService;
private final SequenceService sequenceService; private final SequenceService sequenceService;
/** /**
@ -70,4 +71,16 @@ public class SequenceController {
return sequenceService.buildSql(rdbWebConverter.sequenceRequest2param(request.getOldSequence()), sequence) return sequenceService.buildSql(rdbWebConverter.sequenceRequest2param(request.getOldSequence()), sequence)
.map(rdbWebConverter::dto2vo); .map(rdbWebConverter::dto2vo);
} }
/**
* Delete sequence
*
* @param request
* @return
*/
@PostMapping("/delete")
public ActionResult delete(@Valid @RequestBody SequenceDeleteRequest request){
DropParam dropParam = rdbWebConverter.sequenceDelete2dropParam(request);
return sequenceService.drop(dropParam);
}
} }

View File

@ -149,8 +149,24 @@ public abstract class RdbWebConverter {
* @param request * @param request
* @return * @return
*/ */
@Mappings({
@Mapping(source = "tableName", target = "name"),
@Mapping(source = "schemaName", target = "schema")
})
public abstract DropParam tableDelete2dropParam(TableDeleteRequest request); public abstract DropParam tableDelete2dropParam(TableDeleteRequest request);
/**
* Parameter conversion
*
* @param request
* @return
*/
@Mappings({
@Mapping(source = "sequenceName", target = "name"),
@Mapping(source = "schemaName", target = "schema")
})
public abstract DropParam sequenceDelete2dropParam(SequenceDeleteRequest request);
/** /**
* Model conversion * Model conversion

View File

@ -0,0 +1,20 @@
package ai.chat2db.server.web.api.controller.rdb.request;
import ai.chat2db.server.web.api.controller.data.source.request.DataSourceBaseRequest;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
/**
* Delete sequence sql request
*
* @author Sylphy
*/
@Data
public class SequenceDeleteRequest extends DataSourceBaseRequest {
/**
* Sequence Name
*/
@NotNull
private String sequenceName;
}

View File

@ -84,6 +84,15 @@ public interface DBManage {
*/ */
void dropTable(Connection connection, @NotEmpty String databaseName, String schemaName, @NotEmpty String tableName); void dropTable(Connection connection, @NotEmpty String databaseName, String schemaName, @NotEmpty String tableName);
/**
* Delete sequence structure
*
* @param databaseName
* @param sequenceName
* @return
*/
void dropSequence(Connection connection, @NotEmpty String databaseName, String schemaName, @NotEmpty String sequenceName);
/** /**
* delete function * delete function
* *

View File

@ -13,6 +13,7 @@ import ai.chat2db.spi.sql.SQLExecutor;
import ai.chat2db.spi.ssh.SSHManager; import ai.chat2db.spi.ssh.SSHManager;
import ai.chat2db.spi.util.ResultSetUtils; import ai.chat2db.spi.util.ResultSetUtils;
import com.jcraft.jsch.Session; import com.jcraft.jsch.Session;
import jakarta.validation.constraints.NotEmpty;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.sql.Connection; import java.sql.Connection;
@ -21,6 +22,8 @@ import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static ai.chat2db.server.tools.base.constant.SymbolConstant.DOT;
/** /**
* @author jipengfei * @author jipengfei
* @version : DefaultDBManage.java * @version : DefaultDBManage.java
@ -213,6 +216,12 @@ public class DefaultDBManage implements DBManage {
SQLExecutor.getInstance().execute(connection, sql, resultSet -> null); SQLExecutor.getInstance().execute(connection, sql, resultSet -> null);
} }
@Override
public void dropSequence(Connection connection, @NotEmpty String databaseName, String schemaName, @NotEmpty String sequenceName){
String sql = "DROP SEQUENCE " + schemaName + DOT + sequenceName;
SQLExecutor.getInstance().execute(connection, sql, resultSet -> null);
}
public void exportTableData(Connection connection, String databaseName, String schemaName, String tableName, AsyncContext asyncContext) { public void exportTableData(Connection connection, String databaseName, String schemaName, String tableName, AsyncContext asyncContext) {
SqlBuilder sqlBuilder = Chat2DBContext.getSqlBuilder(); SqlBuilder sqlBuilder = Chat2DBContext.getSqlBuilder();
String tableQuerySql = sqlBuilder.buildTableQuerySql(databaseName, schemaName, tableName); String tableQuerySql = sqlBuilder.buildTableQuerySql(databaseName, schemaName, tableName);