1use crate::ValueWrap;
2use mysql_async::Statement;
3use std::{
4 borrow::Cow,
5 fmt::{self, Debug, Display},
6 mem,
7};
8use tank_core::{AsValue, Error, Prepared, Result, Value};
9
10#[derive(Debug)]
11pub struct MySQLPrepared {
16 pub(crate) statement: Statement,
17 pub(crate) params: Vec<Value>,
18 pub(crate) index: u64,
19}
20
21impl MySQLPrepared {
22 pub(crate) fn new(statement: Statement) -> Self {
23 Self {
24 statement,
25 params: Vec::new(),
26 index: 0,
27 }
28 }
29 pub(crate) fn take_params(&mut self) -> Result<mysql_async::Params> {
30 self.index = 0;
31 Ok(mysql_async::Params::Positional(
32 mem::take(&mut self.params)
33 .into_iter()
34 .map(|v| ValueWrap(Cow::Owned(v)).try_into())
35 .collect::<Result<_>>()?,
36 ))
37 }
38}
39
40impl Prepared for MySQLPrepared {
41 fn as_any(self: Box<Self>) -> Box<dyn std::any::Any> {
42 self
43 }
44 fn clear_bindings(&mut self) -> Result<&mut Self> {
45 self.params.clear();
46 self.index = 0;
47 Ok(self)
48 }
49 fn bind(&mut self, value: impl AsValue) -> Result<&mut Self> {
50 self.bind_index(value, self.index)
51 }
52 fn bind_index(&mut self, value: impl AsValue, index: u64) -> Result<&mut Self> {
53 let len = self.statement.num_params();
54 if self.params.is_empty() {
55 self.params.resize_with(len as _, Default::default);
56 }
57 let target = self
58 .params
59 .get_mut(index as usize)
60 .ok_or(Error::msg(format!(
61 "Index {index} cannot be bound, the query has only {len} parameters",
62 )))?;
63 *target = value.as_value();
64 self.index = index + 1;
65 Ok(self)
66 }
67}
68
69impl Display for MySQLPrepared {
70 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71 f.write_str("MySQLPrepared: ")?;
72 self.statement.fmt(f)
73 }
74}