Skip to main content

jellyflow_runtime/runtime/store/history/
mod.rs

1//! Undo/redo history replay for `NodeGraphStore`.
2
3mod replay;
4
5use crate::profile::{ApplyPipelineError, GraphProfile};
6
7use self::replay::{HistoryReplayDirection, HistoryReplayPipeline};
8use super::dispatch_profile::DispatchProfile;
9use super::{DispatchError, DispatchOutcome, NodeGraphStore};
10
11impl NodeGraphStore {
12    /// Undoes the last committed transaction.
13    pub fn undo(&mut self) -> Result<Option<DispatchOutcome>, DispatchError> {
14        self.replay_history(HistoryReplayDirection::Undo, DispatchProfile::StoreProfile)
15            .map_err(DispatchError::Apply)
16    }
17
18    /// Undoes the last committed transaction using an externally-owned profile pipeline.
19    pub fn undo_with_profile(
20        &mut self,
21        profile: &mut dyn GraphProfile,
22    ) -> Result<Option<DispatchOutcome>, ApplyPipelineError> {
23        self.replay_history(
24            HistoryReplayDirection::Undo,
25            DispatchProfile::External(profile),
26        )
27    }
28
29    /// Redoes the last undone transaction.
30    pub fn redo(&mut self) -> Result<Option<DispatchOutcome>, DispatchError> {
31        self.replay_history(HistoryReplayDirection::Redo, DispatchProfile::StoreProfile)
32            .map_err(DispatchError::Apply)
33    }
34
35    /// Redoes the last undone transaction using an externally-owned profile pipeline.
36    pub fn redo_with_profile(
37        &mut self,
38        profile: &mut dyn GraphProfile,
39    ) -> Result<Option<DispatchOutcome>, ApplyPipelineError> {
40        self.replay_history(
41            HistoryReplayDirection::Redo,
42            DispatchProfile::External(profile),
43        )
44    }
45
46    fn replay_history(
47        &mut self,
48        direction: HistoryReplayDirection,
49        dispatch_profile: DispatchProfile<'_>,
50    ) -> Result<Option<DispatchOutcome>, ApplyPipelineError> {
51        let Some(replayed) = HistoryReplayPipeline::new(self, direction, dispatch_profile).run()?
52        else {
53            return Ok(None);
54        };
55
56        let patch = self.prepare_committed_graph_patch(replayed.graph, replayed.committed);
57        Ok(Some(self.complete_committed_patch(patch)))
58    }
59}