优化sync_system代码质量

This commit is contained in:
strepsiades
2026-04-01 11:52:57 +08:00
parent eb02fd32a5
commit 8f4727a772
46 changed files with 1431 additions and 890 deletions
@@ -1,8 +1,16 @@
from pydantic import BaseModel, Field
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 schemas.project_extensions.project_detail import ProjectDetailKey, ProjectDetailProject
class ProjectDetailDomainOption(BaseModel):
pull_group_production_plans: bool = Field(True, description="固定将集团保供/爬坡/挑战产能计划按 pull 处理")
class ProjectDetailSyncStrategy(DefaultSyncStrategy[ProjectDetailProject]):
"""
ProjectDetail 同步策略(项目容量信息)。
@@ -13,6 +21,12 @@ class ProjectDetailSyncStrategy(DefaultSyncStrategy[ProjectDetailProject]):
"""
schema = ProjectDetailProject
domain_option_model = ProjectDetailDomainOption
_GROUP_PRODUCTION_PLAN_KEYS = {
"ensure_production",
"climb_production",
"challenge_production",
}
default_config = StrategyConfig(
auto_bind=True,
@@ -21,16 +35,54 @@ class ProjectDetailSyncStrategy(DefaultSyncStrategy[ProjectDetailProject]):
local_orphan_action=OrphanAction.NONE,
remote_orphan_action=OrphanAction.NONE,
update_direction=UpdateDirection.PUSH,
field_direction_key="key",
field_direction_overrides={
"ensure_production": UpdateDirection.PULL,
"climb_production": UpdateDirection.PULL,
"challenge_production": UpdateDirection.PULL,
},
)
def preprocess_compare_payload(self, payload: dict) -> dict:
normalized = dict(payload or {})
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(
node_type=self.node_type,
local_collection=self.local_collection,
remote_collection=self.remote_collection,
binding_manager=self.binding_manager,
)
pull_pairs = []
generic_pairs = []
for pair in await self.collect_update_pairs():
if self._should_pull_pair(pair.local_node, pair.remote_node):
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
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
emit_schema_diff_report(self, validator)
return list(updated_by_id.values())
@property
def domain_option(self) -> ProjectDetailDomainOption:
return ProjectDetailDomainOption.model_validate(self.config.domain_option)
def normalize_compare_payload(self, data: dict | None, data_id_map=None) -> dict:
normalized = super().normalize_compare_payload(data, data_id_map)
key = normalized.get("key")
if isinstance(key, ProjectDetailKey):
key = key.value
@@ -76,3 +128,20 @@ class ProjectDetailSyncStrategy(DefaultSyncStrategy[ProjectDetailProject]):
items.append(normalized_item)
return items
@staticmethod
def _extract_pair_key(local_node, remote_node) -> str | None:
local_data = local_node.get_data() or {}
remote_data = remote_node.get_data() or {}
key = local_data.get("key", remote_data.get("key"))
if isinstance(key, ProjectDetailKey):
return key.value
if isinstance(key, str):
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