Skip to main content

cufflink_pgcodec/
error.rs

1//! A Postgres failure as a guest receives it: the structured [`DbError`] of
2//! `db_call`, and the text of the legacy calls.
3
4use cufflink_types::db::{DbError, DbErrorFields, DbErrorKind};
5use std::error::Error;
6use tokio_postgres::error::ErrorPosition;
7
8/// The server's error fields when Postgres reported one; otherwise the
9/// failure is the connection's (closed socket, I/O, protocol).
10pub fn from_pg(error: &tokio_postgres::Error) -> DbError {
11    match error.as_db_error() {
12        Some(db) => DbErrorFields {
13            code: Some(db.code().code().to_string()),
14            kind: DbErrorKind::from_sqlstate(db.code().code()),
15            message: db.message().to_string(),
16            detail: db.detail().map(str::to_string),
17            hint: db.hint().map(str::to_string),
18            constraint: db.constraint().map(str::to_string),
19            table: db.table().map(str::to_string),
20            column: db.column().map(str::to_string),
21            schema: db.schema().map(str::to_string),
22            position: db.position().and_then(|position| match position {
23                ErrorPosition::Original(at) => Some(*at),
24                ErrorPosition::Internal { .. } => None,
25            }),
26        }
27        .into(),
28        None => DbError::new(DbErrorKind::Connection, flatten(error)),
29    }
30}
31
32fn flatten(error: &tokio_postgres::Error) -> String {
33    match error.source() {
34        Some(source) => format!("{error}: {source}"),
35        None => error.to_string(),
36    }
37}
38
39/// `tokio_postgres::Error` renders as the bare string "db error": what is
40/// worth reading (the constraint name, the syntax error, the detail line)
41/// hangs off its source, which is what the legacy calls hand a guest.
42pub fn server_message(error: &tokio_postgres::Error) -> String {
43    match error.source() {
44        Some(source) => source.to_string(),
45        None => error.to_string(),
46    }
47}