mf_transform/
batch_step.rs1use std::sync::Arc;
2
3use mf_model::{schema::Schema, tree::Tree};
4use mf_model::rpds::HashTrieMap;
5use crate::{transform_error, TransformResult};
6
7use super::step::{Step, StepResult};
8
9#[derive(Debug, Clone)]
13pub struct BatchStep {
14 pub steps: Vec<Arc<dyn Step>>,
15}
16
17impl BatchStep {
18 pub fn new(steps: Vec<Arc<dyn Step>>) -> Self {
19 Self { steps }
20 }
21}
22
23impl Step for BatchStep {
24 fn name(&self) -> String {
25 "batch_step".to_string()
26 }
27
28 fn apply(
29 &self,
30 dart: &mut Tree,
31 schema: Arc<Schema>,
32 ) -> TransformResult<StepResult> {
33 let mut inverses: Vec<Arc<dyn Step>> =
36 Vec::with_capacity(self.steps.len());
37
38 for step in &self.steps {
39 if let Some(inv) = step.invert(&Arc::new(dart.clone())) {
41 inverses.push(inv);
42 } else {
43 inverses.push(Arc::new(crate::attr_step::AttrStep::new(
44 "__invalid__".into(),
47 HashTrieMap::new_sync(),
48 )));
49 }
50
51 match step.apply(dart, schema.clone()) {
53 Ok(res) => {
54 if let Some(message) = res.failed {
55 for inv in inverses.into_iter().rev() {
57 let _ = inv.apply(dart, schema.clone());
58 }
59 return Err(transform_error(message));
60 }
61 },
62 Err(e) => {
63 for inv in inverses.into_iter().rev() {
65 let _ = inv.apply(dart, schema.clone());
66 }
67 return Err(e);
68 },
69 }
70 }
71
72 Ok(StepResult::ok())
73 }
74
75 fn serialize(&self) -> Option<Vec<u8>> {
76 None
78 }
79
80 fn invert(
81 &self,
82 dart: &Arc<Tree>,
83 ) -> Option<Arc<dyn Step>> {
84 let mut invs: Vec<Arc<dyn Step>> = Vec::new();
87 for step in &self.steps {
88 if let Some(inv) = step.invert(dart) {
89 invs.push(inv);
90 }
91 }
92 if invs.is_empty() {
93 None
94 } else {
95 invs.reverse();
96 Some(Arc::new(BatchStep::new(invs)))
97 }
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104 use crate::{attr_step::AttrStep, node_step::AddNodeStep};
105 use mf_model::{
106 attrs::Attrs,
107 node::Node,
108 node_definition::{NodeTree, NodeSpec},
109 schema::{Schema, SchemaSpec},
110 tree::Tree,
111 };
112 use serde_json::json;
113 use std::collections::HashMap;
114 use mf_model::rpds::ht_map_sync;
115
116 fn create_schema() -> Arc<Schema> {
117 let mut nodes = HashMap::new();
118 nodes.insert(
119 "doc".to_string(),
120 NodeSpec {
121 content: None,
122 marks: None,
123 group: None,
124 desc: None,
125 attrs: None,
126 },
127 );
128 let spec = SchemaSpec {
129 nodes,
130 marks: HashMap::new(),
131 top_node: Some("doc".to_string()),
132 };
133 Arc::new(Schema::compile(spec).expect("测试 Schema 编译失败"))
134 }
135
136 #[test]
137 fn batch_step_apply_and_invert() {
138 let schema = create_schema();
139 let root = Node::new(
140 "doc",
141 "doc".to_string(),
142 Attrs::default(),
143 vec![],
144 vec![],
145 );
146 let mut tree = Tree::new(root);
147
148 let child = Node::new(
150 "n1",
151 "doc".to_string(),
152 Attrs::default(),
153 vec![],
154 vec![],
155 );
156 let add = Arc::new(AddNodeStep::new(
157 "doc".into(),
158 vec![NodeTree(child, vec![])],
159 ));
160 let set = Arc::new(AttrStep::new(
161 "n1".into(),
162 ht_map_sync! ["k".into()=>json!(1)],
163 ));
164
165 let batch = BatchStep::new(vec![add, set]);
166 let res = batch.apply(&mut tree, schema.clone());
167 assert!(res.is_ok());
168
169 let inv = batch.invert(&Arc::new(tree.clone())).unwrap();
171 let r = inv.apply(&mut tree, schema);
172 assert!(r.is_ok());
173 }
174}