feat: 项目整体命名修改cache-schema-checker
All checks were successful
缓存序列化结构检查 / cache-schema-check (push) Has been skipped

This commit is contained in:
2026-07-14 11:03:34 +08:00
parent 114b053733
commit 110beb79c0
42 changed files with 197 additions and 199 deletions

View File

@@ -0,0 +1,151 @@
package com.codechecker.cache.diff;
import com.codechecker.cache.schema.FieldSchema;
import com.codechecker.cache.schema.JsonType;
import com.codechecker.cache.schema.TypeSchema;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 对比两个版本的 {@link TypeSchema},输出结构变更列表。基于叶子字段路径集合进行差异分析。
*/
public class SchemaDiffer {
/**
* @return 结构变更列表(不含 keyPattern/location 上下文,由调用方补充)
*/
public List<SchemaChange> diff(TypeSchema oldSchema, TypeSchema newSchema) {
List<SchemaChange> changes = new ArrayList<>();
Map<String, JsonType> oldLeaves = leaves(oldSchema);
Map<String, JsonType> newLeaves = leaves(newSchema);
Set<String> removed = new LinkedHashSet<>(oldLeaves.keySet());
removed.removeAll(newLeaves.keySet());
Set<String> added = new LinkedHashSet<>(newLeaves.keySet());
added.removeAll(oldLeaves.keySet());
// 类型变更(同路径)
for (String path : oldLeaves.keySet()) {
if (newLeaves.containsKey(path)) {
JsonType oldType = oldLeaves.get(path);
JsonType newType = newLeaves.get(path);
if (oldType != newType) {
SchemaChange c = new SchemaChange(ChangeType.TYPE_CHANGED);
c.setFieldPath(path);
c.setOldValue(oldType.name());
c.setNewValue(newType.name());
c.setMessage("字段 " + path + " 类型由 " + oldType + " 变为 " + newType);
changes.add(c);
}
}
}
// 路径迁移检测removed 的路径是某 added 路径的后缀)
List<String[]> moves = new ArrayList<>();
Set<String> matchedRemoved = new LinkedHashSet<>();
Set<String> matchedAdded = new LinkedHashSet<>();
for (String r : removed) {
for (String a : added) {
if (matchedAdded.contains(a)) {
continue;
}
if (isSuffix(a, r)) {
moves.add(new String[]{r, a});
matchedRemoved.add(r);
matchedAdded.add(a);
break;
}
}
}
// 包装层检测:多个迁移共享同一新前缀
Map<String, Integer> prefixCount = new LinkedHashMap<>();
for (String[] move : moves) {
String a = move[1];
if (a.contains(".")) {
String prefix = a.substring(0, a.indexOf('.'));
prefixCount.merge(prefix, 1, Integer::sum);
}
}
for (Map.Entry<String, Integer> e : prefixCount.entrySet()) {
if (e.getValue() >= 2) {
SchemaChange c = new SchemaChange(ChangeType.WRAPPER_ADDED);
c.setFieldPath(e.getKey());
c.setNewValue(e.getKey());
c.setMessage("新增包装层 " + e.getKey() + ",原顶层字段被下移至该层(影响 " + e.getValue() + " 个字段)");
changes.add(c);
}
}
for (String[] move : moves) {
SchemaChange c = new SchemaChange(ChangeType.FIELD_PATH_MOVED);
c.setFieldPath(move[1]);
c.setOldValue(move[0]);
c.setNewValue(move[1]);
c.setMessage("字段路径迁移:" + move[0] + "" + move[1]);
changes.add(c);
}
// 剩余删除
for (String r : removed) {
if (matchedRemoved.contains(r)) {
continue;
}
SchemaChange c = new SchemaChange(ChangeType.FIELD_REMOVED);
c.setFieldPath(r);
c.setOldValue(oldLeaves.get(r).name());
c.setMessage("删除字段 " + r);
changes.add(c);
}
// 剩余新增
for (String a : added) {
if (matchedAdded.contains(a)) {
continue;
}
SchemaChange c = new SchemaChange(ChangeType.FIELD_ADDED);
c.setFieldPath(a);
c.setNewValue(newLeaves.get(a).name());
c.setMessage("新增字段 " + a);
changes.add(c);
}
return changes;
}
private Map<String, JsonType> leaves(TypeSchema schema) {
Map<String, JsonType> result = new LinkedHashMap<>();
for (FieldSchema f : schema.getFields().values()) {
if (f.getJsonType() != JsonType.OBJECT && f.getJsonType() != JsonType.ARRAY) {
result.put(f.getPath(), f.getJsonType());
}
}
return result;
}
/**
* 判断 full 的按段后缀是否等于 suffix如 vo.dbName 的后缀是 dbName
*/
private boolean isSuffix(String full, String suffix) {
if (full.equals(suffix)) {
return false;
}
String[] fullSeg = full.split("\\.");
String[] sufSeg = suffix.split("\\.");
if (sufSeg.length >= fullSeg.length) {
return false;
}
for (int i = 1; i <= sufSeg.length; i++) {
if (!fullSeg[fullSeg.length - i].equals(sufSeg[sufSeg.length - i])) {
return false;
}
}
return true;
}
}