use serde::{Deserialize, Serialize};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum Error {
#[error("Database error: {0}")]
Database(#[from] velesdb_core::Error),
#[error("Collection '{0}' not found")]
CollectionNotFound(String),
#[error("Invalid configuration: {0}")]
InvalidConfig(String),
#[error("Serialization error: {0}")]
Serialization(String),
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
}
#[derive(Debug, Serialize, Deserialize)]
pub struct CommandError {
pub message: String,
pub code: String,
}
impl From<Error> for CommandError {
fn from(err: Error) -> Self {
let code = match &err {
Error::Database(core_err) => core_err.code(),
Error::CollectionNotFound(_) => "VELES-002",
Error::InvalidConfig(_) => "INVALID_CONFIG",
Error::Serialization(_) => "SERIALIZATION_ERROR",
Error::Io(_) => "VELES-011",
};
Self {
message: err.to_string(),
code: code.to_string(),
}
}
}
impl From<serde_json::Error> for Error {
fn from(err: serde_json::Error) -> Self {
Self::Serialization(err.to_string())
}
}
pub type Result<T> = std::result::Result<T, Error>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_display_collection_not_found() {
let err = Error::CollectionNotFound("test_collection".to_string());
let message = err.to_string();
assert_eq!(message, "Collection 'test_collection' not found");
}
#[test]
fn test_error_display_invalid_config() {
let err = Error::InvalidConfig("missing dimension".to_string());
let message = err.to_string();
assert_eq!(message, "Invalid configuration: missing dimension");
}
#[test]
fn test_command_error_from_error() {
let err = Error::CollectionNotFound("docs".to_string());
let cmd_err: CommandError = err.into();
assert_eq!(cmd_err.code, "VELES-002");
assert!(cmd_err.message.contains("docs"));
}
#[test]
fn test_command_error_codes() {
let cases = vec![
(Error::CollectionNotFound("x".to_string()), "VELES-002"),
(Error::InvalidConfig("x".to_string()), "INVALID_CONFIG"),
(Error::Serialization("x".to_string()), "SERIALIZATION_ERROR"),
];
for (err, expected_code) in cases {
let cmd_err: CommandError = err.into();
assert_eq!(cmd_err.code, expected_code);
}
}
#[test]
fn test_command_error_database_uses_core_code() {
let core_err = velesdb_core::Error::CollectionExists("test".to_string());
let err = Error::Database(core_err);
let cmd_err: CommandError = err.into();
assert_eq!(cmd_err.code, "VELES-001");
}
#[test]
fn test_command_error_io_uses_veles_011() {
let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file gone");
let err = Error::Io(io_err);
let cmd_err: CommandError = err.into();
assert_eq!(cmd_err.code, "VELES-011");
}
}