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    ///
28    /// Default implementation returns `Default::default()` for the associated
29    /// `Driver`. Executors that carry per-connection or pooled driver state
30    /// should override this method to return the appropriate driver instance.
31    fn driver(&self) -> Self::Driver
32    where
33        Self: Sized,
34    {
35        Default::default()
36    }
37
38    /// Prepare a query for later execution.
39    fn prepare(
40        &mut self,
41        query: String,
42    ) -> impl Future<Output = Result<Query<Self::Driver>>> + Send;
43
44    /// Run a query, streaming `QueryResult` items.
45    fn run<'s>(
46        &'s mut self,
47        query: impl AsQuery<Self::Driver> + 's,
48    ) -> impl Stream<Item = Result<QueryResult>> + Send;
49
50    /// Stream only labeled rows (filters non-row results).
51    fn fetch<'s>(
52        &'s mut self,
53        query: impl AsQuery<Self::Driver> + 's,
54    ) -> impl Stream<Item = Result<RowLabeled>> + Send {
55        self.run(query).filter_map(|v| async move {
56            match v {
57                Ok(QueryResult::Row(v)) => Some(Ok(v)),
58                Err(e) => Some(Err(e)),
59                _ => None,
60            }
61        })
62    }
63
64    /// Execute and aggregate affected rows.
65    fn execute<'s>(
66        &'s mut self,
67        query: impl AsQuery<Self::Driver> + 's,
68    ) -> impl Future<Output = Result<RowsAffected>> + Send {
69        self.run(query)
70            .filter_map(|v| async move {
71                match v {
72                    Ok(QueryResult::Affected(v)) => Some(Ok(v)),
73                    Err(e) => Some(Err(e)),
74                    _ => None,
75                }
76            })
77            .try_collect()
78    }
79
80    /// Insert many entities efficiently.
81    fn append<'a, E, It>(
82        &mut self,
83        entities: It,
84    ) -> impl Future<Output = Result<RowsAffected>> + Send
85    where
86        E: Entity + 'a,
87        It: IntoIterator<Item = &'a E> + Send,
88        <It as IntoIterator>::IntoIter: Send,
89    {
90        let mut query = String::new();
91        self.driver()
92            .sql_writer()
93            .write_insert(&mut query, entities, false);
94        self.execute(query)
95    }
96}