sz_rust_workflow/definition/
models.rs1use serde::{Deserialize, Serialize};
5
6use super::node::{Node, NodeEdge};
7use super::strategy::Transition;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
11#[serde(rename_all = "lowercase")]
12pub enum DefinitionFormat {
13 Yaml,
14 Json,
15}
16
17impl DefinitionFormat {
18 pub fn detect(text: &str) -> Self {
20 let trimmed = text.trim_start();
21 if trimmed.starts_with('{') {
22 Self::Json
23 } else {
24 Self::Yaml
25 }
26 }
27}
28
29#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
31pub struct FlowDefinition {
32 pub flow_key: String,
34 pub version: semver::Version,
36 pub name: String,
38 pub nodes: Vec<Node>,
40 pub start_node: String,
42 #[serde(default)]
44 pub active: bool,
45 #[serde(default)]
47 pub deprecated: bool,
48 #[serde(default, skip_serializing_if = "Option::is_none")]
50 pub machine: Option<StateMachineDefinition>,
51 #[serde(default, skip_serializing_if = "Option::is_none")]
53 pub flow: Option<ApprovalFlowDefinition>,
54}
55
56#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
58pub struct StateMachineDefinition {
59 pub initial_state: String,
61 pub states: Vec<String>,
63 pub transitions: Vec<Transition>,
65}
66
67#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
69pub struct ApprovalFlowDefinition {
70 pub edges: Vec<NodeEdge>,
72}
73
74impl FlowDefinition {
75 pub fn find_node(&self, node_id: &str) -> Option<&Node> {
77 self.nodes.iter().find(|n| n.node_id == node_id)
78 }
79
80 pub fn node_ids(&self) -> Vec<&str> {
82 self.nodes.iter().map(|n| n.node_id.as_str()).collect()
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::super::node::{NodeConfig, NodeType};
89 use super::*;
90
91 fn sample_definition() -> FlowDefinition {
92 FlowDefinition {
93 flow_key: "leave_request".into(),
94 version: semver::Version::new(1, 0, 0),
95 name: "请假申请".into(),
96 nodes: vec![
97 Node {
98 node_id: "start".into(),
99 node_type: NodeType::Start,
100 config: NodeConfig::Start { next: "end".into() },
101 },
102 Node {
103 node_id: "end".into(),
104 node_type: NodeType::End,
105 config: NodeConfig::End,
106 },
107 ],
108 start_node: "start".into(),
109 active: true,
110 deprecated: false,
111 machine: None,
112 flow: None,
113 }
114 }
115
116 #[test]
117 fn flow_definition_serde() {
118 let def = sample_definition();
119 let json = serde_json::to_string(&def).unwrap();
120 let back: FlowDefinition = serde_json::from_str(&json).unwrap();
121 assert_eq!(def, back);
122 }
123
124 #[test]
125 fn flow_definition_yaml_serde() {
126 let def = sample_definition();
127 let yaml = serde_yaml::to_string(&def).unwrap();
128 let back: FlowDefinition = serde_yaml::from_str(&yaml).unwrap();
129 assert_eq!(def, back);
130 }
131
132 #[test]
133 fn format_detect() {
134 assert_eq!(
135 DefinitionFormat::detect("{ \"flow_key\": \"x\" }"),
136 DefinitionFormat::Json
137 );
138 assert_eq!(
139 DefinitionFormat::detect("flow_key: x"),
140 DefinitionFormat::Yaml
141 );
142 assert_eq!(DefinitionFormat::detect(" {"), DefinitionFormat::Json);
143 }
144
145 #[test]
146 fn find_node() {
147 let def = sample_definition();
148 assert!(def.find_node("start").is_some());
149 assert!(def.find_node("nonexistent").is_none());
150 }
151
152 #[test]
153 fn node_ids() {
154 let def = sample_definition();
155 assert_eq!(def.node_ids(), vec!["start", "end"]);
156 }
157
158 #[test]
159 fn state_machine_definition_serde() {
160 let sm = StateMachineDefinition {
161 initial_state: "draft".into(),
162 states: vec!["draft".into(), "review".into(), "approved".into()],
163 transitions: vec![Transition {
164 from: "draft".into(),
165 to: "review".into(),
166 event: "submit".into(),
167 guard: None,
168 }],
169 };
170 let json = serde_json::to_string(&sm).unwrap();
171 let back: StateMachineDefinition = serde_json::from_str(&json).unwrap();
172 assert_eq!(sm, back);
173 }
174
175 #[test]
176 fn approval_flow_definition_serde() {
177 let af = ApprovalFlowDefinition {
178 edges: vec![NodeEdge {
179 from: "start".into(),
180 to: "approve".into(),
181 condition: None,
182 }],
183 };
184 let json = serde_json::to_string(&af).unwrap();
185 let back: ApprovalFlowDefinition = serde_json::from_str(&json).unwrap();
186 assert_eq!(af, back);
187 }
188
189 #[test]
190 fn full_definition_with_machine_and_flow() {
191 let mut def = sample_definition();
192 def.machine = Some(StateMachineDefinition {
193 initial_state: "draft".into(),
194 states: vec!["draft".into(), "done".into()],
195 transitions: vec![],
196 });
197 def.flow = Some(ApprovalFlowDefinition { edges: vec![] });
198 let json = serde_json::to_string(&def).unwrap();
199 let back: FlowDefinition = serde_json::from_str(&json).unwrap();
200 assert_eq!(def, back);
201 }
202}