Skip to main content

sz_rust_workflow/api/
version_manager.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2024-2026 SZ-Rust Team
3//
4use std::sync::Arc;
5
6use serde::Serialize;
7
8use crate::error::{WorkflowError, WorkflowErrorCode, WorkflowResult};
9use crate::repository::{DefinitionId, DefinitionRepository};
10
11/// 定义摘要。
12#[derive(Debug, Clone, Serialize)]
13pub struct DefinitionSummary {
14    pub id: DefinitionId,
15    pub flow_key: String,
16    pub version: String,
17    pub name: String,
18    pub active: bool,
19    pub deprecated: bool,
20}
21
22/// 版本管理器,对齐 spec 5.6。
23pub struct VersionManager {
24    definition_repo: Arc<dyn DefinitionRepository>,
25}
26
27impl VersionManager {
28    pub fn new(definition_repo: Arc<dyn DefinitionRepository>) -> Self {
29        Self { definition_repo }
30    }
31
32    /// 列出某流程标识所有版本。
33    pub async fn list_versions(&self, flow_key: &str) -> WorkflowResult<Vec<DefinitionSummary>> {
34        let defs = self.definition_repo.list_versions(flow_key).await?;
35        Ok(defs
36            .into_iter()
37            .map(|d| DefinitionSummary {
38                id: String::new(),
39                flow_key: d.flow_key,
40                version: d.version.to_string(),
41                name: d.name,
42                active: d.active,
43                deprecated: d.deprecated,
44            })
45            .collect())
46    }
47
48    /// 设置生效版本。
49    pub async fn set_active(&self, id: &DefinitionId) -> WorkflowResult<()> {
50        let def = self.definition_repo.get(id).await?.ok_or_else(|| {
51            WorkflowError::with_field(WorkflowErrorCode::VersionNotFound, "版本不存在", "id", id)
52        })?;
53        if def.deprecated {
54            return Err(WorkflowError::with_field(
55                WorkflowErrorCode::VersionNotFound,
56                "已弃用版本不可设为生效",
57                "id",
58                id,
59            ));
60        }
61        self.definition_repo.set_active(id).await
62    }
63
64    /// 弃用版本。
65    pub async fn deprecate(&self, id: &DefinitionId) -> WorkflowResult<()> {
66        self.definition_repo.deprecate(id).await
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73    use crate::definition::FlowDefinition;
74    use crate::repository::InMemoryDefinitionRepository;
75
76    fn make_def(key: &str, ver: &str, active: bool) -> FlowDefinition {
77        FlowDefinition {
78            flow_key: key.into(),
79            version: semver::Version::parse(ver).unwrap(),
80            name: "test".into(),
81            nodes: vec![],
82            start_node: "start".into(),
83            active,
84            deprecated: false,
85            machine: None,
86            flow: None,
87        }
88    }
89
90    #[tokio::test]
91    async fn list_versions() {
92        let repo = Arc::new(InMemoryDefinitionRepository::default());
93        repo.save(&make_def("test", "1.0.0", true)).await.unwrap();
94        repo.save(&make_def("test", "2.0.0", false)).await.unwrap();
95        let mgr = VersionManager::new(repo);
96        let versions = mgr.list_versions("test").await.unwrap();
97        assert_eq!(versions.len(), 2);
98    }
99
100    #[tokio::test]
101    async fn set_active_not_found() {
102        let repo = Arc::new(InMemoryDefinitionRepository::default());
103        let mgr = VersionManager::new(repo);
104        let result = mgr.set_active(&"nonexistent".to_string()).await;
105        assert!(result.is_err());
106        assert_eq!(result.unwrap_err().code, WorkflowErrorCode::VersionNotFound);
107    }
108}