astro_run/types/
id.rs

1use crate::Error;
2use serde::{Deserialize, Serialize};
3
4pub type Id = String;
5
6#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Hash, Eq, Default)]
7pub struct WorkflowId(Id);
8
9#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Hash, Eq, Default)]
10pub struct JobId(Id, Id);
11
12#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Hash, Eq, Default)]
13pub struct StepId(Id, Id, usize);
14
15impl WorkflowId {
16  pub fn new(id: impl Into<String>) -> Self {
17    WorkflowId(id.into())
18  }
19
20  pub fn inner(&self) -> Id {
21    self.0.clone()
22  }
23}
24
25impl JobId {
26  pub fn new(workflow_id: impl Into<String>, job_id: impl Into<String>) -> Self {
27    JobId(workflow_id.into(), job_id.into())
28  }
29
30  pub fn workflow_id(&self) -> WorkflowId {
31    WorkflowId(self.0.clone())
32  }
33
34  pub fn job_key(&self) -> Id {
35    self.1.clone()
36  }
37}
38
39impl StepId {
40  pub fn new(workflow_id: impl Into<String>, job_id: impl Into<String>, step_id: usize) -> Self {
41    StepId(workflow_id.into(), job_id.into(), step_id)
42  }
43
44  pub fn workflow_id(&self) -> WorkflowId {
45    WorkflowId(self.0.clone())
46  }
47
48  pub fn job_id(&self) -> JobId {
49    JobId(self.0.clone(), self.1.clone())
50  }
51
52  pub fn job_key(&self) -> Id {
53    self.1.clone()
54  }
55
56  pub fn step_number(&self) -> usize {
57    self.2
58  }
59}
60
61impl std::fmt::Display for WorkflowId {
62  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63    write!(f, "{}", self.0)
64  }
65}
66
67impl std::fmt::Display for JobId {
68  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69    write!(f, "{}/{}", self.0, self.1)
70  }
71}
72
73impl std::fmt::Display for StepId {
74  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
75    write!(f, "{}/{}/{}", self.0, self.1, self.2)
76  }
77}
78
79impl TryFrom<&str> for WorkflowId {
80  type Error = Error;
81
82  fn try_from(value: &str) -> Result<Self, Self::Error> {
83    if value.is_empty() {
84      Err(Error::internal_runtime_error("WorkflowId cannot be empty"))
85    } else {
86      Ok(WorkflowId(value.to_string()))
87    }
88  }
89}
90
91impl TryFrom<&str> for JobId {
92  type Error = Error;
93
94  fn try_from(value: &str) -> Result<Self, Self::Error> {
95    let parts: Vec<&str> = value.split('/').collect();
96    if parts.len() != 2 {
97      Err(Error::internal_runtime_error(
98        "JobId must be in the format of <workflow_id>/<job_key>",
99      ))
100    } else {
101      Ok(JobId(parts[0].to_string(), parts[1].to_string()))
102    }
103  }
104}
105
106impl TryFrom<&str> for StepId {
107  type Error = Error;
108
109  fn try_from(value: &str) -> Result<Self, Self::Error> {
110    let parts: Vec<&str> = value.split('/').collect();
111    if parts.len() != 3 {
112      Err(Error::internal_runtime_error(
113        "StepId must be in the format of <workflow_id>/<job_key>/<step_number>",
114      ))
115    } else {
116      let step_number = parts[2]
117        .parse::<usize>()
118        .map_err(|_| Error::internal_runtime_error("Step number must be a number"))?;
119      Ok(StepId(
120        parts[0].to_string(),
121        parts[1].to_string(),
122        step_number,
123      ))
124    }
125  }
126}
127
128#[cfg(test)]
129mod tests {
130  use super::*;
131
132  #[test]
133  fn test_workflow_id() {
134    let workflow_id = WorkflowId::new("test");
135    assert_eq!(workflow_id, WorkflowId("test".to_string()));
136  }
137
138  #[test]
139  fn test_job_id() {
140    let job_id = JobId::new("workflow", "job");
141    assert_eq!(job_id, JobId("workflow".to_string(), "job".to_string()));
142    assert_eq!(job_id.workflow_id(), WorkflowId("workflow".to_string()));
143    assert_eq!(job_id.job_key(), "job".to_string());
144  }
145
146  #[test]
147  fn test_step_id() {
148    let step_id = StepId::new("workflow", "job", 1);
149    assert_eq!(
150      step_id,
151      StepId("workflow".to_string(), "job".to_string(), 1)
152    );
153    assert_eq!(step_id.workflow_id(), WorkflowId("workflow".to_string()));
154    assert_eq!(
155      step_id.job_id(),
156      JobId("workflow".to_string(), "job".to_string())
157    );
158    assert_eq!(step_id.job_key(), "job".to_string());
159    assert_eq!(step_id.step_number(), 1);
160  }
161
162  #[test]
163  fn test_workflow_id_to_string() {
164    let workflow_id = WorkflowId::new("test");
165    assert_eq!(workflow_id.to_string(), "test".to_string());
166  }
167
168  #[test]
169  fn test_job_id_to_string() {
170    let job_id = JobId::new("workflow", "job");
171    assert_eq!(job_id.to_string(), "workflow/job".to_string());
172  }
173
174  #[test]
175  fn test_step_id_to_string() {
176    let step_id = StepId::new("workflow", "job", 1);
177    assert_eq!(step_id.to_string(), "workflow/job/1".to_string());
178  }
179
180  #[test]
181  fn test_workflow_id_try_from() {
182    let workflow_id = WorkflowId::try_from("test").unwrap();
183    assert_eq!(workflow_id, WorkflowId("test".to_string()));
184  }
185
186  #[test]
187  fn test_job_id_try_from() {
188    let job_id = JobId::try_from("workflow/job").unwrap();
189    assert_eq!(job_id, JobId("workflow".to_string(), "job".to_string()));
190  }
191
192  #[test]
193  fn test_step_id_try_from() {
194    let step_id = StepId::try_from("workflow/job/1").unwrap();
195    assert_eq!(
196      step_id,
197      StepId("workflow".to_string(), "job".to_string(), 1)
198    );
199  }
200
201  #[test]
202  fn test_workflow_id_try_from_empty() {
203    let workflow_id = WorkflowId::try_from("");
204    assert!(workflow_id.is_err());
205  }
206
207  #[test]
208  fn test_job_id_try_from_empty() {
209    let job_id = JobId::try_from("");
210    assert!(job_id.is_err());
211  }
212
213  #[test]
214  fn test_step_id_try_from_empty() {
215    let step_id = StepId::try_from("");
216    assert!(step_id.is_err());
217  }
218
219  #[test]
220  fn test_job_id_try_from_invalid() {
221    let job_id = JobId::try_from("workflow");
222    assert!(job_id.is_err());
223  }
224
225  #[test]
226  fn test_step_id_try_from_invalid() {
227    let step_id = StepId::try_from("workflow/job");
228    assert!(step_id.is_err());
229  }
230}