Skip to main content

jellyflow_runtime/runtime/xyflow/apply/
mod.rs

1//! Apply helpers for XyFlow-style changes (controlled mode).
2//!
3//! In ReactFlow, consumers that keep their own node/edge state receive `NodeChange`/`EdgeChange`
4//! and apply them via helpers (`applyNodeChanges`, `applyEdgeChanges`).
5//!
6//! In Jellyflow, the authoritative representation is a `Graph` (hash maps) and undo/redo is
7//! powered by reversible `GraphTransaction`. This module provides best-effort, order-preserving
8//! application of change events to a `Graph` for controlled integrations.
9//!
10//! Use `NodeGraphStore::dispatch_changes` when an integration wants canonical transaction
11//! validation, profile middleware, undo/redo, and atomic failure semantics. These helpers
12//! intentionally keep the XyFlow-style "apply what exists, ignore what does not" contract.
13
14mod edges;
15mod nodes;
16mod ordered;
17
18use crate::runtime::xyflow::changes::{EdgeChange, NodeChange, NodeGraphChanges};
19use jellyflow_core::core::Graph;
20
21pub use ordered::{
22    XyFlowDimensionAttribute, XyFlowDimensionsSetAttributes, XyFlowEdgeChange, XyFlowEdgeElement,
23    XyFlowNodeChange, XyFlowNodeElement, apply_xyflow_edge_changes, apply_xyflow_node_changes,
24};
25
26#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
27pub struct ApplyChangesReport {
28    pub applied: usize,
29    pub ignored: usize,
30}
31
32impl ApplyChangesReport {
33    pub fn did_change(&self) -> bool {
34        self.applied > 0
35    }
36
37    pub fn applied(&self) -> usize {
38        self.applied
39    }
40
41    pub fn ignored(&self) -> usize {
42        self.ignored
43    }
44
45    pub(crate) fn mark_applied(&mut self) {
46        self.applied += 1;
47    }
48
49    pub(crate) fn mark_ignored(&mut self) {
50        self.ignored += 1;
51    }
52}
53
54pub fn apply_graph_changes(graph: &mut Graph, changes: &NodeGraphChanges) -> ApplyChangesReport {
55    ApplyChangesPlanner::new(graph).apply_graph_changes(changes)
56}
57
58pub fn apply_node_changes(graph: &mut Graph, changes: &[NodeChange]) -> ApplyChangesReport {
59    ApplyChangesPlanner::new(graph).apply_node_changes(changes)
60}
61
62pub fn apply_edge_changes(graph: &mut Graph, changes: &[EdgeChange]) -> ApplyChangesReport {
63    ApplyChangesPlanner::new(graph).apply_edge_changes(changes)
64}
65
66struct ApplyChangesPlanner<'a> {
67    graph: &'a mut Graph,
68    report: ApplyChangesReport,
69}
70
71impl<'a> ApplyChangesPlanner<'a> {
72    fn new(graph: &'a mut Graph) -> Self {
73        Self {
74            graph,
75            report: ApplyChangesReport::default(),
76        }
77    }
78
79    fn apply_graph_changes(mut self, changes: &NodeGraphChanges) -> ApplyChangesReport {
80        self.apply_nodes(changes.nodes());
81        self.apply_edges(changes.edges());
82        self.finish()
83    }
84
85    fn apply_node_changes(mut self, changes: &[NodeChange]) -> ApplyChangesReport {
86        self.apply_nodes(changes);
87        self.finish()
88    }
89
90    fn apply_edge_changes(mut self, changes: &[EdgeChange]) -> ApplyChangesReport {
91        self.apply_edges(changes);
92        self.finish()
93    }
94
95    fn finish(self) -> ApplyChangesReport {
96        self.report
97    }
98
99    fn mark_applied(&mut self) {
100        self.report.mark_applied();
101    }
102
103    fn mark_ignored(&mut self) {
104        self.report.mark_ignored();
105    }
106}