同步用户相关修改

This commit is contained in:
strepsiades
2026-03-24 15:13:46 +08:00
parent 8ee0131d47
commit 67370657db
5 changed files with 171 additions and 85 deletions
+70 -43
View File
@@ -219,8 +219,24 @@ class IDResolver:
# 遍历所有字段
for field_name, value in list(data_dict.items()):
# 判断是否是ID字段
is_id_field = field_name.endswith("_id") or field_name.endswith("_ids") or field_name == "id"
is_id_field = field_name.endswith("_id") or field_name == "id"
is_primary_id_field = field_name in ("id", "_id")
is_depend_field = field_name in depend_field_names
if isinstance(value, list):
if not is_depend_field:
continue
data_dict[field_name] = await self._resolve_list_id_field_value(
value=value,
hint=id_field_hints.get(field_name),
node=node,
node_type=node_type,
field_name=field_name,
to_remote=to_remote,
logger=logger,
)
continue
if not is_id_field:
continue
@@ -230,9 +246,6 @@ class IDResolver:
if value == "":
continue
# 判断是否是依赖字段
is_depend_field = field_name in depend_field_names
# 获取node_type提示
hint = id_field_hints.get(field_name)
@@ -240,6 +253,24 @@ class IDResolver:
if is_primary_id_field and not hint:
hint = node_type
if isinstance(value, list):
if not is_depend_field:
continue
data_dict[field_name] = await self._resolve_list_id_field_value(
value=value,
hint=hint,
node=node,
node_type=node_type,
field_name=field_name,
to_remote=to_remote,
logger=logger,
)
continue
if not is_id_field and not is_depend_field:
continue
# 解析ID
target_value = await self._resolve_id_field_value(
value=value,
@@ -330,6 +361,9 @@ class IDResolver:
for field_name, dep_type in depend_fields.items():
original_value = data.get(field_name)
resolved_value = resolved_data.get(field_name)
if isinstance(original_value, list):
continue
# 原本有值(源端 ID),但解析后为空(找不到目标端 ID)
# 说明依赖节点虽然在源端存在,但在目标端还没就绪
@@ -345,19 +379,6 @@ class IDResolver:
@staticmethod
def _has_unresolved_dependency_value(original_value: Any, resolved_value: Any) -> bool:
if isinstance(original_value, list) and isinstance(resolved_value, list):
if len(original_value) != len(resolved_value):
return True
for original_item, resolved_item in zip(original_value, resolved_value):
if original_item in (None, ""):
continue
if not resolved_item:
return True
return False
if isinstance(original_value, list):
return any(item not in (None, "") for item in original_value) and not resolved_value
return bool(original_value) and not resolved_value
async def _resolve_id_field_value(
@@ -374,32 +395,15 @@ class IDResolver:
logger,
) -> Any:
if isinstance(value, list):
resolved_items = []
has_failure = False
for item in value:
if item is None or item == "":
resolved_items.append("")
continue
target_id = await self.resolve_id(str(item), hint, to_remote=to_remote)
if target_id is None:
has_failure = True
resolved_items.append("")
else:
resolved_items.append(target_id)
if has_failure:
self._log_id_resolution_failure(
logger=logger,
node=node,
node_type=node_type,
field_name=field_name,
value=value,
is_depend_field=is_depend_field,
is_primary_id_field=is_primary_id_field,
to_remote=to_remote,
)
return resolved_items
return await self._resolve_list_id_field_value(
value=value,
hint=hint,
node=node,
node_type=node_type,
field_name=field_name,
to_remote=to_remote,
logger=logger,
)
target_id = await self.resolve_id(str(value), hint, to_remote=to_remote)
if target_id is None:
@@ -417,6 +421,29 @@ class IDResolver:
return target_id
async def _resolve_list_id_field_value(
self,
*,
value: list[Any],
hint: Optional[str],
node: "SyncNode",
node_type: str,
field_name: str,
to_remote: bool,
logger,
) -> list[Any]:
resolved_items: list[Any] = []
for item in value:
if item is None or item == "":
continue
target_id = await self.resolve_id(str(item), hint, to_remote=to_remote)
if target_id is not None:
resolved_items.append(target_id)
return resolved_items
@staticmethod
def _log_id_resolution_failure(
*,
@@ -155,6 +155,14 @@ def check_dependency_satisfied(
return True
def _normalize_dependency_field_values(value: Any) -> list[Any]:
if isinstance(value, list):
return [item for item in value if item not in (None, "")]
if value in (None, ""):
return []
return [value]
def collect_dependency_errors(
dependency_nodes: List[Optional["SyncNode"]],
field_names: List[str],
@@ -211,23 +219,29 @@ async def check_dependencies_for_nodes(strategy, nodes: List["SyncNode"], collec
if has_depend_fields and data_present:
for field_name, dep_node_type in strategy.config.depend_fields.items():
dep_data_id = node_data.get(field_name)
if not dep_data_id:
dep_data_values = _normalize_dependency_field_values(node_data.get(field_name))
if not dep_data_values:
continue
is_list_field = isinstance(node_data.get(field_name), list)
dep_node = collection.get_by_data_id(dep_node_type, dep_data_id)
if dep_node is None:
maybe_node_id_ref = collection.get_by_node_id(str(dep_data_id))
if maybe_node_id_ref is not None and maybe_node_id_ref.node_type == dep_node_type:
semantic_errors.append(f"依赖字段 {field_name} 使用了 node_id={dep_data_id},期望 data_id 引用")
for dep_data_id in dep_data_values:
dep_node = collection.get_by_data_id(dep_node_type, dep_data_id)
if dep_node is None:
maybe_node_id_ref = collection.get_by_node_id(str(dep_data_id))
if maybe_node_id_ref is not None and maybe_node_id_ref.node_type == dep_node_type:
semantic_errors.append(
f"依赖字段 {field_name} 使用了 node_id={dep_data_id},期望 data_id 引用"
)
if is_list_field:
continue
depend_nodes.append(dep_node)
depend_field_names.append(field_name)
depend_field_types.append(dep_node_type)
depend_field_values.append(str(dep_data_id))
depend_nodes.append(dep_node)
depend_field_names.append(field_name)
depend_field_types.append(dep_node_type)
depend_field_values.append(str(dep_data_id))
if dep_node:
depend_ids.append(dep_node.node_id)
if dep_node:
depend_ids.append(dep_node.node_id)
node.depend_ids = depend_ids