Skip to main content

bsql_core/
executor.rs

1//! The `Executor` trait — the runtime contract between generated code and the pool.
2//!
3//! Code generated by `bsql::query!` calls methods on this trait. Both `Pool`
4//! and `PoolConnection` implement it.
5
6use tokio_postgres::types::ToSql;
7
8use crate::error::{BsqlError, BsqlResult};
9use crate::pool::{Pool, PoolConnection};
10use crate::transaction::Transaction;
11
12/// Execute a prepared query and return raw rows.
13///
14/// This trait is sealed — it cannot be implemented outside of bsql-core.
15/// The generated code calls `query_raw` and `execute_raw` on either `&Pool`
16/// or `&PoolConnection`.
17pub trait Executor: sealed::Sealed {
18    /// Execute a query and return all rows.
19    fn query_raw(
20        &self,
21        sql: &str,
22        params: &[&(dyn ToSql + Sync)],
23    ) -> impl std::future::Future<Output = BsqlResult<Vec<tokio_postgres::Row>>> + Send;
24
25    /// Execute a query and return the number of affected rows.
26    fn execute_raw(
27        &self,
28        sql: &str,
29        params: &[&(dyn ToSql + Sync)],
30    ) -> impl std::future::Future<Output = BsqlResult<u64>> + Send;
31}
32
33mod sealed {
34    pub trait Sealed {}
35    impl Sealed for super::Pool {}
36    impl Sealed for super::PoolConnection {}
37    impl Sealed for super::Transaction {}
38}
39
40impl Executor for Pool {
41    async fn query_raw(
42        &self,
43        sql: &str,
44        params: &[&(dyn ToSql + Sync)],
45    ) -> BsqlResult<Vec<tokio_postgres::Row>> {
46        let conn = self.acquire().await?;
47        conn.query_raw(sql, params).await
48    }
49
50    async fn execute_raw(&self, sql: &str, params: &[&(dyn ToSql + Sync)]) -> BsqlResult<u64> {
51        let conn = self.acquire().await?;
52        conn.execute_raw(sql, params).await
53    }
54}
55
56impl Executor for PoolConnection {
57    async fn query_raw(
58        &self,
59        sql: &str,
60        params: &[&(dyn ToSql + Sync)],
61    ) -> BsqlResult<Vec<tokio_postgres::Row>> {
62        // prepare_cached: prepares on first use, reuses on subsequent calls.
63        // Named statements persist across borrows of the same connection.
64        let stmt = self
65            .inner
66            .prepare_cached(sql)
67            .await
68            .map_err(BsqlError::from)?;
69
70        self.inner
71            .query(&stmt, params)
72            .await
73            .map_err(BsqlError::from)
74    }
75
76    async fn execute_raw(&self, sql: &str, params: &[&(dyn ToSql + Sync)]) -> BsqlResult<u64> {
77        let stmt = self
78            .inner
79            .prepare_cached(sql)
80            .await
81            .map_err(BsqlError::from)?;
82
83        self.inner
84            .execute(&stmt, params)
85            .await
86            .map_err(BsqlError::from)
87    }
88}
89
90impl Executor for Transaction {
91    async fn query_raw(
92        &self,
93        sql: &str,
94        params: &[&(dyn ToSql + Sync)],
95    ) -> BsqlResult<Vec<tokio_postgres::Row>> {
96        self.connection().query_raw(sql, params).await
97    }
98
99    async fn execute_raw(&self, sql: &str, params: &[&(dyn ToSql + Sync)]) -> BsqlResult<u64> {
100        self.connection().execute_raw(sql, params).await
101    }
102}