feat: support version diff (#52)

* feat: implementation diff processor

* fix: checkstyle

* feat: ignore sync if without change

* fix: checkstyle

* feat:add databasir diff api

* feat:update frontend resources
This commit is contained in:
vran
2022-03-19 15:01:15 +08:00
committed by GitHub
parent 64df3d028c
commit 747ae14da2
113 changed files with 9668 additions and 274 deletions

View File

@@ -32,6 +32,7 @@ public enum DomainErrors implements DatabasirErrors {
MUST_NOT_MODIFY_SYSTEM_DEFAULT_DATABASE_TYPE("A_10017", "禁止修改系统默认数据库类型"),
DOWNLOAD_DRIVER_ERROR("A_10018", "驱动下载失败"),
INVALID_DATABASE_TYPE_URL_PATTERN("A_10019", "不合法的 url pattern"),
DOCUMENT_VERSION_IS_INVALID("A_10020", "文档版本不合法"),
;
private final String errCode;

View File

@@ -1,9 +0,0 @@
package com.databasir.core.domain.document.converter;
public interface BaseConverter {
@NullToEmpty
default String nullToEmpty(String s) {
return s == null ? "" : s;
}
}

View File

@@ -0,0 +1,71 @@
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.DatabaseMeta;
import com.databasir.core.meta.data.IndexMeta;
import com.databasir.core.meta.data.TableMeta;
import com.databasir.dao.tables.pojos.*;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
@Mapper(componentModel = "spring", uses = JsonConverter.class)
public interface DatabaseMetaConverter {
default DatabaseMeta of(DatabaseDocumentPojo database,
List<TableDocumentPojo> tables,
List<TableColumnDocumentPojo> columns,
List<TableIndexDocumentPojo> indexes,
List<TableTriggerDocumentPojo> triggers,
List<TableForeignKeyDocumentPojo> foreignKeys) {
var columnMap = groupBy(columns, TableColumnDocumentPojo::getTableDocumentId);
var indexMap = groupBy(indexes, TableIndexDocumentPojo::getTableDocumentId);
var triggerMap = groupBy(triggers, TableTriggerDocumentPojo::getTableDocumentId);
var fkMap = groupBy(foreignKeys, TableForeignKeyDocumentPojo::getTableDocumentId);
return of(database, tables, columnMap, indexMap, triggerMap, fkMap);
}
default DatabaseMeta of(DatabaseDocumentPojo database,
List<TableDocumentPojo> tables,
Map<Integer, List<TableColumnDocumentPojo>> columnGroupByTableId,
Map<Integer, List<TableIndexDocumentPojo>> indexGroupByTableId,
Map<Integer, List<TableTriggerDocumentPojo>> triggerGroupByTableId,
Map<Integer, List<TableForeignKeyDocumentPojo>> fkGroupByTableId) {
List<TableMeta> tableMetas = tables.stream()
.map(table -> {
Integer id = table.getId();
var columns = columnGroupByTableId.getOrDefault(id, Collections.emptyList());
var indexes = indexGroupByTableId.getOrDefault(id, Collections.emptyList());
var triggers = triggerGroupByTableId.getOrDefault(id, Collections.emptyList());
var foreignKeys = fkGroupByTableId.getOrDefault(id, Collections.emptyList());
return of(table, columns, indexes, triggers, foreignKeys);
})
.collect(Collectors.toList());
return of(database, tableMetas);
}
DatabaseMeta of(DatabaseDocumentPojo database, List<TableMeta> tables);
TableMeta of(TableDocumentPojo table,
List<TableColumnDocumentPojo> columns,
List<TableIndexDocumentPojo> indexes,
List<TableTriggerDocumentPojo> triggers,
List<TableForeignKeyDocumentPojo> foreignKeys);
ColumnMeta of(TableColumnDocumentPojo pojo);
@Mapping(target = "isUniqueKey", source = "pojo.isUnique")
@Mapping(target = "columnNames", source = "pojo.columnNameArray")
IndexMeta of(TableIndexDocumentPojo pojo);
default <R> Map<Integer, List<R>> groupBy(List<R> content, Function<R, Integer> idMapping) {
return content.stream()
.collect(Collectors.groupingBy(idMapping));
}
}

View File

@@ -14,7 +14,7 @@ import java.util.List;
import java.util.stream.Collectors;
@Mapper(componentModel = "spring", uses = JsonConverter.class, unmappedTargetPolicy = ReportingPolicy.WARN)
public interface DocumentPojoConverter extends BaseConverter {
public interface DocumentPojoConverter {
@Mapping(target = "databaseName", source = "meta.databaseName")
@Mapping(target = "schemaName", source = "meta.schemaName")
@@ -23,7 +23,6 @@ public interface DocumentPojoConverter extends BaseConverter {
com.databasir.core.meta.data.DatabaseMeta meta,
Long version);
@Mapping(target = "comment", qualifiedBy = NullToEmpty.class)
TableDocumentPojo toTablePojo(Integer databaseDocumentId,
com.databasir.core.meta.data.TableMeta meta);
@@ -35,7 +34,6 @@ public interface DocumentPojoConverter extends BaseConverter {
.collect(Collectors.toList());
}
@Mapping(target = "comment", qualifiedBy = NullToEmpty.class)
TableColumnDocumentPojo toColumnPojo(Integer databaseDocumentId,
Integer tableDocumentId,
ColumnMeta meta);

View File

@@ -1,14 +0,0 @@
package com.databasir.core.domain.document.converter;
import org.mapstruct.Qualifier;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Qualifier
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface NullToEmpty {
}

View File

@@ -2,7 +2,11 @@ package com.databasir.core.domain.document.service;
import com.databasir.core.Databasir;
import com.databasir.core.DatabasirConfig;
import com.databasir.core.diff.Diffs;
import com.databasir.core.diff.data.DiffType;
import com.databasir.core.diff.data.RootDiff;
import com.databasir.core.domain.DomainErrors;
import com.databasir.core.domain.document.converter.DatabaseMetaConverter;
import com.databasir.core.domain.document.converter.DocumentPojoConverter;
import com.databasir.core.domain.document.converter.DocumentResponseConverter;
import com.databasir.core.domain.document.converter.DocumentSimpleResponseConverter;
@@ -74,6 +78,8 @@ public class DocumentService {
private final DocumentSimpleResponseConverter documentSimpleResponseConverter;
private final DatabaseMetaConverter databaseMetaConverter;
private final JsonConverter jsonConverter;
private final List<DocumentFileGenerator> documentFileGenerators;
@@ -82,19 +88,37 @@ public class DocumentService {
public void syncByProjectId(Integer projectId) {
projectDao.selectOptionalById(projectId)
.orElseThrow(DomainErrors.PROJECT_NOT_FOUND::exception);
DatabaseMeta meta = retrieveDatabaseMeta(projectId);
Optional<DatabaseDocumentPojo> latestDocumentOpt = databaseDocumentDao.selectNotArchivedByProjectId(projectId);
if (latestDocumentOpt.isPresent()) {
DatabaseDocumentPojo latestDocument = latestDocumentOpt.get();
Integer previousDocumentId = latestDocument.getId();
DatabaseMeta current = retrieveDatabaseMeta(projectId);
Optional<DatabaseDocumentPojo> originalOption = databaseDocumentDao.selectNotArchivedByProjectId(projectId);
if (originalOption.isPresent()) {
DatabaseDocumentPojo original = originalOption.get();
DatabaseMeta originalMeta = retrieveOriginalDatabaseMeta(original);
RootDiff diff = Diffs.diff(originalMeta, current);
if (diff.getDiffType() == DiffType.NONE) {
log.info("ignore project {} {} sync data, because without change",
projectId,
original.getDatabaseName());
return;
}
Integer previousDocumentId = original.getId();
// archive old version
databaseDocumentDao.updateIsArchiveById(previousDocumentId, true);
saveNewDocument(meta, latestDocument.getVersion() + 1, latestDocument.getProjectId());
saveNewDocument(current, original.getVersion() + 1, original.getProjectId());
} else {
saveNewDocument(meta, 1L, projectId);
saveNewDocument(current, 1L, projectId);
}
}
private DatabaseMeta retrieveOriginalDatabaseMeta(DatabaseDocumentPojo original) {
Integer docId = original.getId();
List<TableDocumentPojo> tables = tableDocumentDao.selectByDatabaseDocumentId(docId);
List<TableColumnDocumentPojo> columns = tableColumnDocumentDao.selectByDatabaseDocumentId(docId);
List<TableIndexDocumentPojo> indexes = tableIndexDocumentDao.selectByDatabaseMetaId(docId);
List<TableTriggerDocumentPojo> triggers = tableTriggerDocumentDao.selectByDatabaseDocumentId(docId);
List<TableForeignKeyDocumentPojo> fks = tableForeignKeyDocumentDao.selectByDatabaseDocumentId(docId);
return databaseMetaConverter.of(original, tables, columns, indexes, triggers, fks);
}
private DatabaseMeta retrieveDatabaseMeta(Integer projectId) {
ProjectSyncRulePojo rule = projectSyncRuleDao.selectByProjectId(projectId);
DataSourcePojo dataSource = dataSourceDao.selectByProjectId(projectId);
@@ -325,4 +349,20 @@ public class DocumentService {
.ifPresent(generator -> generator.generate(context, out));
});
}
public RootDiff diff(Integer projectId, Long originalVersion, Long currentVersion) {
var original = databaseDocumentDao.selectOptionalByProjectIdAndVersion(projectId, originalVersion)
.orElseThrow(DomainErrors.DOCUMENT_VERSION_IS_INVALID::exception);
DatabaseDocumentPojo current;
if (currentVersion == null) {
current = databaseDocumentDao.selectNotArchivedByProjectId(projectId)
.orElseThrow(DomainErrors.DOCUMENT_VERSION_IS_INVALID::exception);
} else {
current = databaseDocumentDao.selectOptionalByProjectIdAndVersion(projectId, currentVersion)
.orElseThrow(DomainErrors.DOCUMENT_VERSION_IS_INVALID::exception);
}
DatabaseMeta currMeta = retrieveOriginalDatabaseMeta(current);
DatabaseMeta originalMeta = retrieveOriginalDatabaseMeta(original);
return Diffs.diff(originalMeta, currMeta);
}
}