from __future__ import annotations from dataclasses import dataclass from sapcli.exceptions import InvalidNameError @dataclass(frozen=True) class ObjectTypeConfig: key: str label: str obj_uri_template: str src_uri_template: str | None collection_uri: str create_content_type: str has_source: bool = True def format_obj_uri(self, name: str, **kwargs: str) -> str: return self.obj_uri_template.format(name=name, **kwargs) def format_src_uri(self, name: str, **kwargs: str) -> str | None: if self.src_uri_template is None: return None return self.src_uri_template.format(name=name, **kwargs) def format_collection_uri(self, **kwargs: str) -> str: return self.collection_uri.format(**kwargs) _OBJECT_TYPE_REGISTRY: dict[str, ObjectTypeConfig] = {} def _register(cfg: ObjectTypeConfig) -> ObjectTypeConfig: _OBJECT_TYPE_REGISTRY[cfg.key] = cfg return cfg REPORT = _register(ObjectTypeConfig( key="report", label="程序(REPORT)", obj_uri_template="/sap/bc/adt/programs/programs/{name}", src_uri_template="/sap/bc/adt/programs/programs/{name}/source/main", collection_uri="/sap/bc/adt/programs/programs", create_content_type="application/vnd.sap.adt.programs.programs.v2+xml", )) CLASS = _register(ObjectTypeConfig( key="class", label="类(CLASS)", obj_uri_template="/sap/bc/adt/oo/classes/{name}", src_uri_template="/sap/bc/adt/oo/classes/{name}/source/main", collection_uri="/sap/bc/adt/oo/classes", create_content_type="application/vnd.sap.adt.oo.classes.v1+xml", )) FUNCTION = _register(ObjectTypeConfig( key="function", label="函数模块(FUNCTION)", obj_uri_template="/sap/bc/adt/functions/groups/{group}/fmodules/{name}", src_uri_template="/sap/bc/adt/functions/groups/{group}/fmodules/{name}/source/main", collection_uri="/sap/bc/adt/functions/groups/{group}/fmodules", create_content_type="application/vnd.sap.adt.functions.fmodules.v1+xml", )) FUNCTIONGROUP = _register(ObjectTypeConfig( key="functiongroup", label="函数组(FUNCTION GROUP)", obj_uri_template="/sap/bc/adt/functions/groups/{name}", src_uri_template=None, collection_uri="/sap/bc/adt/functions/groups", create_content_type="application/vnd.sap.adt.functions.groups.v2+xml", has_source=False, )) INTERFACE = _register(ObjectTypeConfig( key="interface", label="接口(INTERFACE)", obj_uri_template="/sap/bc/adt/oo/interfaces/{name}", src_uri_template="/sap/bc/adt/oo/interfaces/{name}/source/main", collection_uri="/sap/bc/adt/oo/interfaces", create_content_type="application/vnd.sap.adt.oo.interfaces.v1+xml", )) DOMAIN = _register(ObjectTypeConfig( key="domain", label="域(DOMAIN)", obj_uri_template="/sap/bc/adt/ddic/domains/{name}", src_uri_template="/sap/bc/adt/ddic/domains/{name}/source/main", collection_uri="/sap/bc/adt/ddic/domains", create_content_type="application/vnd.sap.adt.domains.v2+xml", )) DATAELEMENT = _register(ObjectTypeConfig( key="dataelement", label="数据元素(DATA ELEMENT)", obj_uri_template="/sap/bc/adt/ddic/dataelements/{name}", src_uri_template="/sap/bc/adt/ddic/dataelements/{name}/source/main", collection_uri="/sap/bc/adt/ddic/dataelements", create_content_type="application/vnd.sap.adt.dataelements.v2+xml", )) TABLE = _register(ObjectTypeConfig( key="table", label="透明表(TABLE)", obj_uri_template="/sap/bc/adt/ddic/tables/{name}", src_uri_template="/sap/bc/adt/ddic/tables/{name}/source/main", collection_uri="/sap/bc/adt/ddic/tables", create_content_type="application/vnd.sap.adt.ddic.tables.v1+xml", )) STRUCTURE = _register(ObjectTypeConfig( key="structure", label="结构(STRUCTURE)", obj_uri_template="/sap/bc/adt/ddic/structures/{name}", src_uri_template="/sap/bc/adt/ddic/structures/{name}/source/main", collection_uri="/sap/bc/adt/ddic/structures", create_content_type="application/vnd.sap.adt.ddic.structures.v1+xml", )) TABLETYPE = _register(ObjectTypeConfig( key="tabletype", label="表类型(TABLE TYPE)", obj_uri_template="/sap/bc/adt/vit/wb/object_type/ttypda/object_name/{name}", src_uri_template=None, collection_uri="/sap/bc/adt/ddic/tabletypes", create_content_type="application/vnd.sap.adt.ddic.tabletypes.v1+xml", has_source=False, )) INCLUDE = _register(ObjectTypeConfig( key="include", label="Include程序(INCLUDE)", obj_uri_template="/sap/bc/adt/programs/includes/{name}", src_uri_template="/sap/bc/adt/programs/includes/{name}/source/main", collection_uri="/sap/bc/adt/programs/includes", create_content_type="application/vnd.sap.adt.programs.includes.v2+xml", )) CDSVIEW = _register(ObjectTypeConfig( key="cdsview", label="CDS视图(CDS VIEW)", obj_uri_template="/sap/bc/adt/dds/ddl/sources/{name}", src_uri_template="/sap/bc/adt/dds/ddl/sources/{name}/content", collection_uri="/sap/bc/adt/dds/ddl/sources", create_content_type="text/plain", )) MESSAGECLASS = _register(ObjectTypeConfig( key="messageclass", label="消息类(MESSAGE CLASS)", obj_uri_template="/sap/bc/adt/oo/t100/messages/classes/{name}", src_uri_template=None, collection_uri="/sap/bc/adt/oo/t100/messages/classes", create_content_type="application/vnd.sap.adt.t100.message.classes.v1+xml", has_source=False, )) VIEW = _register(ObjectTypeConfig( key="view", label="数据库视图(VIEW)", obj_uri_template="/sap/bc/adt/ddic/views/{name}", src_uri_template="/sap/bc/adt/ddic/views/{name}/source/main", collection_uri="/sap/bc/adt/ddic/views", create_content_type="application/vnd.sap.adt.ddic.views.v1+xml", )) SEARCHHELP = _register(ObjectTypeConfig( key="searchhelp", label="搜索帮助(SEARCH HELP)", obj_uri_template="/sap/bc/adt/ddic/searchhelps/{name}", src_uri_template=None, collection_uri="/sap/bc/adt/ddic/searchhelps", create_content_type="application/vnd.sap.adt.ddic.searchhelps.v1+xml", has_source=False, )) LOCKOBJECT = _register(ObjectTypeConfig( key="lockobject", label="锁对象(LOCK OBJECT)", obj_uri_template="/sap/bc/adt/ddic/lockobjects/{name}", src_uri_template=None, collection_uri="/sap/bc/adt/ddic/lockobjects", create_content_type="application/vnd.sap.adt.ddic.lockobjects.v1+xml", has_source=False, )) def get_type_config(key: str) -> ObjectTypeConfig: if key not in _OBJECT_TYPE_REGISTRY: raise ValueError(f"不支持的对象类型: {key}") return _OBJECT_TYPE_REGISTRY[key] def all_type_keys() -> list[str]: return list(_OBJECT_TYPE_REGISTRY.keys()) @dataclass(frozen=True) class ParsedName: obj_uri: str src_uri: str | None display_name: str file_base: str def parse_object_name(name: str, obj_type: str) -> ParsedName: cfg = get_type_config(obj_type) if obj_type == "function": if "/" not in name: raise InvalidNameError( "function 类型需要'函数组名/函数模块名' 格式,例如: ZGROUP/Z_MY_FUNC" ) group, fm = name.split("/", 1) group = group.strip() fm = fm.strip() if not group or not fm: raise InvalidNameError("函数组名和函数模块名不能为空") return ParsedName( obj_uri=cfg.format_obj_uri(fm.lower(), group=group.lower()), src_uri=cfg.format_src_uri(fm.lower(), group=group.lower()), display_name=name, file_base=fm.lower(), ) # VIT 端点需要大写名称以返回完整元数据;去掉前导 / if obj_type == "tabletype": clean = name.lstrip("/") name_upper = clean.upper() return ParsedName( obj_uri=cfg.format_obj_uri(name_upper), src_uri=cfg.format_src_uri(name_upper), display_name=clean, file_base=clean.lower(), ) name_lower = name.lower() return ParsedName( obj_uri=cfg.format_obj_uri(name_lower), src_uri=cfg.format_src_uri(name_lower), display_name=name, file_base=name_lower, )