use crate::flat::BinaryFlatIndexError;
use crate::hnsw::GraphError;
use crate::persistence::PersistenceError;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum EdgeVecError {
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error(transparent)]
Persistence(#[from] PersistenceError),
#[error(transparent)]
Graph(#[from] GraphError),
#[error(transparent)]
FlatIndex(#[from] BinaryFlatIndexError),
#[error("Validation error: {0}")]
Validation(String),
}
#[derive(Debug, Clone, PartialEq, Error)]
pub enum BatchError {
#[error("Empty batch: cannot insert zero vectors")]
EmptyBatch,
#[error("Dimension mismatch for vector {vector_id}: expected {expected}, got {actual}")]
DimensionMismatch {
expected: usize,
actual: usize,
vector_id: u64,
},
#[error("Duplicate vector ID: {vector_id}")]
DuplicateId {
vector_id: u64,
},
#[error("Invalid vector {vector_id}: {reason}")]
InvalidVector {
vector_id: u64,
reason: String,
},
#[error("Capacity exceeded: current={current}, max={max}")]
CapacityExceeded {
current: usize,
max: usize,
},
#[error("Internal error: {message}")]
InternalError {
message: String,
},
}
use wasm_bindgen::prelude::*;
impl From<EdgeVecError> for JsValue {
fn from(err: EdgeVecError) -> Self {
let (code, msg) = match &err {
EdgeVecError::Io(e) => ("ERR_IO", e.to_string()),
EdgeVecError::Persistence(pe) => match pe {
PersistenceError::Io(e) => ("ERR_IO", e.to_string()),
PersistenceError::ChecksumMismatch { .. }
| PersistenceError::Corrupted(_)
| PersistenceError::InvalidMagic { .. } => ("ERR_CORRUPTION", pe.to_string()),
_ => ("ERR_PERSISTENCE", pe.to_string()),
},
EdgeVecError::Graph(ge) => match ge {
GraphError::ConfigMismatch { .. } | GraphError::DimensionMismatch { .. } => {
("ERR_DIMENSION", ge.to_string())
}
GraphError::CapacityExceeded => ("ERR_CAPACITY", ge.to_string()),
_ => ("ERR_GRAPH", ge.to_string()),
},
EdgeVecError::FlatIndex(fe) => match fe {
BinaryFlatIndexError::InvalidDimensions(_)
| BinaryFlatIndexError::DimensionMismatch { .. } => {
("ERR_DIMENSION", fe.to_string())
}
BinaryFlatIndexError::CapacityOverflow(_, _) => ("ERR_CAPACITY", fe.to_string()),
},
EdgeVecError::Validation(msg) => ("ERR_VALIDATION", msg.clone()),
};
let obj = js_sys::Object::new();
let _ = js_sys::Reflect::set(&obj, &"code".into(), &code.into());
let _ = js_sys::Reflect::set(&obj, &"message".into(), &msg.into());
obj.into()
}
}
impl From<BatchError> for JsValue {
fn from(err: BatchError) -> Self {
let (code, msg) = match &err {
BatchError::EmptyBatch => ("EMPTY_BATCH", err.to_string()),
BatchError::DimensionMismatch { .. } => ("DIMENSION_MISMATCH", err.to_string()),
BatchError::DuplicateId { .. } => ("DUPLICATE_ID", err.to_string()),
BatchError::InvalidVector { .. } => ("INVALID_VECTOR", err.to_string()),
BatchError::CapacityExceeded { .. } => ("CAPACITY_EXCEEDED", err.to_string()),
BatchError::InternalError { .. } => ("INTERNAL_ERROR", err.to_string()),
};
let obj = js_sys::Object::new();
let _ = js_sys::Reflect::set(&obj, &"code".into(), &code.into());
let _ = js_sys::Reflect::set(&obj, &"message".into(), &msg.into());
obj.into()
}
}