sea_orm/database/
executor.rs

1use crate::{
2    AccessMode, ConnectionTrait, DatabaseConnection, DatabaseTransaction, DbBackend, DbErr,
3    ExecResult, IsolationLevel, QueryResult, Statement, TransactionError, TransactionTrait,
4};
5use crate::{Schema, SchemaBuilder};
6use std::future::Future;
7use std::pin::Pin;
8
9/// A wrapper that holds either a reference to a [`DatabaseConnection`] or [`DatabaseTransaction`].
10#[derive(Debug)]
11pub enum DatabaseExecutor<'c> {
12    /// A reference to a database connection
13    Connection(&'c DatabaseConnection),
14    /// A reference to a database transaction
15    Transaction(&'c DatabaseTransaction),
16}
17
18impl<'c> From<&'c DatabaseConnection> for DatabaseExecutor<'c> {
19    fn from(conn: &'c DatabaseConnection) -> Self {
20        Self::Connection(conn)
21    }
22}
23
24impl<'c> From<&'c DatabaseTransaction> for DatabaseExecutor<'c> {
25    fn from(trans: &'c DatabaseTransaction) -> Self {
26        Self::Transaction(trans)
27    }
28}
29
30impl ConnectionTrait for DatabaseExecutor<'_> {
31    fn get_database_backend(&self) -> DbBackend {
32        match self {
33            DatabaseExecutor::Connection(conn) => conn.get_database_backend(),
34            DatabaseExecutor::Transaction(trans) => trans.get_database_backend(),
35        }
36    }
37
38    fn execute_raw(&self, stmt: Statement) -> Result<ExecResult, DbErr> {
39        match self {
40            DatabaseExecutor::Connection(conn) => conn.execute_raw(stmt),
41            DatabaseExecutor::Transaction(trans) => trans.execute_raw(stmt),
42        }
43    }
44
45    fn execute_unprepared(&self, sql: &str) -> Result<ExecResult, DbErr> {
46        match self {
47            DatabaseExecutor::Connection(conn) => conn.execute_unprepared(sql),
48            DatabaseExecutor::Transaction(trans) => trans.execute_unprepared(sql),
49        }
50    }
51
52    fn query_one_raw(&self, stmt: Statement) -> Result<Option<QueryResult>, DbErr> {
53        match self {
54            DatabaseExecutor::Connection(conn) => conn.query_one_raw(stmt),
55            DatabaseExecutor::Transaction(trans) => trans.query_one_raw(stmt),
56        }
57    }
58
59    fn query_all_raw(&self, stmt: Statement) -> Result<Vec<QueryResult>, DbErr> {
60        match self {
61            DatabaseExecutor::Connection(conn) => conn.query_all_raw(stmt),
62            DatabaseExecutor::Transaction(trans) => trans.query_all_raw(stmt),
63        }
64    }
65}
66
67impl TransactionTrait for DatabaseExecutor<'_> {
68    type Transaction = DatabaseTransaction;
69
70    fn begin(&self) -> Result<DatabaseTransaction, DbErr> {
71        match self {
72            DatabaseExecutor::Connection(conn) => conn.begin(),
73            DatabaseExecutor::Transaction(trans) => trans.begin(),
74        }
75    }
76
77    fn begin_with_config(
78        &self,
79        isolation_level: Option<IsolationLevel>,
80        access_mode: Option<AccessMode>,
81    ) -> Result<DatabaseTransaction, DbErr> {
82        match self {
83            DatabaseExecutor::Connection(conn) => {
84                conn.begin_with_config(isolation_level, access_mode)
85            }
86            DatabaseExecutor::Transaction(trans) => {
87                trans.begin_with_config(isolation_level, access_mode)
88            }
89        }
90    }
91
92    fn transaction<F, T, E>(&self, callback: F) -> Result<T, TransactionError<E>>
93    where
94        F: for<'c> FnOnce(&'c DatabaseTransaction) -> Result<T, E>,
95        E: std::fmt::Display + std::fmt::Debug,
96    {
97        match self {
98            DatabaseExecutor::Connection(conn) => conn.transaction(callback),
99            DatabaseExecutor::Transaction(trans) => trans.transaction(callback),
100        }
101    }
102
103    fn transaction_with_config<F, T, E>(
104        &self,
105        callback: F,
106        isolation_level: Option<IsolationLevel>,
107        access_mode: Option<AccessMode>,
108    ) -> Result<T, TransactionError<E>>
109    where
110        F: for<'c> FnOnce(&'c DatabaseTransaction) -> Result<T, E>,
111        E: std::fmt::Display + std::fmt::Debug,
112    {
113        match self {
114            DatabaseExecutor::Connection(conn) => {
115                conn.transaction_with_config(callback, isolation_level, access_mode)
116            }
117            DatabaseExecutor::Transaction(trans) => {
118                trans.transaction_with_config(callback, isolation_level, access_mode)
119            }
120        }
121    }
122}
123
124/// A trait for converting into [`DatabaseExecutor`]
125pub trait IntoDatabaseExecutor<'c>
126where
127    Self: 'c,
128{
129    /// Convert into a [`DatabaseExecutor`]
130    fn into_database_executor(self) -> DatabaseExecutor<'c>;
131}
132
133impl<'c> IntoDatabaseExecutor<'c> for DatabaseExecutor<'c> {
134    fn into_database_executor(self) -> DatabaseExecutor<'c> {
135        self
136    }
137}
138
139impl<'c> IntoDatabaseExecutor<'c> for &'c DatabaseConnection {
140    fn into_database_executor(self) -> DatabaseExecutor<'c> {
141        DatabaseExecutor::Connection(self)
142    }
143}
144
145impl<'c> IntoDatabaseExecutor<'c> for &'c DatabaseTransaction {
146    fn into_database_executor(self) -> DatabaseExecutor<'c> {
147        DatabaseExecutor::Transaction(self)
148    }
149}
150
151impl DatabaseExecutor<'_> {
152    /// Creates a [`SchemaBuilder`] for this backend
153    pub fn get_schema_builder(&self) -> SchemaBuilder {
154        Schema::new(self.get_database_backend()).builder()
155    }
156
157    #[cfg(feature = "entity-registry")]
158    #[cfg_attr(docsrs, doc(cfg(feature = "entity-registry")))]
159    /// Builds a schema for all the entities in the given module
160    pub fn get_schema_registry(&self, prefix: &str) -> SchemaBuilder {
161        let schema = Schema::new(self.get_database_backend());
162        crate::EntityRegistry::build_schema(schema, prefix)
163    }
164}