cronback_lib/database/
errors.rs

1use sqlx::postgres::PgDatabaseError;
2use sqlx::sqlite::SqliteError;
3use thiserror::Error;
4
5const SQLITE_UNIQUE_CONSTRAINT_FAILED_CODE: &str = "2067";
6const POSTGRES_UNIQUE_CONSTRAINT_FAILED_CODE: &str = "23505";
7
8#[derive(Error, Debug)]
9pub enum DatabaseError {
10    #[error("serialization error: {0}")]
11    Parse(#[from] serde_json::Error),
12
13    #[error("constraint error: violated unique constraint")]
14    DuplicateRecord,
15
16    #[error("database error: {0}")]
17    DB(sea_orm::DbErr),
18}
19
20impl From<sea_orm::DbErr> for DatabaseError {
21    fn from(value: sea_orm::DbErr) -> Self {
22        match value {
23            | sea_orm::DbErr::Exec(sea_orm::RuntimeErr::SqlxError(
24                sqlx::Error::Database(db_err),
25            )) if is_duplicate_record_error(db_err.as_ref()) => {
26                DatabaseError::DuplicateRecord
27            }
28            | _ => DatabaseError::DB(value),
29        }
30    }
31}
32
33fn is_duplicate_record_error(db_err: &dyn sqlx::error::DatabaseError) -> bool {
34    if db_err.try_downcast_ref::<SqliteError>().is_some() {
35        return db_err.code().map(|a| a.to_string())
36            == Some(SQLITE_UNIQUE_CONSTRAINT_FAILED_CODE.to_string());
37    }
38    if db_err.try_downcast_ref::<PgDatabaseError>().is_some() {
39        return db_err.code().map(|a| a.to_string())
40            == Some(POSTGRES_UNIQUE_CONSTRAINT_FAILED_CODE.to_string());
41    }
42    false
43}