Skip to main content

sz_rust_workflow/api/
designer.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2024-2026 SZ-Rust Team
3//
4use std::sync::Arc;
5
6use crate::definition::{DefinitionFormat, DefinitionParser, DefinitionValidator, ValidationIssue};
7use crate::error::{WorkflowError, WorkflowErrorCode, WorkflowResult};
8use crate::repository::{DefinitionId, DefinitionRepository};
9
10use super::version_manager::VersionManager;
11
12/// 设计器 API,对齐 spec 5.6。
13pub struct DesignerApi {
14    parser: DefinitionParser,
15    validator: DefinitionValidator,
16    definition_repo: Arc<dyn DefinitionRepository>,
17    version_manager: Arc<VersionManager>,
18}
19
20impl DesignerApi {
21    pub fn new(
22        validator: DefinitionValidator,
23        definition_repo: Arc<dyn DefinitionRepository>,
24        version_manager: Arc<VersionManager>,
25    ) -> Self {
26        Self {
27            parser: DefinitionParser::new(),
28            validator,
29            definition_repo,
30            version_manager,
31        }
32    }
33
34    /// 校验定义(不持久化)。
35    pub async fn validate_definition(
36        &self,
37        text: &str,
38        format: DefinitionFormat,
39    ) -> WorkflowResult<Vec<ValidationIssue>> {
40        let def = self.parser.parse(text, format)?;
41        self.validator.validate(&def).await
42    }
43
44    /// 导入定义(校验 + 持久化)。
45    pub async fn import_definition(
46        &self,
47        text: &str,
48        format: DefinitionFormat,
49    ) -> WorkflowResult<DefinitionId> {
50        let def = self.parser.parse(text, format)?;
51        let issues = self.validator.validate(&def).await?;
52        let has_errors = issues
53            .iter()
54            .any(|i| i.severity == crate::definition::IssueSeverity::Error);
55        if has_errors {
56            return Err(WorkflowError::new(
57                WorkflowErrorCode::StructureIncomplete,
58                "定义校验失败,存在 Error 级问题",
59            )
60            .with_details(serde_json::to_value(&issues).unwrap_or_default()));
61        }
62        self.definition_repo.save(&def).await
63    }
64
65    /// 导出定义。
66    pub async fn export_definition(
67        &self,
68        id: &DefinitionId,
69        format: DefinitionFormat,
70    ) -> WorkflowResult<String> {
71        let def = self.definition_repo.get(id).await?.ok_or_else(|| {
72            WorkflowError::with_field(
73                WorkflowErrorCode::DefinitionNotFound,
74                "定义不存在",
75                "id",
76                id,
77            )
78        })?;
79        match format {
80            DefinitionFormat::Json => serde_json::to_string(&def).map_err(|e| {
81                WorkflowError::new(
82                    WorkflowErrorCode::FormatUnsupported,
83                    format!("序列化失败:{e}"),
84                )
85            }),
86            DefinitionFormat::Yaml => serde_yaml::to_string(&def).map_err(|e| {
87                WorkflowError::new(
88                    WorkflowErrorCode::FormatUnsupported,
89                    format!("序列化失败:{e}"),
90                )
91            }),
92        }
93    }
94
95    /// 获取版本管理器引用。
96    pub fn version_manager(&self) -> &VersionManager {
97        &self.version_manager
98    }
99}
100
101#[cfg(test)]
102mod tests {
103    use super::*;
104    use crate::repository::InMemoryDefinitionRepository;
105
106    const VALID_YAML: &str = r#"
107flow_key: leave_req
108version: "1.0.0"
109name: 请假
110nodes:
111  - node_id: start
112    node_type: start
113    kind: start
114    next: end
115  - node_id: end
116    node_type: end
117    kind: end
118start_node: start
119"#;
120
121    #[tokio::test]
122    async fn validate_definition() {
123        let repo = Arc::new(InMemoryDefinitionRepository::default());
124        let vm = Arc::new(VersionManager::new(repo.clone()));
125        let api = DesignerApi::new(DefinitionValidator::new_noop(), repo, vm);
126        let issues = api
127            .validate_definition(VALID_YAML, DefinitionFormat::Yaml)
128            .await
129            .unwrap();
130        let errors: Vec<_> = issues
131            .iter()
132            .filter(|i| i.severity == crate::definition::IssueSeverity::Error)
133            .collect();
134        assert!(errors.is_empty());
135    }
136
137    #[tokio::test]
138    async fn import_and_export() {
139        let repo = Arc::new(InMemoryDefinitionRepository::default());
140        let vm = Arc::new(VersionManager::new(repo.clone()));
141        let api = DesignerApi::new(DefinitionValidator::new_noop(), repo, vm);
142        let id = api
143            .import_definition(VALID_YAML, DefinitionFormat::Yaml)
144            .await
145            .unwrap();
146        let exported = api
147            .export_definition(&id, DefinitionFormat::Json)
148            .await
149            .unwrap();
150        assert!(exported.contains("leave_req"));
151    }
152
153    #[tokio::test]
154    async fn export_not_found() {
155        let repo = Arc::new(InMemoryDefinitionRepository::default());
156        let vm = Arc::new(VersionManager::new(repo.clone()));
157        let api = DesignerApi::new(DefinitionValidator::new_noop(), repo, vm);
158        let result = api
159            .export_definition(&"nonexistent".to_string(), DefinitionFormat::Json)
160            .await;
161        assert!(result.is_err());
162        assert_eq!(
163            result.unwrap_err().code,
164            WorkflowErrorCode::DefinitionNotFound
165        );
166    }
167}