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}
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);