tank_postgres/
prepared.rs1use crate::{ValueWrap, util::postgres_type_to_value};
2use anyhow::anyhow;
3use std::{
4 borrow::Cow,
5 fmt::{self, Debug, Display},
6 mem,
7};
8use tank_core::{AsValue, Prepared, Result, RowLabels, ValueOwned};
9use tokio_postgres::Statement;
10
11#[derive(Debug)]
13pub struct PostgresPrepared {
14 pub(crate) statement: Statement,
15 pub(crate) labels: RowLabels,
16 pub(crate) params: Vec<ValueOwned>,
17 pub(crate) index: u64,
18}
19
20impl PostgresPrepared {
21 pub(crate) fn new(statement: Statement) -> Self {
22 let labels = statement
23 .columns()
24 .iter()
25 .map(|c| c.name().to_string())
26 .collect();
27 Self {
28 statement,
29 labels,
30 params: Vec::new(),
31 index: 0,
32 }
33 }
34
35 #[inline]
36 pub(crate) fn take_params(&mut self) -> Result<Vec<ValueWrap<'static>>> {
37 self.index = 0;
38 if self.params.is_empty() {
39 return Ok(Vec::new());
40 }
41 let types = self.statement.params();
42 mem::take(&mut self.params)
43 .into_iter()
44 .enumerate()
45 .map(|(i, param)| {
46 Ok(ValueWrap(Cow::Owned(
47 param.try_as(&postgres_type_to_value(&types[i]))?,
48 )))
49 })
50 .collect()
51 }
52}
53
54impl Prepared for PostgresPrepared {
55 fn as_any(self: Box<Self>) -> Box<dyn std::any::Any> {
56 self
57 }
58
59 fn is_empty(&self) -> bool {
60 false
61 }
62
63 fn clear_bindings(&mut self) -> Result<&mut Self> {
64 self.params.clear();
65 self.index = 0;
66 Ok(self)
67 }
68
69 fn bind(&mut self, value: impl AsValue) -> Result<&mut Self> {
70 self.bind_index(value, self.index)
71 }
72
73 fn bind_index(&mut self, value: impl AsValue, index: u64) -> Result<&mut Self> {
74 let len = self.statement.params().len();
75 self.params.resize_with(len, Default::default);
76 let target = self.params.get_mut(index as usize).ok_or_else(|| {
77 anyhow!("Index {index} cannot be bound, the query has only {len} parameters")
78 })?;
79 *target = value.as_value().into_owned();
80 self.index = index + 1;
81 Ok(self)
82 }
83}
84
85impl Display for PostgresPrepared {
86 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87 f.write_str("PostgresPrepared: ")?;
88 self.statement.fmt(f)
89 }
90}