#[derive(Debug, thiserror::Error)]
pub enum ProjectionError {
#[error("projection: db error: {0}")]
Db(#[from] sea_orm::DbErr),
#[error("projection: json error: {0}")]
Json(#[from] serde_json::Error),
#[error("projection: broadcast error: {0}")]
Broadcast(String),
#[error("projection: events error: {0}")]
Events(String),
#[error("projection: state not found for {name}/{key}")]
StateNotFound { name: &'static str, key: String },
}
impl From<ferro_broadcast::Error> for ProjectionError {
fn from(e: ferro_broadcast::Error) -> Self {
Self::Broadcast(e.to_string())
}
}
impl From<ferro_events::Error> for ProjectionError {
fn from(e: ferro_events::Error) -> Self {
Self::Events(e.to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn db_from_sea_orm_dberr() {
let db_err = sea_orm::DbErr::Custom("test".into());
let e: ProjectionError = ProjectionError::from(db_err);
assert!(matches!(e, ProjectionError::Db(_)));
assert!(e.to_string().starts_with("projection: db error: "));
}
#[test]
fn json_from_serde_json_error() {
let j: serde_json::Error =
serde_json::from_str::<serde_json::Value>("not json").unwrap_err();
let e: ProjectionError = ProjectionError::from(j);
assert!(matches!(e, ProjectionError::Json(_)));
assert!(e.to_string().starts_with("projection: json error: "));
}
#[test]
fn broadcast_display() {
let e = ProjectionError::Broadcast("oops".into());
assert_eq!(e.to_string(), "projection: broadcast error: oops");
}
#[test]
fn events_display() {
let e = ProjectionError::Events("oops".into());
assert_eq!(e.to_string(), "projection: events error: oops");
}
#[test]
fn state_not_found_display() {
let e = ProjectionError::StateNotFound {
name: "inventory.dashboard",
key: "warehouse-a".into(),
};
assert_eq!(
e.to_string(),
"projection: state not found for inventory.dashboard/warehouse-a"
);
}
}