249 lines
6.2 KiB
Rust
249 lines
6.2 KiB
Rust
//! Error types for Attune services
|
|
//!
|
|
//! This module provides a unified error handling approach across all services.
|
|
|
|
use thiserror::Error;
|
|
|
|
use crate::mq::MqError;
|
|
|
|
/// Result type alias using Attune's Error type
|
|
pub type Result<T> = std::result::Result<T, Error>;
|
|
|
|
/// Main error type for Attune services
|
|
#[derive(Debug, Error)]
|
|
pub enum Error {
|
|
/// Database errors
|
|
#[error("Database error: {0}")]
|
|
Database(#[from] sqlx::Error),
|
|
|
|
/// Serialization/deserialization errors
|
|
#[error("Serialization error: {0}")]
|
|
Serialization(#[from] serde_json::Error),
|
|
|
|
/// I/O errors
|
|
#[error("I/O error: {0}")]
|
|
Io(String),
|
|
|
|
/// Validation errors
|
|
#[error("Validation error: {0}")]
|
|
Validation(String),
|
|
|
|
/// Not found errors
|
|
#[error("Not found: {entity} with {field}={value}")]
|
|
NotFound {
|
|
entity: String,
|
|
field: String,
|
|
value: String,
|
|
},
|
|
|
|
/// Already exists errors
|
|
#[error("Already exists: {entity} with {field}={value}")]
|
|
AlreadyExists {
|
|
entity: String,
|
|
field: String,
|
|
value: String,
|
|
},
|
|
|
|
/// Invalid state errors
|
|
#[error("Invalid state: {0}")]
|
|
InvalidState(String),
|
|
|
|
/// Permission denied errors
|
|
#[error("Permission denied: {0}")]
|
|
PermissionDenied(String),
|
|
|
|
/// Authentication errors
|
|
#[error("Authentication failed: {0}")]
|
|
AuthenticationFailed(String),
|
|
|
|
/// Configuration errors
|
|
#[error("Configuration error: {0}")]
|
|
Configuration(String),
|
|
|
|
/// Encryption/decryption errors
|
|
#[error("Encryption error: {0}")]
|
|
Encryption(String),
|
|
|
|
/// Timeout errors
|
|
#[error("Operation timed out: {0}")]
|
|
Timeout(String),
|
|
|
|
/// External service errors
|
|
#[error("External service error: {0}")]
|
|
ExternalService(String),
|
|
|
|
/// Worker errors
|
|
#[error("Worker error: {0}")]
|
|
Worker(String),
|
|
|
|
/// Execution errors
|
|
#[error("Execution error: {0}")]
|
|
Execution(String),
|
|
|
|
/// Schema validation errors
|
|
#[error("Schema validation error: {0}")]
|
|
SchemaValidation(String),
|
|
|
|
/// Generic internal errors
|
|
#[error("Internal error: {0}")]
|
|
Internal(String),
|
|
|
|
/// Wrapped anyhow errors for compatibility
|
|
#[error(transparent)]
|
|
Other(#[from] anyhow::Error),
|
|
}
|
|
|
|
impl Error {
|
|
/// Create a NotFound error
|
|
pub fn not_found(
|
|
entity: impl Into<String>,
|
|
field: impl Into<String>,
|
|
value: impl Into<String>,
|
|
) -> Self {
|
|
Self::NotFound {
|
|
entity: entity.into(),
|
|
field: field.into(),
|
|
value: value.into(),
|
|
}
|
|
}
|
|
|
|
/// Create an AlreadyExists error
|
|
pub fn already_exists(
|
|
entity: impl Into<String>,
|
|
field: impl Into<String>,
|
|
value: impl Into<String>,
|
|
) -> Self {
|
|
Self::AlreadyExists {
|
|
entity: entity.into(),
|
|
field: field.into(),
|
|
value: value.into(),
|
|
}
|
|
}
|
|
|
|
/// Create a Validation error
|
|
pub fn validation(msg: impl Into<String>) -> Self {
|
|
Self::Validation(msg.into())
|
|
}
|
|
|
|
/// Create an InvalidState error
|
|
pub fn invalid_state(msg: impl Into<String>) -> Self {
|
|
Self::InvalidState(msg.into())
|
|
}
|
|
|
|
/// Create a PermissionDenied error
|
|
pub fn permission_denied(msg: impl Into<String>) -> Self {
|
|
Self::PermissionDenied(msg.into())
|
|
}
|
|
|
|
/// Create an AuthenticationFailed error
|
|
pub fn authentication_failed(msg: impl Into<String>) -> Self {
|
|
Self::AuthenticationFailed(msg.into())
|
|
}
|
|
|
|
/// Create a Configuration error
|
|
pub fn configuration(msg: impl Into<String>) -> Self {
|
|
Self::Configuration(msg.into())
|
|
}
|
|
|
|
/// Create an Encryption error
|
|
pub fn encryption(msg: impl Into<String>) -> Self {
|
|
Self::Encryption(msg.into())
|
|
}
|
|
|
|
/// Create a Timeout error
|
|
pub fn timeout(msg: impl Into<String>) -> Self {
|
|
Self::Timeout(msg.into())
|
|
}
|
|
|
|
/// Create an ExternalService error
|
|
pub fn external_service(msg: impl Into<String>) -> Self {
|
|
Self::ExternalService(msg.into())
|
|
}
|
|
|
|
/// Create a Worker error
|
|
pub fn worker(msg: impl Into<String>) -> Self {
|
|
Self::Worker(msg.into())
|
|
}
|
|
|
|
/// Create an Execution error
|
|
pub fn execution(msg: impl Into<String>) -> Self {
|
|
Self::Execution(msg.into())
|
|
}
|
|
|
|
/// Create a SchemaValidation error
|
|
pub fn schema_validation(msg: impl Into<String>) -> Self {
|
|
Self::SchemaValidation(msg.into())
|
|
}
|
|
|
|
/// Create an Internal error
|
|
pub fn internal(msg: impl Into<String>) -> Self {
|
|
Self::Internal(msg.into())
|
|
}
|
|
|
|
/// Create an I/O error
|
|
pub fn io(msg: impl Into<String>) -> Self {
|
|
Self::Io(msg.into())
|
|
}
|
|
|
|
/// Check if this is a database error
|
|
pub fn is_database(&self) -> bool {
|
|
matches!(self, Self::Database(_))
|
|
}
|
|
|
|
/// Check if this is a not found error
|
|
pub fn is_not_found(&self) -> bool {
|
|
matches!(self, Self::NotFound { .. })
|
|
}
|
|
|
|
/// Check if this is an authentication error
|
|
pub fn is_auth_error(&self) -> bool {
|
|
matches!(
|
|
self,
|
|
Self::AuthenticationFailed(_) | Self::PermissionDenied(_)
|
|
)
|
|
}
|
|
}
|
|
|
|
/// Convert MqError to Error
|
|
impl From<MqError> for Error {
|
|
fn from(err: MqError) -> Self {
|
|
Self::Internal(format!("Message queue error: {}", err))
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_not_found_error() {
|
|
let err = Error::not_found("Pack", "ref", "mypack");
|
|
assert!(err.is_not_found());
|
|
assert_eq!(err.to_string(), "Not found: Pack with ref=mypack");
|
|
}
|
|
|
|
#[test]
|
|
fn test_already_exists_error() {
|
|
let err = Error::already_exists("Action", "ref", "myaction");
|
|
assert_eq!(err.to_string(), "Already exists: Action with ref=myaction");
|
|
}
|
|
|
|
#[test]
|
|
fn test_validation_error() {
|
|
let err = Error::validation("Invalid input");
|
|
assert_eq!(err.to_string(), "Validation error: Invalid input");
|
|
}
|
|
|
|
#[test]
|
|
fn test_is_auth_error() {
|
|
let err1 = Error::authentication_failed("Invalid token");
|
|
assert!(err1.is_auth_error());
|
|
|
|
let err2 = Error::permission_denied("No access");
|
|
assert!(err2.is_auth_error());
|
|
|
|
let err3 = Error::validation("Bad input");
|
|
assert!(!err3.is_auth_error());
|
|
}
|
|
}
|