xitca_postgres/
from_sql.rs1use 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
10pub trait FromSqlExt<'a>: Sized {
25 fn from_sql_ext(ty: &Type, col: (&Range<usize>, &'a Bytes)) -> Result<Self, FromSqlError>;
30
31 #[allow(unused_variables)]
38 #[inline]
39 fn from_sql_null_ext(ty: &Type) -> Result<Self, FromSqlError> {
40 Err(Box::new(WasNull))
41 }
42
43 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 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 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}