1use yrs::{Array, ArrayPrelim, Map, MapPrelim, TransactionMut, WriteTxn};
4use mf_transform::{
5 step::Step,
6 node_step::{AddNodeStep, RemoveNodeStep},
7 attr_step::AttrStep,
8 mark_step::{AddMarkStep, RemoveMarkStep},
9};
10use mf_model::node::Node;
11
12use crate::mapping_v2::{
13 typed_converter::{TypedStepConverter, ConversionContext},
14 error::{ConversionError, ConversionResult},
15};
16use crate::{types::StepResult, utils::Utils};
17
18#[derive(Debug, Default, Clone)]
23pub struct SimpleNodeAddConverter;
24
25impl TypedStepConverter<AddNodeStep> for SimpleNodeAddConverter {
26 fn convert_typed(
27 &self,
28 step: &AddNodeStep,
29 txn: &mut TransactionMut,
30 context: &ConversionContext,
31 ) -> ConversionResult<StepResult> {
32 if step.nodes.is_empty() {
34 return Err(ConversionError::validation_failed(
35 "AddNodeStep",
36 "节点列表不能为空",
37 ));
38 }
39
40 let nodes_map = txn.get_or_insert_map("nodes");
41
42 let meta_map = txn.get_or_insert_map("meta");
44 let root_id = meta_map.get(txn, "root_id");
45
46 if let Some(root_id) = root_id {
48 if root_id.to_string(txn) != *step.parent_id {
49 let parent_node_data = Utils::get_or_create_node_data_map(
50 &nodes_map,
51 txn,
52 &step.parent_id,
53 );
54 let content_array =
55 Utils::get_or_create_content_array(&parent_node_data, txn);
56
57 for node_enum in &step.nodes {
58 content_array.push_back(
59 txn,
60 yrs::Any::String(node_enum.0.id.clone().into()),
61 );
62 }
63 }
64 }
65
66 let mut inserted_count = 0;
68 for node_enum in &step.nodes {
69 insert_node_recursive(&nodes_map, txn, node_enum)?;
70 inserted_count += 1;
71 }
72
73 Ok(StepResult {
74 step_id: uuid::Uuid::new_v4().to_string(),
75 step_name: step.name().to_string(),
76 description: format!(
77 "成功添加 {} 个节点到父节点 {}",
78 inserted_count, step.parent_id
79 ),
80 timestamp: context.timestamp,
81 client_id: context.client_id.clone(),
82 })
83 }
84
85 fn validate_step(
86 &self,
87 step: &AddNodeStep,
88 _context: &ConversionContext,
89 ) -> ConversionResult<()> {
90 if step.nodes.is_empty() {
91 return Err(ConversionError::validation_failed(
92 "AddNodeStep",
93 "节点列表不能为空",
94 ));
95 }
96
97 Ok(())
98 }
99
100 fn converter_name() -> &'static str {
101 "SimpleNodeAddConverter"
102 }
103
104 fn step_type_name() -> &'static str {
105 "AddNodeStep"
106 }
107
108 fn priority() -> u8 {
109 10
110 }
111
112 fn supports_concurrent_execution() -> bool {
113 true
114 }
115}
116
117#[derive(Debug, Default, Clone)]
122pub struct SimpleNodeRemoveConverter;
123
124impl TypedStepConverter<RemoveNodeStep> for SimpleNodeRemoveConverter {
125 fn convert_typed(
126 &self,
127 step: &RemoveNodeStep,
128 txn: &mut TransactionMut,
129 context: &ConversionContext,
130 ) -> ConversionResult<StepResult> {
131 let nodes_map = txn.get_or_insert_map("nodes");
132 let mut removed_count = 0;
133
134 for node_id in &step.node_ids {
135 if nodes_map.get(txn, node_id).is_some() {
136 nodes_map.remove(txn, node_id);
137 removed_count += 1;
138 }
139 }
140
141 Ok(StepResult {
142 step_id: uuid::Uuid::new_v4().to_string(),
143 step_name: step.name().to_string(),
144 description: format!("成功删除 {removed_count} 个节点"),
145 timestamp: context.timestamp,
146 client_id: context.client_id.clone(),
147 })
148 }
149
150 fn validate_step(
151 &self,
152 step: &RemoveNodeStep,
153 _context: &ConversionContext,
154 ) -> ConversionResult<()> {
155 if step.node_ids.is_empty() {
156 return Err(ConversionError::validation_failed(
157 "RemoveNodeStep",
158 "节点ID列表不能为空",
159 ));
160 }
161
162 Ok(())
163 }
164
165 fn converter_name() -> &'static str {
166 "SimpleNodeRemoveConverter"
167 }
168
169 fn step_type_name() -> &'static str {
170 "RemoveNodeStep"
171 }
172
173 fn priority() -> u8 {
174 10
175 }
176
177 fn supports_concurrent_execution() -> bool {
178 true
179 }
180}
181
182#[derive(Debug, Default, Clone)]
187pub struct SimpleAttrConverter;
188
189impl TypedStepConverter<AttrStep> for SimpleAttrConverter {
190 fn convert_typed(
191 &self,
192 step: &AttrStep,
193 txn: &mut TransactionMut,
194 context: &ConversionContext,
195 ) -> ConversionResult<StepResult> {
196 if step.values.is_empty() {
197 return Err(ConversionError::validation_failed(
198 "AttrStep",
199 "属性值不能为空",
200 ));
201 }
202
203 let nodes_map = txn.get_or_insert_map("nodes");
204 let node_data_map =
205 Utils::get_or_create_node_data_map(&nodes_map, txn, &step.id);
206 let attrs_map =
207 Utils::get_or_create_node_attrs_map(&node_data_map, txn);
208
209 for (key, value) in &step.values {
210 attrs_map.insert(
211 txn,
212 key.clone(),
213 Utils::json_value_to_yrs_any(value),
214 );
215 }
216
217 Ok(StepResult {
218 step_id: uuid::Uuid::new_v4().to_string(),
219 step_name: step.name().to_string(),
220 description: format!(
221 "更新节点 {} 的 {} 个属性",
222 step.id,
223 step.values.keys().len()
224 ),
225 timestamp: context.timestamp,
226 client_id: context.client_id.clone(),
227 })
228 }
229
230 fn validate_step(
231 &self,
232 step: &AttrStep,
233 _context: &ConversionContext,
234 ) -> ConversionResult<()> {
235 if step.values.is_empty() {
236 return Err(ConversionError::validation_failed(
237 "AttrStep",
238 "属性值不能为空",
239 ));
240 }
241
242 Ok(())
243 }
244
245 fn converter_name() -> &'static str {
246 "SimpleAttrConverter"
247 }
248
249 fn step_type_name() -> &'static str {
250 "AttrStep"
251 }
252
253 fn priority() -> u8 {
254 10
255 }
256
257 fn supports_concurrent_execution() -> bool {
258 true
259 }
260}
261
262#[derive(Debug, Default, Clone)]
267pub struct SimpleMarkAddConverter;
268
269impl TypedStepConverter<AddMarkStep> for SimpleMarkAddConverter {
270 fn convert_typed(
271 &self,
272 step: &AddMarkStep,
273 txn: &mut TransactionMut,
274 context: &ConversionContext,
275 ) -> ConversionResult<StepResult> {
276 let nodes_map = txn.get_or_insert_map("nodes");
277 let node_data_map =
278 Utils::get_or_create_node_data_map(&nodes_map, txn, &step.id);
279 let marks_array = Utils::get_or_create_marks_array(&node_data_map, txn);
280
281 for mark in &step.marks {
282 Utils::add_mark_to_array(&marks_array, txn, mark);
283 }
284
285 Ok(StepResult {
286 step_id: uuid::Uuid::new_v4().to_string(),
287 step_name: step.name().to_string(),
288 description: format!(
289 "为节点 {} 添加 {} 个标记",
290 step.id,
291 step.marks.len()
292 ),
293 timestamp: context.timestamp,
294 client_id: context.client_id.clone(),
295 })
296 }
297
298 fn validate_step(
299 &self,
300 step: &AddMarkStep,
301 _context: &ConversionContext,
302 ) -> ConversionResult<()> {
303 if step.marks.is_empty() {
304 return Err(ConversionError::validation_failed(
305 "AddMarkStep",
306 "标记列表不能为空",
307 ));
308 }
309
310 Ok(())
311 }
312
313 fn converter_name() -> &'static str {
314 "SimpleMarkAddConverter"
315 }
316
317 fn step_type_name() -> &'static str {
318 "AddMarkStep"
319 }
320
321 fn priority() -> u8 {
322 10
323 }
324
325 fn supports_concurrent_execution() -> bool {
326 true
327 }
328}
329
330#[derive(Debug, Default, Clone)]
335pub struct SimpleMarkRemoveConverter;
336
337impl TypedStepConverter<RemoveMarkStep> for SimpleMarkRemoveConverter {
338 fn convert_typed(
339 &self,
340 step: &RemoveMarkStep,
341 txn: &mut TransactionMut,
342 context: &ConversionContext,
343 ) -> ConversionResult<StepResult> {
344 let nodes_map = txn.get_or_insert_map("nodes");
345 let node_data_map =
346 Utils::get_or_create_node_data_map(&nodes_map, txn, &step.id);
347 let marks_array = Utils::get_or_create_marks_array(&node_data_map, txn);
348
349 let mut removed_count = 0;
350 for mark_type in &step.mark_types {
351 if remove_mark_by_type(&marks_array, txn, mark_type)? {
352 removed_count += 1;
353 }
354 }
355
356 Ok(StepResult {
357 step_id: uuid::Uuid::new_v4().to_string(),
358 step_name: step.name().to_string(),
359 description: format!(
360 "从节点 {} 删除 {} 个标记",
361 step.id, removed_count
362 ),
363 timestamp: context.timestamp,
364 client_id: context.client_id.clone(),
365 })
366 }
367
368 fn validate_step(
369 &self,
370 step: &RemoveMarkStep,
371 _context: &ConversionContext,
372 ) -> ConversionResult<()> {
373 if step.mark_types.is_empty() {
374 return Err(ConversionError::validation_failed(
375 "RemoveMarkStep",
376 "标记类型列表不能为空",
377 ));
378 }
379
380 Ok(())
381 }
382
383 fn converter_name() -> &'static str {
384 "SimpleMarkRemoveConverter"
385 }
386
387 fn step_type_name() -> &'static str {
388 "RemoveMarkStep"
389 }
390
391 fn priority() -> u8 {
392 10
393 }
394
395 fn supports_concurrent_execution() -> bool {
396 true
397 }
398}
399
400fn insert_node_recursive(
406 nodes_map: &yrs::types::map::MapRef,
407 txn: &mut TransactionMut,
408 node_enum: &mf_model::node_definition::NodeTree,
409) -> ConversionResult<()> {
410 insert_single_node(nodes_map, txn, &node_enum.0)?;
412
413 for child_enum in &node_enum.1 {
415 insert_node_recursive(nodes_map, txn, child_enum)?;
416 }
417
418 Ok(())
419}
420
421fn insert_single_node(
423 nodes_map: &yrs::types::map::MapRef,
424 txn: &mut TransactionMut,
425 node: &Node,
426) -> ConversionResult<()> {
427 let node_data_map =
428 Utils::get_or_create_node_data_map(nodes_map, txn, &node.id);
429
430 node_data_map.insert(txn, "type", node.r#type.clone());
432
433 let attrs_map =
435 node_data_map.insert(txn, "attrs", MapPrelim::<yrs::Any>::new());
436 for (key, value) in node.attrs.iter() {
437 attrs_map.insert(txn, key.clone(), Utils::json_value_to_yrs_any(value));
438 }
439
440 let content_array = node_data_map.insert(
442 txn,
443 "content",
444 ArrayPrelim::from(Vec::<yrs::Any>::new()),
445 );
446 for child_id in &node.content {
447 content_array.push_back(txn, yrs::Any::String(child_id.clone().into()));
448 }
449
450 let marks_array = node_data_map.insert(
452 txn,
453 "marks",
454 ArrayPrelim::from(Vec::<yrs::Any>::new()),
455 );
456 for mark in &node.marks {
457 Utils::add_mark_to_array(&marks_array, txn, mark);
458 }
459
460 Ok(())
461}
462
463fn remove_mark_by_type(
465 marks_array: &yrs::types::array::ArrayRef,
466 txn: &mut TransactionMut,
467 mark_type: &str,
468) -> ConversionResult<bool> {
469 let len = marks_array.len(txn);
470
471 for i in (0..len).rev() {
472 if let Some(yrs::types::Value::YMap(mark_map)) = marks_array.get(txn, i)
473 {
474 if let Some(type_value) = mark_map.get(txn, "type") {
475 let current_mark_type = match type_value {
476 yrs::types::Value::Any(any) => any.to_string(),
477 _ => continue,
478 };
479
480 if current_mark_type == mark_type {
481 marks_array.remove(txn, i);
482 return Ok(true);
483 }
484 }
485 }
486 }
487
488 Ok(false)
489}
490
491#[ctor::ctor]
493fn register_simple_converters() {
494 use crate::mapping_v2::converter_registry::register_global_converter;
495
496 register_global_converter::<AddNodeStep, SimpleNodeAddConverter>();
497 register_global_converter::<RemoveNodeStep, SimpleNodeRemoveConverter>();
498 register_global_converter::<AttrStep, SimpleAttrConverter>();
499 register_global_converter::<AddMarkStep, SimpleMarkAddConverter>();
500 register_global_converter::<RemoveMarkStep, SimpleMarkRemoveConverter>();
501
502 tracing::info!("✅ 已注册所有简化版转换器");
503}