Browse Source

refactor diff api (#138)

* ref: migrate diff logic to list api

* feat: update frontend resources

* fix: checkstyle
master
vran 3 years ago
committed by GitHub
parent
commit
573a82b96d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 24
      api/src/main/java/com/databasir/api/DocumentController.java
  2. 0
      api/src/main/resources/static/css/15.a8ab2b3e.css
  3. 0
      api/src/main/resources/static/css/966.a8ab2b3e.css
  4. 2
      api/src/main/resources/static/index.html
  5. 33
      api/src/main/resources/static/js/15.60b89ed2.js
  6. 1
      api/src/main/resources/static/js/15.60b89ed2.js.map
  7. 2
      api/src/main/resources/static/js/674-legacy.7ef39287.js
  8. 2
      api/src/main/resources/static/js/674-legacy.7ef39287.js.map
  9. 2
      api/src/main/resources/static/js/674.8d18db01.js
  10. 2
      api/src/main/resources/static/js/674.8d18db01.js.map
  11. 33
      api/src/main/resources/static/js/707-legacy.1cb0b60a.js
  12. 1
      api/src/main/resources/static/js/707-legacy.1cb0b60a.js.map
  13. 33
      api/src/main/resources/static/js/815.f05e1fa5.js
  14. 1
      api/src/main/resources/static/js/815.f05e1fa5.js.map
  15. 33
      api/src/main/resources/static/js/966-legacy.c5a65fd8.js
  16. 1
      api/src/main/resources/static/js/966-legacy.c5a65fd8.js.map
  17. 4
      api/src/main/resources/static/js/app-legacy.f7b5df54.js
  18. 2
      api/src/main/resources/static/js/app-legacy.f7b5df54.js.map
  19. 4
      api/src/main/resources/static/js/app.71b7975b.js
  20. 2
      api/src/main/resources/static/js/app.71b7975b.js.map
  21. 15
      core/src/main/java/com/databasir/core/domain/document/comparator/DiffResult.java
  22. 188
      core/src/main/java/com/databasir/core/domain/document/comparator/DocumentDiffs.java
  23. 25
      core/src/main/java/com/databasir/core/domain/document/comparator/TableDiffResult.java
  24. 5
      core/src/main/java/com/databasir/core/domain/document/converter/DatabaseMetaConverter.java
  25. 7
      core/src/main/java/com/databasir/core/domain/document/converter/DocumentPojoConverter.java
  26. 4
      core/src/main/java/com/databasir/core/domain/document/converter/DocumentSimpleResponseConverter.java
  27. 3
      core/src/main/java/com/databasir/core/domain/document/data/DatabaseDocumentResponse.java
  28. 9
      core/src/main/java/com/databasir/core/domain/document/data/DatabaseDocumentSimpleResponse.java
  29. 11
      core/src/main/java/com/databasir/core/domain/document/data/DiffAble.java
  30. 16
      core/src/main/java/com/databasir/core/domain/document/data/TableDocumentRequest.java
  31. 33
      core/src/main/java/com/databasir/core/domain/document/data/TableDocumentResponse.java
  32. 245
      core/src/main/java/com/databasir/core/domain/document/service/DocumentService.java
  33. 2
      core/src/main/java/com/databasir/core/infrastructure/event/subscriber/SystemStartedEventSubscriber.java
  34. 3
      dao/src/main/java/com/databasir/dao/impl/TableColumnDocumentDao.java
  35. 15
      dao/src/main/java/com/databasir/dao/impl/TableDocumentDao.java
  36. 3
      dao/src/main/java/com/databasir/dao/impl/TableForeignKeyDocumentDao.java
  37. 3
      dao/src/main/java/com/databasir/dao/impl/TableIndexDocumentDao.java
  38. 3
      dao/src/main/java/com/databasir/dao/impl/TableTriggerDocumentDao.java
  39. 2
      databasir-frontend

24
api/src/main/java/com/databasir/api/DocumentController.java

@ -2,7 +2,6 @@ package com.databasir.api;
import com.databasir.api.common.LoginUserContext;
import com.databasir.common.JsonData;
import com.databasir.core.diff.data.RootDiff;
import com.databasir.core.domain.document.data.*;
import com.databasir.core.domain.document.generator.DocumentFileType;
import com.databasir.core.domain.document.service.DocumentService;
@ -20,6 +19,7 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
import javax.validation.Valid;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Optional;
@ -43,13 +43,6 @@ public class DocumentController {
return JsonData.ok(taskIdOpt);
}
@GetMapping(Routes.Document.DIFF)
public JsonData<RootDiff> diff(@PathVariable Integer projectId,
@RequestParam(name = "originalVersion") Long originalVersion,
@RequestParam(required = false) Long currentVersion) {
return JsonData.ok(documentService.diff(projectId, originalVersion, currentVersion));
}
@GetMapping(Routes.Document.GET_ONE)
public JsonData<DatabaseDocumentResponse> getByProjectId(@PathVariable Integer projectId,
@RequestParam(required = false) Long version) {
@ -85,16 +78,17 @@ public class DocumentController {
@GetMapping(Routes.Document.GET_SIMPLE_ONE)
public JsonData<DatabaseDocumentSimpleResponse> getSimpleByProjectId(@PathVariable Integer projectId,
@RequestParam(required = false)
Long version) {
return JsonData.ok(documentService.getSimpleOneByProjectId(projectId, version));
Long version,
@RequestParam(required = false)
Long originalVersion) {
return JsonData.ok(documentService.getSimpleOneByProjectId(projectId, version, originalVersion));
}
@PostMapping(Routes.Document.GET_TABLE_DETAIL)
public JsonData<List<TableDocumentResponse>> getTableDocument(
@PathVariable Integer projectId,
@PathVariable Integer documentId,
@RequestBody List<Integer> tableIds) {
return JsonData.ok(documentService.getTableDetails(projectId, documentId, tableIds));
public JsonData<List<TableDocumentResponse>> getTableDocument(@PathVariable Integer projectId,
@PathVariable Integer documentId,
@RequestBody @Valid TableDocumentRequest request) {
return JsonData.ok(documentService.getTableDetails(projectId, documentId, request));
}
@GetMapping(Routes.Document.LIST_TABLES)

0
api/src/main/resources/static/css/707.a8ab2b3e.css → api/src/main/resources/static/css/15.a8ab2b3e.css

0
api/src/main/resources/static/css/815.a8ab2b3e.css → api/src/main/resources/static/css/966.a8ab2b3e.css

2
api/src/main/resources/static/index.html

@ -1 +1 @@
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><title>databasir</title><script defer="defer" type="module" src="/js/chunk-vendors.9effab81.js"></script><script defer="defer" type="module" src="/js/app.bc6973d3.js"></script><link href="/css/chunk-vendors.81898547.css" rel="stylesheet"><link href="/css/app.15b40a89.css" rel="stylesheet"><script defer="defer" src="/js/chunk-vendors-legacy.fb0c8458.js" nomodule></script><script defer="defer" src="/js/app-legacy.f8c04b90.js" nomodule></script></head><body><noscript><strong>We're sorry but databasir doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><title>databasir</title><script defer="defer" type="module" src="/js/chunk-vendors.9effab81.js"></script><script defer="defer" type="module" src="/js/app.71b7975b.js"></script><link href="/css/chunk-vendors.81898547.css" rel="stylesheet"><link href="/css/app.15b40a89.css" rel="stylesheet"><script defer="defer" src="/js/chunk-vendors-legacy.fb0c8458.js" nomodule></script><script defer="defer" src="/js/app-legacy.f7b5df54.js" nomodule></script></head><body><noscript><strong>We're sorry but databasir doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>

33
api/src/main/resources/static/js/15.60b89ed2.js

File diff suppressed because one or more lines are too long

1
api/src/main/resources/static/js/15.60b89ed2.js.map

File diff suppressed because one or more lines are too long

2
api/src/main/resources/static/js/674-legacy.7c89889f.js → api/src/main/resources/static/js/674-legacy.7ef39287.js

File diff suppressed because one or more lines are too long

2
api/src/main/resources/static/js/674-legacy.7c89889f.js.map → api/src/main/resources/static/js/674-legacy.7ef39287.js.map

File diff suppressed because one or more lines are too long

2
api/src/main/resources/static/js/674.89830f99.js → api/src/main/resources/static/js/674.8d18db01.js

File diff suppressed because one or more lines are too long

2
api/src/main/resources/static/js/674.89830f99.js.map → api/src/main/resources/static/js/674.8d18db01.js.map

File diff suppressed because one or more lines are too long

33
api/src/main/resources/static/js/707-legacy.1cb0b60a.js

File diff suppressed because one or more lines are too long

1
api/src/main/resources/static/js/707-legacy.1cb0b60a.js.map

File diff suppressed because one or more lines are too long

33
api/src/main/resources/static/js/815.f05e1fa5.js

File diff suppressed because one or more lines are too long

1
api/src/main/resources/static/js/815.f05e1fa5.js.map

File diff suppressed because one or more lines are too long

33
api/src/main/resources/static/js/966-legacy.c5a65fd8.js

File diff suppressed because one or more lines are too long

1
api/src/main/resources/static/js/966-legacy.c5a65fd8.js.map

File diff suppressed because one or more lines are too long

4
api/src/main/resources/static/js/app-legacy.f8c04b90.js → api/src/main/resources/static/js/app-legacy.f7b5df54.js

File diff suppressed because one or more lines are too long

2
api/src/main/resources/static/js/app-legacy.f8c04b90.js.map → api/src/main/resources/static/js/app-legacy.f7b5df54.js.map

File diff suppressed because one or more lines are too long

4
api/src/main/resources/static/js/app.bc6973d3.js → api/src/main/resources/static/js/app.71b7975b.js

File diff suppressed because one or more lines are too long

2
api/src/main/resources/static/js/app.bc6973d3.js.map → api/src/main/resources/static/js/app.71b7975b.js.map

File diff suppressed because one or more lines are too long

15
core/src/main/java/com/databasir/core/domain/document/comparator/DiffResult.java

@ -0,0 +1,15 @@
package com.databasir.core.domain.document.comparator;
import com.databasir.core.diff.data.DiffType;
import lombok.Data;
import lombok.RequiredArgsConstructor;
@Data
@RequiredArgsConstructor
public class DiffResult {
private final String id;
private final DiffType diffType;
}

188
core/src/main/java/com/databasir/core/domain/document/comparator/DocumentDiffs.java

@ -0,0 +1,188 @@
package com.databasir.core.domain.document.comparator;
import com.databasir.core.diff.data.DiffType;
import com.databasir.core.meta.data.*;
import lombok.extern.slf4j.Slf4j;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
@Slf4j
public class DocumentDiffs {
public static List<TableDiffResult> tableDiff(DatabaseMeta original, DatabaseMeta current) {
return tableDiff(original.getTables(), current.getTables());
}
public static List<TableDiffResult> tableDiff(List<TableMeta> original, List<TableMeta> current) {
Map<String, TableMeta> originalTablesMap = toMap(original, TableMeta::getName);
Map<String, TableMeta> currentTablesMap = toMap(current, TableMeta::getName);
var added = added(originalTablesMap, currentTablesMap)
.stream()
.map(curr -> {
TableDiffResult result = new TableDiffResult(curr.getName(), DiffType.ADDED);
List<DiffResult> columnDiffs =
doDiff(Collections.emptyList(), curr.getColumns(), ColumnMeta::getName);
List<DiffResult> indexDiffs =
doDiff(Collections.emptyList(), curr.getIndexes(), IndexMeta::getName);
List<DiffResult> triggerDiffs =
doDiff(Collections.emptyList(), curr.getTriggers(), TriggerMeta::getName);
List<DiffResult> fkDiffs =
doDiff(Collections.emptyList(),
curr.getForeignKeys(),
fk -> fk.getFkTableName() + "." + fk.getFkColumnName() + "." + fk.getKeySeq());
result.setColumnDiffResults(columnDiffs);
result.setIndexDiffResults(indexDiffs);
result.setTriggerDiffResults(triggerDiffs);
result.setForeignKeyDiffResults(fkDiffs);
return result;
})
.collect(Collectors.toList());
var removed = removed(originalTablesMap, currentTablesMap)
.stream()
.map(old -> {
TableDiffResult result = new TableDiffResult(old.getName(), DiffType.REMOVED);
List<DiffResult> columnDiffs =
doDiff(old.getColumns(), Collections.emptyList(), ColumnMeta::getName);
List<DiffResult> indexDiffs =
doDiff(old.getIndexes(), Collections.emptyList(), IndexMeta::getName);
List<DiffResult> triggerDiffs =
doDiff(old.getTriggers(), Collections.emptyList(), TriggerMeta::getName);
List<DiffResult> fkDiffs =
doDiff(old.getForeignKeys(),
Collections.emptyList(),
fk -> fk.getFkTableName() + "." + fk.getFkColumnName() + "." + fk.getKeySeq());
result.setColumnDiffResults(columnDiffs);
result.setIndexDiffResults(indexDiffs);
result.setTriggerDiffResults(triggerDiffs);
result.setForeignKeyDiffResults(fkDiffs);
return result;
})
.collect(Collectors.toList());
List<TableDiffResult> sameOrModified = currentTablesMap.entrySet()
.stream()
.filter(entry -> originalTablesMap.containsKey(entry.getKey()))
.map(entry -> {
String tableName = entry.getKey();
TableMeta currentTable = entry.getValue();
TableMeta originalTable = originalTablesMap.get(tableName);
List<DiffResult> columnDiffs =
doDiff(originalTable.getColumns(), currentTable.getColumns(), ColumnMeta::getName);
List<DiffResult> indexDiffs =
doDiff(originalTable.getIndexes(), currentTable.getIndexes(), IndexMeta::getName);
List<DiffResult> triggerDiffs =
doDiff(originalTable.getTriggers(), currentTable.getTriggers(), TriggerMeta::getName);
List<DiffResult> fkDiffs =
doDiff(originalTable.getForeignKeys(),
currentTable.getForeignKeys(),
fk -> fk.getFkTableName() + "." + fk.getFkColumnName() + "." + fk.getKeySeq());
DiffType diffType = Objects.equals(currentTable, originalTable) ? DiffType.NONE : DiffType.MODIFIED;
TableDiffResult diffResult = new TableDiffResult(tableName, diffType);
diffResult.setColumnDiffResults(columnDiffs);
diffResult.setIndexDiffResults(indexDiffs);
diffResult.setTriggerDiffResults(triggerDiffs);
diffResult.setForeignKeyDiffResults(fkDiffs);
return diffResult;
})
.collect(Collectors.toList());
List<TableDiffResult> all = new ArrayList<>(16);
all.addAll(sameOrModified);
all.addAll(added);
all.addAll(removed);
return all;
}
private static <T> List<DiffResult> doDiff(List<T> original, List<T> current, Function<T, String> idMapping) {
Map<String, T> originalColumnMap = toMap(original, idMapping);
Map<String, T> currentColumnMap = toMap(current, idMapping);
BiFunction<T, DiffType, DiffResult> mapping = (meta, diffType) -> {
return new DiffResult(idMapping.apply(meta), diffType);
};
List<DiffResult> added = added(originalColumnMap, currentColumnMap)
.stream()
.map(col -> mapping.apply(col, DiffType.ADDED))
.collect(Collectors.toList());
List<DiffResult> removed = removed(originalColumnMap, currentColumnMap)
.stream()
.map(col -> mapping.apply(col, DiffType.REMOVED))
.collect(Collectors.toList());
List<DiffResult> modified = modified(originalColumnMap, currentColumnMap)
.stream()
.map(col -> mapping.apply(col, DiffType.MODIFIED))
.collect(Collectors.toList());
List<DiffResult> same = same(originalColumnMap, currentColumnMap)
.stream()
.map(col -> mapping.apply(col, DiffType.NONE))
.collect(Collectors.toList());
List<DiffResult> columnResults = new ArrayList<>();
columnResults.addAll(same);
columnResults.addAll(added);
columnResults.addAll(modified);
columnResults.addAll(removed);
return columnResults;
}
private static <T> Map<String, T> toMap(List<T> content, Function<T, String> idMapping) {
return content
.stream()
.collect(Collectors.toMap(idMapping, Function.identity(), (a, b) -> {
log.warn("Duplicate key, origin = {}, current = {}", a, b);
return a;
}));
}
private static <T> List<T> added(Map<String, T> originalMapById,
Map<String, T> currentMapById) {
return currentMapById.entrySet()
.stream()
.filter(entry -> !originalMapById.containsKey(entry.getKey()))
.map(Map.Entry::getValue)
.collect(Collectors.toList());
}
private static <T> List<T> removed(Map<String, T> originalMapById,
Map<String, T> currentMapById) {
return originalMapById.entrySet()
.stream()
.filter(entry -> !currentMapById.containsKey(entry.getKey()))
.map(Map.Entry::getValue)
.collect(Collectors.toList());
}
private static <T> List<T> modified(Map<String, T> originalMapById,
Map<String, T> currentMapById) {
return modified(originalMapById, currentMapById, Objects::equals);
}
private static <T> List<T> modified(Map<String, T> originalMapById,
Map<String, T> currentMapById,
BiFunction<T, T, Boolean> sameFunction) {
return currentMapById.entrySet()
.stream()
.filter(entry -> originalMapById.containsKey(entry.getKey()))
.filter(entry -> !sameFunction.apply(entry.getValue(), originalMapById.get(entry.getKey())))
.map(Map.Entry::getValue)
.collect(Collectors.toList());
}
private static <T> List<T> same(Map<String, T> originalMapById,
Map<String, T> currentMapById) {
return same(originalMapById, currentMapById, Objects::equals);
}
private static <T> List<T> same(Map<String, T> originalMapById,
Map<String, T> currentMapById,
BiFunction<T, T, Boolean> sameFunction) {
return currentMapById.entrySet()
.stream()
.filter(entry -> originalMapById.containsKey(entry.getKey()))
.filter(entry -> sameFunction.apply(entry.getValue(), originalMapById.get(entry.getKey())))
.map(Map.Entry::getValue)
.collect(Collectors.toList());
}
}

25
core/src/main/java/com/databasir/core/domain/document/comparator/TableDiffResult.java

@ -0,0 +1,25 @@
package com.databasir.core.domain.document.comparator;
import com.databasir.core.diff.data.DiffType;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import java.util.Collection;
import java.util.Collections;
@Data
@RequiredArgsConstructor
public class TableDiffResult {
private final String id;
private final DiffType diffType;
private Collection<DiffResult> columnDiffResults = Collections.emptyList();
private Collection<DiffResult> indexDiffResults = Collections.emptyList();
private Collection<DiffResult> triggerDiffResults = Collections.emptyList();
private Collection<DiffResult> foreignKeyDiffResults = Collections.emptyList();
}

5
core/src/main/java/com/databasir/core/domain/document/converter/DatabaseMetaConverter.java

@ -1,5 +1,6 @@
package com.databasir.core.domain.document.converter;
import com.databasir.core.domain.document.data.TableDocumentResponse;
import com.databasir.core.infrastructure.converter.JsonConverter;
import com.databasir.core.meta.data.ColumnMeta;
import com.databasir.core.meta.data.DatabaseMeta;
@ -64,6 +65,10 @@ public interface DatabaseMetaConverter {
@Mapping(target = "columnNames", source = "pojo.columnNameArray")
IndexMeta of(TableIndexDocumentPojo pojo);
List<TableMeta> of(List<TableDocumentResponse> table);
TableMeta of(TableDocumentResponse table);
default <R> Map<Integer, List<R>> groupBy(List<R> content, Function<R, Integer> idMapping) {
return content.stream()
.collect(Collectors.groupingBy(idMapping));

7
core/src/main/java/com/databasir/core/domain/document/converter/DocumentPojoConverter.java

@ -1,10 +1,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.core.meta.data.*;
import com.databasir.dao.tables.pojos.*;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
@ -20,7 +17,7 @@ public interface DocumentPojoConverter {
@Mapping(target = "schemaName", source = "meta.schemaName")
@Mapping(target = "isArchive", constant = "false")
DatabaseDocumentPojo toDatabasePojo(Integer projectId,
com.databasir.core.meta.data.DatabaseMeta meta,
DatabaseMeta meta,
Long version);
TableDocumentPojo toTablePojo(Integer databaseDocumentId,

4
core/src/main/java/com/databasir/core/domain/document/converter/DocumentSimpleResponseConverter.java

@ -1,5 +1,6 @@
package com.databasir.core.domain.document.converter;
import com.databasir.core.diff.data.DiffType;
import com.databasir.core.domain.document.data.DatabaseDocumentSimpleResponse;
import com.databasir.core.infrastructure.converter.JsonConverter;
import com.databasir.dao.tables.pojos.DatabaseDocumentPojo;
@ -19,7 +20,8 @@ public interface DocumentSimpleResponseConverter {
@Mapping(target = "createAt", source = "databaseDocument.createAt")
@Mapping(target = "documentVersion", source = "databaseDocument.version")
DatabaseDocumentSimpleResponse of(DatabaseDocumentPojo databaseDocument,
List<DatabaseDocumentSimpleResponse.TableData> tables);
List<DatabaseDocumentSimpleResponse.TableData> tables,
DiffType diffType);
DatabaseDocumentSimpleResponse.TableData of(TableDocumentPojo tables,
Integer discussionCount,

3
core/src/main/java/com/databasir/core/domain/document/data/DatabaseDocumentResponse.java

@ -1,5 +1,6 @@
package com.databasir.core.domain.document.data;
import com.databasir.core.diff.data.DiffType;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -32,4 +33,6 @@ public class DatabaseDocumentResponse {
private LocalDateTime createAt;
private DiffType diffType;
}

9
core/src/main/java/com/databasir/core/domain/document/data/DatabaseDocumentSimpleResponse.java

@ -1,5 +1,6 @@
package com.databasir.core.domain.document.data;
import com.databasir.core.diff.data.DiffType;
import lombok.Data;
import java.time.LocalDateTime;
@ -25,8 +26,10 @@ public class DatabaseDocumentSimpleResponse {
private LocalDateTime createAt;
private DiffType diffType;
@Data
public static class TableData {
public static class TableData implements DiffAble<TableData> {
private Integer id;
@ -39,5 +42,9 @@ public class DatabaseDocumentSimpleResponse {
private Integer discussionCount;
private String description;
private DiffType diffType;
private TableData original;
}
}

11
core/src/main/java/com/databasir/core/domain/document/data/DiffAble.java

@ -0,0 +1,11 @@
package com.databasir.core.domain.document.data;
import com.databasir.core.diff.data.DiffType;
public interface DiffAble<T> {
void setDiffType(DiffType diffType);
void setOriginal(T t);
}

16
core/src/main/java/com/databasir/core/domain/document/data/TableDocumentRequest.java

@ -0,0 +1,16 @@
package com.databasir.core.domain.document.data;
import lombok.Data;
import java.util.Collection;
import java.util.Collections;
@Data
public class TableDocumentRequest {
private Collection<Integer> tableIds = Collections.emptyList();
private Long originalVersion;
private Long currentVersion;
}

33
core/src/main/java/com/databasir/core/domain/document/data/TableDocumentResponse.java

@ -1,5 +1,6 @@
package com.databasir.core.domain.document.data;
import com.databasir.core.diff.data.DiffType;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -13,7 +14,7 @@ import java.util.List;
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class TableDocumentResponse {
public class TableDocumentResponse implements DiffAble<TableDocumentResponse> {
private Integer id;
@ -41,11 +42,15 @@ public class TableDocumentResponse {
private LocalDateTime createAt;
private DiffType diffType;
private TableDocumentResponse original;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class ColumnDocumentResponse {
public static class ColumnDocumentResponse implements DiffAble<ColumnDocumentResponse> {
private Integer id;
private String name;
@ -71,13 +76,17 @@ public class TableDocumentResponse {
private Integer discussionCount;
private LocalDateTime createAt;
private DiffType diffType;
private ColumnDocumentResponse original;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class IndexDocumentResponse {
public static class IndexDocumentResponse implements DiffAble<IndexDocumentResponse> {
private Integer id;
@ -89,13 +98,17 @@ public class TableDocumentResponse {
private List<String> columnNames = new ArrayList<>();
private LocalDateTime createAt;
private DiffType diffType;
private IndexDocumentResponse original;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class ForeignKeyDocumentResponse {
public static class ForeignKeyDocumentResponse implements DiffAble<ForeignKeyDocumentResponse> {
private Integer id;
@ -105,6 +118,8 @@ public class TableDocumentResponse {
private String fkColumnName;
private Integer keySeq;
private String pkName;
private String pkTableName;
@ -116,13 +131,17 @@ public class TableDocumentResponse {
private String deleteRule;
private LocalDateTime createAt;
private DiffType diffType;
private ForeignKeyDocumentResponse original;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class TriggerDocumentResponse {
public static class TriggerDocumentResponse implements DiffAble<TriggerDocumentResponse> {
private Integer id;
@ -137,5 +156,9 @@ public class TableDocumentResponse {
private String triggerCreateAt;
private LocalDateTime createAt;
private DiffType diffType;
private TriggerDocumentResponse original;
}
}

245
core/src/main/java/com/databasir/core/domain/document/service/DocumentService.java

@ -7,8 +7,12 @@ 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.comparator.DiffResult;
import com.databasir.core.domain.document.comparator.DocumentDiffs;
import com.databasir.core.domain.document.comparator.TableDiffResult;
import com.databasir.core.domain.document.converter.*;
import com.databasir.core.domain.document.data.*;
import com.databasir.core.domain.document.data.TableDocumentResponse.ForeignKeyDocumentResponse;
import com.databasir.core.domain.document.event.DocumentUpdated;
import com.databasir.core.domain.document.generator.DocumentFileGenerator;
import com.databasir.core.domain.document.generator.DocumentFileType;
@ -16,6 +20,7 @@ import com.databasir.core.infrastructure.connection.DatabaseConnectionService;
import com.databasir.core.infrastructure.converter.JsonConverter;
import com.databasir.core.infrastructure.event.EventPublisher;
import com.databasir.core.meta.data.DatabaseMeta;
import com.databasir.core.meta.data.TableMeta;
import com.databasir.dao.impl.*;
import com.databasir.dao.tables.pojos.*;
import com.databasir.dao.value.DocumentDiscussionCountPojo;
@ -32,12 +37,12 @@ import org.springframework.util.CollectionUtils;
import java.io.OutputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import static java.util.Collections.emptyList;
@Service
@RequiredArgsConstructor
@Slf4j
@ -51,8 +56,6 @@ public class DocumentService {
private final DataSourcePropertyDao dataSourcePropertyDao;
private final SysKeyDao sysKeyDao;
private final DatabaseConnectionService databaseConnectionService;
private final DatabaseDocumentDao databaseDocumentDao;
@ -199,13 +202,16 @@ public class DocumentService {
projectId, meta.getDatabaseName(), version);
}
public Optional<DatabaseDocumentSimpleResponse> getSimpleOneByProjectId(Integer projectId, Long version) {
public Optional<DatabaseDocumentSimpleResponse> getSimpleOneByProjectId(Integer projectId,
Long version,
Long originalVersion) {
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);
@ -213,7 +219,7 @@ public class DocumentService {
documentDiscussionDao.selectTableDiscussionCount(projectId)
.stream()
.collect(Collectors.toMap(d -> d.getTableName(), d -> d.getCount(), (a, b) -> a));
Map<String, String> descriptionMapByTableName =
var descriptionMapByTableName =
documentDescriptionDao.selectTableDescriptionByProjectId(projectId)
.stream()
.collect(Collectors.toMap(d -> d.getTableName(), d -> d.getContent(), (a, b) -> a));
@ -222,10 +228,70 @@ public class DocumentService {
discussionCountMapByTableName,
descriptionMapByTableName
);
return documentSimpleResponseConverter.of(document, tableMetas);
// if original version is not null mean version diff enabled
if (originalVersion != null) {
var originalDocument =
databaseDocumentDao.selectOptionalByProjectIdAndVersion(projectId, originalVersion)
.orElseThrow(DomainErrors.DOCUMENT_VERSION_IS_INVALID::exception);
var originalTables = tableDocumentDao.selectByDatabaseDocumentId(originalDocument.getId());
var originalTableMetas = documentSimpleResponseConverter.of(
originalTables,
discussionCountMapByTableName,
descriptionMapByTableName
);
var originalMap = originalTableMetas.stream()
.collect(Collectors.toMap(t -> t.getName(), Function.identity(), (a, b) -> a));
var currentMap = tableMetas.stream()
.collect(Collectors.toMap(t -> t.getName(), Function.identity(), (a, b) -> a));
List<TableDiffResult> diffResults = tableDiffs(projectId, originalVersion, version);
List<DatabaseDocumentSimpleResponse.TableData> result = new ArrayList<>();
for (TableDiffResult diffResult : diffResults) {
var cur = currentMap.get(diffResult.getId());
var org = originalMap.get(diffResult.getId());
if (diffResult.getDiffType() == DiffType.ADDED) {
cur.setDiffType(DiffType.ADDED);
result.add(cur);
} else if (diffResult.getDiffType() == DiffType.MODIFIED) {
cur.setDiffType(DiffType.MODIFIED);
cur.setOriginal(org);
result.add(cur);
} else if (diffResult.getDiffType() == DiffType.REMOVED) {
org.setDiffType(DiffType.REMOVED);
result.add(org);
} else {
cur.setDiffType(DiffType.NONE);
result.add(cur);
}
}
result.sort(Comparator.comparing(DatabaseDocumentSimpleResponse.TableData::getName));
DiffType diffType = result.stream()
.anyMatch(t -> t.getDiffType() == DiffType.MODIFIED) ? DiffType.MODIFIED : DiffType.NONE;
return documentSimpleResponseConverter.of(document, result, diffType);
} else {
tableMetas.sort(Comparator.comparing(DatabaseDocumentSimpleResponse.TableData::getName));
return documentSimpleResponseConverter.of(document, tableMetas, DiffType.NONE);
}
});
}
public List<TableDiffResult> tableDiffs(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 DocumentDiffs.tableDiff(originalMeta, currMeta);
}
public Optional<DatabaseDocumentResponse> getOneByProjectId(Integer projectId, Long version) {
Optional<DatabaseDocumentPojo> documentOption;
@ -252,11 +318,11 @@ public class DocumentService {
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());
var subColumns = columnsGroupByTableMetaId.getOrDefault(tableId, emptyList());
var subIndexes = indexesGroupByTableMetaId.getOrDefault(tableId, emptyList());
var subTriggers = triggersGroupByTableMetaId.getOrDefault(tableId, emptyList());
var subForeignKeys =
foreignKeysGroupByTableMetaId.getOrDefault(tableId, Collections.emptyList());
foreignKeysGroupByTableMetaId.getOrDefault(tableId, emptyList());
return documentResponseConverter.of(
table,
subColumns,
@ -284,10 +350,10 @@ public class DocumentService {
public List<TableDocumentResponse> getTableDetails(Integer projectId,
Integer databaseDocumentId,
List<Integer> tableIds) {
Collection<Integer> tableIds) {
// maybe deleted
if (CollectionUtils.isEmpty(tableIds) || !projectDao.existsById(projectId)) {
return Collections.emptyList();
return emptyList();
}
var tables =
tableDocumentDao.selectByDatabaseDocumentIdAndIdIn(databaseDocumentId, tableIds);
@ -338,10 +404,10 @@ public class DocumentService {
return tables.stream()
.map(table -> {
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 subColumns = columnsGroupByTableMetaId.getOrDefault(tableId, emptyList());
var subIndexes = indexesGroupByTableMetaId.getOrDefault(tableId, emptyList());
var subForeignKeys = foreignKeysGroupByTableMetaId.getOrDefault(tableId, emptyList());
var subTriggers = triggersGroupByTableMetaId.getOrDefault(tableId, emptyList());
var discussionCount = discussionCountMapByJoinName.get(table.getName());
var description = descriptionMapByJoinName.get(table.getName());
var columnResponses = documentResponseConverter.of(
@ -362,6 +428,87 @@ public class DocumentService {
.collect(Collectors.toList());
}
public List<TableDocumentResponse> getTableDetails(Integer projectId,
Integer databaseDocumentId,
TableDocumentRequest request) {
// maybe deleted
if (CollectionUtils.isEmpty(request.getTableIds()) || !projectDao.existsById(projectId)) {
return emptyList();
}
var current = this.getTableDetails(projectId, databaseDocumentId, request.getTableIds());
if (request.getOriginalVersion() != null) {
DatabaseDocumentPojo doc =
databaseDocumentDao.selectOptionalByProjectIdAndVersion(projectId, request.getOriginalVersion())
.orElseThrow(DomainErrors.DOCUMENT_VERSION_IS_INVALID::exception);
List<String> tableNames = current.stream().map(t -> t.getName()).distinct().collect(Collectors.toList());
List<Integer> originalTableIds =
tableDocumentDao.selectTableIdsByDatabaseDocumentIdAndTableNameIn(doc.getId(), tableNames);
var original = this.getTableDetails(projectId, doc.getId(), originalTableIds);
Map<String, TableDocumentResponse> currentMapByName = current.stream()
.collect(Collectors.toMap(TableDocumentResponse::getName, Function.identity(), (a, b) -> a));
Map<String, TableDocumentResponse> originalMapByName = original.stream()
.collect(Collectors.toMap(TableDocumentResponse::getName, Function.identity(), (a, b) -> a));
List<TableMeta> currentMeta = databaseMetaConverter.of(current);
List<TableMeta> originalMeta = databaseMetaConverter.of(original);
List<TableDiffResult> diffs = DocumentDiffs.tableDiff(originalMeta, currentMeta);
return diffs.stream()
.map(diff -> {
if (diff.getDiffType() == DiffType.ADDED) {
TableDocumentResponse c = currentMapByName.get(diff.getId());
c.setDiffType(DiffType.ADDED);
var cols =
diff(diff.getColumnDiffResults(), emptyList(), c.getColumns(), i -> i.getName());
c.setColumns(cols);
var indexes =
diff(diff.getIndexDiffResults(), emptyList(), c.getIndexes(), i -> i.getName());
c.setIndexes(indexes);
var foreignKeys = foreignKeyDiff(diff.getForeignKeyDiffResults(),
emptyList(), c.getForeignKeys());
c.setForeignKeys(foreignKeys);
var triggers =
diff(diff.getTriggerDiffResults(), emptyList(), c.getTriggers(), t -> t.getName());
c.setTriggers(triggers);
return c;
}
if (diff.getDiffType() == DiffType.REMOVED) {
TableDocumentResponse t = originalMapByName.get(diff.getId());
t.setDiffType(DiffType.REMOVED);
return t;
}
if (diff.getDiffType() == DiffType.MODIFIED) {
TableDocumentResponse c = currentMapByName.get(diff.getId());
TableDocumentResponse o = originalMapByName.get(diff.getId());
c.setDiffType(DiffType.MODIFIED);
c.setOriginal(o);
var cols =
diff(diff.getColumnDiffResults(), o.getColumns(), c.getColumns(),
col -> col.getName());
c.setColumns(cols);
var indexes =
diff(diff.getIndexDiffResults(), o.getIndexes(), c.getIndexes(), i -> i.getName());
c.setIndexes(indexes);
var foreignKeys = foreignKeyDiff(diff.getForeignKeyDiffResults(),
o.getForeignKeys(), c.getForeignKeys());
c.setForeignKeys(foreignKeys);
var triggers =
diff(diff.getTriggerDiffResults(), o.getTriggers(), c.getTriggers(),
t -> t.getName());
c.setTriggers(triggers);
return c;
}
TableDocumentResponse t = currentMapByName.get(diff.getId());
t.setDiffType(DiffType.NONE);
return t;
})
.sorted(Comparator.comparing(TableDocumentResponse::getName))
.collect(Collectors.toList());
} else {
current.sort(Comparator.comparing(TableDocumentResponse::getName));
return current;
}
}
public void export(Integer projectId,
Long version,
DocumentFileType type,
@ -379,22 +526,6 @@ public class DocumentService {
});
}
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);
}
public List<TableResponse> getTableAndColumns(Integer projectId, Long version) {
Optional<DatabaseDocumentPojo> documentOption;
if (version == null) {
@ -403,7 +534,7 @@ public class DocumentService {
documentOption = databaseDocumentDao.selectOptionalByProjectIdAndVersion(projectId, version);
}
if (documentOption.isEmpty()) {
return Collections.emptyList();
return emptyList();
} else {
DatabaseDocumentPojo databaseDoc = documentOption.get();
var tables = tableDocumentDao.selectByDatabaseDocumentId(databaseDoc.getId());
@ -413,4 +544,46 @@ public class DocumentService {
return tableResponseConverter.from(tables, columnMapByTableId);
}
}
private <T extends DiffAble> List<T> diff(Collection<DiffResult> diffs,
Collection<T> original,
Collection<T> current,
Function<T, String> idMapping) {
var currentMapByName = current.stream()
.collect(Collectors.toMap(idMapping, Function.identity(), (a, b) -> a));
var originalMapByName = original.stream()
.collect(Collectors.toMap(idMapping, Function.identity(), (a, b) -> a));
return diffs.stream().map(diff -> {
if (diff.getDiffType() == DiffType.ADDED) {
var t = currentMapByName.get(diff.getId());
t.setDiffType(DiffType.ADDED);
return t;
}
if (diff.getDiffType() == DiffType.REMOVED) {
var t = originalMapByName.get(diff.getId());
t.setDiffType(DiffType.REMOVED);
return t;
}
if (diff.getDiffType() == DiffType.MODIFIED) {
var c = currentMapByName.get(diff.getId());
var o = originalMapByName.get(diff.getId());
c.setDiffType(DiffType.MODIFIED);
c.setOriginal(o);
return c;
}
var t = currentMapByName.get(diff.getId());
t.setDiffType(DiffType.NONE);
return t;
})
.collect(Collectors.toList());
}
private List<ForeignKeyDocumentResponse> foreignKeyDiff(Collection<DiffResult> diffs,
Collection<ForeignKeyDocumentResponse> original,
Collection<ForeignKeyDocumentResponse> current) {
Function<ForeignKeyDocumentResponse, String> idMapping = fk -> {
return fk.getFkTableName() + "." + fk.getFkColumnName() + "." + fk.getKeySeq();
};
return diff(diffs, original, current, idMapping);
}
}

2
core/src/main/java/com/databasir/core/infrastructure/event/subscriber/SystemStartedEventSubscriber.java

@ -61,7 +61,7 @@ public class SystemStartedEventSubscriber {
DocumentTemplatePropertyPojo pojo = new DocumentTemplatePropertyPojo();
pojo.setType(type);
pojo.setKey(key);
pojo.setDefaultValue(fieldChineseMap.get(key));
pojo.setDefaultValue(fieldChineseMap.getOrDefault(key, def));
return pojo;
};
// table field name;

3
dao/src/main/java/com/databasir/dao/impl/TableColumnDocumentDao.java

@ -6,6 +6,7 @@ import org.jooq.DSLContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@ -30,7 +31,7 @@ public class TableColumnDocumentDao extends BaseDao<TableColumnDocumentPojo> {
}
public List<TableColumnDocumentPojo> selectByDatabaseDocumentIdAndTableIdIn(Integer schemaDocumentId,
List<Integer> tableIdIn) {
Collection<Integer> tableIdIn) {
if (tableIdIn == null || tableIdIn.isEmpty()) {
return Collections.emptyList();
}

15
dao/src/main/java/com/databasir/dao/impl/TableDocumentDao.java

@ -7,6 +7,7 @@ import org.jooq.DSLContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
@ -32,7 +33,7 @@ public class TableDocumentDao extends BaseDao<TableDocumentPojo> {
}
public List<TableDocumentPojo> selectByDatabaseDocumentIdAndIdIn(Integer databaseDocumentId,
List<Integer> idList) {
Collection<Integer> idList) {
if (idList == null || idList.isEmpty()) {
return Collections.emptyList();
}
@ -60,4 +61,16 @@ public class TableDocumentDao extends BaseDao<TableDocumentPojo> {
.and(TABLE_DOCUMENT.ID.eq(id)))
.fetchOptionalInto(TableDocumentPojo.class);
}
public List<Integer> selectTableIdsByDatabaseDocumentIdAndTableNameIn(Integer databaseDocumentId,
Collection<String> tableNames) {
if (tableNames == null || tableNames.isEmpty()) {
return Collections.emptyList();
}
return getDslContext()
.select(TABLE_DOCUMENT.ID).from(TABLE_DOCUMENT)
.where(TABLE_DOCUMENT.DATABASE_DOCUMENT_ID.eq(databaseDocumentId)
.and(TABLE_DOCUMENT.NAME.in(tableNames)))
.fetchInto(Integer.class);
}
}

3
dao/src/main/java/com/databasir/dao/impl/TableForeignKeyDocumentDao.java

@ -6,6 +6,7 @@ import org.jooq.DSLContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@ -30,7 +31,7 @@ public class TableForeignKeyDocumentDao extends BaseDao<TableForeignKeyDocumentP
}
public List<TableForeignKeyDocumentPojo> selectByDatabaseDocumentIdAndTableIdIn(Integer databaseDocumentId,
List<Integer> tableIdIn) {
Collection<Integer> tableIdIn) {
if (tableIdIn == null || tableIdIn.isEmpty()) {
return Collections.emptyList();
}

3
dao/src/main/java/com/databasir/dao/impl/TableIndexDocumentDao.java

@ -6,6 +6,7 @@ import org.jooq.DSLContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@ -30,7 +31,7 @@ public class TableIndexDocumentDao extends BaseDao<TableIndexDocumentPojo> {
}
public List<TableIndexDocumentPojo> selectByDatabaseDocumentIdAndIdIn(Integer documentId,
List<Integer> tableIdIn) {
Collection<Integer> tableIdIn) {
if (tableIdIn == null || tableIdIn.isEmpty()) {
return Collections.emptyList();
}

3
dao/src/main/java/com/databasir/dao/impl/TableTriggerDocumentDao.java

@ -6,6 +6,7 @@ import org.jooq.DSLContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@ -30,7 +31,7 @@ public class TableTriggerDocumentDao extends BaseDao<TableTriggerDocumentPojo> {
}
public List<TableTriggerDocumentPojo> selectByDatabaseDocumentIdAndIdIn(Integer documentId,
List<Integer> tableIdIn) {
Collection<Integer> tableIdIn) {
if (tableIdIn == null || tableIdIn.isEmpty()) {
return Collections.emptyList();
}

2
databasir-frontend

@ -1 +1 @@
Subproject commit 6dac399b514868bc6be0209da9c4cbb0f8759ca0
Subproject commit 5ed5897c7cd9a0f097068c120539037fc5509f3f
Loading…
Cancel
Save