Skip to main content

mf_collab_client/mapping_v2/
simple_converters.rs

1/// 简化版转换器实现
2/// 不使用宏,直接实现 TypedStepConverter trait
3use 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// ================================
19// 节点添加转换器
20// ================================
21
22#[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        // 验证步骤
33        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        // 获取根节点ID
43        let meta_map = txn.get_or_insert_map("meta");
44        let root_id = meta_map.get(txn, "root_id");
45
46        // 如果不是根节点,需要更新父节点的content数组
47        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        // 插入所有节点
67        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// ================================
118// 节点删除转换器
119// ================================
120
121#[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// ================================
183// 属性转换器
184// ================================
185
186#[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// ================================
263// 标记添加转换器
264// ================================
265
266#[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// ================================
331// 标记删除转换器
332// ================================
333
334#[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
400// ================================
401// 辅助函数
402// ================================
403
404/// 递归插入节点
405fn 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    // 插入当前节点
411    insert_single_node(nodes_map, txn, &node_enum.0)?;
412
413    // 递归插入子节点
414    for child_enum in &node_enum.1 {
415        insert_node_recursive(nodes_map, txn, child_enum)?;
416    }
417
418    Ok(())
419}
420
421/// 插入单个节点
422fn 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    // 设置节点类型
431    node_data_map.insert(txn, "type", node.r#type.clone());
432
433    // 设置属性
434    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    // 设置内容
441    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    // 设置标记
451    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
463/// 按类型删除标记
464fn 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// 自动注册所有转换器
492#[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}