1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
use std::result::Result as StdResult;

use rmpv::Value;

use crate::{
    codec::{consts::keys, request::Execute},
    errors::DecodingError,
    utils::{find_and_take_single_key_in_map, value_to_map},
    Executor, ExecutorExt, Result, SqlResponse, Tuple,
};

#[derive(Debug)]
pub struct PreparedSqlStatement<E> {
    stmt_id: u64,
    executor: E,
}

impl<E> PreparedSqlStatement<E> {
    fn new(stmt_id: u64, executor: E) -> Self {
        Self { stmt_id, executor }
    }

    pub fn from_prepare_response(response: Value, executor: E) -> StdResult<Self, DecodingError> {
        let map = value_to_map(response).map_err(|err| err.in_other("OK prepare response body"))?;
        let value = find_and_take_single_key_in_map(keys::SQL_STMT_ID, map).ok_or_else(|| {
            DecodingError::missing_key("SQL_STMT_ID").in_other("OK prepare response body")
        })?;
        let stmt_id: u64 = rmpv::ext::deserialize_from(value)
            .map_err(|err| DecodingError::from(err).in_key("SQL_STMT_ID"))?;
        Ok(Self::new(stmt_id, executor))
    }

    pub(crate) fn stmt_id(&self) -> u64 {
        self.stmt_id
    }
}

impl<E: Clone> Clone for PreparedSqlStatement<E> {
    fn clone(&self) -> Self {
        Self {
            stmt_id: self.stmt_id,
            executor: self.executor.clone(),
        }
    }
}

impl<E: Executor> PreparedSqlStatement<E> {
    /// Execute prepared SQL query with parameters.
    pub async fn execute<T>(&self, binds: T) -> Result<SqlResponse>
    where
        T: Tuple + Send,
    {
        Ok(SqlResponse(
            self.executor
                .send_request(Execute::new_statement_id(self.stmt_id, binds))
                .await?,
        ))
    }
}

impl<E: Clone> PreparedSqlStatement<&E> {
    pub fn with_cloned_executor(&self) -> PreparedSqlStatement<E> {
        PreparedSqlStatement {
            stmt_id: self.stmt_id,
            executor: self.executor.clone(),
        }
    }
}