IndexDiffProcessor类
public class IndexDiffProcessor implements DiffProcessor<IndexMeta> {
@Override
public FieldDiff process(String fieldName, List<IndexMeta> original, List<IndexMeta> current) {
return diffTableField(original, current, fieldName, IndexMeta::getName);
}
}
- 当IndexDiffProcessor类实现DiffProcessor类之后,IndexDiffProcessor就具有父类当中的属性和方法,定义一个处理方法,
- diffTableField方法调用的toMap方法
toMap类
default 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;
}));
}
-
Collectors.toMap方法当中的参数类型
-
T – 输入元素的类型
-
K– 键映射函数的输出类型
-
U – 值映射函数的输出类型
-
收集器将元素收集到一个Map中
-
identify()返回一个始终返回其输入参数的函数
-
-> 对两个相同类型的操作数的操作,产生与操作数相同类型的结果,
-
使用合并组合a,b的结果功能,根据指定的格式和参数在warn记录消息,返回起始值a
private final IndexDiffProcessor indexDiffProcessor = new IndexDiffProcessor();
private final ColumnDiffProcessor columnDiffProcessor = new ColumnDiffProcessor();
private final TriggerDiffProcessor triggerDiffProcessor = new TriggerDiffProcessor();
private final ForeignKeyDiffProcessor foreignKeyDiffProcessor = new ForeignKeyDiffProcessor();
private static final TableMeta EMPTY = new TableMeta();
- 初始化索引差异处理器
- 初始化列差异处理器
- 初始化触发器差异处理器
- 初始化外键差异处理器
- 创建一个空的表元函数(所含元素有表名,类型,评论,表所包含的列,触发器,索引,外键)
added类
private List<TableMeta> added(Map<String, TableMeta> originalMap,
Map<String, TableMeta> currentMap) {
return currentMap.entrySet()
.stream()
.filter(entry -> !originalMap.containsKey(entry.getKey()))
.map(Map.Entry::getValue)
.collect(Collectors.toList());
}
- 得到当前值的映射集合,可修改
- 返回以此集合为源的顺序流
- ->表示一个参数的谓数(布尔值函数)
- 如果添加元素有初始值映射中不包含的元素,返回此元素组成的流
- 返回与此entry对应的值,将值应用于流的元素的结果。
- 将输入元素按照遇到的顺序收集到一个列表中,之后返回这个列表
removed类
private List<TableMeta> removed(Map<String, TableMeta> originalMap,
Map<String, TableMeta> currentMap) {
return originalMap.entrySet()
.stream()
.filter(entry -> !currentMap.containsKey(entry.getKey()))
.map(Map.Entry::getValue)
.collect(Collectors.toList());
}
-
得到起始值的映射集合,可修改
-
返回以此集合为源的顺序流
-
->表示一个参数的谓数(布尔值函数)
-
如果选定的元素为当前值映射中不包含的元素,返回此元素组成的流
-
返回与此entry对应的值,将值应用于流的元素的结果。
-
将输入元素按照遇到的顺序收集到一个列表中,之后返回这个列表
fields类
private List<FieldDiff> fields(TableMeta original, TableMeta current) {
List<FieldDiff> fields = new ArrayList<>();
// ignore tables diff
Class<TableMeta> clazz = TableMeta.class;
List<String> ignoredFields = List.of("columns", "indexes", "triggers", "foreignKeys");
Arrays.stream(clazz.getDeclaredFields())
.filter(field -> !ignoredFields.contains(field.getName()))
.forEach(field -> {
try {
field.setAccessible(true);
Object originalValue = original == null ? null : field.get(original);
Object currentValue = current == null ? null : field.get(current);
if (!Objects.equals(originalValue, currentValue)) {
DiffType diffType;
if (originalValue == null) {
diffType = DiffType.ADDED;
} else if (currentValue == null) {
diffType = DiffType.REMOVED;
} else {
diffType = DiffType.MODIFIED;
}
fields.add(FieldDiff.builder()
.diffType(diffType)
.fieldName(field.getName())
.original(originalValue)
.current(currentValue)
.build());
}
} catch (IllegalAccessException e) {
log.error("diff field failed", e);
}
});
return fields;
}
-
差异字段类型(字段名称,差异类型,初始值,当前值,创建一个字段列表,用来存储字段间的差异)
-
表的元数据(名称,类型,评论,表的列,触发器,索引,外键所组成的列表)
-
返回包括四个元素的不可修改列表(列,索引,触发器,外键),返回该类的所有声明字段的Field字段数组,将忽略字段列表中,不包含字段名称的元素组成的流中的每个元素执行下列操作
-
setAccessible设置可访问,当为 true 时,accessible 标志会抑制 Java 语言访问控制检查,以仅启用对这些不可修改的最终字段的读取访问。
-
字段提供有关类或接口的单个字段的信息和对它们的动态访问,get方法获得对象original表示的字段的值作为初始值映射。
-
get方法获得对象current表示的字段的值作为当前值映射。
-
如果初始值映射和当前值映射不相同,找到它们之间的差异类型。
-
如果起始值映射为空,当前值映射有值,表明它们值之间的差异类型为添加
-
如果起始值有值,当前值为空,表明它们值之间的差异类型为移除
-
如果起始值和当前值都不为空的话,表明它们值之间的差异类型为修改
-
字段名添加字段差异这个类中差异类型,此Field对象表示的字段名称,起始值映射和当前值映射,build表示构造完成。如果这个过程中出现了异常,在error级别记录日志(获取差异字段失败)。
-
最后返回字段名。
diffTableField类
private FieldDiff diffTableField(TableMeta original, TableMeta current) {
FieldDiff columns =
columnDiffProcessor.process("columns", original.getColumns(), current.getColumns());
FieldDiff indexes =
indexDiffProcessor.process("indexes", original.getIndexes(), current.getIndexes());
FieldDiff triggers =
triggerDiffProcessor.process("triggers", original.getTriggers(), current.getTriggers());
FieldDiff foreignKeys =
foreignKeyDiffProcessor.process("foreignKeys", original.getForeignKeys(), current.getForeignKeys());
List<FieldDiff> otherFields = fields(original, current);
List<FieldDiff> fields = new ArrayList<>();
fields.add(columns);
fields.add(indexes);
fields.add(foreignKeys);
fields.add(triggers);
fields.addAll(otherFields);
DiffType diffType;
if (original == EMPTY) {
diffType = DiffType.ADDED;
} else if (current == EMPTY) {
diffType = DiffType.REMOVED;
} else {
diffType = DiffType.MODIFIED;
}
return FieldDiff.builder()
.diffType(diffType)
.fieldName(original == EMPTY ? current.getName() : original.getName())
.original(current == EMPTY ? original : null)
.current(original == EMPTY ? current : null)
.fields(fields)
.build();
}
- 寻找列元素,得到起始值的列和当前值的列进行处理,查看是否符合删除,添加,修改这些条件,找到它们之间的差异元素并且进行返回
- 寻找索引元素,得到起始值的索引和当前值的索引进行处理,查看是否符合删除,添加,修改这些条件,如果是修改的话,找到它们之间的差异元素并且进行返回
- 寻找触发器元素,得到起始值的触发器和当前值的触发器,如上进行处理
- 寻找外键元素,得到起始值的外键元素和当前值的外键元素
- 创建一个可以存储字段名称的列表
- 将得到的列名,索引,外键,触发器以及其他元素加入到存储列表中
- 确定起始值和当前值的差异类型,如果起始值为空,差异类型为添加类型,如果当前值为空,差异类型为删除类型,如果起始值和当前值都不为空并且值不同,差异类型为修改类型
- 寻找字段之间的差异值,将差异类型加入,寻找字段名称,如果起始值为空,就将当前值的名称加入到字段中,接着将起始值和当前值加入到字段中,如果当前值为空,那么就加入起始值,否则就返回null
- 如果current字段中起始值为null,将current值加入到字段中,否则返回null
- 将字段之间的差异值返回,build表示差异值构造完成
process类
@Override
public FieldDiff process(String fieldName, List<TableMeta> original, List<TableMeta> current) {
// diff tables field
Map<String, TableMeta> originalMap = toMap(original, TableMeta::getName);
Map<String, TableMeta> currentMap = toMap(current, TableMeta::getName);
List<FieldDiff> tables = new ArrayList<>();
List<TableMeta> added = added(originalMap, currentMap);
List<TableMeta> removed = removed(originalMap, currentMap);
// added
List<FieldDiff> addedFields = added.stream()
.map(table -> diffTableField(EMPTY, table))
.collect(Collectors.toList());
tables.addAll(addedFields);
// removed
List<FieldDiff> removedFields = removed.stream()
.map(table -> diffTableField(table, EMPTY))
.collect(Collectors.toList());
tables.addAll(removedFields);
// modified
List<FieldDiff> modified = originalMap.entrySet()
.stream()
.filter(entry -> currentMap.containsKey(entry.getKey()))
.filter(entry -> !Objects.equals(entry.getValue(), currentMap.get(entry.getKey())))
.map(entry -> {
TableMeta originalValue = entry.getValue();
TableMeta currentValue = currentMap.get(entry.getKey());
return diffTableField(originalValue, currentValue);
})
.collect(Collectors.toList());
tables.addAll(modified);
DiffType tablesDiffType;
if (!modified.isEmpty()) {
tablesDiffType = DiffType.MODIFIED;
} else if (!addedFields.isEmpty()) {
tablesDiffType = DiffType.ADDED;
} else if (!removedFields.isEmpty()) {
tablesDiffType = DiffType.REMOVED;
} else {
tablesDiffType = DiffType.NONE;
}
FieldDiff tablesField = FieldDiff.builder()
.diffType(tablesDiffType)
.fieldName(fieldName)
.fields(tables)
.build();
return tablesField;
}
-
表元素有 名称 类型 评论 列名 触发器 索引 外键,process中的参数定义一个文件名称,original和current列表存储表元素
-
toMap方法将original和current值中的name转换为初始值和当前值映射,创建一个列表用来存储字段之间的差异值
-
added列表用来存储currentMap中含有,但originalMap中不包含的表元素
-
removed列表用来存储originalMap中含有,但currentMap中不包含的表元素
-
map方法,返回由给定函数应用于此流的元素的结果组成的流,R 代表新流的元素类型,找出added中起始值为null和当前值之间的差异字段集合成列表加入到tables中,找出removed中起始值为table和当前值之间的差异字段集合成列表加入到tables中
-
将起始值映射包含的映射Set视图转换成此集合为源的顺序流
-
如果当前值映射中也包含初始值映射中存在的条目,才将它们之间共同存在的条目返回,entry的值和当前值映射中包含的entry值如果不相等的情况下再将其返回
-
map返回新流的元素类型,起始值为entry的值,当前值为currentMap中所包含的entry的值,将它们之间的差异字段收集到列表中
-
接下来判断表的差异类型,如果修改标识不为空,则表差异类型为modified,接下来也这样判断添加和删除字段,如果为空,表直接不存在差异,为none
-
构造差异值字段,返回它的差异类型,字段名称,起始值和当前值之间的差异字段作为表的字段名称来返回