|
@@ -901,6 +901,33 @@ def _get_node_or_error(
|
|
|
return node_row
|
|
return node_row
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+def _resolve_root_node_id(
|
|
|
|
|
+ node_map: dict[str, TopologyNode], parents_by_node: dict[str, list[str]]
|
|
|
|
|
+) -> str:
|
|
|
|
|
+ root_ids = [node_id for node_id in node_map if not parents_by_node.get(node_id)]
|
|
|
|
|
+ if not root_ids:
|
|
|
|
|
+ raise ValueError("root node not found in cache")
|
|
|
|
|
+ root_ids.sort(
|
|
|
|
|
+ key=lambda item: (
|
|
|
|
|
+ node_map[item].level if node_map[item].level is not None else 10**9,
|
|
|
|
|
+ node_map[item].path_text or node_map[item].node_name,
|
|
|
|
|
+ item,
|
|
|
|
|
+ )
|
|
|
|
|
+ )
|
|
|
|
|
+ return root_ids[0]
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def _normalize_requested_node_id(
|
|
|
|
|
+ raw_node_id: str,
|
|
|
|
|
+ node_map: dict[str, TopologyNode],
|
|
|
|
|
+ parents_by_node: dict[str, list[str]],
|
|
|
|
|
+) -> str:
|
|
|
|
|
+ normalized = _text(raw_node_id)
|
|
|
|
|
+ if normalized.lower() != "root":
|
|
|
|
|
+ return normalized
|
|
|
|
|
+ return _resolve_root_node_id(node_map, parents_by_node)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
def _node_payload(node_row: TopologyNode) -> dict[str, Any]:
|
|
def _node_payload(node_row: TopologyNode) -> dict[str, Any]:
|
|
|
return {
|
|
return {
|
|
|
"node_id": node_row.node_id,
|
|
"node_id": node_row.node_id,
|
|
@@ -1066,7 +1093,7 @@ def _topology_metadata_payload(
|
|
|
def get_topology_node(
|
|
def get_topology_node(
|
|
|
project_key: str,
|
|
project_key: str,
|
|
|
topology_id: int,
|
|
topology_id: int,
|
|
|
- node_id: str,
|
|
|
|
|
|
|
+ node_id: str = "root",
|
|
|
*,
|
|
*,
|
|
|
include_siblings: bool = True,
|
|
include_siblings: bool = True,
|
|
|
include_children: bool = True,
|
|
include_children: bool = True,
|
|
@@ -1084,20 +1111,25 @@ def get_topology_node(
|
|
|
group_rows = _load_group_rows(session, project_key)
|
|
group_rows = _load_group_rows(session, project_key)
|
|
|
group_path_map = _group_path_map(group_rows)
|
|
group_path_map = _group_path_map(group_rows)
|
|
|
registry_row = _get_registry_or_error(session, project_key, topology_id)
|
|
registry_row = _get_registry_or_error(session, project_key, topology_id)
|
|
|
- node_row = _get_node_or_error(session, project_key, topology_id, node_id)
|
|
|
|
|
node_map = _load_node_map(session, project_key, topology_id)
|
|
node_map = _load_node_map(session, project_key, topology_id)
|
|
|
parents_by_node, children_by_node = _load_adjacency(
|
|
parents_by_node, children_by_node = _load_adjacency(
|
|
|
session, project_key, topology_id
|
|
session, project_key, topology_id
|
|
|
)
|
|
)
|
|
|
|
|
+ resolved_node_id = _normalize_requested_node_id(
|
|
|
|
|
+ node_id, node_map, parents_by_node
|
|
|
|
|
+ )
|
|
|
|
|
+ node_row = _get_node_or_error(
|
|
|
|
|
+ session, project_key, topology_id, resolved_node_id
|
|
|
|
|
+ )
|
|
|
|
|
|
|
|
- parent_ids = parents_by_node.get(node_id, [])
|
|
|
|
|
- child_ids = children_by_node.get(node_id, []) if include_children else []
|
|
|
|
|
|
|
+ parent_ids = parents_by_node.get(resolved_node_id, [])
|
|
|
|
|
+ child_ids = children_by_node.get(resolved_node_id, []) if include_children else []
|
|
|
sibling_ids: list[str] = []
|
|
sibling_ids: list[str] = []
|
|
|
if include_siblings and len(parent_ids) == 1:
|
|
if include_siblings and len(parent_ids) == 1:
|
|
|
sibling_ids = [
|
|
sibling_ids = [
|
|
|
candidate
|
|
candidate
|
|
|
for candidate in children_by_node.get(parent_ids[0], [])
|
|
for candidate in children_by_node.get(parent_ids[0], [])
|
|
|
- if candidate != node_id
|
|
|
|
|
|
|
+ if candidate != resolved_node_id
|
|
|
]
|
|
]
|
|
|
|
|
|
|
|
return {
|
|
return {
|