tank_postgres/
prepared.rs

1use crate::{PostgresTransaction, ValueHolder};
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<ValueHolder>>, Portal>,
13}
14
15impl PostgresPrepared {
16    pub(crate) fn new(statement: Statement) -> Self {
17        Self {
18            statement,
19            index: Default::default(),
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 portal = transaction
41            .0
42            .bind_raw(
43                &self.statement,
44                mem::take(params).into_iter().map(Option::unwrap),
45            )
46            .await?;
47        self.value = Either::Right(portal.clone());
48        Ok(portal)
49    }
50    pub(crate) fn get_portal(&self) -> Option<Portal> {
51        if let Either::Right(portal) = &self.value {
52            portal.clone().into()
53        } else {
54            None
55        }
56    }
57}
58
59impl Prepared for PostgresPrepared {
60    fn bind<V: AsValue>(&mut self, value: V) -> Result<&mut Self> {
61        self.bind_index(value, self.index)
62    }
63    fn bind_index<V: AsValue>(&mut self, value: V, index: u64) -> Result<&mut Self> {
64        let Either::Left(params) = &mut self.value else {
65            return Err(Error::msg("The prepared statement is already complete"));
66        };
67        params.reserve(self.statement.params().len());
68        params[index as usize] = Some(value.as_value().into());
69        Ok(self)
70    }
71}
72
73impl Display for PostgresPrepared {
74    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75        self.statement.fmt(f)
76    }
77}