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> {
141 self.operation
142 .as_ref()
143 .and_then(|op| op.get_retry_payload())
144 }
145
146 pub fn attempt(&self) -> Option<u32> {
152 self.operation.as_ref().and_then(|op| op.get_attempt())
153 }
154
155 pub fn callback_id(&self) -> Option<String> {
164 self.operation
165 .as_ref()
166 .and_then(|op| op.callback_details.as_ref())
167 .and_then(|details| details.callback_id.clone())
168 }
169}
170
171#[cfg(test)]
172mod tests {
173 use super::*;
174 use crate::error::ErrorObject;
175
176 fn create_operation(status: OperationStatus) -> Operation {
177 let mut op = Operation::new("test-op", OperationType::Step);
178 op.status = status;
179 op
180 }
181
182 fn create_succeeded_operation() -> Operation {
183 let mut op = Operation::new("test-op", OperationType::Step);
184 op.status = OperationStatus::Succeeded;
185 op.result = Some(r#"{"value": 42}"#.to_string());
186 op
187 }
188
189 fn create_failed_operation() -> Operation {
190 let mut op = Operation::new("test-op", OperationType::Step);
191 op.status = OperationStatus::Failed;
192 op.error = Some(ErrorObject::new("TestError", "Something went wrong"));
193 op
194 }
195
196 #[test]
197 fn test_empty_checkpoint_result() {
198 let result = CheckpointedResult::empty();
199 assert!(!result.is_existent());
200 assert!(!result.is_succeeded());
201 assert!(!result.is_failed());
202 assert!(!result.is_cancelled());
203 assert!(!result.is_timed_out());
204 assert!(!result.is_stopped());
205 assert!(!result.is_terminal());
206 assert!(result.status().is_none());
207 assert!(result.operation_type().is_none());
208 assert!(result.result().is_none());
209 assert!(result.error().is_none());
210 assert!(result.operation().is_none());
211 }
212
213 #[test]
214 fn test_succeeded_checkpoint_result() {
215 let op = create_succeeded_operation();
216 let result = CheckpointedResult::new(Some(op));
217
218 assert!(result.is_existent());
219 assert!(result.is_succeeded());
220 assert!(!result.is_failed());
221 assert!(result.is_terminal());
222 assert_eq!(result.status(), Some(OperationStatus::Succeeded));
223 assert_eq!(result.operation_type(), Some(OperationType::Step));
224 assert_eq!(result.result(), Some(r#"{"value": 42}"#));
225 assert!(result.error().is_none());
226 }
227
228 #[test]
229 fn test_failed_checkpoint_result() {
230 let op = create_failed_operation();
231 let result = CheckpointedResult::new(Some(op));
232
233 assert!(result.is_existent());
234 assert!(!result.is_succeeded());
235 assert!(result.is_failed());
236 assert!(result.is_terminal());
237 assert_eq!(result.status(), Some(OperationStatus::Failed));
238 assert!(result.result().is_none());
239 assert!(result.error().is_some());
240 assert_eq!(result.error().unwrap().error_type, "TestError");
241 }
242
243 #[test]
244 fn test_cancelled_checkpoint_result() {
245 let op = create_operation(OperationStatus::Cancelled);
246 let result = CheckpointedResult::new(Some(op));
247
248 assert!(result.is_existent());
249 assert!(result.is_cancelled());
250 assert!(result.is_terminal());
251 }
252
253 #[test]
254 fn test_timed_out_checkpoint_result() {
255 let op = create_operation(OperationStatus::TimedOut);
256 let result = CheckpointedResult::new(Some(op));
257
258 assert!(result.is_existent());
259 assert!(result.is_timed_out());
260 assert!(result.is_terminal());
261 }
262
263 #[test]
264 fn test_stopped_checkpoint_result() {
265 let op = create_operation(OperationStatus::Stopped);
266 let result = CheckpointedResult::new(Some(op));
267
268 assert!(result.is_existent());
269 assert!(result.is_stopped());
270 assert!(result.is_terminal());
271 }
272
273 #[test]
274 fn test_pending_checkpoint_result() {
275 let op = create_operation(OperationStatus::Pending);
276 let result = CheckpointedResult::new(Some(op));
277
278 assert!(result.is_existent());
279 assert!(result.is_pending());
280 assert!(!result.is_ready());
281 assert!(!result.is_terminal());
282 }
283
284 #[test]
285 fn test_ready_checkpoint_result() {
286 let op = create_operation(OperationStatus::Ready);
287 let result = CheckpointedResult::new(Some(op));
288
289 assert!(result.is_existent());
290 assert!(result.is_ready());
291 assert!(!result.is_pending());
292 assert!(!result.is_terminal());
293 }
294
295 #[test]
296 fn test_started_checkpoint_result() {
297 let op = create_operation(OperationStatus::Started);
298 let result = CheckpointedResult::new(Some(op));
299
300 assert!(result.is_existent());
301 assert!(!result.is_succeeded());
302 assert!(!result.is_failed());
303 assert!(!result.is_terminal());
304 }
305
306 #[test]
307 fn test_into_operation() {
308 let op = create_succeeded_operation();
309 let result = CheckpointedResult::new(Some(op));
310
311 let operation = result.into_operation();
312 assert!(operation.is_some());
313 assert_eq!(operation.unwrap().operation_id, "test-op");
314 }
315}