Redesign document history model (#39)

* feat: jooq model generate

* refactor: redesign document history model

* fix: checkstyle

* feat: add batch query table api

* fix: checkstyle

* feat: update frontend resources
This commit is contained in:
vran
2022-03-09 23:39:57 +08:00
committed by GitHub
parent 4ee98da074
commit 86d6d8d3aa
96 changed files with 508 additions and 3171 deletions

View File

@@ -1,20 +0,0 @@
package com.databasir.core.domain.document.converter;
import com.databasir.core.domain.document.data.DatabaseDocumentResponse;
import com.databasir.core.infrastructure.converter.JsonConverter;
import com.databasir.dao.tables.pojos.DatabaseDocumentHistoryPojo;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.ReportingPolicy;
@Mapper(componentModel = "spring", uses = JsonConverter.class, unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface DocumentHistoryPojoConverter {
@Mapping(target = "databaseDocumentObject", source = "databaseMetaObject")
@Mapping(target = "id", ignore = true)
@Mapping(target = "createAt", ignore = true)
DatabaseDocumentHistoryPojo of(DatabaseDocumentResponse databaseMetaObject,
Integer projectId,
Integer databaseDocumentId,
Long version);
}

View File

@@ -16,16 +16,11 @@ import java.util.stream.Collectors;
public interface DocumentPojoConverter extends BaseConverter {
@Mapping(target = "databaseName", source = "meta.databaseName")
@Mapping(target = "isArchive", constant = "false")
DatabaseDocumentPojo toDatabasePojo(Integer projectId,
com.databasir.core.meta.data.DatabaseMeta meta,
Long version);
@Mapping(target = "databaseName", source = "meta.databaseName")
DatabaseDocumentPojo toDatabasePojo(Integer projectId,
com.databasir.core.meta.data.DatabaseMeta meta,
Integer id,
Long version);
@Mapping(target = "comment", qualifiedBy = NullToEmpty.class)
TableDocumentPojo toTablePojo(Integer databaseDocumentId,
com.databasir.core.meta.data.TableMeta meta);

View File

@@ -0,0 +1,21 @@
package com.databasir.core.domain.document.converter;
import com.databasir.core.domain.document.data.DatabaseDocumentSimpleResponse;
import com.databasir.core.infrastructure.converter.JsonConverter;
import com.databasir.dao.tables.pojos.DatabaseDocumentPojo;
import com.databasir.dao.tables.pojos.TableDocumentPojo;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.ReportingPolicy;
import java.util.List;
@Mapper(componentModel = "spring", uses = JsonConverter.class, unmappedTargetPolicy = ReportingPolicy.WARN)
public interface DocumentSimpleResponseConverter {
@Mapping(target = "id", source = "databaseDocument.id")
@Mapping(target = "createAt", source = "databaseDocument.createAt")
@Mapping(target = "documentVersion", source = "databaseDocument.version")
DatabaseDocumentSimpleResponse of(DatabaseDocumentPojo databaseDocument,
List<TableDocumentPojo> tables);
}

View File

@@ -0,0 +1,37 @@
package com.databasir.core.domain.document.data;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Data
public class DatabaseDocumentSimpleResponse {
private Integer id;
private String databaseName;
private String productName;
private String productVersion;
private Integer documentVersion;
private List<TableData> tables = new ArrayList<>();
private LocalDateTime createAt;
@Data
public static class TableData {
private Integer id;
private String name;
private String type;
private String comment;
}
}

View File

@@ -13,6 +13,8 @@ import java.time.LocalDateTime;
@Builder
public class DatabaseDocumentVersionResponse {
private Integer databaseDocumentId;
private Long version;
private LocalDateTime createAt;

View File

@@ -3,10 +3,11 @@ package com.databasir.core.domain.document.service;
import com.databasir.core.Databasir;
import com.databasir.core.DatabasirConfig;
import com.databasir.core.domain.DomainErrors;
import com.databasir.core.domain.document.converter.DocumentHistoryPojoConverter;
import com.databasir.core.domain.document.converter.DocumentPojoConverter;
import com.databasir.core.domain.document.converter.DocumentResponseConverter;
import com.databasir.core.domain.document.converter.DocumentSimpleResponseConverter;
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.infrastructure.connection.DatabaseConnectionService;
import com.databasir.core.infrastructure.converter.JsonConverter;
@@ -20,6 +21,7 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.sql.Connection;
import java.util.*;
@@ -53,30 +55,28 @@ public class DocumentService {
private final TableTriggerDocumentDao tableTriggerDocumentDao;
private final DatabaseDocumentHistoryDao databaseDocumentHistoryDao;
private final DocumentPojoConverter documentPojoConverter;
private final DocumentResponseConverter documentResponseConverter;
private final DocumentHistoryPojoConverter documentHistoryPojoConverter;
private final DocumentSimpleResponseConverter documentSimpleResponseConverter;
private final JsonConverter jsonConverter;
@Transactional
public void syncByProjectId(Integer projectId) {
ProjectPojo project = projectDao.selectOptionalById(projectId)
projectDao.selectOptionalById(projectId)
.orElseThrow(DomainErrors.PROJECT_NOT_FOUND::exception);
DatabaseMeta meta = retrieveDatabaseMeta(projectId);
Optional<DatabaseDocumentPojo> historyDocumentOpt = databaseDocumentDao.selectOptionalByProjectId(projectId);
if (historyDocumentOpt.isPresent()) {
DatabaseDocumentPojo historyDocument = historyDocumentOpt.get();
Integer previousDocumentId = historyDocument.getId();
saveAsHistory(historyDocument);
deleteDeprecatedDocument(previousDocumentId);
saveNewDocument(meta, historyDocument.getVersion() + 1, historyDocument.getProjectId(), previousDocumentId);
Optional<DatabaseDocumentPojo> latestDocumentOpt = databaseDocumentDao.selectNotArchivedByProjectId(projectId);
if (latestDocumentOpt.isPresent()) {
DatabaseDocumentPojo latestDocument = latestDocumentOpt.get();
Integer previousDocumentId = latestDocument.getId();
// archive old version
databaseDocumentDao.updateIsArchiveById(previousDocumentId, true);
saveNewDocument(meta, latestDocument.getVersion() + 1, latestDocument.getProjectId());
} else {
saveNewDocument(meta, 1L, projectId, null);
saveNewDocument(meta, 1L, projectId);
}
}
@@ -93,42 +93,12 @@ public class DocumentService {
.orElseThrow(DomainErrors.DATABASE_META_NOT_FOUND::exception);
}
private void saveAsHistory(DatabaseDocumentPojo databaseDocument) {
// save history
Integer projectId = databaseDocument.getProjectId();
Integer databaseMetaId = databaseDocument.getId();
DatabaseDocumentResponse databaseDocumentResponse = getOneByProjectId(projectId, null).orElse(null);
Long currVersion = databaseDocument.getVersion();
DatabaseDocumentHistoryPojo documentHistoryPojo =
documentHistoryPojoConverter.of(databaseDocumentResponse, projectId, databaseMetaId, currVersion);
databaseDocumentHistoryDao.insertAndReturnId(documentHistoryPojo);
log.info("save old meta info to history success");
}
private void deleteDeprecatedDocument(Integer databaseDocumentId) {
// delete old meta info
tableDocumentDao.deleteByDatabaseDocumentId(databaseDocumentId);
tableColumnDocumentDao.deleteByDatabaseDocumentId(databaseDocumentId);
tableIndexDocumentDao.deleteByDatabaseMetaId(databaseDocumentId);
tableTriggerDocumentDao.deleteByDatabaseDocumentId(databaseDocumentId);
log.info("delete old meta info success");
}
private void saveNewDocument(DatabaseMeta meta,
Long version,
Integer projectId,
Integer databaseDocumentId) {
Integer projectId) {
Integer currentDatabaseDocumentId = databaseDocumentId;
if (databaseDocumentId == null) {
var pojo = documentPojoConverter.toDatabasePojo(projectId, meta, 1L);
currentDatabaseDocumentId = databaseDocumentDao.insertAndReturnId(pojo);
} else {
var pojo = documentPojoConverter.toDatabasePojo(projectId, meta, databaseDocumentId, version);
databaseDocumentDao.update(pojo);
}
final Integer docId = currentDatabaseDocumentId;
var pojo = documentPojoConverter.toDatabasePojo(projectId, meta, version);
final Integer docId = databaseDocumentDao.insertAndReturnId(pojo);
meta.getTables().forEach(table -> {
TableDocumentPojo tableMeta =
documentPojoConverter.toTablePojo(docId, table);
@@ -143,55 +113,106 @@ public class DocumentService {
documentPojoConverter.toTriggerPojo(docId, tableMetaId, table.getTriggers());
tableTriggerDocumentDao.batchInsert(tableTriggerMetas);
});
log.info("save new meta info success");
log.info("save new version document success: projectId = {}, name = {}, version = {}",
projectId, meta.getDatabaseName(), version);
}
public Optional<DatabaseDocumentResponse> getOneByProjectId(Integer projectId, Long version) {
public Optional<DatabaseDocumentSimpleResponse> getSimpleOneByProjectId(Integer projectId, Long version) {
if (version == null) {
return databaseDocumentDao.selectOptionalByProjectId(projectId)
return databaseDocumentDao.selectNotArchivedByProjectId(projectId)
.map(document -> {
Integer id = document.getId();
var tables = tableDocumentDao.selectByDatabaseDocumentId(id);
var columns = tableColumnDocumentDao.selectByDatabaseDocumentId(id);
var indexes = tableIndexDocumentDao.selectByDatabaseMetaId(id);
var triggers = tableTriggerDocumentDao.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));
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);
})
.collect(Collectors.toList());
return documentResponseConverter.of(document, tableDocumentResponseList);
return documentSimpleResponseConverter.of(document, tables);
});
} else {
return databaseDocumentHistoryDao.selectOptionalByProjectIdAndVersion(projectId, version)
.map(obj -> jsonConverter.of(obj.getDatabaseDocumentObject()));
return databaseDocumentDao.selectOptionalByProjectIdAndVersion(projectId, version)
.map(document -> {
Integer id = document.getId();
var tables = tableDocumentDao.selectByDatabaseDocumentId(id);
return documentSimpleResponseConverter.of(document, tables);
});
}
}
public Page<DatabaseDocumentVersionResponse> getVersionsBySchemaSourceId(Integer projectId, Pageable page) {
return databaseDocumentDao.selectOptionalByProjectId(projectId)
.map(schemaMeta ->
databaseDocumentHistoryDao.selectVersionPageByDatabaseDocumentId(page, schemaMeta.getId())
public Optional<DatabaseDocumentResponse> getOneByProjectId(Integer projectId, Long version) {
Optional<DatabaseDocumentPojo> documentOption;
if (version == null) {
documentOption = databaseDocumentDao.selectNotArchivedByProjectId(projectId);
} else {
documentOption = databaseDocumentDao.selectOptionalByProjectIdAndVersion(projectId, version);
}
return documentOption.map(document -> {
Integer id = document.getId();
var tables = tableDocumentDao.selectByDatabaseDocumentId(id);
var columns = tableColumnDocumentDao.selectByDatabaseDocumentId(id);
var indexes = tableIndexDocumentDao.selectByDatabaseMetaId(id);
var triggers = tableTriggerDocumentDao.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));
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);
})
.collect(Collectors.toList());
return documentResponseConverter.of(document, tableDocumentResponseList);
});
}
public Page<DatabaseDocumentVersionResponse> getVersionsByProjectId(Integer projectId, Pageable page) {
return databaseDocumentDao.selectNotArchivedByProjectId(projectId)
.map(databaseDocument ->
databaseDocumentDao.selectVersionPageByProjectId(page, projectId)
.map(history -> DatabaseDocumentVersionResponse.builder()
.databaseDocumentId(history.getId())
.version(history.getVersion())
.createAt(history.getCreateAt())
.build()))
.orElseGet(Page::empty);
}
public List<DatabaseDocumentResponse.TableDocumentResponse> getTableDetails(Integer projectId,
Integer databaseDocumentId,
List<Integer> tableIds) {
// maybe deleted
if (CollectionUtils.isEmpty(tableIds) || !projectDao.existsById(projectId)) {
return Collections.emptyList();
}
var tables =
tableDocumentDao.selectByDatabaseDocumentIdAndIdIn(databaseDocumentId, tableIds);
var columns =
tableColumnDocumentDao.selectByDatabaseDocumentIdAndTableIdIn(databaseDocumentId, tableIds);
var indexes =
tableIndexDocumentDao.selectByDatabaseDocumentIdAndIdIn(databaseDocumentId, tableIds);
var triggers =
tableTriggerDocumentDao.selectByDatabaseDocumentIdAndIdIn(databaseDocumentId, tableIds);
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));
return 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);
})
.collect(Collectors.toList());
}
public Optional<String> toMarkdown(Integer projectId, Long version) {
return getOneByProjectId(projectId, version)
.map(doc -> {

View File

@@ -4,11 +4,19 @@ import com.databasir.core.domain.group.data.GroupCreateRequest;
import com.databasir.core.domain.group.data.GroupUpdateRequest;
import com.databasir.dao.tables.pojos.GroupPojo;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
@Mapper(componentModel = "spring")
public interface GroupPojoConverter {
@Mapping(target = "id", ignore = true)
@Mapping(target = "deleted", ignore = true)
@Mapping(target = "createAt", ignore = true)
@Mapping(target = "updateAt", ignore = true)
GroupPojo of(GroupCreateRequest groupCreateRequest);
@Mapping(target = "deleted", ignore = true)
@Mapping(target = "createAt", ignore = true)
@Mapping(target = "updateAt", ignore = true)
GroupPojo of(GroupUpdateRequest groupUpdateRequest);
}