Skip to main content

ruvector_collections/
error.rs

1//! Error types for collection management
2
3use thiserror::Error;
4
5/// Result type for collection operations
6pub type Result<T> = std::result::Result<T, CollectionError>;
7
8/// Errors that can occur during collection management
9#[derive(Debug, Error)]
10pub enum CollectionError {
11    /// Collection was not found
12    #[error("Collection not found: {name}")]
13    CollectionNotFound {
14        /// Name of the missing collection
15        name: String,
16    },
17
18    /// Collection already exists
19    #[error("Collection already exists: {name}")]
20    CollectionAlreadyExists {
21        /// Name of the existing collection
22        name: String,
23    },
24
25    /// Alias was not found
26    #[error("Alias not found: {alias}")]
27    AliasNotFound {
28        /// Name of the missing alias
29        alias: String,
30    },
31
32    /// Alias already exists
33    #[error("Alias already exists: {alias}")]
34    AliasAlreadyExists {
35        /// Name of the existing alias
36        alias: String,
37    },
38
39    /// Invalid collection configuration
40    #[error("Invalid configuration: {message}")]
41    InvalidConfiguration {
42        /// Error message
43        message: String,
44    },
45
46    /// Alias points to non-existent collection
47    #[error("Alias '{alias}' points to non-existent collection '{collection}'")]
48    InvalidAlias {
49        /// Alias name
50        alias: String,
51        /// Target collection name
52        collection: String,
53    },
54
55    /// Cannot delete collection with active aliases
56    #[error("Cannot delete collection '{collection}' because it has active aliases: {aliases:?}")]
57    CollectionHasAliases {
58        /// Collection name
59        collection: String,
60        /// List of aliases
61        aliases: Vec<String>,
62    },
63
64    /// Invalid collection name
65    #[error("Invalid collection name: {name} - {reason}")]
66    InvalidName {
67        /// Collection name
68        name: String,
69        /// Reason for invalidity
70        reason: String,
71    },
72
73    /// Core database error
74    #[error("Database error: {0}")]
75    DatabaseError(#[from] ruvector_core::error::RuvectorError),
76
77    /// IO error
78    #[error("IO error: {0}")]
79    IoError(#[from] std::io::Error),
80
81    /// Serialization error
82    #[error("Serialization error: {0}")]
83    SerializationError(String),
84}
85
86impl From<serde_json::Error> for CollectionError {
87    fn from(err: serde_json::Error) -> Self {
88        CollectionError::SerializationError(err.to_string())
89    }
90}
91
92impl From<bincode::error::EncodeError> for CollectionError {
93    fn from(err: bincode::error::EncodeError) -> Self {
94        CollectionError::SerializationError(err.to_string())
95    }
96}
97
98impl From<bincode::error::DecodeError> for CollectionError {
99    fn from(err: bincode::error::DecodeError) -> Self {
100        CollectionError::SerializationError(err.to_string())
101    }
102}
103
104#[cfg(test)]
105mod tests {
106    use super::*;
107
108    #[test]
109    fn test_collection_not_found_display() {
110        let err = CollectionError::CollectionNotFound {
111            name: "missing".to_string(),
112        };
113        assert_eq!(err.to_string(), "Collection not found: missing");
114    }
115
116    #[test]
117    fn test_collection_already_exists_display() {
118        let err = CollectionError::CollectionAlreadyExists {
119            name: "dup".to_string(),
120        };
121        assert_eq!(err.to_string(), "Collection already exists: dup");
122    }
123
124    #[test]
125    fn test_alias_not_found_display() {
126        let err = CollectionError::AliasNotFound {
127            alias: "no_alias".to_string(),
128        };
129        assert_eq!(err.to_string(), "Alias not found: no_alias");
130    }
131
132    #[test]
133    fn test_alias_already_exists_display() {
134        let err = CollectionError::AliasAlreadyExists {
135            alias: "dup_alias".to_string(),
136        };
137        assert_eq!(err.to_string(), "Alias already exists: dup_alias");
138    }
139
140    #[test]
141    fn test_invalid_configuration_display() {
142        let err = CollectionError::InvalidConfiguration {
143            message: "bad param".to_string(),
144        };
145        assert_eq!(err.to_string(), "Invalid configuration: bad param");
146    }
147
148    #[test]
149    fn test_invalid_alias_display() {
150        let err = CollectionError::InvalidAlias {
151            alias: "a".to_string(),
152            collection: "c".to_string(),
153        };
154        assert_eq!(
155            err.to_string(),
156            "Alias 'a' points to non-existent collection 'c'"
157        );
158    }
159
160    #[test]
161    fn test_collection_has_aliases_display() {
162        let err = CollectionError::CollectionHasAliases {
163            collection: "main".to_string(),
164            aliases: vec!["a1".to_string(), "a2".to_string()],
165        };
166        let msg = err.to_string();
167        assert!(msg.contains("main"));
168        assert!(msg.contains("a1"));
169        assert!(msg.contains("a2"));
170    }
171
172    #[test]
173    fn test_invalid_name_display() {
174        let err = CollectionError::InvalidName {
175            name: "bad!".to_string(),
176            reason: "special chars".to_string(),
177        };
178        assert_eq!(
179            err.to_string(),
180            "Invalid collection name: bad! - special chars"
181        );
182    }
183
184    #[test]
185    fn test_serialization_error_display() {
186        let err = CollectionError::SerializationError("parse fail".to_string());
187        assert_eq!(err.to_string(), "Serialization error: parse fail");
188    }
189
190    #[test]
191    fn test_io_error_conversion() {
192        let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file missing");
193        let err: CollectionError = io_err.into();
194        match err {
195            CollectionError::IoError(e) => {
196                assert_eq!(e.kind(), std::io::ErrorKind::NotFound);
197            }
198            other => panic!("Expected IoError, got: {:?}", other),
199        }
200    }
201
202    #[test]
203    fn test_serde_json_error_conversion() {
204        let json_err = serde_json::from_str::<serde_json::Value>("{{bad json").unwrap_err();
205        let err: CollectionError = json_err.into();
206        match err {
207            CollectionError::SerializationError(msg) => {
208                assert!(!msg.is_empty());
209            }
210            other => panic!("Expected SerializationError, got: {:?}", other),
211        }
212    }
213
214    #[test]
215    fn test_error_is_debug() {
216        let err = CollectionError::CollectionNotFound {
217            name: "test".to_string(),
218        };
219        let debug_str = format!("{:?}", err);
220        assert!(debug_str.contains("CollectionNotFound"));
221    }
222}