rust_query/
query.rs

1use std::{
2    cell::{Cell, RefCell},
3    collections::BTreeMap,
4    fmt::Debug,
5    marker::PhantomData,
6    ops::{Deref, DerefMut},
7};
8
9use rusqlite::Connection;
10use sea_query::SqliteQueryBuilder;
11use sea_query_rusqlite::{RusqliteBinder, RusqliteValues};
12use self_cell::{MutBorrow, self_cell};
13
14use crate::{
15    alias::MyAlias,
16    rows::Rows,
17    select::{Cacher, DynPrepared, IntoSelect, Prepared, Row, SelectImpl},
18    transaction::TXN,
19};
20
21/// This is the type used by the [crate::Transaction::query] method.
22pub struct Query<'t, 'inner, S> {
23    pub(crate) phantom: PhantomData<&'t ()>,
24    pub(crate) q: Rows<'inner, S>,
25}
26
27impl<'inner, S> Deref for Query<'_, 'inner, S> {
28    type Target = Rows<'inner, S>;
29
30    fn deref(&self) -> &Self::Target {
31        &self.q
32    }
33}
34
35impl<S> DerefMut for Query<'_, '_, S> {
36    fn deref_mut(&mut self) -> &mut Self::Target {
37        &mut self.q
38    }
39}
40
41type Stmt<'x> = rusqlite::CachedStatement<'x>;
42type RRows<'a> = rusqlite::Rows<'a>;
43
44self_cell!(
45    pub struct OwnedRows<'x> {
46        owner: MutBorrow<Stmt<'x>>,
47
48        #[covariant]
49        dependent: RRows,
50    }
51);
52
53/// Lazy iterator over rows from a query.
54///
55/// This is currently invariant in `'inner` due to [MutBorrow].
56/// Would be nice to relax this variance in the future.
57pub struct Iter<'inner, O> {
58    // The actual OwnedRows is stored in a thread local
59    inner_phantom: PhantomData<(OwnedRows<'inner>, *const ())>,
60    inner: usize,
61
62    prepared: DynPrepared<O>,
63    cached: Vec<MyAlias>,
64}
65
66impl<O> Iterator for Iter<'_, O> {
67    type Item = O;
68
69    fn next(&mut self) -> Option<Self::Item> {
70        TXN.with_borrow_mut(|combi| {
71            let combi = combi.as_mut().unwrap();
72            combi.with_dependent_mut(|_txn, row_store| {
73                // If rows is already dropped then we just return None.
74                // This can happen if this is called in a thread_local destructor or something.
75                let rows = row_store.get_mut(self.inner)?;
76                rows.with_dependent_mut(|_, rows| {
77                    let row = rows.next().unwrap()?;
78                    Some(self.prepared.call(Row::new(row, &self.cached)))
79                })
80            })
81        })
82    }
83}
84
85impl<O> Drop for Iter<'_, O> {
86    fn drop(&mut self) {
87        TXN.with_borrow_mut(|combi| {
88            let combi = combi.as_mut().unwrap();
89            combi.with_dependent_mut(|_txn, row_store| {
90                // If the rows is already dropped that is fine.
91                // This can happen if this is called in a thread_local destructor or something.
92                row_store.try_remove(self.inner);
93            })
94        })
95    }
96}
97
98impl<'t, 'inner, S> Query<'t, 'inner, S> {
99    /// Turn a database query into a [Vec] of results.
100    ///
101    /// The order of rows that is returned is unstable. This means that the order may change between any two
102    /// executions of the exact same query. If a specific order (or even a consistent order) is required,
103    /// then you have to use something like [slice::sort].
104    pub fn into_vec<O>(&self, select: impl IntoSelect<'inner, S, Out = O>) -> Vec<O> {
105        self.into_iter(select).collect()
106    }
107
108    /// Turn a database query into an iterator of results.
109    ///
110    /// The order of rows that is returned is unstable. This means that the order may change between any two
111    /// executions of the exact same query. If a specific order (or even a consistent order) is required,
112    /// then you have to use something like [slice::sort].
113    pub fn into_iter<O>(&self, select: impl IntoSelect<'inner, S, Out = O>) -> Iter<'t, O> {
114        let mut cacher = Cacher::new();
115        let prepared = select.into_select().inner.prepare(&mut cacher);
116        let (select, cached) = self.ast.clone().full().simple(cacher.columns);
117        let (sql, values) = select.build_rusqlite(SqliteQueryBuilder);
118
119        TXN.with_borrow_mut(|txn| {
120            let combi = txn.as_mut().unwrap();
121
122            combi.with_dependent_mut(|conn, rows_store| {
123                track_stmt(conn.get(), &sql, &values);
124                let statement = MutBorrow::new(conn.get().prepare_cached(&sql).unwrap());
125
126                let idx = rows_store.insert(OwnedRows::new(statement, |stmt| {
127                    stmt.borrow_mut().query(&*values.as_params()).unwrap()
128                }));
129
130                Iter {
131                    inner: idx,
132                    inner_phantom: PhantomData,
133                    prepared,
134                    cached,
135                }
136            })
137        })
138    }
139}
140
141pub(crate) fn track_stmt(conn: &Connection, sql: &String, values: &RusqliteValues) {
142    if COLLECT.get() {
143        SQL_AND_PLAN.with_borrow_mut(|map| {
144            map.entry(sql.clone())
145                .or_insert_with(|| get_node(conn, values, sql));
146        });
147    }
148}
149
150thread_local! {
151    static COLLECT: Cell<bool> = const { Cell::new(false) };
152    static SQL_AND_PLAN: RefCell<BTreeMap<String, Node>> = const { RefCell::new(BTreeMap::new()) };
153}
154
155pub fn get_plan<R>(f: impl FnOnce() -> R) -> (R, BTreeMap<String, Node>) {
156    let old = COLLECT.get();
157    COLLECT.set(true);
158    let res = f();
159    COLLECT.set(old);
160    (res, SQL_AND_PLAN.take())
161}
162
163fn get_node(conn: &Connection, values: &RusqliteValues, sql: &str) -> Node {
164    let mut prepared = conn.prepare(&format!("EXPLAIN QUERY PLAN {sql}")).unwrap();
165    let rows = prepared
166        .query_map(&*values.as_params(), |row| {
167            Ok((
168                row.get_unwrap("parent"),
169                Node {
170                    id: row.get_unwrap("id"),
171                    detail: row.get_unwrap("detail"),
172                    children: vec![],
173                },
174            ))
175        })
176        .unwrap();
177    let mut out = Node {
178        id: 0,
179        detail: "QUERY PLAN".to_owned(),
180        children: vec![],
181    };
182    rows.for_each(|res| {
183        let (id, node) = res.unwrap();
184        out.get_mut(id).children.push(node);
185    });
186
187    out
188}
189
190pub struct Node {
191    id: i64,
192    detail: String,
193    children: Vec<Node>,
194}
195
196impl Node {
197    fn get_mut(&mut self, id: i64) -> &mut Node {
198        if self.id == id {
199            return self;
200        }
201        self.children.last_mut().unwrap().get_mut(id)
202    }
203}
204
205impl Debug for Node {
206    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
207        f.write_str(&self.detail)?;
208        if !self.children.is_empty() {
209            f.write_str(" ")?;
210            f.debug_list().entries(&self.children).finish()?;
211        }
212        Ok(())
213    }
214}