use thiserror::Error;
#[derive(Debug, Error)]
pub enum VectorError {
#[error("index error: {0}")]
Index(String),
#[error("store error: {0}")]
Store(Box<sqlx::Error>),
#[error("embedding error: {0}")]
Embedding(String),
#[error("gRPC error: {0}")]
Grpc(Box<tonic::Status>),
#[error("collection '{name}': {reason}")]
Collection {
name: String,
reason: String,
},
#[error("dimension mismatch: expected {expected}, got {got}")]
DimensionMismatch {
expected: usize,
got: usize,
},
#[error("serialization error: {0}")]
Serialization(Box<serde_json::Error>),
#[error("io error: {0}")]
Io(Box<std::io::Error>),
#[error("config error: {0}")]
Config(String),
#[error("search error: {0}")]
SearchError(String),
#[error("filter error: {0}")]
FilterError(String),
#[error("{entity} with id '{id}' not found")]
NotFound {
entity: String,
id: String,
},
}
impl VectorError {
pub fn is_not_found(&self) -> bool {
matches!(self, VectorError::NotFound { .. })
}
pub fn is_dimension_mismatch(&self) -> bool {
matches!(self, VectorError::DimensionMismatch { .. })
}
pub fn is_collection_error(&self) -> bool {
matches!(self, VectorError::Collection { .. })
}
}
impl From<sqlx::Error> for VectorError {
fn from(value: sqlx::Error) -> Self {
VectorError::Store(Box::new(value))
}
}
impl From<tonic::Status> for VectorError {
fn from(value: tonic::Status) -> Self {
VectorError::Grpc(Box::new(value))
}
}
impl From<serde_json::Error> for VectorError {
fn from(value: serde_json::Error) -> Self {
VectorError::Serialization(Box::new(value))
}
}
impl From<std::io::Error> for VectorError {
fn from(value: std::io::Error) -> Self {
VectorError::Io(Box::new(value))
}
}
impl From<VectorError> for tonic::Status {
fn from(e: VectorError) -> tonic::Status {
match &e {
VectorError::NotFound { entity, id } => {
tonic::Status::not_found(format!("{entity} '{id}' not found"))
}
VectorError::DimensionMismatch { expected, got } => tonic::Status::invalid_argument(
format!("dimension mismatch: expected {expected}, got {got}"),
),
VectorError::Collection { name, reason } => {
tonic::Status::invalid_argument(format!("collection '{name}': {reason}"))
}
VectorError::Config(msg) => tonic::Status::invalid_argument(msg.clone()),
VectorError::Embedding(msg) => tonic::Status::internal(msg.clone()),
VectorError::Index(msg) => tonic::Status::internal(msg.clone()),
VectorError::SearchError(msg) => tonic::Status::internal(msg.clone()),
VectorError::FilterError(msg) => tonic::Status::internal(msg.clone()),
VectorError::Grpc(status) => status.as_ref().clone(),
_ => tonic::Status::internal(e.to_string()),
}
}
}
pub type VectorResult<T> = Result<T, VectorError>;