durable_execution_sdk/state/
checkpoint_result.rs1use crate::error::ErrorObject;
7use crate::operation::{Operation, OperationStatus, OperationType};
8
9#[derive(Debug, Clone)]
14pub struct CheckpointedResult {
15 operation: Option<Operation>,
17}
18
19impl CheckpointedResult {
20 pub fn new(operation: Option<Operation>) -> Self {
22 Self { operation }
23 }
24
25 pub fn empty() -> Self {
27 Self { operation: None }
28 }
29
30 pub fn is_existent(&self) -> bool {
32 self.operation.is_some()
33 }
34
35 pub fn is_succeeded(&self) -> bool {
37 self.operation
38 .as_ref()
39 .map(|op| op.status == OperationStatus::Succeeded)
40 .unwrap_or(false)
41 }
42
43 pub fn is_failed(&self) -> bool {
45 self.operation
46 .as_ref()
47 .map(|op| op.status == OperationStatus::Failed)
48 .unwrap_or(false)
49 }
50
51 pub fn is_cancelled(&self) -> bool {
53 self.operation
54 .as_ref()
55 .map(|op| op.status == OperationStatus::Cancelled)
56 .unwrap_or(false)
57 }
58
59 pub fn is_timed_out(&self) -> bool {
61 self.operation
62 .as_ref()
63 .map(|op| op.status == OperationStatus::TimedOut)
64 .unwrap_or(false)
65 }
66
67 pub fn is_stopped(&self) -> bool {
69 self.operation
70 .as_ref()
71 .map(|op| op.status == OperationStatus::Stopped)
72 .unwrap_or(false)
73 }
74
75 pub fn is_pending(&self) -> bool {
78 self.operation
79 .as_ref()
80 .map(|op| op.status == OperationStatus::Pending)
81 .unwrap_or(false)
82 }
83
84 pub fn is_ready(&self) -> bool {
87 self.operation
88 .as_ref()
89 .map(|op| op.status == OperationStatus::Ready)
90 .unwrap_or(false)
91 }
92
93 pub fn is_terminal(&self) -> bool {
95 self.operation
96 .as_ref()
97 .map(|op| op.status.is_terminal())
98 .unwrap_or(false)
99 }
100
101 pub fn status(&self) -> Option<OperationStatus> {
103 self.operation.as_ref().map(|op| op.status)
104 }
105
106 pub fn operation_type(&self) -> Option<OperationType> {
108 self.operation.as_ref().map(|op| op.operation_type)
109 }
110
111 pub fn result(&self) -> Option<&str> {
114 self.operation.as_ref().and_then(|op| op.get_result())
115 }
116
117 pub fn error(&self) -> Option<&ErrorObject> {
119 self.operation.as_ref().and_then(|op| op.error.as_ref())
120 }
121
122 pub fn operation(&self) -> Option<&Operation> {
124 self.operation.as_ref()
125 }
126
127 pub fn into_operation(self) -> Option<Operation> {
129 self.operation
130 }
131
132 pub fn retry_payload(&self) -> Option<&str> {
145 self.operation
146 .as_ref()
147 .and_then(|op| op.get_retry_payload())
148 }
149
150 pub fn attempt(&self) -> Option<u32> {
160 self.operation.as_ref().and_then(|op| op.get_attempt())
161 }
162
163 pub fn callback_id(&self) -> Option<String> {
172 self.operation
173 .as_ref()
174 .and_then(|op| op.callback_details.as_ref())
175 .and_then(|details| details.callback_id.clone())
176 }
177}
178
179#[cfg(test)]
180mod tests {
181 use super::*;
182 use crate::error::ErrorObject;
183
184 fn create_operation(status: OperationStatus) -> Operation {
185 let mut op = Operation::new("test-op", OperationType::Step);
186 op.status = status;
187 op
188 }
189
190 fn create_succeeded_operation() -> Operation {
191 let mut op = Operation::new("test-op", OperationType::Step);
192 op.status = OperationStatus::Succeeded;
193 op.result = Some(r#"{"value": 42}"#.to_string());
194 op
195 }
196
197 fn create_failed_operation() -> Operation {
198 let mut op = Operation::new("test-op", OperationType::Step);
199 op.status = OperationStatus::Failed;
200 op.error = Some(ErrorObject::new("TestError", "Something went wrong"));
201 op
202 }
203
204 #[test]
205 fn test_empty_checkpoint_result() {
206 let result = CheckpointedResult::empty();
207 assert!(!result.is_existent());
208 assert!(!result.is_succeeded());
209 assert!(!result.is_failed());
210 assert!(!result.is_cancelled());
211 assert!(!result.is_timed_out());
212 assert!(!result.is_stopped());
213 assert!(!result.is_terminal());
214 assert!(result.status().is_none());
215 assert!(result.operation_type().is_none());
216 assert!(result.result().is_none());
217 assert!(result.error().is_none());
218 assert!(result.operation().is_none());
219 }
220
221 #[test]
222 fn test_succeeded_checkpoint_result() {
223 let op = create_succeeded_operation();
224 let result = CheckpointedResult::new(Some(op));
225
226 assert!(result.is_existent());
227 assert!(result.is_succeeded());
228 assert!(!result.is_failed());
229 assert!(result.is_terminal());
230 assert_eq!(result.status(), Some(OperationStatus::Succeeded));
231 assert_eq!(result.operation_type(), Some(OperationType::Step));
232 assert_eq!(result.result(), Some(r#"{"value": 42}"#));
233 assert!(result.error().is_none());
234 }
235
236 #[test]
237 fn test_failed_checkpoint_result() {
238 let op = create_failed_operation();
239 let result = CheckpointedResult::new(Some(op));
240
241 assert!(result.is_existent());
242 assert!(!result.is_succeeded());
243 assert!(result.is_failed());
244 assert!(result.is_terminal());
245 assert_eq!(result.status(), Some(OperationStatus::Failed));
246 assert!(result.result().is_none());
247 assert!(result.error().is_some());
248 assert_eq!(result.error().unwrap().error_type, "TestError");
249 }
250
251 #[test]
252 fn test_cancelled_checkpoint_result() {
253 let op = create_operation(OperationStatus::Cancelled);
254 let result = CheckpointedResult::new(Some(op));
255
256 assert!(result.is_existent());
257 assert!(result.is_cancelled());
258 assert!(result.is_terminal());
259 }
260
261 #[test]
262 fn test_timed_out_checkpoint_result() {
263 let op = create_operation(OperationStatus::TimedOut);
264 let result = CheckpointedResult::new(Some(op));
265
266 assert!(result.is_existent());
267 assert!(result.is_timed_out());
268 assert!(result.is_terminal());
269 }
270
271 #[test]
272 fn test_stopped_checkpoint_result() {
273 let op = create_operation(OperationStatus::Stopped);
274 let result = CheckpointedResult::new(Some(op));
275
276 assert!(result.is_existent());
277 assert!(result.is_stopped());
278 assert!(result.is_terminal());
279 }
280
281 #[test]
282 fn test_pending_checkpoint_result() {
283 let op = create_operation(OperationStatus::Pending);
284 let result = CheckpointedResult::new(Some(op));
285
286 assert!(result.is_existent());
287 assert!(result.is_pending());
288 assert!(!result.is_ready());
289 assert!(!result.is_terminal());
290 }
291
292 #[test]
293 fn test_ready_checkpoint_result() {
294 let op = create_operation(OperationStatus::Ready);
295 let result = CheckpointedResult::new(Some(op));
296
297 assert!(result.is_existent());
298 assert!(result.is_ready());
299 assert!(!result.is_pending());
300 assert!(!result.is_terminal());
301 }
302
303 #[test]
304 fn test_started_checkpoint_result() {
305 let op = create_operation(OperationStatus::Started);
306 let result = CheckpointedResult::new(Some(op));
307
308 assert!(result.is_existent());
309 assert!(!result.is_succeeded());
310 assert!(!result.is_failed());
311 assert!(!result.is_terminal());
312 }
313
314 #[test]
315 fn test_into_operation() {
316 let op = create_succeeded_operation();
317 let result = CheckpointedResult::new(Some(op));
318
319 let operation = result.into_operation();
320 assert!(operation.is_some());
321 assert_eq!(operation.unwrap().operation_id, "test-op");
322 }
323}