certflow.services.model_param_mapping_service 源代码

"""型号参数对照表服务

收口 ModelParamMapping 的 ORM 类与 CRUD 逻辑,供控制器层(Controller)调用,
消除控制器直接依赖 ``certflow.models.*`` 的跨层边。视图(View)只经控制器门面
访问,不直接触碰本服务或模型层。

架构层次:View → Controller (ModelParamMappingController)
         → Service (ModelParamMappingService) → Model (ModelParamMapping)
"""

from __future__ import annotations

from typing import Any

from sqlalchemy.orm import Session

from certflow.models.model_param_mapping import ModelParamMapping
from certflow.services.dict_csv_sync import DictCsvSync


[文档] class ModelParamMappingService: """型号参数对照表服务 — 控制器与模型之间的业务调度层。 CRUD 逻辑从原 ``ModelParamMappingController`` 下沉至此,控制器仅做事务提交。 """ # CSV 列序 / 类型 / 唯一键(与 dictionaries.yaml 的 model_param_mappings 段一致) CSV_COLUMNS = [ "product_model", "pressure_value", "test_standard", "working_temp", "working_medium", ] CSV_FIELD_TYPES = { "product_model": "text", "pressure_value": "text", "test_standard": "text", "working_temp": "text", "working_medium": "text", } CSV_UNIQUE_KEYS = ["product_model"] def __init__(self, session: Session) -> None: """初始化服务;绑定数据库会话。 Args: session: SQLAlchemy 会话(通常由 BaseController.get_service 注入)。 """ self.session = session self._csv_sync = DictCsvSync( ModelParamMapping, csv_columns=self.CSV_COLUMNS, field_types=self.CSV_FIELD_TYPES, unique_keys=self.CSV_UNIQUE_KEYS, )
[文档] def list_all(self) -> list[ModelParamMapping]: """返回全部型号参数对照记录(按 id 升序)。""" return self.session.query(ModelParamMapping).order_by(ModelParamMapping.id).all()
[文档] def get_by_id(self, mapping_id: int) -> ModelParamMapping | None: """按主键获取记录。""" return self.session.get(ModelParamMapping, mapping_id)
[文档] def get_by_model(self, product_model: str) -> ModelParamMapping | None: """按产品型号查询对照记录。""" return self.session.query(ModelParamMapping).filter_by(product_model=product_model).first()
[文档] def create(self, data: dict[str, Any]) -> ModelParamMapping: """新增记录(不提交,交由控制器统一 commit)。""" obj = ModelParamMapping(**data) self.session.add(obj) self.session.flush() return obj
[文档] def update(self, mapping_id: int, data: dict[str, Any]) -> ModelParamMapping | None: """更新记录(不提交);id 不存在返回 None。""" obj = self.session.get(ModelParamMapping, mapping_id) if obj is None: return None for key, value in data.items(): setattr(obj, key, value) return obj
[文档] def delete(self, mapping_id: int) -> bool: """删除记录(不提交);id 不存在返回 False。""" obj = self.session.get(ModelParamMapping, mapping_id) if obj is None: return False self.session.delete(obj) return True
[文档] def seed_common_models(self) -> int: """幂等灌入常见型号→压力示例,库非空则跳过(不破坏已有数据)。""" if self.session.query(ModelParamMapping).first() is not None: return 0 samples = [ ("Z41H-16C", "1.6MPa", "GB/T 13927-2008", "≤200℃", "水、蒸汽", "manual"), ("Z41H-25C", "2.5MPa", "GB/T 13927-2008", "≤425℃", "水、蒸汽", "manual"), ("Z41H-40C", "4.0MPa", "GB/T 13927-2008", "≤425℃", "水、蒸汽", "manual"), ] for ( product_model, pressure_value, test_standard, working_temp, working_medium, source, ) in samples: self.session.add( ModelParamMapping( product_model=product_model, pressure_value=pressure_value, test_standard=test_standard, working_temp=working_temp, working_medium=working_medium, source=source, usage_count=0, ) ) return len(samples)
[文档] def upsert_for_learnback( self, product_model: str, updates: dict[str, str], strategy: str = "conservative", overwrite_manual: bool = False, ) -> None: """打印成功后学回型号字典(保守合并语义,见 docs/PRINT_BLUEPRINT.md §2.4)。 - 不存在 → 新建 source='auto-learned',应用全部非空 updates。 - 已存在且 source=='manual' 且 overwrite_manual=False → 整条不动(人工权威)。 - 已存在且非 manual → 按策略合并。 """ obj = self.session.query(ModelParamMapping).filter_by(product_model=product_model).first() if obj is None: obj = ModelParamMapping( product_model=product_model, source="auto-learned", usage_count=0 ) self.session.add(obj) elif obj.source == "manual" and not overwrite_manual: return # 人工权威,绝不自动覆盖 if strategy == "last_write_wins": for col, val in updates.items(): if val: setattr(obj, col, val) else: # conservative / field_level:仅补缺 for col, val in updates.items(): if not val: continue cur = getattr(obj, col, None) or "" if not cur: setattr(obj, col, val) obj.usage_count = (obj.usage_count or 0) + 1 if obj.source != "manual": obj.source = "auto-learned"
[文档] def export_csv(self, path: str | Any) -> int: """把当前 model_param_mappings 表整表导出为 CSV 快照,返回行数。""" return self._csv_sync.export_csv(self.session, path)
[文档] def import_csv(self, path: str | Any) -> dict[str, int]: """把 CSV 快照 upsert 回 model_param_mappings 表,返回统计。""" return self._csv_sync.import_csv(self.session, path)
# 供控制器/其他模块从服务层间接引用模型类,避免 controller 直连 certflow.models。 __all__ = ["ModelParamMapping", "ModelParamMappingService"]