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};
7
8pub type FromSqlError = Box<dyn std::error::Error + Sync + Send>;
9
10pub trait FromSqlExt<'a>: Sized {
25 fn from_sql_nullable_ext(ty: &Type, col: (&Range<usize>, &'a Bytes)) -> Result<Self, FromSqlError>;
31
32 fn accepts(ty: &Type) -> bool;
34}
35
36impl<'a> FromSqlExt<'a> for BytesStr {
37 fn from_sql_nullable_ext(ty: &Type, (range, buf): (&Range<usize>, &'a Bytes)) -> Result<Self, FromSqlError> {
38 fn adjust_range(name: &str, range: &Range<usize>, buf: &Bytes) -> Result<(usize, usize), FromSqlError> {
40 if buf[range.start] == 1u8 {
41 Ok((range.start + 1, range.end))
42 } else {
43 Err(format!("only {name} version 1 supported").into())
44 }
45 }
46
47 if range.is_empty() {
48 return <&str as FromSql>::from_sql_null(ty)
49 .map(|_| unreachable!("<&str as FromSql>::from_sql_null should always yield Result::Err branch"));
50 }
51
52 let (start, end) = match ty.name() {
53 "ltree" => adjust_range("ltree", range, buf)?,
54 "lquery" => adjust_range("lquery", range, buf)?,
55 "ltxtquery" => adjust_range("ltxtquery", range, buf)?,
56 _ => (range.start, range.end),
57 };
58
59 BytesStr::try_from(buf.slice(start..end)).map_err(Into::into)
60 }
61
62 #[inline]
63 fn accepts(ty: &Type) -> bool {
64 <&str as FromSql>::accepts(ty)
65 }
66}
67
68impl<'a> FromSqlExt<'a> for Option<BytesStr> {
69 #[inline]
70 fn from_sql_nullable_ext(ty: &Type, col: (&Range<usize>, &'a Bytes)) -> Result<Self, FromSqlError> {
71 BytesStr::from_sql_nullable_ext(ty, col).map(Some)
72 }
73
74 #[inline]
75 fn accepts(ty: &Type) -> bool {
76 <BytesStr as FromSqlExt>::accepts(ty)
77 }
78}
79
80impl<'a> FromSqlExt<'a> for Bytes {
81 #[inline]
82 fn from_sql_nullable_ext(ty: &Type, (range, buf): (&Range<usize>, &'a Bytes)) -> Result<Self, FromSqlError> {
83 if range.is_empty() {
84 return <&[u8] as FromSql>::from_sql_null(ty)
85 .map(|_| unreachable!("<&[u8] as FromSql>::from_sql_null should always yield Result::Err branch"));
86 }
87
88 Ok(buf.slice(range.start..range.end))
89 }
90
91 #[inline]
92 fn accepts(ty: &Type) -> bool {
93 <&[u8] as FromSql>::accepts(ty)
94 }
95}
96
97impl<'a> FromSqlExt<'a> for Option<Bytes> {
98 #[inline]
99 fn from_sql_nullable_ext(ty: &Type, col: (&Range<usize>, &'a Bytes)) -> Result<Self, FromSqlError> {
100 Bytes::from_sql_nullable_ext(ty, col).map(Some)
101 }
102
103 #[inline]
104 fn accepts(ty: &Type) -> bool {
105 <Bytes as FromSqlExt>::accepts(ty)
106 }
107}