diff --git a/api/src/main/java/com/databasir/api/DocumentController.java b/api/src/main/java/com/databasir/api/DocumentController.java index 288432a..7a1b409 100644 --- a/api/src/main/java/com/databasir/api/DocumentController.java +++ b/api/src/main/java/com/databasir/api/DocumentController.java @@ -5,6 +5,7 @@ import com.databasir.common.SystemException; import com.databasir.core.domain.document.data.DatabaseDocumentResponse; import com.databasir.core.domain.document.data.DatabaseDocumentSimpleResponse; import com.databasir.core.domain.document.data.DatabaseDocumentVersionResponse; +import com.databasir.core.domain.document.data.TableDocumentResponse; import com.databasir.core.domain.document.service.DocumentService; import com.databasir.core.domain.log.annotation.Operation; import lombok.RequiredArgsConstructor; @@ -89,7 +90,7 @@ public class DocumentController { } @PostMapping(Routes.Document.GET_TABLE_DETAIL) - public JsonData> getTableDocument( + public JsonData> getTableDocument( @PathVariable Integer projectId, @PathVariable Integer documentId, @RequestBody List tableIds) { diff --git a/core/src/main/java/com/databasir/core/domain/document/converter/DocumentPojoConverter.java b/core/src/main/java/com/databasir/core/domain/document/converter/DocumentPojoConverter.java index 5b3de08..435cb20 100644 --- a/core/src/main/java/com/databasir/core/domain/document/converter/DocumentPojoConverter.java +++ b/core/src/main/java/com/databasir/core/domain/document/converter/DocumentPojoConverter.java @@ -2,6 +2,7 @@ package com.databasir.core.domain.document.converter; import com.databasir.core.infrastructure.converter.JsonConverter; import com.databasir.core.meta.data.ColumnMeta; +import com.databasir.core.meta.data.ForeignKeyMeta; import com.databasir.core.meta.data.IndexMeta; import com.databasir.core.meta.data.TriggerMeta; import com.databasir.dao.tables.pojos.*; @@ -66,4 +67,19 @@ public interface DocumentPojoConverter extends BaseConverter { Integer tableDocumentId, TriggerMeta meta); + + default List toForeignKeyPojo(Integer docId, + Integer tableMetaId, + List foreignKeys) { + return foreignKeys.stream() + .map(key -> toForeignKeyPojo(docId, tableMetaId, key)) + .collect(Collectors.toList()); + } + + @Mapping(target = "id", ignore = true) + @Mapping(target = "createAt", ignore = true) + TableForeignKeyDocumentPojo toForeignKeyPojo(Integer databaseDocumentId, + Integer tableDocumentId, + ForeignKeyMeta foreignKey); + } diff --git a/core/src/main/java/com/databasir/core/domain/document/converter/DocumentResponseConverter.java b/core/src/main/java/com/databasir/core/domain/document/converter/DocumentResponseConverter.java index f0f3557..1e81575 100644 --- a/core/src/main/java/com/databasir/core/domain/document/converter/DocumentResponseConverter.java +++ b/core/src/main/java/com/databasir/core/domain/document/converter/DocumentResponseConverter.java @@ -1,6 +1,7 @@ package com.databasir.core.domain.document.converter; import com.databasir.core.domain.document.data.DatabaseDocumentResponse; +import com.databasir.core.domain.document.data.TableDocumentResponse; import com.databasir.core.infrastructure.converter.JsonConverter; import com.databasir.dao.tables.pojos.*; import org.mapstruct.Mapper; @@ -16,28 +17,32 @@ public interface DocumentResponseConverter { @Mapping(target = "columns", source = "columns") @Mapping(target = "indexes", source = "indexes") + @Mapping(target = "foreignKeys", source = "foreignKeys") @Mapping(target = "triggers", source = "triggers") - DatabaseDocumentResponse.TableDocumentResponse of(TableDocumentPojo tableDocument, - List columns, - List indexes, - List triggers); + TableDocumentResponse of(TableDocumentPojo tableDocument, + List columns, + List indexes, + List foreignKeys, + List triggers); @Mapping(target = "columns", source = "columns") @Mapping(target = "indexes", source = "indexes") + @Mapping(target = "foreignKeys", source = "foreignKeys") @Mapping(target = "triggers", source = "triggers") @SuppressWarnings("checkstyle:all") - DatabaseDocumentResponse.TableDocumentResponse of(TableDocumentPojo tableDocument, - Integer discussionCount, - String description, - List columns, - List indexes, - List triggers); + TableDocumentResponse of(TableDocumentPojo tableDocument, + Integer discussionCount, + String description, + List columns, + List indexes, + List foreignKeys, + List triggers); - DatabaseDocumentResponse.TableDocumentResponse.ColumnDocumentResponse of(TableColumnDocumentPojo pojo, - Integer discussionCount, - String description); + TableDocumentResponse.ColumnDocumentResponse of(TableColumnDocumentPojo pojo, + Integer discussionCount, + String description); - default List of( + default List of( List columns, String tableName, Map discussionCountMapByJoinName, @@ -52,11 +57,11 @@ public interface DocumentResponseConverter { } @Mapping(target = "columnNames", source = "columnNameArray") - DatabaseDocumentResponse.TableDocumentResponse.IndexDocumentResponse of(TableIndexDocumentPojo indexDocument); + TableDocumentResponse.IndexDocumentResponse of(TableIndexDocumentPojo indexDocument); @Mapping(target = "id", source = "databaseDocument.id") @Mapping(target = "createAt", source = "databaseDocument.createAt") @Mapping(target = "documentVersion", source = "databaseDocument.version") DatabaseDocumentResponse of(DatabaseDocumentPojo databaseDocument, - List tables); + List tables); } diff --git a/core/src/main/java/com/databasir/core/domain/document/data/DatabaseDocumentResponse.java b/core/src/main/java/com/databasir/core/domain/document/data/DatabaseDocumentResponse.java index e3cebe0..ddd42c6 100644 --- a/core/src/main/java/com/databasir/core/domain/document/data/DatabaseDocumentResponse.java +++ b/core/src/main/java/com/databasir/core/domain/document/data/DatabaseDocumentResponse.java @@ -32,104 +32,4 @@ public class DatabaseDocumentResponse { private LocalDateTime createAt; - @Data - @NoArgsConstructor - @AllArgsConstructor - @Builder - public static class TableDocumentResponse { - - private Integer id; - - private String name; - - private String type; - - private String comment; - - private Integer discussionCount; - - private String description; - - @Builder.Default - private List columns = new ArrayList<>(); - - @Builder.Default - private List indexes = new ArrayList<>(); - - @Builder.Default - private List triggers = new ArrayList<>(); - - private LocalDateTime createAt; - - @Data - @NoArgsConstructor - @AllArgsConstructor - @Builder - public static class ColumnDocumentResponse { - private Integer id; - - private String name; - - private String type; - - private Integer size; - - private Integer decimalDigits; - - private String comment; - - private String description; - - private Boolean isPrimaryKey; - - private String nullable; - - private String autoIncrement; - - private String defaultValue; - - private Integer discussionCount; - - private LocalDateTime createAt; - } - - @Data - @NoArgsConstructor - @AllArgsConstructor - @Builder - public static class IndexDocumentResponse { - - private Integer id; - - private String name; - - private Boolean isUnique; - - @Builder.Default - private List columnNames = new ArrayList<>(); - - private LocalDateTime createAt; - } - - @Data - @NoArgsConstructor - @AllArgsConstructor - @Builder - public static class TriggerDocumentResponse { - - private Integer id; - - private String name; - - private String timing; - - private String manipulation; - - private String statement; - - private String triggerCreateAt; - - private LocalDateTime createAt; - } - } } diff --git a/core/src/main/java/com/databasir/core/domain/document/data/TableDocumentResponse.java b/core/src/main/java/com/databasir/core/domain/document/data/TableDocumentResponse.java new file mode 100644 index 0000000..ab7db5b --- /dev/null +++ b/core/src/main/java/com/databasir/core/domain/document/data/TableDocumentResponse.java @@ -0,0 +1,141 @@ +package com.databasir.core.domain.document.data; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class TableDocumentResponse { + + private Integer id; + + private String name; + + private String type; + + private String comment; + + private Integer discussionCount; + + private String description; + + @Builder.Default + private List columns = new ArrayList<>(); + + @Builder.Default + private List indexes = new ArrayList<>(); + + @Builder.Default + private List foreignKeys = new ArrayList<>(); + + @Builder.Default + private List triggers = new ArrayList<>(); + + private LocalDateTime createAt; + + @Data + @NoArgsConstructor + @AllArgsConstructor + @Builder + public static class ColumnDocumentResponse { + private Integer id; + + private String name; + + private String type; + + private Integer size; + + private Integer decimalDigits; + + private String comment; + + private String description; + + private Boolean isPrimaryKey; + + private String nullable; + + private String autoIncrement; + + private String defaultValue; + + private Integer discussionCount; + + private LocalDateTime createAt; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + @Builder + public static class IndexDocumentResponse { + + private Integer id; + + private String name; + + private Boolean isUnique; + + @Builder.Default + private List columnNames = new ArrayList<>(); + + private LocalDateTime createAt; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + @Builder + public static class ForeignKeyDocumentResponse { + + private Integer id; + + private String fkName; + + private String fkTableName; + + private String fkColumnName; + + private String pkName; + + private String pkTableName; + + private String pkColumnName; + + private String updateRule; + + private String deleteRule; + + private LocalDateTime createAt; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + @Builder + public static class TriggerDocumentResponse { + + private Integer id; + + private String name; + + private String timing; + + private String manipulation; + + private String statement; + + private String triggerCreateAt; + + private LocalDateTime createAt; + } +} \ No newline at end of file diff --git a/core/src/main/java/com/databasir/core/domain/document/service/DocumentService.java b/core/src/main/java/com/databasir/core/domain/document/service/DocumentService.java index 3743db0..e0336fb 100644 --- a/core/src/main/java/com/databasir/core/domain/document/service/DocumentService.java +++ b/core/src/main/java/com/databasir/core/domain/document/service/DocumentService.java @@ -9,6 +9,7 @@ import com.databasir.core.domain.document.converter.DocumentSimpleResponseConver import com.databasir.core.domain.document.data.DatabaseDocumentResponse; import com.databasir.core.domain.document.data.DatabaseDocumentSimpleResponse; import com.databasir.core.domain.document.data.DatabaseDocumentVersionResponse; +import com.databasir.core.domain.document.data.TableDocumentResponse; import com.databasir.core.infrastructure.connection.DatabaseConnectionService; import com.databasir.core.infrastructure.converter.JsonConverter; import com.databasir.core.meta.data.DatabaseMeta; @@ -57,6 +58,8 @@ public class DocumentService { private final TableTriggerDocumentDao tableTriggerDocumentDao; + private final TableForeignKeyDocumentDao tableForeignKeyDocumentDao; + private final DocumentDiscussionDao documentDiscussionDao; private final DocumentDescriptionDao documentDescriptionDao; @@ -109,26 +112,29 @@ public class DocumentService { TableDocumentPojo tableMeta = documentPojoConverter.toTablePojo(docId, table); Integer tableMetaId = tableDocumentDao.insertAndReturnId(tableMeta); - List tableColumnMetas = - documentPojoConverter.toColumnPojo(docId, tableMetaId, table.getColumns()); - tableColumnDocumentDao.batchInsert(tableColumnMetas); - List tableIndexMetas = - documentPojoConverter.toIndexPojo(docId, tableMetaId, table.getIndexes()) - .stream() - .filter(index -> { - if (index.getName() != null) { - return true; - } else { - log.warn("ignore table {} index {}, cause name is null", table.getName(), index); - return false; - } - }) - .collect(Collectors.toList()); + // column + var columns = documentPojoConverter.toColumnPojo(docId, tableMetaId, table.getColumns()); + tableColumnDocumentDao.batchInsert(columns); + // index + var indexes = documentPojoConverter.toIndexPojo(docId, tableMetaId, table.getIndexes()) + .stream() + .filter(index -> { + if (index.getName() != null) { + return true; + } else { + log.warn("ignore table {} index {}, cause name is null", table.getName(), index); + return false; + } + }) + .collect(Collectors.toList()); + tableIndexDocumentDao.batchInsert(indexes); + // foreign key + var foreignKeys = documentPojoConverter.toForeignKeyPojo(docId, tableMetaId, table.getForeignKeys()); + tableForeignKeyDocumentDao.batchInsert(foreignKeys); - tableIndexDocumentDao.batchInsert(tableIndexMetas); - List tableTriggerMetas = - documentPojoConverter.toTriggerPojo(docId, tableMetaId, table.getTriggers()); - tableTriggerDocumentDao.batchInsert(tableTriggerMetas); + // trigger + var triggers = documentPojoConverter.toTriggerPojo(docId, tableMetaId, table.getTriggers()); + tableTriggerDocumentDao.batchInsert(triggers); }); log.info("save new version document success: projectId = {}, name = {}, version = {}", projectId, meta.getDatabaseName(), version); @@ -175,19 +181,29 @@ public class DocumentService { var columns = tableColumnDocumentDao.selectByDatabaseDocumentId(id); var indexes = tableIndexDocumentDao.selectByDatabaseMetaId(id); var triggers = tableTriggerDocumentDao.selectByDatabaseDocumentId(id); + var foreignKeys = tableForeignKeyDocumentDao.selectByDatabaseDocumentId(id); Map> columnsGroupByTableMetaId = columns.stream() .collect(Collectors.groupingBy(TableColumnDocumentPojo::getTableDocumentId)); Map> indexesGroupByTableMetaId = indexes.stream() .collect(Collectors.groupingBy(TableIndexDocumentPojo::getTableDocumentId)); Map> triggersGroupByTableMetaId = triggers.stream() .collect(Collectors.groupingBy(TableTriggerDocumentPojo::getTableDocumentId)); + Map> foreignKeysGroupByTableMetaId = foreignKeys.stream() + .collect(Collectors.groupingBy(TableForeignKeyDocumentPojo::getTableDocumentId)); var tableDocumentResponseList = tables.stream() .map(table -> { Integer tableId = table.getId(); var subColumns = columnsGroupByTableMetaId.getOrDefault(tableId, Collections.emptyList()); var subIndexes = indexesGroupByTableMetaId.getOrDefault(tableId, Collections.emptyList()); var subTriggers = triggersGroupByTableMetaId.getOrDefault(tableId, Collections.emptyList()); - return documentResponseConverter.of(table, subColumns, subIndexes, subTriggers); + var subForeignKeys = foreignKeysGroupByTableMetaId.getOrDefault(tableId, Collections.emptyList()); + return documentResponseConverter.of( + table, + subColumns, + subIndexes, + subForeignKeys, + subTriggers + ); }) .collect(Collectors.toList()); return documentResponseConverter.of(document, tableDocumentResponseList); @@ -207,9 +223,9 @@ public class DocumentService { .orElseGet(Page::empty); } - public List getTableDetails(Integer projectId, - Integer databaseDocumentId, - List tableIds) { + public List getTableDetails(Integer projectId, + Integer databaseDocumentId, + List tableIds) { // maybe deleted if (CollectionUtils.isEmpty(tableIds) || !projectDao.existsById(projectId)) { return Collections.emptyList(); @@ -228,6 +244,12 @@ public class DocumentService { Map> indexesGroupByTableMetaId = indexes.stream() .collect(Collectors.groupingBy(TableIndexDocumentPojo::getTableDocumentId)); + // foreign keys + var foreignKeys = + tableForeignKeyDocumentDao.selectByDatabaseDocumentIdAndTableIdIn(databaseDocumentId, tableIds); + Map> foreignKeysGroupByTableMetaId = foreignKeys.stream() + .collect(Collectors.groupingBy(TableForeignKeyDocumentPojo::getTableDocumentId)); + // trigger var triggers = tableTriggerDocumentDao.selectByDatabaseDocumentIdAndIdIn(databaseDocumentId, tableIds); @@ -259,18 +281,24 @@ public class DocumentService { Integer tableId = table.getId(); var subColumns = columnsGroupByTableMetaId.getOrDefault(tableId, Collections.emptyList()); var subIndexes = indexesGroupByTableMetaId.getOrDefault(tableId, Collections.emptyList()); + var subForeignKeys = foreignKeysGroupByTableMetaId.getOrDefault(tableId, Collections.emptyList()); var subTriggers = triggersGroupByTableMetaId.getOrDefault(tableId, Collections.emptyList()); var discussionCount = discussionCountMapByJoinName.get(table.getName()); var description = descriptionMapByJoinName.get(table.getName()); - var columnResponses = - documentResponseConverter.of( - subColumns, - table.getName(), - discussionCountMapByJoinName, - descriptionMapByJoinName); - return documentResponseConverter.of(table, discussionCount, description, columnResponses, + var columnResponses = documentResponseConverter.of( + subColumns, + table.getName(), + discussionCountMapByJoinName, + descriptionMapByJoinName); + return documentResponseConverter.of( + table, + discussionCount, + description, + columnResponses, subIndexes, - subTriggers); + subForeignKeys, + subTriggers + ); }) .collect(Collectors.toList()); } @@ -284,13 +312,13 @@ public class DocumentService { builder.secondTitle("overview"); List> overviewContent = new ArrayList<>(); for (int i = 0; i < doc.getTables().size(); i++) { - DatabaseDocumentResponse.TableDocumentResponse table = doc.getTables().get(i); + TableDocumentResponse table = doc.getTables().get(i); overviewContent.add(List.of((i + 1) + "", table.getName(), table.getType(), table.getComment())); } builder.table(List.of("", "表名", "类型", "备注"), overviewContent); - Function + Function columnDefaultValueMapping = column -> { if (Objects.equals(column.getNullable(), "YES")) { return Objects.requireNonNullElse(column.getDefaultValue(), "null"); diff --git a/dao/src/main/java/com/databasir/dao/impl/TableForeignKeyDocumentDao.java b/dao/src/main/java/com/databasir/dao/impl/TableForeignKeyDocumentDao.java new file mode 100644 index 0000000..330f571 --- /dev/null +++ b/dao/src/main/java/com/databasir/dao/impl/TableForeignKeyDocumentDao.java @@ -0,0 +1,43 @@ +package com.databasir.dao.impl; + +import com.databasir.dao.tables.pojos.TableForeignKeyDocumentPojo; +import lombok.Getter; +import org.jooq.DSLContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +import java.util.Collections; +import java.util.List; + +import static com.databasir.dao.Tables.TABLE_FOREIGN_KEY_DOCUMENT; + +@Repository +public class TableForeignKeyDocumentDao extends BaseDao { + + @Autowired + @Getter + private DSLContext dslContext; + + public TableForeignKeyDocumentDao() { + super(TABLE_FOREIGN_KEY_DOCUMENT, TableForeignKeyDocumentPojo.class); + } + + public List selectByDatabaseDocumentId(Integer databaseDocumentId) { + return getDslContext() + .selectFrom(TABLE_FOREIGN_KEY_DOCUMENT) + .where(TABLE_FOREIGN_KEY_DOCUMENT.DATABASE_DOCUMENT_ID.eq(databaseDocumentId)) + .fetchInto(TableForeignKeyDocumentPojo.class); + } + + public List selectByDatabaseDocumentIdAndTableIdIn(Integer databaseDocumentId, + List tableIdIn) { + if (tableIdIn == null || tableIdIn.isEmpty()) { + return Collections.emptyList(); + } + return getDslContext() + .selectFrom(TABLE_FOREIGN_KEY_DOCUMENT) + .where(TABLE_FOREIGN_KEY_DOCUMENT.DATABASE_DOCUMENT_ID.eq(databaseDocumentId) + .and(TABLE_FOREIGN_KEY_DOCUMENT.TABLE_DOCUMENT_ID.in(tableIdIn))) + .fetchInto(TableForeignKeyDocumentPojo.class); + } +}