xitca_postgres/
from_sql.rs

1use core::ops::Range;
2
3use xitca_io::bytes::Bytes;
4use xitca_unsafe_collection::bytes::BytesStr;
5
6use super::types::{FromSql, Type, WasNull};
7
8pub type FromSqlError = Box<dyn core::error::Error + Sync + Send>;
9
10/// extension trait for [FromSql]
11///
12/// instead of working with explicit reference as `&[u8]` for parsing raw sql bytes this extension
13/// offers cheap copy/slicing of [Bytes] type for reference counting based zero copy parsing.
14///
15/// # Examples
16/// ```rust
17/// # use xitca_postgres::row::Row;
18/// use xitca_unsafe_collection::bytes::BytesStr; // a reference counted &str type has FromSqlExt impl
19/// fn parse_row(row: Row<'_>) {
20///     let s = row.get_zc::<BytesStr>(0); // parse index0 column with zero copy.
21///     println!("{}", s.as_str());
22/// }
23/// ```
24pub trait FromSqlExt<'a>: Sized {
25    /// byte parser of non null Postgres type
26    /// [Type] represents the Postgres type hint which Self must be matching.
27    /// [Bytes] represents the reference of raw bytes of row data Self belongs to.
28    /// [Range] represents the start and end indexing into the raw data for correctly parsing Self.
29    fn from_sql_ext(ty: &Type, col: (&Range<usize>, &'a Bytes)) -> Result<Self, FromSqlError>;
30
31    /// Creates a new value of this type from a `NULL` SQL value.
32    ///
33    /// The caller of this method is responsible for ensuring that this type
34    /// is compatible with the Postgres `Type`.
35    ///
36    /// The default implementation returns `Err(Box::new(WasNull))`.
37    #[allow(unused_variables)]
38    #[inline]
39    fn from_sql_null_ext(ty: &Type) -> Result<Self, FromSqlError> {
40        Err(Box::new(WasNull))
41    }
42
43    /// A convenience function that delegates to `from_sql` and `from_sql_null`.
44    fn from_sql_nullable_ext(ty: &Type, col: (&Range<usize>, &'a Bytes)) -> Result<Self, FromSqlError> {
45        match col.0.is_empty() {
46            false => Self::from_sql_ext(ty, col),
47            true => Self::from_sql_null_ext(ty),
48        }
49    }
50
51    /// Determines if a value of this type can be created from the specified Postgres `Type`.
52    fn accepts_ext(ty: &Type) -> bool;
53}
54
55impl<'a> FromSqlExt<'a> for BytesStr {
56    fn from_sql_ext(ty: &Type, (range, buf): (&Range<usize>, &'a Bytes)) -> Result<Self, FromSqlError> {
57        // copy/paste from postgres-protocol dependency.
58        fn adjust_start(name: &str, range_start: usize, buf: &Bytes) -> Result<usize, FromSqlError> {
59            if buf[range_start] == 1u8 {
60                Ok(range_start + 1)
61            } else {
62                Err(format!("only {name} version 1 supported").into())
63            }
64        }
65
66        let start = match ty.name() {
67            "ltree" => adjust_start("ltree", range.start, buf)?,
68            "lquery" => adjust_start("lquery", range.start, buf)?,
69            "ltxtquery" => adjust_start("ltxtquery", range.start, buf)?,
70            _ => range.start,
71        };
72
73        BytesStr::try_from(buf.slice(start..range.end)).map_err(Into::into)
74    }
75
76    #[inline]
77    fn accepts_ext(ty: &Type) -> bool {
78        <&str as FromSql>::accepts(ty)
79    }
80}
81
82impl<'a> FromSqlExt<'a> for Bytes {
83    #[inline]
84    fn from_sql_ext(_: &Type, (range, buf): (&Range<usize>, &'a Bytes)) -> Result<Self, FromSqlError> {
85        Ok(buf.slice(range.start..range.end))
86    }
87
88    #[inline]
89    fn accepts_ext(ty: &Type) -> bool {
90        <&[u8] as FromSql>::accepts(ty)
91    }
92}
93
94impl<'a, T> FromSqlExt<'a> for Option<T>
95where
96    T: FromSqlExt<'a>,
97{
98    #[inline]
99    fn from_sql_ext(ty: &Type, raw: (&Range<usize>, &'a Bytes)) -> Result<Option<T>, FromSqlError> {
100        <T as FromSqlExt>::from_sql_ext(ty, raw).map(Some)
101    }
102
103    #[inline]
104    fn from_sql_null_ext(_: &Type) -> Result<Option<T>, FromSqlError> {
105        Ok(None)
106    }
107
108    #[inline]
109    fn accepts_ext(ty: &Type) -> bool {
110        <T as FromSqlExt>::accepts_ext(ty)
111    }
112}