83 lines
3 KiB
Python
83 lines
3 KiB
Python
# Copyright (c) 2025 Patrick Motsch
|
|
"""
|
|
Graph helpers for Pick-not-Push: materialize connectionReference as explicit DataRefs.
|
|
|
|
Runtime: executeGraph deep-copies the version graph and applies materialize_connection_refs
|
|
so downstream nodes resolve connection UUIDs from upstream output.connection.id.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import copy
|
|
import logging
|
|
from typing import Any, Dict, List
|
|
|
|
from modules.features.graphicalEditor.nodeDefinitions import STATIC_NODE_TYPES
|
|
from modules.features.graphicalEditor.portTypes import resolve_output_schema_name
|
|
from modules.workflows.automation2.graphUtils import buildConnectionMap, getInputSources
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
_NODE_DEF_BY_ID = {n["id"]: n for n in STATIC_NODE_TYPES}
|
|
|
|
_SCHEMAS_WITH_CONNECTION = frozenset(
|
|
{"FileList", "DocumentList", "EmailList", "TaskList", "EmailDraft", "UdmDocument"},
|
|
)
|
|
|
|
|
|
def _data_ref(node_id: str, path: List[Any]) -> Dict[str, Any]:
|
|
return {"type": "ref", "nodeId": node_id, "path": list(path)}
|
|
|
|
|
|
def materializeConnectionRefs(graph: Dict[str, Any]) -> Dict[str, Any]:
|
|
"""
|
|
Deep-copy graph and set empty connectionReference (userConnection params) to
|
|
DataRef { nodeId: upstreamPort0, path: ['connection','id'] } when upstream
|
|
output schema carries connection provenance.
|
|
"""
|
|
g = copy.deepcopy(graph)
|
|
nodes: List[Dict[str, Any]] = g.get("nodes") or []
|
|
connections = g.get("connections") or []
|
|
if not nodes:
|
|
return g
|
|
|
|
conn_map = buildConnectionMap(connections)
|
|
node_by_id = {n["id"]: n for n in nodes if n.get("id")}
|
|
|
|
for node in nodes:
|
|
nid = node.get("id")
|
|
ntype = node.get("type")
|
|
if not nid or not ntype:
|
|
continue
|
|
node_def = _NODE_DEF_BY_ID.get(ntype)
|
|
if not node_def:
|
|
continue
|
|
pdefs = node_def.get("parameters") or []
|
|
has_conn = any(
|
|
p.get("name") == "connectionReference" and p.get("frontendType") == "userConnection"
|
|
for p in pdefs
|
|
)
|
|
if not has_conn:
|
|
continue
|
|
params = node.get("parameters")
|
|
if not isinstance(params, dict):
|
|
node["parameters"] = {}
|
|
params = node["parameters"]
|
|
cur = params.get("connectionReference")
|
|
if cur not in (None, "", {}):
|
|
continue
|
|
input_sources = getInputSources(nid, conn_map)
|
|
if 0 not in input_sources:
|
|
continue
|
|
src_id, _ = input_sources[0]
|
|
src_node = node_by_id.get(src_id) or {}
|
|
src_def = _NODE_DEF_BY_ID.get(src_node.get("type") or "")
|
|
if not src_def:
|
|
continue
|
|
out_port = (src_def.get("outputPorts") or {}).get(0, {}) or {}
|
|
out_schema = resolve_output_schema_name(src_node, out_port if isinstance(out_port, dict) else {})
|
|
if out_schema not in _SCHEMAS_WITH_CONNECTION:
|
|
continue
|
|
params["connectionReference"] = _data_ref(src_id, ["connection", "id"])
|
|
logger.debug("materializeConnectionRefs: %s.connectionReference -> ref %s.connection.id", nid, src_id)
|
|
|
|
return g
|