version_migrate/
errors.rs

1//! Error types for migration operations.
2
3use thiserror::Error;
4
5/// Error types that can occur during migration operations.
6#[derive(Error, Debug)]
7pub enum MigrationError {
8    /// Failed to deserialize the data.
9    #[error("Failed to deserialize: {0}")]
10    DeserializationError(String),
11
12    /// Failed to serialize the data.
13    #[error("Failed to serialize: {0}")]
14    SerializationError(String),
15
16    /// The requested entity type was not found in the migrator.
17    #[error("Entity '{0}' not found")]
18    EntityNotFound(String),
19
20    /// No migration path is defined for the given entity and version.
21    #[error("No migration path defined for entity '{entity}' version '{version}'")]
22    MigrationPathNotDefined {
23        /// The entity name.
24        entity: String,
25        /// The version that has no migration path.
26        version: String,
27    },
28
29    /// A migration step failed during execution.
30    #[error("Migration failed from '{from}' to '{to}': {error}")]
31    MigrationStepFailed {
32        /// The source version.
33        from: String,
34        /// The target version.
35        to: String,
36        /// The error message.
37        error: String,
38    },
39
40    /// A circular migration path was detected.
41    #[error("Circular migration path detected in entity '{entity}': {path}")]
42    CircularMigrationPath {
43        /// The entity name.
44        entity: String,
45        /// The path that forms a cycle.
46        path: String,
47    },
48
49    /// Version ordering is invalid (not following semver rules).
50    #[error("Invalid version order in entity '{entity}': '{from}' -> '{to}' (versions must increase according to semver)")]
51    InvalidVersionOrder {
52        /// The entity name.
53        entity: String,
54        /// The source version.
55        from: String,
56        /// The target version.
57        to: String,
58    },
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64
65    #[test]
66    fn test_error_display_deserialization() {
67        let err = MigrationError::DeserializationError("invalid JSON".to_string());
68        let display = format!("{}", err);
69        assert!(display.contains("Failed to deserialize"));
70        assert!(display.contains("invalid JSON"));
71    }
72
73    #[test]
74    fn test_error_display_serialization() {
75        let err = MigrationError::SerializationError("invalid data".to_string());
76        let display = format!("{}", err);
77        assert!(display.contains("Failed to serialize"));
78        assert!(display.contains("invalid data"));
79    }
80
81    #[test]
82    fn test_error_display_entity_not_found() {
83        let err = MigrationError::EntityNotFound("user".to_string());
84        let display = format!("{}", err);
85        assert!(display.contains("Entity 'user' not found"));
86    }
87
88    #[test]
89    fn test_error_display_migration_path_not_defined() {
90        let err = MigrationError::MigrationPathNotDefined {
91            entity: "task".to_string(),
92            version: "2.0.0".to_string(),
93        };
94        let display = format!("{}", err);
95        assert!(display.contains("No migration path defined"));
96        assert!(display.contains("task"));
97        assert!(display.contains("2.0.0"));
98    }
99
100    #[test]
101    fn test_error_display_migration_step_failed() {
102        let err = MigrationError::MigrationStepFailed {
103            from: "1.0.0".to_string(),
104            to: "2.0.0".to_string(),
105            error: "field missing".to_string(),
106        };
107        let display = format!("{}", err);
108        assert!(display.contains("Migration failed"));
109        assert!(display.contains("1.0.0"));
110        assert!(display.contains("2.0.0"));
111        assert!(display.contains("field missing"));
112    }
113
114    #[test]
115    fn test_error_debug() {
116        let err = MigrationError::EntityNotFound("test".to_string());
117        let debug = format!("{:?}", err);
118        assert!(debug.contains("EntityNotFound"));
119    }
120
121    #[test]
122    fn test_error_is_std_error() {
123        let err = MigrationError::DeserializationError("test".to_string());
124        // MigrationError should implement std::error::Error
125        let _: &dyn std::error::Error = &err;
126    }
127
128    #[test]
129    fn test_error_display_circular_migration_path() {
130        let err = MigrationError::CircularMigrationPath {
131            entity: "task".to_string(),
132            path: "1.0.0 -> 2.0.0 -> 1.0.0".to_string(),
133        };
134        let display = format!("{}", err);
135        assert!(display.contains("Circular migration path"));
136        assert!(display.contains("task"));
137        assert!(display.contains("1.0.0 -> 2.0.0 -> 1.0.0"));
138    }
139
140    #[test]
141    fn test_error_display_invalid_version_order() {
142        let err = MigrationError::InvalidVersionOrder {
143            entity: "task".to_string(),
144            from: "2.0.0".to_string(),
145            to: "1.0.0".to_string(),
146        };
147        let display = format!("{}", err);
148        assert!(display.contains("Invalid version order"));
149        assert!(display.contains("task"));
150        assert!(display.contains("2.0.0"));
151        assert!(display.contains("1.0.0"));
152        assert!(display.contains("must increase"));
153    }
154}