Skip to main content

rust_query/
query.rs

1use std::{
2    cell::{Cell, RefCell},
3    collections::BTreeMap,
4    fmt::{Debug, Display},
5    marker::PhantomData,
6    ops::{Deref, DerefMut},
7    rc::Rc,
8};
9
10use rusqlite::Connection;
11use self_cell::{MutBorrow, self_cell};
12
13use crate::{
14    IntoExpr,
15    lower::{
16        self,
17        emit::{self, IndexMap},
18        list_writer::ListWriter,
19        ord_rc::OrdRc,
20    },
21    rows::Rows,
22    select::{Cacher, DynPrepared, IntoSelect, Prepared, Row, SelectImpl},
23    transaction::TXN,
24    value::OrdTyp,
25};
26
27/// This is the type used by the [crate::Transaction::query] method.
28pub struct Query<'t, 'inner, S> {
29    pub(crate) phantom: PhantomData<&'t ()>,
30    pub(crate) q: Rows<'inner, S>,
31}
32
33impl<'inner, S> Deref for Query<'_, 'inner, S> {
34    type Target = Rows<'inner, S>;
35
36    fn deref(&self) -> &Self::Target {
37        &self.q
38    }
39}
40
41impl<S> DerefMut for Query<'_, '_, S> {
42    fn deref_mut(&mut self) -> &mut Self::Target {
43        &mut self.q
44    }
45}
46
47type Stmt<'x> = rusqlite::CachedStatement<'x>;
48type RRows<'a> = rusqlite::Rows<'a>;
49
50self_cell!(
51    pub struct OwnedRows<'x> {
52        owner: MutBorrow<Stmt<'x>>,
53
54        #[covariant]
55        dependent: RRows,
56    }
57);
58
59/// Lazy iterator over rows from a query.
60///
61/// This is currently invariant in `'inner` due to [MutBorrow].
62/// Would be nice to relax this variance in the future.
63pub struct Iter<'inner, O> {
64    // The actual OwnedRows is stored in a thread local
65    inner_phantom: PhantomData<(OwnedRows<'inner>, *const ())>,
66    inner: usize,
67
68    prepared: DynPrepared<O>,
69    cached: Vec<String>,
70}
71
72impl<O> Iterator for Iter<'_, O> {
73    type Item = O;
74
75    fn next(&mut self) -> Option<Self::Item> {
76        TXN.with_borrow_mut(|combi| {
77            let combi = combi.as_mut().unwrap();
78            combi.with_dependent_mut(|_txn, row_store| {
79                // If rows is already dropped then we just return None.
80                // This can happen if this is called in a thread_local destructor or something.
81                let rows = row_store.get_mut(self.inner)?;
82                rows.with_dependent_mut(|_, rows| {
83                    let row = rows.next().unwrap()?;
84                    Some(self.prepared.call(Row::new(row, &self.cached)))
85                })
86            })
87        })
88    }
89}
90
91impl<O> Drop for Iter<'_, O> {
92    fn drop(&mut self) {
93        TXN.with_borrow_mut(|combi| {
94            let combi = combi.as_mut().unwrap();
95            combi.with_dependent_mut(|_txn, row_store| {
96                // If the rows is already dropped that is fine.
97                // This can happen if this is called in a thread_local destructor or something.
98                row_store.try_remove(self.inner);
99            })
100        })
101    }
102}
103
104impl<'t, 'inner, S> Query<'t, 'inner, S> {
105    /// Turn a database query into a [Vec] of results.
106    ///
107    /// The order of rows that is returned is unstable. This means that the order may change between any two
108    /// executions of the exact same query. If a specific order (or even a consistent order) is required,
109    /// then you have to use something like [slice::sort].
110    pub fn into_vec<O>(&self, select: impl IntoSelect<'inner, S, Out = O>) -> Vec<O> {
111        self.into_iter(select).collect()
112    }
113
114    /// Turn a database query into an iterator of results.
115    ///
116    /// The order of rows that is returned is unstable. This means that the order may change between any two
117    /// executions of the exact same query. If a specific order (or even a consistent order) is required,
118    /// then you have to use something like [slice::sort]. See also [Self::order_by].
119    pub fn into_iter<O>(&self, select: impl IntoSelect<'inner, S, Out = O>) -> Iter<'t, O> {
120        self.order_by().into_iter(select)
121    }
122
123    /// Use [Self::order_by] to refine the order or retrieved rows (partially).
124    /// This is useful if not all rows are retrieved, e.g. for top N style queries.
125    ///
126    /// Every additional call to [OrderBy::asc] and [OrderBy::desc] refines the order further.
127    /// This means that e.g. `order_by().asc(category).asc(priority)`, will have all items
128    /// with the same `category` grouped together and only within the group are items sorted
129    /// by priority.
130    pub fn order_by<'q>(&'q self) -> OrderBy<'q, 't, 'inner, S> {
131        OrderBy {
132            query: self,
133            order: Vec::new(),
134        }
135    }
136}
137
138#[derive(Clone)]
139enum Order {
140    Asc,
141    Desc,
142}
143
144impl Display for Order {
145    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
146        match self {
147            Order::Asc => f.write_str("ASC"),
148            Order::Desc => f.write_str("DESC"),
149        }
150    }
151}
152
153/// This is the result of calling [Query::order_by].
154///
155/// Use [Self::asc] and [Self::desc] to refine the order of the returned rows.
156#[derive(Clone)]
157pub struct OrderBy<'q, 't, 'inner, S> {
158    query: &'q Query<'t, 'inner, S>,
159    order: Vec<(Rc<lower::Expr>, Order)>,
160}
161
162impl<'t, 'inner, S> OrderBy<'_, 't, 'inner, S> {
163    /// Add an additional value to sort on in ascending order.
164    pub fn asc<'q, T: OrdTyp>(mut self, key: impl IntoExpr<'inner, S, Typ = T>) -> Self {
165        self.order.push((key.into_expr().inner, Order::Asc));
166        self
167    }
168
169    /// Add an additional value to sort on in descending order.
170    pub fn desc<'q, T: OrdTyp>(mut self, key: impl IntoExpr<'inner, S, Typ = T>) -> Self {
171        self.order.push((key.into_expr().inner, Order::Desc));
172        self
173    }
174
175    /// Turn a database query into an iterator of results.
176    ///
177    /// Results are ordered as specified by [Self::asc] and [Self::desc].
178    ///
179    /// Rows of which the order is not determined by the calls to [Self::asc] and [Self::desc],
180    /// are returned in unspecified order. See also [Query::into_iter].
181    pub fn into_iter<O>(&self, select: impl IntoSelect<'inner, S, Out = O>) -> Iter<'t, O> {
182        let mut cacher = Cacher::new();
183        let prepared = select.into_select().inner.prepare(&mut cacher);
184
185        let mut selected = IndexMap::default();
186        let cached_aliases = cacher
187            .columns
188            .into_iter()
189            .map(|expr| {
190                let (idx, ()) = selected.insert_with(expr, |_| ());
191                format!("s{idx}")
192            })
193            .collect();
194
195        let order_by_cols: Vec<_> = self
196            .order
197            .iter()
198            .map(|(col, order)| {
199                let (idx, _) = selected.insert_with(col.clone(), |_| ());
200                (idx, order)
201            })
202            .collect();
203
204        let rows = self.query.ast.as_ref().clone();
205        let mut stmt = emit::Stmt::default();
206        let forwarded = rows.emit(&mut stmt, false, &selected);
207        assert!(forwarded.is_empty());
208
209        if !order_by_cols.is_empty() {
210            stmt.write(" ORDER BY ");
211            let mut list = ListWriter::new(&mut stmt, ", ");
212            for (idx, order) in order_by_cols {
213                list.item().write(idx + 1).write(" ").write(order);
214            }
215        }
216
217        TXN.with_borrow_mut(|txn| {
218            let combi = txn.as_mut().unwrap();
219
220            combi.with_dependent_mut(|conn, rows_store| {
221                track_stmt(conn.get(), &stmt.sql, &stmt.params);
222                let cached = MutBorrow::new(conn.get().prepare_cached(&stmt.sql).unwrap());
223
224                let idx = rows_store.insert(OwnedRows::new(cached, |cached| {
225                    cached
226                        .borrow_mut()
227                        .query(rusqlite::params_from_iter(stmt.params))
228                        .unwrap()
229                }));
230
231                Iter {
232                    inner: idx,
233                    inner_phantom: PhantomData,
234                    prepared,
235                    cached: cached_aliases,
236                }
237            })
238        })
239    }
240}
241
242pub(crate) fn track_stmt(
243    conn: &Connection,
244    sql: &String,
245    values: &[OrdRc<rusqlite::types::Value>],
246) {
247    if COLLECT.get() {
248        SQL_AND_PLAN.with_borrow_mut(|map| {
249            map.entry(sql.clone())
250                .or_insert_with(|| get_node(conn, values, sql));
251        });
252    }
253}
254
255thread_local! {
256    static COLLECT: Cell<bool> = const { Cell::new(false) };
257    static SQL_AND_PLAN: RefCell<BTreeMap<String, Node>> = const { RefCell::new(BTreeMap::new()) };
258}
259
260pub fn get_plan<R>(f: impl FnOnce() -> R) -> (R, BTreeMap<String, Node>) {
261    let old = COLLECT.get();
262    COLLECT.set(true);
263    let res = f();
264    COLLECT.set(old);
265    (res, SQL_AND_PLAN.take())
266}
267
268fn get_node(conn: &Connection, values: &[OrdRc<rusqlite::types::Value>], sql: &str) -> Node {
269    let mut prepared = conn.prepare(&format!("EXPLAIN QUERY PLAN {sql}")).unwrap();
270    let rows = prepared
271        .query_map(rusqlite::params_from_iter(values), |row| {
272            Ok((
273                row.get_unwrap("parent"),
274                Node {
275                    id: row.get_unwrap("id"),
276                    detail: row.get_unwrap("detail"),
277                    children: vec![],
278                },
279            ))
280        })
281        .unwrap();
282    let mut out = Node {
283        id: 0,
284        detail: "QUERY PLAN".to_owned(),
285        children: vec![],
286    };
287    rows.for_each(|res| {
288        let (id, node) = res.unwrap();
289        out.get_mut(id).children.push(node);
290    });
291
292    out
293}
294
295pub struct Node {
296    id: i64,
297    detail: String,
298    children: Vec<Node>,
299}
300
301impl Node {
302    fn get_mut(&mut self, id: i64) -> &mut Node {
303        if self.id == id {
304            return self;
305        }
306        self.children.last_mut().unwrap().get_mut(id)
307    }
308}
309
310impl Debug for Node {
311    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
312        f.write_str(&self.detail)?;
313        if !self.children.is_empty() {
314            f.write_str(" ")?;
315            f.debug_list().entries(&self.children).finish()?;
316        }
317        Ok(())
318    }
319}