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    #[error("TransactionError - AlreadyVoided: transaction '{0}' is already voided")]
23    AlreadyVoided(TransactionId),
24}
25
26impl From<sqlx::Error> for TransactionError {
27    fn from(e: sqlx::Error) -> Self {
28        match e {
29            sqlx::Error::Database(ref err) if err.is_unique_violation() => {
30                if err.constraint().is_none() {
31                    return Self::Sqlx(e);
32                };
33
34                let detail = err
35                    .downcast_ref::<sqlx::postgres::PgDatabaseError>()
36                    .detail();
37
38                if let Some(detail_msg) = detail {
39                    let re = Regex::new(r"Key \((?P<field>[^)]+)\)=\((?P<value>[^)]+)\)").unwrap();
40
41                    if let Some(caps) = re.captures(detail_msg) {
42                        let field = &caps["field"];
43                        let value = &caps["value"];
44
45                        match field {
46                            "external_id" => return Self::DuplicateExternalId(value.to_string()),
47                            "id" => return Self::DuplicateId(value.to_string()),
48                            _ => {}
49                        }
50                    }
51                }
52
53                Self::Sqlx(e)
54            }
55            e => Self::Sqlx(e),
56        }
57    }
58}
59
60es_entity::from_es_entity_error!(TransactionError);