修改多个问题,优化代码结构

This commit is contained in:
strepsiades
2026-04-01 16:23:43 +08:00
parent 8f4727a772
commit 7c49df94fc
29 changed files with 968 additions and 504 deletions
@@ -1,9 +1,18 @@
from pydantic import BaseModel, Field
from ...common.sync_node import SyncNode
from ...sync_system.strategy import DefaultSyncStrategy
from ...sync_system.config import StrategyConfig, OrphanAction, UpdateDirection
from ...sync_system.strategy_ops.compare_ops import build_data_id_normalization_map
from ...sync_system.strategy_ops.update_ops import emit_schema_diff_report, _build_schema_diff_validator
from ...sync_system.strategy_ops.bind_ops import (
apply_auto_bind_updates,
collect_auto_bind_ready_nodes,
collect_bind_entry_nodes,
plan_auto_bind_updates,
phase_core_state,
phase_dependency_check,
refresh_bind_data_id,
)
from ...sync_system.strategy_ops import BoundNodePair
from schemas.project_extensions.project_detail import ProjectDetailKey, ProjectDetailProject
@@ -37,45 +46,108 @@ class ProjectDetailSyncStrategy(DefaultSyncStrategy[ProjectDetailProject]):
update_direction=UpdateDirection.PUSH,
)
async def update(self):
self.ensure_runtime()
validator = _build_schema_diff_validator(self)
self._active_schema_diff_validator = validator
data_id_map = await build_data_id_normalization_map(
async def bind(self) -> None:
runtime = self.ensure_runtime()
local_nodes, remote_nodes = collect_bind_entry_nodes(
node_type=self.node_type,
local_collection=self.local_collection,
remote_collection=self.remote_collection,
)
await phase_core_state(
node_type=self.node_type,
runtime=runtime,
binding_manager=self.binding_manager,
local_nodes=local_nodes,
remote_nodes=remote_nodes,
)
await phase_dependency_check(
node_type=self.node_type,
runtime=runtime,
depend_fields=dict(self.config.depend_fields),
local_nodes=local_nodes,
remote_nodes=remote_nodes,
local_collection=self.local_collection,
remote_collection=self.remote_collection,
)
local_nodes, remote_nodes = collect_auto_bind_ready_nodes(
node_type=self.node_type,
local_collection=self.local_collection,
remote_collection=self.remote_collection,
)
local_create_enabled = self.config.local_orphan_action == OrphanAction.CREATE_REMOTE
remote_create_enabled = self.config.remote_orphan_action == OrphanAction.CREATE_LOCAL
local_orphan_create_enabled_by_node = {
node.node_id: local_create_enabled for node in local_nodes
}
remote_orphan_create_enabled_by_node = {
node.node_id: remote_create_enabled for node in remote_nodes
}
if self.domain_option.pull_group_production_plans:
for node in local_nodes:
if self._extract_node_key(node) in self._GROUP_PRODUCTION_PLAN_KEYS:
local_orphan_create_enabled_by_node[node.node_id] = False
for node in remote_nodes:
if self._extract_node_key(node) in self._GROUP_PRODUCTION_PLAN_KEYS:
remote_orphan_create_enabled_by_node[node.node_id] = True
pending_updates = await plan_auto_bind_updates(
node_type=self.node_type,
config=self.config,
local_collection=self.local_collection,
remote_collection=self.remote_collection,
binding_manager=self.binding_manager,
local_nodes=local_nodes,
remote_nodes=remote_nodes,
id_field_hints=dict(self.config.depend_fields),
local_orphan_create_enabled_by_node=local_orphan_create_enabled_by_node,
remote_orphan_create_enabled_by_node=remote_orphan_create_enabled_by_node,
)
await apply_auto_bind_updates(
node_type=self.node_type,
runtime=runtime,
binding_manager=self.binding_manager,
pending_auto_bind_updates=pending_updates,
)
await refresh_bind_data_id(
node_type=self.node_type,
local_collection=self.local_collection,
remote_collection=self.remote_collection,
binding_manager=self.binding_manager,
)
async def process_update_pairs(
self,
pairs: list[BoundNodePair],
data_id_map: dict[str, str] | None = None,
) -> dict[str, SyncNode]:
pull_keys = self._GROUP_PRODUCTION_PLAN_KEYS if self.domain_option.pull_group_production_plans else set()
pull_pairs = []
generic_pairs = []
for pair in await self.collect_update_pairs():
if self._should_pull_pair(pair.local_node, pair.remote_node):
for pair in pairs:
pair_key = self._extract_pair_key(pair.local_node, pair.remote_node)
if pair_key in pull_keys:
pull_pairs.append(pair)
else:
generic_pairs.append(pair)
updated_by_id = {}
try:
for pair in pull_pairs:
updated_node = await self.prepare_update_for_direction(
pair.local_node,
pair.remote_node,
UpdateDirection.PULL,
data_id_map,
)
if updated_node is not None:
updated_by_id[updated_node.node_id] = updated_node
updated_by_id: dict[str, SyncNode] = {}
for pair in pull_pairs:
updated_node = await self.prepare_update_for_direction(
pair.local_node,
pair.remote_node,
UpdateDirection.PULL,
data_id_map,
)
if updated_node is not None:
updated_by_id[updated_node.node_id] = updated_node
for pair in generic_pairs:
for updated_node in await self.update_pair(pair.local_node, pair.remote_node, data_id_map):
updated_by_id[updated_node.node_id] = updated_node
finally:
self._active_schema_diff_validator = None
for pair in generic_pairs:
for updated_node in await self.update_pair(pair.local_node, pair.remote_node, data_id_map):
updated_by_id[updated_node.node_id] = updated_node
emit_schema_diff_report(self, validator)
return list(updated_by_id.values())
return updated_by_id
@property
def domain_option(self) -> ProjectDetailDomainOption:
@@ -129,6 +201,16 @@ class ProjectDetailSyncStrategy(DefaultSyncStrategy[ProjectDetailProject]):
return items
@staticmethod
def _extract_node_key(node: SyncNode) -> str | None:
data = node.get_data() or {}
key = data.get("key")
if isinstance(key, ProjectDetailKey):
return key.value
if isinstance(key, str):
return key
return None
@staticmethod
def _extract_pair_key(local_node, remote_node) -> str | None:
local_data = local_node.get_data() or {}
@@ -141,7 +223,3 @@ class ProjectDetailSyncStrategy(DefaultSyncStrategy[ProjectDetailProject]):
return key
return None
def _should_pull_pair(self, local_node, remote_node) -> bool:
if not self.domain_option.pull_group_production_plans:
return False
return self._extract_pair_key(local_node, remote_node) in self._GROUP_PRODUCTION_PLAN_KEYS