moduforge_core/state/
transaction.rs1use std::sync::Arc;
2use std::time::{SystemTime, UNIX_EPOCH};
3
4use async_trait::async_trait;
5
6use super::state::State;
7use crate::model::node::Node;
8use crate::model::node_pool::{Draft, NodePool};
9use crate::model::patch::Patch;
10use crate::model::schema::Schema;
11use crate::transform::attr_step::AttrStep;
12use crate::transform::node_step::AddNodeStep;
13use crate::transform::step::{Step, StepResult};
14use crate::transform::transform::{Transform, TransformError};
15use crate::transform::{ConcreteStep, PatchStep};
16use std::fmt::Debug;
17
18#[async_trait]
21pub trait Command: Send + Sync + Debug {
22 async fn execute(
23 &self,
24 tr: &mut Transaction,
25 ) -> Result<(), TransformError>;
26 fn name(&self) -> String;
27}
28
29#[derive(Debug, Clone)]
31pub struct Transaction {
32 pub meta: im::HashMap<String, Arc<dyn std::any::Any>>,
34 pub id: u64,
36 pub steps: im::Vector<Arc<dyn Step>>,
38 pub patches: im::Vector<Vec<Patch>>,
40 pub doc: Arc<NodePool>,
42 pub draft: Draft,
44 pub schema: Arc<Schema>,
46}
47unsafe impl Send for Transaction {}
48unsafe impl Sync for Transaction {}
49
50impl Transform for Transaction {
51 fn step(
55 &mut self,
56 step: Arc<dyn Step>,
57 ) -> Result<(), TransformError> {
58 let result = step.apply(&mut self.draft, self.schema.clone())?;
59 match result.failed {
60 Some(message) => Err(TransformError::new(message)),
61 None => {
62 self.add_step(step, result);
63 Ok(())
64 },
65 }
66 }
67 fn doc_changed(&self) -> bool {
69 !self.steps.is_empty()
70 }
71 fn add_step(
73 &mut self,
74 step: Arc<dyn Step>,
75 result: StepResult,
76 ) {
77 self.steps.push_back(step);
78 self.patches.push_back(result.patches);
79 self.doc = result.doc.unwrap();
80 }
81}
82impl Transaction {
83 pub async fn transaction(
86 &mut self,
87 call_back: Arc<dyn Command>,
88 ) {
89 self.draft.begin = true;
90 let result = call_back.execute(self).await;
91 self.draft.begin = false;
92 if result.is_ok() {
93 let result = self.draft.commit();
94 self.add_step(Arc::new(PatchStep { patches: result.patches.clone() }), result);
95 }
96 }
97 pub fn new(state: &State) -> Self {
101 let now: u64 = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_nanos() as u64;
102
103 let node = state.doc();
104 Transaction {
105 meta: im::HashMap::new(),
106 id: now,
107 steps: im::Vector::new(),
108 doc: node,
109 schema: state.schema(),
110 draft: Draft::new(state.doc()),
111 patches: im::Vector::new(),
112 }
113 }
114 pub fn doc(&self) -> Arc<NodePool> {
116 self.doc.clone()
117 }
118 pub fn as_concrete(step: &Arc<dyn Step>) -> ConcreteStep {
120 step.to_concrete()
121 }
122 pub fn set_node_attribute(
126 &mut self,
127 id: String,
128 values: im::HashMap<String, String>,
129 ) {
130 let _ = self.step(Arc::new(AttrStep::new(id, values)));
131 }
132 pub fn add_node(
136 &mut self,
137 parent_id: String,
138 node: Node,
139 ) {
140 let _ = self.step(Arc::new(AddNodeStep::new(parent_id, node)));
141 }
142 pub fn set_time(
144 &mut self,
145 id: u64,
146 ) -> &mut Self {
147 self.id = id;
148 self
149 }
150 pub fn set_meta<K, T: std::any::Any>(
154 &mut self,
155 key: K,
156 value: T,
157 ) -> &mut Self
158 where
159 K: Into<String>,
160 {
161 let key_str = key.into();
162 self.meta.insert(key_str, Arc::new(value));
163 self
164 }
165 pub fn get_meta<T: 'static, K>(
169 &self,
170 key: K,
171 ) -> Option<&T>
172 where
173 K: Into<String>,
174 {
175 let key_str = key.into();
176 self.meta.get(&key_str)?.downcast_ref::<T>()
177 }
178}