1use std::sync::Arc;
2
3use moduforge_model::{
4 node_type::NodeEnum, schema::Schema, tree::Tree, types::NodeId,
5};
6
7use crate::transform_error;
8
9use super::{
10 step::{Step, StepResult},
11 TransformResult,
12};
13use serde::{Deserialize, Serialize};
14#[derive(Debug, Serialize, Deserialize, Clone)]
16pub struct AddNodeStep {
17 parent_id: NodeId,
18 nodes: Vec<NodeEnum>,
19}
20impl AddNodeStep {
21 pub fn new(
22 parent_id: NodeId,
23 nodes: Vec<NodeEnum>,
24 ) -> Self {
25 AddNodeStep { parent_id, nodes }
26 }
27}
28impl Step for AddNodeStep {
29 fn name(&self) -> String {
30 "add_node_step".to_string()
31 }
32 fn apply(
33 &self,
34 dart: &mut Tree,
35 schema: Arc<Schema>,
36 ) -> TransformResult<StepResult> {
37 let _ = schema;
38 let result = dart.add(&self.parent_id, self.nodes.clone());
39 match result {
40 Ok(_) => Ok(StepResult::ok()),
41 Err(e) => Err(transform_error(e.to_string())),
42 }
43 }
44 fn serialize(&self) -> Option<Vec<u8>> {
45 serde_json::to_vec(self).ok()
46 }
47
48 fn invert(
49 &self,
50 _: &Arc<Tree>,
51 ) -> Option<Arc<dyn Step>> {
52 fn collect_node_ids(node_enum: &NodeEnum) -> Vec<NodeId> {
54 let mut ids: Vec<String> = vec![node_enum.0.id.clone()];
55 for child in &node_enum.1 {
56 ids.extend(collect_node_ids(child));
57 }
58 ids
59 }
60
61 let mut all_node_ids = Vec::new();
63 for node_enum in &self.nodes {
64 all_node_ids.extend(collect_node_ids(node_enum));
65 }
66
67 if !all_node_ids.is_empty() {
68 return Some(Arc::new(RemoveNodeStep::new(
69 self.parent_id.clone(),
70 all_node_ids,
71 )));
72 }
73 None
74 }
75}
76#[derive(Debug, Serialize, Deserialize, Clone)]
78pub struct RemoveNodeStep {
79 parent_id: NodeId,
80 node_ids: Vec<NodeId>,
81}
82impl RemoveNodeStep {
83 pub fn new(
84 parent_id: NodeId,
85 node_ids: Vec<NodeId>,
86 ) -> Self {
87 RemoveNodeStep { parent_id, node_ids }
88 }
89}
90impl Step for RemoveNodeStep {
91 fn name(&self) -> String {
92 "remove_node_step".to_string()
93 }
94 fn apply(
95 &self,
96 dart: &mut Tree,
97 schema: Arc<Schema>,
98 ) -> TransformResult<StepResult> {
99 let _ = schema;
100 let result = dart.remove_node(&self.parent_id, self.node_ids.clone());
101 match result {
102 Ok(_) => Ok(StepResult::ok()),
103 Err(e) => Err(transform_error(e.to_string())), }
105 }
106 fn serialize(&self) -> Option<Vec<u8>> {
107 serde_json::to_vec(self).ok()
108 }
109
110 fn invert(
111 &self,
112 dart: &Arc<Tree>,
113 ) -> Option<Arc<dyn Step>> {
114 let mut nodes_to_restore = Vec::new();
116
117 for node_id in &self.node_ids {
118 if let Some(node_enum) = dart.all_children(node_id, None) {
119 nodes_to_restore.push(node_enum);
120 }
121 }
122
123 if !nodes_to_restore.is_empty() {
124 Some(Arc::new(AddNodeStep::new(
125 self.parent_id.clone(),
126 nodes_to_restore,
127 )))
128 } else {
129 None
130 }
131 }
132}
133
134#[derive(Debug, Serialize, Deserialize, Clone)]
135pub struct MoveNodeStep {
136 source_parent_id: NodeId,
137 target_parent_id: NodeId,
138 node_id: NodeId,
139 position: Option<usize>, }
141
142impl MoveNodeStep {
143 pub fn new(
144 source_parent_id: NodeId,
145 target_parent_id: NodeId,
146 node_id: NodeId,
147 position: Option<usize>,
148 ) -> Self {
149 MoveNodeStep { source_parent_id, target_parent_id, node_id, position }
150 }
151}
152
153impl Step for MoveNodeStep {
154 fn name(&self) -> String {
155 "move_node_step".to_string()
156 }
157 fn apply(
158 &self,
159 dart: &mut Tree,
160 schema: Arc<Schema>,
161 ) -> TransformResult<StepResult> {
162 let _ = schema;
163
164 match dart.move_node(
165 &self.source_parent_id,
166 &self.target_parent_id,
167 &self.node_id,
168 self.position,
169 ) {
170 Ok(()) => Ok(StepResult::ok()),
171 Err(err) => Err(transform_error(err.to_string())),
172 }
173 }
174 fn serialize(&self) -> Option<Vec<u8>> {
175 serde_json::to_vec(self).ok()
176 }
177
178 fn invert(
179 &self,
180 dart: &Arc<Tree>,
181 ) -> Option<Arc<dyn Step>> {
182 match dart.get_node(&self.node_id) {
183 Some(_) => Some(Arc::new(MoveNodeStep::new(
184 self.target_parent_id.clone(),
185 self.source_parent_id.clone(),
186 self.node_id.clone(),
187 self.position,
188 ))),
189 None => None,
190 }
191 }
192}
193
194#[cfg(test)]
195mod tests {
196 use super::*;
197 use moduforge_model::{
198 node::Node,
199 node_type::{NodeEnum, NodeType, NodeSpec},
200 schema::{Schema, SchemaSpec, AttributeSpec},
201 tree::Tree,
202 attrs::Attrs,
203 mark::Mark,
204 };
205 use std::collections::HashMap;
206 use std::sync::Arc;
207
208 fn create_test_node(id: &str) -> Node {
209 Node::new(id, "test".to_string(), Attrs::default(), vec![], vec![])
210 }
211
212 fn create_test_schema() -> Arc<Schema> {
213 let mut nodes = HashMap::new();
214 nodes.insert(
215 "test".to_string(),
216 NodeSpec {
217 content: None,
218 marks: None,
219 group: None,
220 desc: Some("Test node".to_string()),
221 attrs: None,
222 },
223 );
224
225 let spec = SchemaSpec {
226 nodes,
227 marks: HashMap::new(),
228 top_node: Some("test".to_string()),
229 };
230
231 Arc::new(Schema::compile(spec).unwrap())
232 }
233
234 fn create_test_tree() -> Tree {
235 let root = create_test_node("root");
236 Tree::new(root)
237 }
238
239 #[test]
240 fn test_add_node_step() {
241 let mut tree = create_test_tree();
242 let schema = create_test_schema();
243
244 let node = create_test_node("root");
246 let test = create_test_node("test");
247 let node_enum = NodeEnum(node, vec![NodeEnum(test, vec![])]);
248 let step =
249 AddNodeStep::new("root".to_string(), vec![node_enum.clone()]);
250 let result = step.apply(&mut tree, schema.clone());
251 assert!(result.is_ok());
252
253 assert!(tree.get_node(&"test".to_string()).is_some());
255
256 let inverted = step.invert(&Arc::new(tree.clone()));
258 assert!(inverted.is_some());
259
260 if let Some(inverted_step) = inverted {
262 let result = inverted_step.apply(&mut tree, schema);
263 assert!(result.is_ok());
264 assert!(tree.get_node(&"test".to_string()).is_none());
266 }
267 }
268
269 #[test]
270 fn test_remove_node_step() {
271 let mut tree = create_test_tree();
272 let schema = create_test_schema();
273
274 let node = create_test_node("test");
276 tree.add_node(&"root".to_string(), &vec![node]).unwrap();
277
278 let step =
279 RemoveNodeStep::new("root".to_string(), vec!["test".to_string()]);
280 let result = step.apply(&mut tree, schema.clone());
281 assert!(result.is_ok());
282
283 assert!(tree.get_node(&"test".to_string()).is_none());
285
286 let inverted = step.invert(&Arc::new(tree.clone()));
288 assert!(inverted.is_some());
289 }
290
291 #[test]
292 fn test_move_node_step() {
293 let mut tree = create_test_tree();
294 let schema = create_test_schema();
295
296 let source = create_test_node("source");
298 let target = create_test_node("target");
299 let node = create_test_node("node");
300
301 tree.add_node(&"root".to_string(), &vec![source]).unwrap();
302 tree.add_node(&"root".to_string(), &vec![target]).unwrap();
303 tree.add_node(&"source".to_string(), &vec![node]).unwrap();
304
305 let step = MoveNodeStep::new(
306 "source".to_string(),
307 "target".to_string(),
308 "node".to_string(),
309 None,
310 );
311
312 let result = step.apply(&mut tree, schema.clone());
313 assert!(result.is_ok());
314
315 let target_node = tree.get_node(&"target".to_string()).unwrap();
317 assert!(target_node.content.contains(&"node".to_string()));
318
319 let inverted = step.invert(&Arc::new(tree.clone()));
321 assert!(inverted.is_some());
322 }
323}