Skip to main content

tank_core/query/
query.rs

1use crate::{
2    AsValue, Driver, DynQuery, Error, Prepared, Result, RowLabeled, RowsAffected, truncate_long,
3};
4use std::fmt::{self, Display};
5
6#[derive(Default, Clone, Debug)]
7pub struct RawQuery(pub String);
8
9impl Display for RawQuery {
10    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
11        write!(f, "{}", truncate_long!(self.0))
12    }
13}
14
15/// Executable query: raw SQL or prepared statement.
16#[derive(Debug)]
17pub enum Query<D: Driver> {
18    /// Unprepared SQL text.
19    Raw(RawQuery),
20    /// Driver prepared statement.
21    Prepared(D::Prepared),
22}
23
24impl<D: Driver> Query<D> {
25    /// Create a raw query
26    pub fn raw(value: String) -> Self {
27        Query::Raw(RawQuery(value))
28    }
29    /// Create a prepared query
30    pub fn prepared(value: D::Prepared) -> Self {
31        Query::Prepared(value)
32    }
33    /// Returns `true` when this `Query` contains a backend-prepared statement.
34    pub fn is_prepared(&self) -> bool {
35        matches!(self, Query::Prepared(..))
36    }
37    /// Clear all bound values.
38    pub fn clear_bindings(&mut self) -> Result<&mut Self> {
39        if let Self::Prepared(prepared) = self {
40            prepared.clear_bindings()?;
41        };
42        Ok(self)
43    }
44    /// Append a bound value.
45    /// It results in an error if the query is not prepared.
46    pub fn bind(&mut self, value: impl AsValue) -> Result<&mut Self> {
47        let Self::Prepared(prepared) = self else {
48            return Err(Error::msg("Cannot bind a raw query"));
49        };
50        prepared.bind(value)?;
51        Ok(self)
52    }
53    /// Bind a value at a specific index.
54    /// It results in an error if the query is not prepared.
55    pub fn bind_index(&mut self, value: impl AsValue, index: u64) -> Result<&mut Self> {
56        let Self::Prepared(prepared) = self else {
57            return Err(Error::msg("Cannot bind index of a raw query"));
58        };
59        prepared.bind_index(value, index)?;
60        Ok(self)
61    }
62    pub fn into_dyn(self) -> DynQuery {
63        self.into()
64    }
65}
66
67impl<D: Driver> Default for Query<D> {
68    fn default() -> Self {
69        Self::raw(Default::default())
70    }
71}
72
73impl<D: Driver> From<&str> for Query<D> {
74    fn from(value: &str) -> Self {
75        Self::raw(value.into())
76    }
77}
78
79impl<D: Driver> From<String> for Query<D> {
80    fn from(value: String) -> Self {
81        Self::raw(value)
82    }
83}
84
85impl<D, P> From<P> for Query<D>
86where
87    D: Driver<Prepared = P>,
88    P: Prepared,
89{
90    fn from(value: P) -> Self {
91        Self::prepared(value)
92    }
93}
94
95impl<D: Driver> Display for Query<D> {
96    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97        match self {
98            Query::Raw(v) => v.fmt(f),
99            Query::Prepared(query) => query.fmt(f),
100        }
101    }
102}
103
104impl<D: Driver> AsMut<Query<D>> for Query<D> {
105    fn as_mut(&mut self) -> &mut Query<D> {
106        self
107    }
108}
109
110/// Items from `Executor::run`: rows or effects.
111#[derive(Debug)]
112pub enum QueryResult {
113    /// A labeled row
114    Row(RowLabeled),
115    /// A modify effect aggregation
116    Affected(RowsAffected),
117}