cala_ledger/transaction/
error.rs1use 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);