meta下的processor包下的TableDiffProcessor

221 阅读6分钟

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);
   }
}
  1. 当IndexDiffProcessor类实现DiffProcessor类之后,IndexDiffProcessor就具有父类当中的属性和方法,定义一个处理方法,
  2. 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;
            }));
}
  1. Collectors.toMap方法当中的参数类型

  2. T – 输入元素的类型

  3. K– 键映射函数的输出类型

  4. U – 值映射函数的输出类型

  5. 收集器将元素收集到一个Map中

  6. identify()返回一个始终返回其输入参数的函数

  7. -> 对两个相同类型的操作数的操作,产生与操作数相同类型的结果,

  8. 使用合并组合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();
  1. 初始化索引差异处理器
  2. 初始化列差异处理器
  3. 初始化触发器差异处理器
  4. 初始化外键差异处理器
  5. 创建一个空的表元函数(所含元素有表名,类型,评论,表所包含的列,触发器,索引,外键)

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());
}
  1. 得到当前值的映射集合,可修改
  2. 返回以此集合为源的顺序流
  3. ->表示一个参数的谓数(布尔值函数)
  4. 如果添加元素有初始值映射中不包含的元素,返回此元素组成的流
  5. 返回与此entry对应的值,将值应用于流的元素的结果。
  6. 将输入元素按照遇到的顺序收集到一个列表中,之后返回这个列表

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());
}
  1. 得到起始值的映射集合,可修改

  2. 返回以此集合为源的顺序流

  3. ->表示一个参数的谓数(布尔值函数)

  4. 如果选定的元素为当前值映射中不包含的元素,返回此元素组成的流

  5. 返回与此entry对应的值,将值应用于流的元素的结果。

  6. 将输入元素按照遇到的顺序收集到一个列表中,之后返回这个列表

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;
}
  1. 差异字段类型(字段名称,差异类型,初始值,当前值,创建一个字段列表,用来存储字段间的差异)

  2. 表的元数据(名称,类型,评论,表的列,触发器,索引,外键所组成的列表)

  3. 返回包括四个元素的不可修改列表(列,索引,触发器,外键),返回该类的所有声明字段的Field字段数组,将忽略字段列表中,不包含字段名称的元素组成的流中的每个元素执行下列操作

  4. setAccessible设置可访问,当为 true 时,accessible 标志会抑制 Java 语言访问控制检查,以仅启用对这些不可修改的最终字段的读取访问。

  5. 字段提供有关类或接口的单个字段的信息和对它们的动态访问,get方法获得对象original表示的字段的值作为初始值映射。

  6. get方法获得对象current表示的字段的值作为当前值映射。

  7. 如果初始值映射和当前值映射不相同,找到它们之间的差异类型。

  8. 如果起始值映射为空,当前值映射有值,表明它们值之间的差异类型为添加

  9. 如果起始值有值,当前值为空,表明它们值之间的差异类型为移除

  10. 如果起始值和当前值都不为空的话,表明它们值之间的差异类型为修改

  11. 字段名添加字段差异这个类中差异类型,此Field对象表示的字段名称,起始值映射和当前值映射,build表示构造完成。如果这个过程中出现了异常,在error级别记录日志(获取差异字段失败)。

  12. 最后返回字段名。

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();
}
  1. 寻找列元素,得到起始值的列和当前值的列进行处理,查看是否符合删除,添加,修改这些条件,找到它们之间的差异元素并且进行返回
  2. 寻找索引元素,得到起始值的索引和当前值的索引进行处理,查看是否符合删除,添加,修改这些条件,如果是修改的话,找到它们之间的差异元素并且进行返回
  3. 寻找触发器元素,得到起始值的触发器和当前值的触发器,如上进行处理
  4. 寻找外键元素,得到起始值的外键元素和当前值的外键元素
  5. 创建一个可以存储字段名称的列表
  6. 将得到的列名,索引,外键,触发器以及其他元素加入到存储列表中
  7. 确定起始值和当前值的差异类型,如果起始值为空,差异类型为添加类型,如果当前值为空,差异类型为删除类型,如果起始值和当前值都不为空并且值不同,差异类型为修改类型
  8. 寻找字段之间的差异值,将差异类型加入,寻找字段名称,如果起始值为空,就将当前值的名称加入到字段中,接着将起始值和当前值加入到字段中,如果当前值为空,那么就加入起始值,否则就返回null
  9. 如果current字段中起始值为null,将current值加入到字段中,否则返回null
  10. 将字段之间的差异值返回,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;
}
  1. 表元素有 名称 类型 评论 列名 触发器 索引 外键,process中的参数定义一个文件名称,original和current列表存储表元素

  2. toMap方法将original和current值中的name转换为初始值和当前值映射,创建一个列表用来存储字段之间的差异值

  3. added列表用来存储currentMap中含有,但originalMap中不包含的表元素

  4. removed列表用来存储originalMap中含有,但currentMap中不包含的表元素

  5. map方法,返回由给定函数应用于此流的元素的结果组成的流,R 代表新流的元素类型,找出added中起始值为null和当前值之间的差异字段集合成列表加入到tables中,找出removed中起始值为table和当前值之间的差异字段集合成列表加入到tables中

  6. 将起始值映射包含的映射Set视图转换成此集合为源的顺序流

  7. 如果当前值映射中也包含初始值映射中存在的条目,才将它们之间共同存在的条目返回,entry的值和当前值映射中包含的entry值如果不相等的情况下再将其返回

  8. map返回新流的元素类型,起始值为entry的值,当前值为currentMap中所包含的entry的值,将它们之间的差异字段收集到列表中

  9. 接下来判断表的差异类型,如果修改标识不为空,则表差异类型为modified,接下来也这样判断添加和删除字段,如果为空,表直接不存在差异,为none

  10. 构造差异值字段,返回它的差异类型,字段名称,起始值和当前值之间的差异字段作为表的字段名称来返回