feat: support foreign keys

This commit is contained in:
vran 2022-03-15 10:42:50 +08:00
parent 866c55bac7
commit cceb9e7109
7 changed files with 284 additions and 150 deletions

View File

@ -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<List<DatabaseDocumentResponse.TableDocumentResponse>> getTableDocument(
public JsonData<List<TableDocumentResponse>> getTableDocument(
@PathVariable Integer projectId,
@PathVariable Integer documentId,
@RequestBody List<Integer> tableIds) {

View File

@ -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<TableForeignKeyDocumentPojo> toForeignKeyPojo(Integer docId,
Integer tableMetaId,
List<ForeignKeyMeta> 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);
}

View File

@ -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,
TableDocumentResponse of(TableDocumentPojo tableDocument,
List<TableColumnDocumentPojo> columns,
List<TableIndexDocumentPojo> indexes,
List<TableForeignKeyDocumentPojo> foreignKeys,
List<TableTriggerDocumentPojo> 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,
TableDocumentResponse of(TableDocumentPojo tableDocument,
Integer discussionCount,
String description,
List<DatabaseDocumentResponse.TableDocumentResponse.ColumnDocumentResponse> columns,
List<TableDocumentResponse.ColumnDocumentResponse> columns,
List<TableIndexDocumentPojo> indexes,
List<TableForeignKeyDocumentPojo> foreignKeys,
List<TableTriggerDocumentPojo> triggers);
DatabaseDocumentResponse.TableDocumentResponse.ColumnDocumentResponse of(TableColumnDocumentPojo pojo,
TableDocumentResponse.ColumnDocumentResponse of(TableColumnDocumentPojo pojo,
Integer discussionCount,
String description);
default List<DatabaseDocumentResponse.TableDocumentResponse.ColumnDocumentResponse> of(
default List<TableDocumentResponse.ColumnDocumentResponse> of(
List<TableColumnDocumentPojo> columns,
String tableName,
Map<String, Integer> 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<DatabaseDocumentResponse.TableDocumentResponse> tables);
List<TableDocumentResponse> tables);
}

View File

@ -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<ColumnDocumentResponse> columns = new ArrayList<>();
@Builder.Default
private List<IndexDocumentResponse> indexes = new ArrayList<>();
@Builder.Default
private List<TriggerDocumentResponse> 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<String> 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;
}
}
}

View File

@ -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<ColumnDocumentResponse> columns = new ArrayList<>();
@Builder.Default
private List<IndexDocumentResponse> indexes = new ArrayList<>();
@Builder.Default
private List<ForeignKeyDocumentResponse> foreignKeys = new ArrayList<>();
@Builder.Default
private List<TriggerDocumentResponse> 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<String> 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;
}
}

View File

@ -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,11 +112,11 @@ public class DocumentService {
TableDocumentPojo tableMeta =
documentPojoConverter.toTablePojo(docId, table);
Integer tableMetaId = tableDocumentDao.insertAndReturnId(tableMeta);
List<TableColumnDocumentPojo> tableColumnMetas =
documentPojoConverter.toColumnPojo(docId, tableMetaId, table.getColumns());
tableColumnDocumentDao.batchInsert(tableColumnMetas);
List<TableIndexDocumentPojo> tableIndexMetas =
documentPojoConverter.toIndexPojo(docId, tableMetaId, table.getIndexes())
// 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) {
@ -124,11 +127,14 @@ public class DocumentService {
}
})
.collect(Collectors.toList());
tableIndexDocumentDao.batchInsert(indexes);
// foreign key
var foreignKeys = documentPojoConverter.toForeignKeyPojo(docId, tableMetaId, table.getForeignKeys());
tableForeignKeyDocumentDao.batchInsert(foreignKeys);
tableIndexDocumentDao.batchInsert(tableIndexMetas);
List<TableTriggerDocumentPojo> 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<Integer, List<TableColumnDocumentPojo>> columnsGroupByTableMetaId = columns.stream()
.collect(Collectors.groupingBy(TableColumnDocumentPojo::getTableDocumentId));
Map<Integer, List<TableIndexDocumentPojo>> indexesGroupByTableMetaId = indexes.stream()
.collect(Collectors.groupingBy(TableIndexDocumentPojo::getTableDocumentId));
Map<Integer, List<TableTriggerDocumentPojo>> triggersGroupByTableMetaId = triggers.stream()
.collect(Collectors.groupingBy(TableTriggerDocumentPojo::getTableDocumentId));
Map<Integer, List<TableForeignKeyDocumentPojo>> 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,7 +223,7 @@ public class DocumentService {
.orElseGet(Page::empty);
}
public List<DatabaseDocumentResponse.TableDocumentResponse> getTableDetails(Integer projectId,
public List<TableDocumentResponse> getTableDetails(Integer projectId,
Integer databaseDocumentId,
List<Integer> tableIds) {
// maybe deleted
@ -228,6 +244,12 @@ public class DocumentService {
Map<Integer, List<TableIndexDocumentPojo>> indexesGroupByTableMetaId = indexes.stream()
.collect(Collectors.groupingBy(TableIndexDocumentPojo::getTableDocumentId));
// foreign keys
var foreignKeys =
tableForeignKeyDocumentDao.selectByDatabaseDocumentIdAndTableIdIn(databaseDocumentId, tableIds);
Map<Integer, List<TableForeignKeyDocumentPojo>> 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(
var columnResponses = documentResponseConverter.of(
subColumns,
table.getName(),
discussionCountMapByJoinName,
descriptionMapByJoinName);
return documentResponseConverter.of(table, discussionCount, description, columnResponses,
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<List<String>> 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<DatabaseDocumentResponse.TableDocumentResponse.ColumnDocumentResponse, String>
Function<TableDocumentResponse.ColumnDocumentResponse, String>
columnDefaultValueMapping = column -> {
if (Objects.equals(column.getNullable(), "YES")) {
return Objects.requireNonNullElse(column.getDefaultValue(), "null");

View File

@ -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<TableForeignKeyDocumentPojo> {
@Autowired
@Getter
private DSLContext dslContext;
public TableForeignKeyDocumentDao() {
super(TABLE_FOREIGN_KEY_DOCUMENT, TableForeignKeyDocumentPojo.class);
}
public List<TableForeignKeyDocumentPojo> 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<TableForeignKeyDocumentPojo> selectByDatabaseDocumentIdAndTableIdIn(Integer databaseDocumentId,
List<Integer> 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);
}
}