tank_core/
executor.rs

1use crate::{
2    AsQuery, Driver, Entity, Query, QueryResult, Result, RowLabeled, RowsAffected,
3    stream::{Stream, StreamExt, TryStreamExt},
4    writer::SqlWriter,
5};
6use std::future::Future;
7
8/// Async query executor bound to a concrete `Driver`.
9///
10/// Responsibilities:
11/// - Translate high-level operations into driver queries
12/// - Stream results without buffering the entire result set (if possible)
13/// - Provide ergonomic helpers for common patterns
14///
15/// Implementors typically wrap a connection or pooled handle.
16pub trait Executor: Send + Sized {
17    /// Associated driver.
18    type Driver: Driver;
19
20    /// Returns true if the executor accepts multiple SQL statements in a single
21    /// request (e.g. `CREATE; INSERT; SELECT`). Defaults to `true`.
22    fn accepts_multiple_statements(&self) -> bool {
23        true
24    }
25
26    /// Driver instance.
27    fn driver(&self) -> &Self::Driver;
28
29    /// Prepare a query for later execution.
30    fn prepare(
31        &mut self,
32        query: String,
33    ) -> impl Future<Output = Result<Query<Self::Driver>>> + Send;
34
35    /// Run a query, streaming `QueryResult` items.
36    fn run<'s>(
37        &'s mut self,
38        query: impl AsQuery<Self::Driver> + 's,
39    ) -> impl Stream<Item = Result<QueryResult>> + Send;
40
41    /// Stream only labeled rows (filters non-row results).
42    fn fetch<'s>(
43        &'s mut self,
44        query: impl AsQuery<Self::Driver> + 's,
45    ) -> impl Stream<Item = Result<RowLabeled>> + Send {
46        self.run(query).filter_map(|v| async move {
47            match v {
48                Ok(QueryResult::Row(v)) => Some(Ok(v)),
49                Err(e) => Some(Err(e)),
50                _ => None,
51            }
52        })
53    }
54
55    /// Execute and aggregate affected rows.
56    fn execute<'s>(
57        &'s mut self,
58        query: impl AsQuery<Self::Driver> + 's,
59    ) -> impl Future<Output = Result<RowsAffected>> + Send {
60        self.run(query)
61            .filter_map(|v| async move {
62                match v {
63                    Ok(QueryResult::Affected(v)) => Some(Ok(v)),
64                    Err(e) => Some(Err(e)),
65                    _ => None,
66                }
67            })
68            .try_collect()
69    }
70
71    /// Insert many entities efficiently.
72    fn append<'a, E, It>(
73        &mut self,
74        entities: It,
75    ) -> impl Future<Output = Result<RowsAffected>> + Send
76    where
77        E: Entity + 'a,
78        It: IntoIterator<Item = &'a E> + Send,
79        <It as IntoIterator>::IntoIter: Send,
80    {
81        let mut query = String::new();
82        self.driver()
83            .sql_writer()
84            .write_insert(&mut query, entities, false);
85        self.execute(query)
86    }
87}