use crate::types::ChalkError;
#[derive(Debug, thiserror::Error)]
pub enum ChalkClientError {
#[error("configuration error: {0}")]
Config(String),
#[error("authentication error: {0}")]
Auth(String),
#[error("HTTP error: {0}")]
Http(#[from] reqwest::Error),
#[error("API error (status {status}): {message}")]
Api {
status: u16,
message: String,
},
#[error("JSON error: {0}")]
Json(#[from] serde_json::Error),
#[error("YAML error: {0}")]
Yaml(#[from] serde_yaml::Error),
#[error("Arrow error: {0}")]
Arrow(#[from] arrow::error::ArrowError),
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[error("gRPC error: {0}")]
Grpc(Box<tonic::Status>),
#[error("gRPC transport error: {0}")]
GrpcTransport(#[from] tonic::transport::Error),
#[error("server returned {} error(s): {}", .0.len(), .0.first().map(|e| e.message.as_str()).unwrap_or("unknown"))]
ServerErrors(Vec<ChalkError>),
}
impl From<tonic::Status> for ChalkClientError {
fn from(status: tonic::Status) -> Self {
ChalkClientError::Grpc(Box::new(status))
}
}
pub type Result<T> = std::result::Result<T, ChalkClientError>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_display() {
let err = ChalkClientError::Config("missing client_id".into());
assert!(err.to_string().contains("missing client_id"));
let err = ChalkClientError::Api {
status: 401,
message: "unauthorized".into(),
};
assert!(err.to_string().contains("401"));
assert!(err.to_string().contains("unauthorized"));
}
#[test]
fn test_server_errors_display() {
let errors = vec![
ChalkError {
code: "RESOLVER_FAILED".into(),
category: "FIELD".into(),
message: "resolver timed out".into(),
feature: Some("user.age".into()),
resolver: Some("get_user_age".into()),
exception: None,
},
ChalkError {
code: "RESOLVER_FAILED".into(),
category: "FIELD".into(),
message: "another error".into(),
feature: None,
resolver: None,
exception: None,
},
];
let err = ChalkClientError::ServerErrors(errors);
let msg = err.to_string();
assert!(msg.contains("2 error(s)"));
assert!(msg.contains("resolver timed out"));
}
}