ForcePilot/backend/package/yuxi/scheduler/adapters/persistence/mappers.py

134 lines
4.7 KiB
Python
Raw Normal View History

"""ORM ↔ dataclass 映射边界。
本模块是 ``adapters/persistence`` 层负责 ORM 实例 core dataclass 转换的位置
scheduler 限界上下文无敏感字段mapper 仅做字段映射不调用 ``encrypt`` /
``decrypt`` ``external_systems/adapters/persistence/mappers.py`` 不同
设计原则见设计方案 §10
- **mapper 不调用 ORM ``to_dict`` 方法**直接读 ORM 字段构造 dataclass
原因``to_dict`` 返回的 dict 结构与 dataclass 字段不完全一致 DateTime
字段在 ``to_dict`` 中被 ``format_utc_datetime`` 格式化为字符串
- **无敏感字段**scheduler 域所有字段均为明文存储无需加解密
- **处理 None 入参**ORM 实例为 None 时返回 None避免调用方需额外判空
- **仓储层 dataclass core dataclass**``DailyStat`` / ``HandlerSummary``
仓储层与 core 层均有同名 dataclassmapper 按字段名转换
"""
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from yuxi.scheduler.core.models import (
DailyStat as DailyStatDC,
)
from yuxi.scheduler.core.models import (
HandlerSummary as HandlerSummaryDC,
)
from yuxi.scheduler.core.models import (
ScheduledTask as ScheduledTaskDC,
)
from yuxi.scheduler.core.models import (
ScheduledTaskRunLog as ScheduledTaskRunLogDC,
)
if TYPE_CHECKING:
from yuxi.storage.postgres.models_scheduler import (
ScheduledTask as ScheduledTaskORM,
)
from yuxi.storage.postgres.models_scheduler import (
ScheduledTaskRunLog as ScheduledTaskRunLogORM,
)
def orm_to_task(orm: ScheduledTaskORM | None) -> ScheduledTaskDC | None:
"""ORM → dataclass``ScheduledTask`` 字段一一映射。
DateTime 字段直接赋值core ``Any``JSON 字段直接赋值
入参为 None 时返回 None避免调用方需额外判空
"""
if orm is None:
return None
return ScheduledTaskDC(
id=orm.id,
task_id=orm.task_id,
handler_name=orm.handler_name,
owner_scope=orm.owner_scope,
owner_id=orm.owner_id,
schedule_kind=orm.schedule_kind,
cron_expression=orm.cron_expression,
run_at=orm.run_at,
tz=orm.tz,
payload=orm.payload or {},
enabled=orm.enabled,
delete_after_run=orm.delete_after_run,
block_strategy=orm.block_strategy,
stagger_seconds=orm.stagger_seconds,
consecutive_errors=orm.consecutive_errors,
status=orm.status,
last_run_at=orm.last_run_at,
next_run_at=orm.next_run_at,
last_error=orm.last_error,
created_by=orm.created_by,
updated_by=orm.updated_by,
created_at=orm.created_at,
updated_at=orm.updated_at,
is_deleted=orm.is_deleted,
deleted_at=orm.deleted_at,
)
def orm_to_run_log(orm: ScheduledTaskRunLogORM | None) -> ScheduledTaskRunLogDC | None:
"""ORM → dataclass``ScheduledTaskRunLog`` 字段一一映射。
入参为 None 时返回 None避免调用方需额外判空
"""
if orm is None:
return None
return ScheduledTaskRunLogDC(
id=orm.id,
task_id=orm.task_id,
run_id=orm.run_id,
triggered_by=orm.triggered_by,
status=orm.status,
error_message=orm.error_message,
output=orm.output,
started_at=orm.started_at,
finished_at=orm.finished_at,
created_by=orm.created_by,
updated_by=orm.updated_by,
created_at=orm.created_at,
updated_at=orm.updated_at,
is_deleted=orm.is_deleted,
deleted_at=orm.deleted_at,
)
def daily_stat_row_to_dataclass(row: Any) -> DailyStatDC:
"""仓储层 ``DailyStat`` → core ``DailyStat`` dataclass按字段名映射。
仓储层 ``DailyStat`` dataclassrow 可能是 NamedTuple dataclass 实例
统一按字段名读取并转换为 core dataclass
"""
return DailyStatDC(
stat_date=row.stat_date,
handler_name=row.handler_name,
success_count=int(row.success_count),
failure_count=int(row.failure_count),
timeout_count=int(row.timeout_count),
dead_letter_count=int(row.dead_letter_count),
)
def handler_summary_row_to_dataclass(row: Any) -> HandlerSummaryDC:
"""仓储层 ``HandlerSummary`` → core ``HandlerSummary`` dataclass按字段名映射。
仓储层 ``HandlerSummary`` dataclassrow 可能是 NamedTuple dataclass 实例
统一按字段名读取并转换为 core dataclass
"""
return HandlerSummaryDC(
name=row.name,
task_count=int(row.task_count),
last_active_at=row.last_active_at,
)