#[derive(Debug, thiserror::Error)]
pub enum ExecuteError<E: std::error::Error + Send + Sync + 'static> {
#[error(transparent)]
Domain(E),
#[error("optimistic concurrency conflict: retries exhausted")]
Conflict,
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[error("aggregate actor is no longer running")]
ActorGone,
}
#[derive(Debug, thiserror::Error)]
pub enum StateError {
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[error("aggregate actor is no longer running")]
ActorGone,
}
#[derive(Debug, thiserror::Error)]
pub enum DispatchError {
#[error("unknown aggregate type: {0}")]
UnknownAggregateType(String),
#[error("no route registered for command type")]
UnknownCommand,
#[error("command deserialization failed: {0}")]
Deserialization(serde_json::Error),
#[error("command execution failed: {0}")]
Execution(Box<dyn std::error::Error + Send + Sync>),
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, thiserror::Error)]
#[error("test domain error")]
struct TestDomainError;
#[test]
fn execute_error_domain_displays_inner() {
let err: ExecuteError<TestDomainError> = ExecuteError::Domain(TestDomainError);
assert_eq!(err.to_string(), "test domain error");
}
#[test]
fn execute_error_conflict_display() {
let err: ExecuteError<TestDomainError> = ExecuteError::Conflict;
assert_eq!(
err.to_string(),
"optimistic concurrency conflict: retries exhausted"
);
}
#[test]
fn execute_error_io_from_conversion() {
let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file missing");
let err: ExecuteError<TestDomainError> = ExecuteError::from(io_err);
assert!(err.to_string().contains("file missing"));
}
#[test]
fn execute_error_actor_gone_display() {
let err: ExecuteError<TestDomainError> = ExecuteError::ActorGone;
assert_eq!(err.to_string(), "aggregate actor is no longer running");
}
#[test]
fn state_error_io_from_conversion() {
let io_err = std::io::Error::new(std::io::ErrorKind::PermissionDenied, "access denied");
let err: StateError = StateError::from(io_err);
assert!(err.to_string().contains("access denied"));
}
#[test]
fn state_error_actor_gone_display() {
let err = StateError::ActorGone;
assert_eq!(err.to_string(), "aggregate actor is no longer running");
}
const _: () = {
#[allow(dead_code)]
fn assert_send_sync<T: Send + Sync>() {}
#[allow(dead_code)]
fn check() {
assert_send_sync::<ExecuteError<TestDomainError>>();
assert_send_sync::<StateError>();
}
};
}