use thiserror::Error;
#[derive(Debug, Error)]
pub enum StoreError {
#[error("row not found")]
NotFound,
#[error("unique constraint violated: {0}")]
UniqueViolation(String),
#[error("constraint violated: {0}")]
CheckViolation(String),
#[error("foreign-key violation: {0}")]
ForeignKeyViolation(String),
#[error("database error: {0}")]
Database(String),
#[error("json serialization error: {0}")]
Json(String),
#[error("migration error: {0}")]
Migration(String),
}
impl From<sqlx::Error> for StoreError {
fn from(err: sqlx::Error) -> Self {
match err {
sqlx::Error::RowNotFound => Self::NotFound,
sqlx::Error::Database(ref db_err) => {
let constraint = db_err.constraint().unwrap_or("");
let msg = db_err.message().to_string();
let code = db_err.code().map(|c| c.to_string()).unwrap_or_default();
match code.as_str() {
"23505" => Self::UniqueViolation(format!("{constraint}: {msg}")),
"23503" => Self::ForeignKeyViolation(format!("{constraint}: {msg}")),
"23514" | "P0001" => Self::CheckViolation(format!("{constraint}: {msg}")),
_ => Self::Database(format!("{code}: {msg}")),
}
}
sqlx::Error::Migrate(e) => Self::Migration(e.to_string()),
sqlx::Error::ColumnDecode { source, .. } | sqlx::Error::Decode(source) => {
Self::Json(source.to_string())
}
other => Self::Database(other.to_string()),
}
}
}
pub type Result<T> = std::result::Result<T, StoreError>;