es_entity/
one_time_executor.rs

1//! Type-safe wrapper to ensure one database operation per executor.
2
3use crate::operation::AtomicOperation;
4
5pub struct OneTimeExecutor<'c, E>
6where
7    E: sqlx::PgExecutor<'c>,
8{
9    executor: E,
10    _phantom: std::marker::PhantomData<&'c ()>,
11}
12
13impl<'c, E> OneTimeExecutor<'c, E>
14where
15    E: sqlx::PgExecutor<'c>,
16{
17    pub fn new(executor: E) -> Self {
18        OneTimeExecutor {
19            executor,
20            _phantom: std::marker::PhantomData,
21        }
22    }
23
24    pub async fn fetch_all<'q, F, O, A>(
25        self,
26        query: sqlx::query::Map<'q, sqlx::Postgres, F, A>,
27    ) -> Result<Vec<O>, sqlx::Error>
28    where
29        F: FnMut(sqlx::postgres::PgRow) -> Result<O, sqlx::Error> + Send,
30        O: Send + Unpin,
31        A: 'q + Send + sqlx::IntoArguments<'q, sqlx::Postgres>,
32    {
33        query.fetch_all(self.executor).await
34    }
35
36    pub async fn fetch_optional<'q, F, O, A>(
37        self,
38        query: sqlx::query::Map<'q, sqlx::Postgres, F, A>,
39    ) -> Result<Option<O>, sqlx::Error>
40    where
41        F: FnMut(sqlx::postgres::PgRow) -> Result<O, sqlx::Error> + Send,
42        O: Send + Unpin,
43        A: 'q + Send + sqlx::IntoArguments<'q, sqlx::Postgres>,
44    {
45        query.fetch_optional(self.executor).await
46    }
47}
48
49pub trait IntoOneTimeExecutor<'c>: IntoOneTimeExecutorAt<'c> + 'c {}
50impl<'c, T> IntoOneTimeExecutor<'c> for T where T: IntoOneTimeExecutorAt<'c> + 'c {}
51
52pub trait IntoOneTimeExecutorAt<'c> {
53    type Executor: sqlx::PgExecutor<'c>;
54
55    fn into_executor(self) -> OneTimeExecutor<'c, Self::Executor>
56    where
57        Self: 'c;
58}
59
60impl<'c> IntoOneTimeExecutorAt<'c> for &sqlx::PgPool {
61    type Executor = &'c sqlx::PgPool;
62
63    fn into_executor(self) -> OneTimeExecutor<'c, Self::Executor>
64    where
65        Self: 'c,
66    {
67        OneTimeExecutor::new(self)
68    }
69}
70
71impl<'c, O> IntoOneTimeExecutorAt<'c> for &mut O
72where
73    O: AtomicOperation,
74{
75    type Executor = &'c mut sqlx::PgConnection;
76
77    fn into_executor(self) -> OneTimeExecutor<'c, Self::Executor>
78    where
79        Self: 'c,
80    {
81        OneTimeExecutor::new(self.as_executor())
82    }
83}