mf_transform/
node_step.rs

1use std::sync::Arc;
2
3use mf_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/// 添加节点的步骤
15#[derive(Debug, Serialize, Deserialize, Clone)]
16pub struct AddNodeStep {
17    pub parent_id: NodeId,
18    pub 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    // 递归收集单个节点枚举的所有子节点 id
28    pub fn collect_node_ids(node_enum: &NodeEnum) -> Vec<NodeId> {
29        let mut ids: Vec<String> = vec![node_enum.0.id.clone()];
30        for child in &node_enum.1 {
31            ids.extend(Self::collect_node_ids(child));
32        }
33        ids
34    }
35}
36impl Step for AddNodeStep {
37    fn name(&self) -> String {
38        "add_node_step".to_string()
39    }
40    fn apply(
41        &self,
42        dart: &mut Tree,
43        schema: Arc<Schema>,
44    ) -> TransformResult<StepResult> {
45        let _ = schema;
46        let result = dart.add(&self.parent_id, self.nodes.clone());
47        match result {
48            Ok(_) => Ok(StepResult::ok()),
49            Err(e) => Err(transform_error(e.to_string())),
50        }
51    }
52    fn serialize(&self) -> Option<Vec<u8>> {
53        serde_json::to_vec(self).ok()
54    }
55
56    fn invert(
57        &self,
58        _: &Arc<Tree>,
59    ) -> Option<Arc<dyn Step>> {
60        // 收集所有节点的 id(包括顶级节点和所有子节点)
61        let mut all_node_ids = Vec::new();
62        for node_enum in &self.nodes {
63            all_node_ids.extend(Self::collect_node_ids(node_enum));
64        }
65
66        if !all_node_ids.is_empty() {
67            return Some(Arc::new(RemoveNodeStep::new(
68                self.parent_id.clone(),
69                all_node_ids,
70            )));
71        }
72        None
73    }
74}
75/// 删除节点的步骤
76#[derive(Debug, Serialize, Deserialize, Clone)]
77pub struct RemoveNodeStep {
78    pub parent_id: NodeId,
79    pub node_ids: Vec<NodeId>,
80}
81impl RemoveNodeStep {
82    pub fn new(
83        parent_id: NodeId,
84        node_ids: Vec<NodeId>,
85    ) -> Self {
86        RemoveNodeStep { parent_id, node_ids }
87    }
88}
89impl Step for RemoveNodeStep {
90    fn name(&self) -> String {
91        "remove_node_step".to_string()
92    }
93    fn apply(
94        &self,
95        dart: &mut Tree,
96        schema: Arc<Schema>,
97    ) -> TransformResult<StepResult> {
98        let _ = schema;
99        let result = dart.remove_node(&self.parent_id, self.node_ids.clone());
100        match result {
101            Ok(_) => Ok(StepResult::ok()),
102            Err(e) => Err(transform_error(e.to_string())), // 修复:失败时返回Err保持一致性
103        }
104    }
105    fn serialize(&self) -> Option<Vec<u8>> {
106        serde_json::to_vec(self).ok()
107    }
108
109    fn invert(
110        &self,
111        dart: &Arc<Tree>,
112    ) -> Option<Arc<dyn Step>> {
113        // 收集所有要删除的节点及其子树
114        let mut nodes_to_restore = Vec::new();
115
116        for node_id in &self.node_ids {
117            if let Some(node_enum) = dart.all_children(node_id, None) {
118                nodes_to_restore.push(node_enum);
119            }
120        }
121
122        if !nodes_to_restore.is_empty() {
123            Some(Arc::new(AddNodeStep::new(
124                self.parent_id.clone(),
125                nodes_to_restore,
126            )))
127        } else {
128            None
129        }
130    }
131}
132
133#[derive(Debug, Serialize, Deserialize, Clone)]
134pub struct MoveNodeStep {
135    source_parent_id: NodeId,
136    target_parent_id: NodeId,
137    node_id: NodeId,
138    position: Option<usize>, // 目标位置,None 表示追加到末尾
139}
140
141impl MoveNodeStep {
142    pub fn new(
143        source_parent_id: NodeId,
144        target_parent_id: NodeId,
145        node_id: NodeId,
146        position: Option<usize>,
147    ) -> Self {
148        MoveNodeStep { source_parent_id, target_parent_id, node_id, position }
149    }
150}
151
152impl Step for MoveNodeStep {
153    fn name(&self) -> String {
154        "move_node_step".to_string()
155    }
156    fn apply(
157        &self,
158        dart: &mut Tree,
159        schema: Arc<Schema>,
160    ) -> TransformResult<StepResult> {
161        let _ = schema;
162
163        match dart.move_node(
164            &self.source_parent_id,
165            &self.target_parent_id,
166            &self.node_id,
167            self.position,
168        ) {
169            Ok(()) => Ok(StepResult::ok()),
170            Err(err) => Err(transform_error(err.to_string())),
171        }
172    }
173    fn serialize(&self) -> Option<Vec<u8>> {
174        serde_json::to_vec(self).ok()
175    }
176
177    fn invert(
178        &self,
179        dart: &Arc<Tree>,
180    ) -> Option<Arc<dyn Step>> {
181        match dart.get_node(&self.node_id) {
182            Some(_) => Some(Arc::new(MoveNodeStep::new(
183                self.target_parent_id.clone(),
184                self.source_parent_id.clone(),
185                self.node_id.clone(),
186                self.position,
187            ))),
188            None => None,
189        }
190    }
191}
192
193#[cfg(test)]
194mod tests {
195    use super::*;
196    use mf_model::{
197        node::Node,
198        node_type::{NodeEnum, NodeType, NodeSpec},
199        schema::{Schema, SchemaSpec, AttributeSpec},
200        tree::Tree,
201        attrs::Attrs,
202        mark::Mark,
203    };
204    use std::collections::HashMap;
205    use std::sync::Arc;
206
207    fn create_test_node(id: &str) -> Node {
208        Node::new(id, "test".to_string(), Attrs::default(), vec![], vec![])
209    }
210
211    fn create_test_schema() -> Arc<Schema> {
212        let mut nodes = HashMap::new();
213        nodes.insert(
214            "test".to_string(),
215            NodeSpec {
216                content: None,
217                marks: None,
218                group: None,
219                desc: Some("Test node".to_string()),
220                attrs: None,
221            },
222        );
223
224        let spec = SchemaSpec {
225            nodes,
226            marks: HashMap::new(),
227            top_node: Some("test".to_string()),
228        };
229
230        Arc::new(Schema::compile(spec).unwrap())
231    }
232
233    fn create_test_tree() -> Tree {
234        let root = create_test_node("root");
235        Tree::new(root)
236    }
237
238    #[test]
239    fn test_add_node_step() {
240        let mut tree = create_test_tree();
241        let schema = create_test_schema();
242
243        // Create a test node to add
244        let node = create_test_node("root");
245        let test = create_test_node("test");
246        let node_enum = NodeEnum(node, vec![NodeEnum(test, vec![])]);
247        let step =
248            AddNodeStep::new("root".to_string(), vec![node_enum.clone()]);
249        let result = step.apply(&mut tree, schema.clone());
250        assert!(result.is_ok());
251
252        // Verify node was added
253        assert!(tree.get_node(&"test".to_string()).is_some());
254
255        // Test invert
256        let inverted = step.invert(&Arc::new(tree.clone()));
257        assert!(inverted.is_some());
258
259        // Apply inverted step
260        if let Some(inverted_step) = inverted {
261            let result = inverted_step.apply(&mut tree, schema);
262            assert!(result.is_ok());
263            // Verify node was removed
264            assert!(tree.get_node(&"test".to_string()).is_none());
265        }
266    }
267
268    #[test]
269    fn test_remove_node_step() {
270        let mut tree = create_test_tree();
271        let schema = create_test_schema();
272
273        // Add a node first
274        let node = create_test_node("test");
275        tree.add_node(&"root".to_string(), &vec![node]).unwrap();
276
277        let step =
278            RemoveNodeStep::new("root".to_string(), vec!["test".to_string()]);
279        let result = step.apply(&mut tree, schema.clone());
280        assert!(result.is_ok());
281
282        // Verify node was removed
283        assert!(tree.get_node(&"test".to_string()).is_none());
284
285        // Test invert
286        let inverted = step.invert(&Arc::new(tree.clone()));
287        assert!(inverted.is_some());
288    }
289
290    #[test]
291    fn test_move_node_step() {
292        let mut tree = create_test_tree();
293        let schema = create_test_schema();
294
295        // Add source and target nodes
296        let source = create_test_node("source");
297        let target = create_test_node("target");
298        let node = create_test_node("node");
299
300        tree.add_node(&"root".to_string(), &vec![source]).unwrap();
301        tree.add_node(&"root".to_string(), &vec![target]).unwrap();
302        tree.add_node(&"source".to_string(), &vec![node]).unwrap();
303
304        let step = MoveNodeStep::new(
305            "source".to_string(),
306            "target".to_string(),
307            "node".to_string(),
308            None,
309        );
310
311        let result = step.apply(&mut tree, schema.clone());
312        assert!(result.is_ok());
313
314        // Verify node was moved
315        let target_node = tree.get_node(&"target".to_string()).unwrap();
316        assert!(target_node.content.contains(&"node".to_string()));
317
318        // Test invert
319        let inverted = step.invert(&Arc::new(tree.clone()));
320        assert!(inverted.is_some());
321    }
322}