Skip to main content

rupg_types/
error.rs

1//! The error of an input function, with the SQLSTATE and the text that PostgreSQL gives.
2//!
3//! Lifted from `crates/rudb-pgtypes/src/error.rs` of tamnd/rudb at f5f7065a (spec/04 section 4.9).
4
5use rupg_common::SqlState;
6
7/// A value that a type cannot read. The text is the text of PostgreSQL for the same input, so the server can send it in `ErrorResponse` as it is.
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct TypeError {
10    pub sqlstate: SqlState,
11    pub message: String,
12    pub detail: Option<String>,
13    pub hint: Option<String>,
14    /// The context of PostgreSQL, such as the place in a `json` value.
15    pub context: Option<String>,
16}
17
18impl TypeError {
19    pub(crate) fn new(sqlstate: SqlState, message: String) -> TypeError {
20        TypeError { sqlstate, message, detail: None, hint: None, context: None }
21    }
22
23    /// `22P02`, `invalid input syntax for type integer: "1e3"`.
24    pub(crate) fn syntax(type_name: &str, input: &str) -> TypeError {
25        TypeError::new(
26            SqlState::INVALID_TEXT_REPRESENTATION,
27            format!("invalid input syntax for type {type_name}: \"{input}\""),
28        )
29    }
30
31    /// `22003`, `value "99999" is out of range for type smallint`.
32    pub(crate) fn range(input: &str, type_name: &str) -> TypeError {
33        TypeError::new(
34            SqlState::NUMERIC_VALUE_OUT_OF_RANGE,
35            format!("value \"{input}\" is out of range for type {type_name}"),
36        )
37    }
38}
39
40impl std::fmt::Display for TypeError {
41    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42        f.write_str(&self.message)
43    }
44}
45
46impl std::error::Error for TypeError {}
47
48/// The error with the same SQLSTATE, message, detail and hint. [`rupg_common::Error`] has no context line yet, so the context is lost.
49impl From<TypeError> for rupg_common::Error {
50    fn from(error: TypeError) -> rupg_common::Error {
51        let mut out = rupg_common::Error::new(error.sqlstate, error.message);
52        if let Some(detail) = error.detail {
53            out = out.with_detail(detail);
54        }
55        if let Some(hint) = error.hint {
56            out = out.with_hint(hint);
57        }
58        out
59    }
60}