1use thiserror::Error;
5
6#[derive(Debug, Error)]
8pub enum StoreError {
9 #[error("row not found")]
11 NotFound,
12 #[error("unique constraint violated: {0}")]
14 UniqueViolation(String),
15 #[error("constraint violated: {0}")]
17 CheckViolation(String),
18 #[error("foreign-key violation: {0}")]
20 ForeignKeyViolation(String),
21 #[error("database error: {0}")]
23 Database(String),
24 #[error("json serialization error: {0}")]
26 Json(String),
27 #[error("migration error: {0}")]
29 Migration(String),
30}
31
32impl From<sqlx::Error> for StoreError {
33 fn from(err: sqlx::Error) -> Self {
34 match err {
35 sqlx::Error::RowNotFound => Self::NotFound,
36 sqlx::Error::Database(ref db_err) => {
37 let constraint = db_err.constraint().unwrap_or("");
38 let msg = db_err.message().to_string();
39 let code = db_err.code().map(|c| c.to_string()).unwrap_or_default();
40 match code.as_str() {
42 "23505" => Self::UniqueViolation(format!("{constraint}: {msg}")),
43 "23503" => Self::ForeignKeyViolation(format!("{constraint}: {msg}")),
44 "23514" | "P0001" => Self::CheckViolation(format!("{constraint}: {msg}")),
45 _ => Self::Database(format!("{code}: {msg}")),
46 }
47 }
48 sqlx::Error::Migrate(e) => Self::Migration(e.to_string()),
49 sqlx::Error::ColumnDecode { source, .. } | sqlx::Error::Decode(source) => {
50 Self::Json(source.to_string())
51 }
52 other => Self::Database(other.to_string()),
53 }
54 }
55}
56
57pub type Result<T> = std::result::Result<T, StoreError>;