lib_migrations_core/
phase.rs

1/// Deployment phase for a migration.
2///
3/// Migrations are split into phases for safe red-green deployments:
4///
5/// - **PreDeploy**: Runs BEFORE new code is deployed. Must be backward-compatible
6///   with the old code still running. Safe operations: add nullable columns,
7///   create new tables, add indexes.
8///
9/// - **PostDeploy**: Runs AFTER old code is fully terminated. Can include
10///   breaking changes. Operations: drop columns, rename columns, add NOT NULL
11///   constraints, drop tables.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
13pub enum Phase {
14    /// Runs before new code deployment (must be backward-compatible)
15    #[default]
16    PreDeploy,
17    /// Runs after old code is terminated (can be breaking)
18    PostDeploy,
19}
20
21impl Phase {
22    pub fn as_str(&self) -> &'static str {
23        match self {
24            Phase::PreDeploy => "pre-deploy",
25            Phase::PostDeploy => "post-deploy",
26        }
27    }
28}
29
30impl std::fmt::Display for Phase {
31    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32        write!(f, "{}", self.as_str())
33    }
34}
35
36impl std::str::FromStr for Phase {
37    type Err = String;
38
39    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
40        match s.to_lowercase().as_str() {
41            "pre-deploy" | "predeploy" | "pre" => Ok(Phase::PreDeploy),
42            "post-deploy" | "postdeploy" | "post" => Ok(Phase::PostDeploy),
43            _ => Err(format!("Unknown phase: {}. Use 'pre-deploy' or 'post-deploy'", s)),
44        }
45    }
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51
52    #[test]
53    fn test_phase_display() {
54        assert_eq!(Phase::PreDeploy.to_string(), "pre-deploy");
55        assert_eq!(Phase::PostDeploy.to_string(), "post-deploy");
56    }
57
58    #[test]
59    fn test_phase_parse() {
60        assert_eq!("pre-deploy".parse::<Phase>().unwrap(), Phase::PreDeploy);
61        assert_eq!("post-deploy".parse::<Phase>().unwrap(), Phase::PostDeploy);
62        assert_eq!("pre".parse::<Phase>().unwrap(), Phase::PreDeploy);
63        assert_eq!("post".parse::<Phase>().unwrap(), Phase::PostDeploy);
64    }
65
66    #[test]
67    fn test_phase_default() {
68        assert_eq!(Phase::default(), Phase::PreDeploy);
69    }
70}