Skip to main content

tank_core/query/
query.rs

1use crate::{AsValue, Driver, DynQuery, Prepared, Result, Row, RowsAffected, truncate_long};
2use anyhow::anyhow;
3use std::fmt::{self, Display};
4
5/// Byte span of a parameter marker inside a built query
6#[derive(Clone, Copy, Debug, PartialEq, Eq)]
7pub struct QueryParam {
8    pub begin: usize,
9    pub end: usize, // exclusive
10}
11
12#[derive(Default, Clone, Debug)]
13pub struct RawQuery {
14    pub sql: String,
15    pub params: Vec<QueryParam>,
16}
17
18impl RawQuery {
19    pub fn new(sql: String) -> Self {
20        Self {
21            sql,
22            params: Vec::new(),
23        }
24    }
25    pub fn with_params(sql: String, params: Vec<QueryParam>) -> Self {
26        Self { sql, params }
27    }
28    pub fn clear(&mut self) {
29        self.sql.clear();
30        self.params.clear();
31    }
32}
33
34impl From<String> for RawQuery {
35    fn from(value: String) -> Self {
36        Self::new(value)
37    }
38}
39
40impl From<RawQuery> for String {
41    fn from(value: RawQuery) -> Self {
42        value.sql
43    }
44}
45
46impl Display for RawQuery {
47    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48        write!(f, "{}", truncate_long!(self.sql))
49    }
50}
51
52/// Executable query: raw SQL or prepared statement.
53#[derive(Debug)]
54pub enum Query<D: Driver> {
55    /// Raw SQL text.
56    Raw(RawQuery),
57    /// Prepared statement.
58    Prepared(D::Prepared),
59}
60
61impl<D: Driver> Query<D> {
62    /// New raw query.
63    pub fn raw(value: String) -> Self {
64        Query::Raw(value.into())
65    }
66    /// New prepared query.
67    pub fn prepared(value: D::Prepared) -> Self {
68        Query::Prepared(value)
69    }
70    /// True if it is the prepared variant.
71    pub fn is_prepared(&self) -> bool {
72        matches!(self, Query::Prepared(..))
73    }
74    /// Clear bound values.
75    pub fn clear_bindings(&mut self) -> Result<&mut Self> {
76        if let Self::Prepared(prepared) = self {
77            prepared.clear_bindings()?;
78        };
79        Ok(self)
80    }
81    /// Bind value to next placeholder.
82    ///
83    /// Error if not prepared.
84    pub fn bind(&mut self, value: impl AsValue) -> Result<&mut Self> {
85        let Self::Prepared(prepared) = self else {
86            return Err(anyhow!("Cannot bind a raw query"));
87        };
88        prepared.bind(value)?;
89        Ok(self)
90    }
91    /// Bind value at index.
92    ///
93    /// Error if not prepared.
94    pub fn bind_index(&mut self, value: impl AsValue, index: u64) -> Result<&mut Self> {
95        let Self::Prepared(prepared) = self else {
96            return Err(anyhow!("Cannot bind index of a raw query"));
97        };
98        prepared.bind_index(value, index)?;
99        Ok(self)
100    }
101    pub fn into_dyn(self) -> DynQuery {
102        self.into()
103    }
104}
105
106impl<D: Driver> Default for Query<D> {
107    fn default() -> Self {
108        Self::raw(Default::default())
109    }
110}
111
112impl<D: Driver> From<&str> for Query<D> {
113    fn from(value: &str) -> Self {
114        Self::raw(value.into())
115    }
116}
117
118impl<D: Driver> From<String> for Query<D> {
119    fn from(value: String) -> Self {
120        Self::raw(value)
121    }
122}
123
124impl<D, P> From<P> for Query<D>
125where
126    D: Driver<Prepared = P>,
127    P: Prepared,
128{
129    fn from(value: P) -> Self {
130        Self::prepared(value)
131    }
132}
133
134impl<D: Driver> Display for Query<D> {
135    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136        match self {
137            Query::Raw(v) => v.fmt(f),
138            Query::Prepared(query) => query.fmt(f),
139        }
140    }
141}
142
143impl<D: Driver> AsMut<Query<D>> for Query<D> {
144    fn as_mut(&mut self) -> &mut Query<D> {
145        self
146    }
147}
148
149/// Items from `Executor::run`: rows or effects.
150#[derive(Debug)]
151pub enum QueryResult {
152    /// A labeled row
153    Row(Row),
154    /// A modify effect aggregation
155    Affected(RowsAffected),
156}