tank_postgres/
prepared.rs1use crate::{PostgresTransaction, ValueWrap, postgres_type_to_value};
2use std::{
3 fmt::{self, Debug, Display},
4 mem,
5};
6use tank_core::{AsValue, Error, Prepared, Result, future::Either};
7use tokio_postgres::{Portal, Statement};
8
9pub struct PostgresPrepared {
10 pub(crate) statement: Statement,
11 pub(crate) index: u64,
12 pub(crate) value: Either<Vec<Option<ValueWrap>>, Portal>,
13}
14
15impl PostgresPrepared {
16 pub(crate) fn new(statement: Statement) -> Self {
17 Self {
18 statement,
19 index: 0,
20 value: Either::Left(vec![]),
21 }
22 }
23 pub(crate) fn is_complete(&self) -> bool {
24 matches!(self.value, Either::Right(..))
25 }
26 pub(crate) async fn complete<'t>(
27 &mut self,
28 transaction: &mut PostgresTransaction<'t>,
29 ) -> Result<Portal> {
30 let Either::Left(params) = &mut self.value else {
31 return Err(Error::msg("The prepared statement is already complete"));
32 };
33 if let Some(i) = params
34 .iter()
35 .enumerate()
36 .find_map(|(i, v)| if v.is_none() { Some(i) } else { None })
37 {
38 return Err(Error::msg(format!("The parameter {} was not set", i)));
39 }
40 let types = self.statement.params();
41 let mut params = mem::take(params);
42 let mut i = 0;
43 for param in &mut params {
44 *param = Some(ValueWrap(
45 mem::take(param)
46 .unwrap()
47 .0
48 .try_as(&postgres_type_to_value(&types[i]))?,
49 ));
50 i += 1;
51 }
52 let portal = transaction
53 .0
54 .bind_raw(&self.statement, params.into_iter().map(Option::unwrap))
55 .await?;
56 self.value = Either::Right(portal.clone());
57 Ok(portal)
58 }
59 pub(crate) fn get_portal(&self) -> Option<Portal> {
60 if let Either::Right(portal) = &self.value {
61 Some(portal.clone())
62 } else {
63 None
64 }
65 }
66}
67
68impl Prepared for PostgresPrepared {
69 fn bind(&mut self, value: impl AsValue) -> Result<&mut Self> {
70 self.bind_index(value, self.index)
71 }
72 fn bind_index(&mut self, value: impl AsValue, index: u64) -> Result<&mut Self> {
73 let Either::Left(params) = &mut self.value else {
74 return Err(Error::msg("The prepared statement is already complete"));
75 };
76 params.resize_with(self.statement.params().len(), || Default::default());
77 params[index as usize] = Some(value.as_value().into());
78 Ok(self)
79 }
80}
81
82impl Display for PostgresPrepared {
83 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84 self.statement.fmt(f)
85 }
86}