use thiserror::Error;
use crate::embed::config::{API_KEY_ENV, OPENAI_API_KEY_ENV};
#[derive(Debug, Error)]
pub enum EmbedError {
#[error("http error: {0}")]
Http(#[from] reqwest::Error),
#[error("storage error: {0}")]
Storage(#[from] crate::storage::StorageError),
#[error("json error: {0}")]
Json(#[from] serde_json::Error),
#[error("api error ({status}): {body}")]
Api { status: u16, body: String },
#[error("missing API key: set {API_KEY_ENV} or {OPENAI_API_KEY_ENV}")]
MissingApiKey,
#[error("embedding dimension mismatch: expected {expected}, got {actual}")]
DimensionMismatch { expected: usize, actual: usize },
#[error("embedding service unavailable: {0}")]
Unavailable(String),
#[error("embedding table not available (VECTOR extension may be missing)")]
EmbeddingTableNotAvailable,
}
pub type Result<T> = std::result::Result<T, EmbedError>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn embed_error_missing_api_key_display() {
let err = EmbedError::MissingApiKey;
let msg = err.to_string();
assert!(msg.contains("missing API key"), "got: {msg}");
assert!(msg.contains(API_KEY_ENV), "got: {msg}");
}
#[test]
fn embed_error_dimension_mismatch_display() {
let err = EmbedError::DimensionMismatch {
expected: 384,
actual: 128,
};
let msg = err.to_string();
assert!(msg.contains("384"), "got: {msg}");
assert!(msg.contains("128"), "got: {msg}");
}
#[test]
fn embed_error_unavailable_display() {
let err = EmbedError::Unavailable("connection refused".to_string());
let msg = err.to_string();
assert!(msg.contains("unavailable"), "got: {msg}");
assert!(msg.contains("connection refused"), "got: {msg}");
}
#[test]
fn embed_error_api_display() {
let err = EmbedError::Api {
status: 401,
body: "unauthorized".to_string(),
};
let msg = err.to_string();
assert!(msg.contains("401"), "got: {msg}");
assert!(msg.contains("unauthorized"), "got: {msg}");
}
#[test]
fn embed_error_embedding_table_not_available_display() {
let err = EmbedError::EmbeddingTableNotAvailable;
let msg = err.to_string();
assert!(msg.contains("not available"), "got: {msg}");
}
#[test]
fn embed_error_is_send_sync() {
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<EmbedError>();
}
#[test]
fn embed_error_debug_includes_variant() {
let err = EmbedError::MissingApiKey;
let s = format!("{err:?}");
assert!(s.contains("MissingApiKey"), "got: {s}");
}
}