sz_rust_workflow/api/
designer.rs1use 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
12pub 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 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 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 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 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}