tank_core/query/
query.rs

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