Skip to main content

premix_core/
error.rs

1use crate::model::ValidationError;
2
3/// Premix-specific error type with actionable variants.
4#[derive(Debug)]
5pub enum PremixError {
6    /// Underlying sqlx error.
7    Sqlx(sqlx::Error),
8    /// Optimistic locking conflict.
9    VersionConflict,
10    /// Validation failed.
11    Validation(Vec<ValidationError>),
12    /// Generic message error.
13    Message(String),
14}
15
16impl std::fmt::Display for PremixError {
17    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18        match self {
19            Self::Sqlx(err) => write!(f, "sqlx error: {}", err),
20            Self::VersionConflict => write!(f, "version conflict"),
21            Self::Validation(errors) => write!(f, "validation failed ({} errors)", errors.len()),
22            Self::Message(message) => write!(f, "{}", message),
23        }
24    }
25}
26
27impl std::error::Error for PremixError {}
28
29impl From<sqlx::Error> for PremixError {
30    fn from(err: sqlx::Error) -> Self {
31        map_sqlx_error(err)
32    }
33}
34
35impl From<Vec<ValidationError>> for PremixError {
36    fn from(errors: Vec<ValidationError>) -> Self {
37        Self::Validation(errors)
38    }
39}
40
41/// Result alias for Premix operations.
42pub type PremixResult<T> = Result<T, PremixError>;
43
44/// Convert sqlx errors to actionable Premix errors when possible.
45pub fn map_sqlx_error(err: sqlx::Error) -> PremixError {
46    if let sqlx::Error::Protocol(message) = &err {
47        let message = message.to_ascii_lowercase();
48        if message.contains("premix save failed: version conflict") {
49            return PremixError::VersionConflict;
50        }
51    }
52    PremixError::Sqlx(err)
53}