tank-postgres 0.35.0

Postgres driver implementation for Tank: the Rust data layer
Documentation
use crate::ValueWrap;
use std::{
    borrow::Cow,
    fmt::{self, Debug, Display},
    mem,
};
use tank_core::{AsValue, Error, Prepared, Result, Value};
use tokio_postgres::Statement;

/// Postgres prepared statement.
#[derive(Debug)]
pub struct PostgresPrepared {
    pub(crate) statement: Statement,
    pub(crate) params: Vec<Value>,
    pub(crate) index: u64,
}

impl PostgresPrepared {
    pub(crate) fn new(statement: Statement) -> Self {
        Self {
            statement,
            params: Vec::new(),
            index: 0,
        }
    }

    pub(crate) fn take_params(&mut self) -> Vec<ValueWrap<'static>> {
        self.index = 0;
        mem::take(&mut self.params)
            .into_iter()
            .map(|v| ValueWrap(Cow::Owned(v)))
            .collect()
    }
}

impl Prepared for PostgresPrepared {
    fn as_any(self: Box<Self>) -> Box<dyn std::any::Any> {
        self
    }

    fn clear_bindings(&mut self) -> Result<&mut Self> {
        self.params.clear();
        self.index = 0;
        Ok(self)
    }

    fn bind(&mut self, value: impl AsValue) -> Result<&mut Self> {
        self.bind_index(value, self.index)
    }

    fn bind_index(&mut self, value: impl AsValue, index: u64) -> Result<&mut Self> {
        let len = self.statement.params().len();
        self.params.resize_with(len, Default::default);
        let target = self
            .params
            .get_mut(index as usize)
            .ok_or(Error::msg(format!(
                "Index {index} cannot be bound, the query has only {len} parameters",
            )))?;
        *target = value.as_value();
        self.index = index + 1;
        Ok(self)
    }
}

impl Display for PostgresPrepared {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("PostgresPrepared: ")?;
        self.statement.fmt(f)
    }
}