cala_ledger/transaction/
error.rs

1use regex::Regex;
2use thiserror::Error;
3
4use cala_types::primitives::TransactionId;
5
6#[derive(Error, Debug)]
7pub enum TransactionError {
8    #[error("TransactionError - Sqlx: {0}")]
9    Sqlx(sqlx::Error),
10    #[error("TransactionError - NotFound: external id '{0}' not found")]
11    CouldNotFindByExternalId(String),
12    #[error("TransactionError - NotFound: id '{0}' not found")]
13    CouldNotFindById(TransactionId),
14    #[error("TransactionError - EsEntityError: {0}")]
15    EsEntityError(es_entity::EsEntityError),
16    #[error("TransactionError - CursorDestructureError: {0}")]
17    CursorDestructureError(#[from] es_entity::CursorDestructureError),
18    #[error("TransactionError - DuplicateExternalId: external_id '{0}' already exists")]
19    DuplicateExternalId(String),
20    #[error("TransactionError - DuplicateId: id '{0}' already exists")]
21    DuplicateId(String),
22}
23
24impl From<sqlx::Error> for TransactionError {
25    fn from(e: sqlx::Error) -> Self {
26        match e {
27            sqlx::Error::Database(ref err) if err.is_unique_violation() => {
28                if err.constraint().is_none() {
29                    return Self::Sqlx(e);
30                };
31
32                let detail = err
33                    .downcast_ref::<sqlx::postgres::PgDatabaseError>()
34                    .detail();
35
36                if let Some(detail_msg) = detail {
37                    let re = Regex::new(r"Key \((?P<field>[^)]+)\)=\((?P<value>[^)]+)\)").unwrap();
38
39                    if let Some(caps) = re.captures(detail_msg) {
40                        let field = &caps["field"];
41                        let value = &caps["value"];
42
43                        match field {
44                            "external_id" => return Self::DuplicateExternalId(value.to_string()),
45                            "id" => return Self::DuplicateId(value.to_string()),
46                            _ => {}
47                        }
48                    }
49                }
50
51                Self::Sqlx(e)
52            }
53            e => Self::Sqlx(e),
54        }
55    }
56}
57
58es_entity::from_es_entity_error!(TransactionError);