tank_core/
query.rs

1use crate::{AsValue, Driver, Error, Prepared, Result, Value, truncate_long};
2use std::{
3    fmt::{self, Display},
4    sync::Arc,
5};
6
7/// Executable query: raw SQL or prepared statement.
8#[derive(Debug)]
9pub enum Query<D: Driver> {
10    /// Unprepared SQL text.
11    Raw(String),
12    /// Driver prepared statement.
13    Prepared(D::Prepared),
14}
15
16impl<D: Driver> Query<D> {
17    pub fn is_prepared(&self) -> bool {
18        matches!(self, Query::Prepared(..))
19    }
20    /// Clear all bound values.
21    pub fn clear_bindings(&mut self) -> Result<&mut Self> {
22        let Self::Prepared(prepared) = self else {
23            return Err(Error::msg("Cannot clear bindings of a raw query"));
24        };
25        prepared.clear_bindings()?;
26        Ok(self)
27    }
28    /// Append a bound value.
29    /// It results in a error if the query is not prepared.
30    pub fn bind(&mut self, value: impl AsValue) -> Result<&mut Self> {
31        let Self::Prepared(prepared) = self else {
32            return Err(Error::msg("Cannot bind a raw query"));
33        };
34        prepared.bind(value)?;
35        Ok(self)
36    }
37    /// Bind a value at a specific index.
38    /// It results in a error if the query is not prepared.
39    pub fn bind_index(&mut self, value: impl AsValue, index: u64) -> Result<&mut Self> {
40        let Self::Prepared(prepared) = self else {
41            return Err(Error::msg("Cannot bind index of a raw query"));
42        };
43        prepared.bind_index(value, index)?;
44        Ok(self)
45    }
46}
47
48pub trait AsQuery<D: Driver> {
49    type Output: AsMut<Query<D>> + Send;
50    fn as_query(self) -> Self::Output;
51}
52
53impl<D: Driver> AsQuery<D> for Query<D> {
54    type Output = Query<D>;
55    fn as_query(self) -> Self::Output {
56        self
57    }
58}
59
60impl<'q, D: Driver + 'q> AsQuery<D> for &'q mut Query<D> {
61    type Output = &'q mut Query<D>;
62    fn as_query(self) -> Self::Output {
63        self
64    }
65}
66
67impl<D: Driver> AsQuery<D> for String {
68    type Output = Query<D>;
69    fn as_query(self) -> Self::Output {
70        Query::Raw(self)
71    }
72}
73
74impl<D: Driver> AsQuery<D> for &str {
75    type Output = Query<D>;
76    fn as_query(self) -> Self::Output {
77        Query::Raw(self.to_owned())
78    }
79}
80
81impl<D: Driver> Default for Query<D> {
82    fn default() -> Self {
83        Self::Raw(Default::default())
84    }
85}
86
87impl<D: Driver> From<&str> for Query<D> {
88    fn from(value: &str) -> Self {
89        Query::Raw(value.into())
90    }
91}
92
93impl<D: Driver> From<String> for Query<D> {
94    fn from(value: String) -> Self {
95        Query::Raw(value.into())
96    }
97}
98
99impl<D, P> From<P> for Query<D>
100where
101    D: Driver<Prepared = P>,
102    P: Prepared,
103{
104    fn from(value: P) -> Self {
105        Query::Prepared(value)
106    }
107}
108
109impl<D: Driver> Display for Query<D> {
110    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111        match self {
112            Query::Raw(query) => write!(f, "{}", truncate_long!(query)),
113            Query::Prepared(query) => query.fmt(f),
114        }
115    }
116}
117
118impl<D: Driver> AsMut<Query<D>> for Query<D> {
119    fn as_mut(&mut self) -> &mut Query<D> {
120        self
121    }
122}
123
124/// Metadata about modify operations (INSERT/UPDATE/DELETE).
125#[derive(Default, Debug, Clone, Copy)]
126pub struct RowsAffected {
127    /// Optional count of affected rows
128    pub rows_affected: Option<u64>,
129    /// Optional last inserted or affected id
130    pub last_affected_id: Option<i64>,
131}
132
133/// Shared reference-counted column name list.
134pub type RowNames = Arc<[String]>;
135/// Owned row value slice matching `RowNames` length.
136pub type Row = Box<[Value]>;
137
138/// Row with column labels.
139#[derive(Debug, Clone)]
140pub struct RowLabeled {
141    /// Column names
142    pub labels: RowNames,
143    /// Values aligned with labels
144    pub values: Row,
145}
146
147impl RowLabeled {
148    pub fn new(names: RowNames, values: Row) -> Self {
149        Self {
150            labels: names,
151            values,
152        }
153    }
154    pub fn names(&self) -> &[String] {
155        &self.labels
156    }
157    pub fn values(&self) -> &[Value] {
158        &self.values
159    }
160    pub fn get_column(&self, name: &str) -> Option<&Value> {
161        self.labels
162            .iter()
163            .position(|v| v == name)
164            .map(|i| &self.values()[i])
165    }
166}
167
168/// Items from `Executor::run`: rows or effects.
169#[derive(Debug)]
170pub enum QueryResult {
171    /// A labeled row
172    Row(RowLabeled),
173    /// A modify effect aggregation
174    Affected(RowsAffected),
175}
176
177impl Extend<RowsAffected> for RowsAffected {
178    fn extend<T: IntoIterator<Item = RowsAffected>>(&mut self, iter: T) {
179        for elem in iter {
180            if self.rows_affected.is_some() || elem.rows_affected.is_some() {
181                self.rows_affected = Some(
182                    self.rows_affected.unwrap_or_default() + elem.rows_affected.unwrap_or_default(),
183                );
184            }
185            if elem.last_affected_id.is_some() {
186                self.last_affected_id = elem.last_affected_id;
187            }
188        }
189    }
190}
191
192impl From<RowLabeled> for Row {
193    fn from(value: RowLabeled) -> Self {
194        value.values
195    }
196}
197
198impl<'a> From<&'a RowLabeled> for &'a Row {
199    fn from(value: &'a RowLabeled) -> Self {
200        &value.values
201    }
202}
203
204impl From<RowLabeled> for QueryResult {
205    fn from(value: RowLabeled) -> Self {
206        QueryResult::Row(value)
207    }
208}
209
210impl From<RowsAffected> for QueryResult {
211    fn from(value: RowsAffected) -> Self {
212        QueryResult::Affected(value)
213    }
214}