sql_middleware/postgres/
params.rs1use std::error::Error;
2
3use crate::middleware::{ConversionMode, ParamConverter, RowValues, SqlMiddlewareDbError};
4use tokio_postgres::types::{IsNull, ToSql, Type, to_sql_checked};
5use tokio_util::bytes;
6
7pub struct Params<'a> {
9 references: Vec<&'a (dyn ToSql + Sync)>,
10}
11
12impl<'a> Params<'a> {
13 pub fn convert(params: &'a [RowValues]) -> Result<Params<'a>, SqlMiddlewareDbError> {
18 let references: Vec<&(dyn ToSql + Sync)> =
19 params.iter().map(|p| p as &(dyn ToSql + Sync)).collect();
20
21 Ok(Params { references })
22 }
23
24 pub fn convert_for_batch(
29 params: &'a [RowValues],
30 ) -> Result<Vec<&'a (dyn ToSql + Sync + 'a)>, SqlMiddlewareDbError> {
31 let mut references = Vec::with_capacity(params.len());
33
34 for p in params {
36 references.push(p as &(dyn ToSql + Sync));
37 }
38
39 Ok(references)
40 }
41
42 #[must_use]
44 pub fn as_refs(&self) -> &[&(dyn ToSql + Sync)] {
45 &self.references
46 }
47}
48
49impl<'a> ParamConverter<'a> for Params<'a> {
50 type Converted = Params<'a>;
51
52 fn convert_sql_params(
53 params: &'a [RowValues],
54 _mode: ConversionMode,
55 ) -> Result<Self::Converted, SqlMiddlewareDbError> {
56 Self::convert(params)
58 }
59
60 fn supports_mode(_mode: ConversionMode) -> bool {
62 true
63 }
64}
65
66impl ToSql for RowValues {
67 fn to_sql(
68 &self,
69 ty: &Type,
70 out: &mut bytes::BytesMut,
71 ) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
72 match self {
73 RowValues::Int(i) => match *ty {
74 Type::INT8 => (*i).to_sql(ty, out),
75 Type::INT4 => {
76 let v = i32::try_from(*i).map_err(|_| {
77 SqlMiddlewareDbError::ExecutionError(format!(
78 "integer value {i} overflows Postgres INT4 parameter"
79 ))
80 })?;
81 v.to_sql(ty, out)
82 }
83 Type::INT2 => {
84 let v = i16::try_from(*i).map_err(|_| {
85 SqlMiddlewareDbError::ExecutionError(format!(
86 "integer value {i} overflows Postgres INT2 parameter"
87 ))
88 })?;
89 v.to_sql(ty, out)
90 }
91 _ => Err(Box::new(SqlMiddlewareDbError::ExecutionError(format!(
92 "unsupported integer parameter type: {ty:?}"
93 )))),
94 },
95 RowValues::Float(f) => (*f).to_sql(ty, out),
96 RowValues::Text(s) => s.to_sql(ty, out),
97 RowValues::Bool(b) => (*b).to_sql(ty, out),
98 RowValues::Timestamp(dt) => dt.to_sql(ty, out),
99 RowValues::Null => Ok(IsNull::Yes),
100 RowValues::JSON(jsval) => jsval.to_sql(ty, out),
101 RowValues::Blob(bytes) => bytes.to_sql(ty, out),
102 }
103 }
104
105 fn accepts(ty: &Type) -> bool {
106 match *ty {
108 Type::INT2 | Type::INT4 | Type::INT8 | Type::FLOAT4 | Type::FLOAT8 | Type::TEXT | Type::VARCHAR | Type::CHAR | Type::NAME | Type::BOOL | Type::TIMESTAMP | Type::TIMESTAMPTZ | Type::DATE | Type::JSON | Type::JSONB | Type::BYTEA => true, _ => false,
118 }
119 }
120
121 to_sql_checked!();
122}