sevensense_vector/domain/
error.rs1use std::path::PathBuf;
4use thiserror::Error;
5
6use super::entities::{ConfigValidationError, EmbeddingId};
7
8#[derive(Debug, Error)]
10pub enum VectorError {
11 #[error("Dimension mismatch: expected {expected}, got {got}")]
13 DimensionMismatch {
14 expected: usize,
16 got: usize,
18 },
19
20 #[error("Vector with ID {0} already exists")]
22 DuplicateId(EmbeddingId),
23
24 #[error("Vector with ID {0} not found")]
26 NotFound(EmbeddingId),
27
28 #[error("Index capacity exceeded: max {max}, current {current}")]
30 CapacityExceeded {
31 max: usize,
33 current: usize,
35 },
36
37 #[error("Invalid vector data: {0}")]
39 InvalidVector(String),
40
41 #[error("Configuration error: {0}")]
43 ConfigError(#[from] ConfigValidationError),
44
45 #[error("Index is empty")]
47 EmptyIndex,
48
49 #[error("Serialization error: {0}")]
51 SerializationError(String),
52
53 #[error("IO error: {0}")]
55 IoError(#[from] std::io::Error),
56
57 #[error("File not found: {0}")]
59 FileNotFound(PathBuf),
60
61 #[error("Corrupted index file: {0}")]
63 CorruptedFile(String),
64
65 #[error("Failed to acquire lock: {0}")]
67 LockError(String),
68
69 #[error("Operation timed out after {0}ms")]
71 Timeout(u64),
72
73 #[error("Index not initialized")]
75 NotInitialized,
76
77 #[error("Concurrent modification detected")]
79 ConcurrentModification,
80
81 #[error("Graph error: {0}")]
83 GraphError(String),
84
85 #[error("Invalid search parameters: {0}")]
87 InvalidSearchParams(String),
88
89 #[error("Internal error: {0}")]
91 Internal(String),
92}
93
94impl VectorError {
95 pub fn dimension_mismatch(expected: usize, got: usize) -> Self {
97 Self::DimensionMismatch { expected, got }
98 }
99
100 pub fn capacity_exceeded(max: usize, current: usize) -> Self {
102 Self::CapacityExceeded { max, current }
103 }
104
105 pub fn invalid_vector(msg: impl Into<String>) -> Self {
107 Self::InvalidVector(msg.into())
108 }
109
110 pub fn serialization(msg: impl Into<String>) -> Self {
112 Self::SerializationError(msg.into())
113 }
114
115 pub fn corrupted(msg: impl Into<String>) -> Self {
117 Self::CorruptedFile(msg.into())
118 }
119
120 pub fn lock(msg: impl Into<String>) -> Self {
122 Self::LockError(msg.into())
123 }
124
125 pub fn graph(msg: impl Into<String>) -> Self {
127 Self::GraphError(msg.into())
128 }
129
130 pub fn invalid_search(msg: impl Into<String>) -> Self {
132 Self::InvalidSearchParams(msg.into())
133 }
134
135 pub fn internal(msg: impl Into<String>) -> Self {
137 Self::Internal(msg.into())
138 }
139
140 pub fn is_retriable(&self) -> bool {
142 matches!(
143 self,
144 Self::LockError(_) | Self::Timeout(_) | Self::ConcurrentModification
145 )
146 }
147
148 pub fn is_not_found(&self) -> bool {
150 matches!(self, Self::NotFound(_) | Self::FileNotFound(_))
151 }
152}
153
154impl From<bincode::Error> for VectorError {
155 fn from(e: bincode::Error) -> Self {
156 Self::SerializationError(e.to_string())
157 }
158}
159
160impl From<serde_json::Error> for VectorError {
161 fn from(e: serde_json::Error) -> Self {
162 Self::SerializationError(e.to_string())
163 }
164}
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169
170 #[test]
171 fn test_error_messages() {
172 let err = VectorError::dimension_mismatch(1536, 768);
173 assert!(err.to_string().contains("1536"));
174 assert!(err.to_string().contains("768"));
175
176 let err = VectorError::NotFound(EmbeddingId::new());
177 assert!(err.to_string().contains("not found"));
178 }
179
180 #[test]
181 fn test_is_retriable() {
182 assert!(VectorError::lock("test").is_retriable());
183 assert!(VectorError::Timeout(1000).is_retriable());
184 assert!(!VectorError::EmptyIndex.is_retriable());
185 }
186
187 #[test]
188 fn test_is_not_found() {
189 assert!(VectorError::NotFound(EmbeddingId::new()).is_not_found());
190 assert!(VectorError::FileNotFound(PathBuf::from("/test")).is_not_found());
191 assert!(!VectorError::EmptyIndex.is_not_found());
192 }
193}