sea_orm/database/
connection.rs

1use crate::{
2    DatabaseTransaction, DbBackend, DbErr, ExecResult, QueryResult, Statement, StatementBuilder,
3    TransactionError,
4};
5use futures_util::Stream;
6use std::{future::Future, pin::Pin};
7
8/// The generic API for a database connection that can perform query or execute statements.
9/// It abstracts database connection and transaction
10#[async_trait::async_trait]
11pub trait ConnectionTrait: Sync {
12    /// Get the database backend for the connection. This depends on feature flags enabled.
13    fn get_database_backend(&self) -> DbBackend;
14
15    /// Execute a [Statement]
16    async fn execute_raw(&self, stmt: Statement) -> Result<ExecResult, DbErr>;
17
18    /// Execute a [QueryStatement]
19    async fn execute<S: StatementBuilder>(&self, stmt: &S) -> Result<ExecResult, DbErr> {
20        let db_backend = self.get_database_backend();
21        let stmt = db_backend.build(stmt);
22        self.execute_raw(stmt).await
23    }
24
25    /// Execute a unprepared [Statement]
26    async fn execute_unprepared(&self, sql: &str) -> Result<ExecResult, DbErr>;
27
28    /// Execute a [Statement] and return a single row of `QueryResult`
29    async fn query_one_raw(&self, stmt: Statement) -> Result<Option<QueryResult>, DbErr>;
30
31    /// Execute a [QueryStatement] and return a single row of `QueryResult`
32    async fn query_one<S: StatementBuilder>(&self, stmt: &S) -> Result<Option<QueryResult>, DbErr> {
33        let db_backend = self.get_database_backend();
34        let stmt = db_backend.build(stmt);
35        self.query_one_raw(stmt).await
36    }
37
38    /// Execute a [Statement] and return a vector of `QueryResult`
39    async fn query_all_raw(&self, stmt: Statement) -> Result<Vec<QueryResult>, DbErr>;
40
41    /// Execute a [QueryStatement] and return a vector of `QueryResult`
42    async fn query_all<S: StatementBuilder>(&self, stmt: &S) -> Result<Vec<QueryResult>, DbErr> {
43        let db_backend = self.get_database_backend();
44        let stmt = db_backend.build(stmt);
45        self.query_all_raw(stmt).await
46    }
47
48    /// Check if the connection supports `RETURNING` syntax on insert and update
49    fn support_returning(&self) -> bool {
50        let db_backend = self.get_database_backend();
51        db_backend.support_returning()
52    }
53
54    /// Check if the connection is a test connection for the Mock database
55    fn is_mock_connection(&self) -> bool {
56        false
57    }
58}
59
60/// Stream query results
61pub trait StreamTrait: Send + Sync {
62    /// Create a stream for the [QueryResult]
63    type Stream<'a>: Stream<Item = Result<QueryResult, DbErr>> + Send
64    where
65        Self: 'a;
66
67    /// Get the database backend for the connection. This depends on feature flags enabled.
68    fn get_database_backend(&self) -> DbBackend;
69
70    /// Execute a [Statement] and return a stream of results
71    fn stream_raw<'a>(
72        &'a self,
73        stmt: Statement,
74    ) -> Pin<Box<dyn Future<Output = Result<Self::Stream<'a>, DbErr>> + 'a + Send>>;
75
76    /// Execute a [QueryStatement] and return a stream of results
77    fn stream<'a, S: StatementBuilder + Sync>(
78        &'a self,
79        stmt: &S,
80    ) -> Pin<Box<dyn Future<Output = Result<Self::Stream<'a>, DbErr>> + 'a + Send>> {
81        let db_backend = self.get_database_backend();
82        let stmt = db_backend.build(stmt);
83        self.stream_raw(stmt)
84    }
85}
86
87#[derive(Copy, Clone, Debug, PartialEq, Eq)]
88/// Isolation level
89pub enum IsolationLevel {
90    /// Consistent reads within the same transaction read the snapshot established by the first read.
91    RepeatableRead,
92    /// Each consistent read, even within the same transaction, sets and reads its own fresh snapshot.
93    ReadCommitted,
94    /// SELECT statements are performed in a nonlocking fashion, but a possible earlier version of a row might be used.
95    ReadUncommitted,
96    /// All statements of the current transaction can only see rows committed before the first query or data-modification statement was executed in this transaction.
97    Serializable,
98}
99
100impl std::fmt::Display for IsolationLevel {
101    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102        match self {
103            IsolationLevel::RepeatableRead => write!(f, "REPEATABLE READ"),
104            IsolationLevel::ReadCommitted => write!(f, "READ COMMITTED"),
105            IsolationLevel::ReadUncommitted => write!(f, "READ UNCOMMITTED"),
106            IsolationLevel::Serializable => write!(f, "SERIALIZABLE"),
107        }
108    }
109}
110
111#[derive(Copy, Clone, Debug, PartialEq, Eq)]
112/// Access mode
113pub enum AccessMode {
114    /// Data can't be modified in this transaction
115    ReadOnly,
116    /// Data can be modified in this transaction (default)
117    ReadWrite,
118}
119
120impl std::fmt::Display for AccessMode {
121    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122        match self {
123            AccessMode::ReadOnly => write!(f, "READ ONLY"),
124            AccessMode::ReadWrite => write!(f, "READ WRITE"),
125        }
126    }
127}
128
129/// Spawn database transaction
130#[async_trait::async_trait]
131pub trait TransactionTrait {
132    /// Execute SQL `BEGIN` transaction.
133    /// Returns a Transaction that can be committed or rolled back
134    async fn begin(&self) -> Result<DatabaseTransaction, DbErr>;
135
136    /// Execute SQL `BEGIN` transaction with isolation level and/or access mode.
137    /// Returns a Transaction that can be committed or rolled back
138    async fn begin_with_config(
139        &self,
140        isolation_level: Option<IsolationLevel>,
141        access_mode: Option<AccessMode>,
142    ) -> Result<DatabaseTransaction, DbErr>;
143
144    /// Execute the function inside a transaction.
145    /// If the function returns an error, the transaction will be rolled back. If it does not return an error, the transaction will be committed.
146    async fn transaction<F, T, E>(&self, callback: F) -> Result<T, TransactionError<E>>
147    where
148        F: for<'c> FnOnce(
149                &'c DatabaseTransaction,
150            ) -> Pin<Box<dyn Future<Output = Result<T, E>> + Send + 'c>>
151            + Send,
152        T: Send,
153        E: std::fmt::Display + std::fmt::Debug + Send;
154
155    /// Execute the function inside a transaction with isolation level and/or access mode.
156    /// If the function returns an error, the transaction will be rolled back. If it does not return an error, the transaction will be committed.
157    async fn transaction_with_config<F, T, E>(
158        &self,
159        callback: F,
160        isolation_level: Option<IsolationLevel>,
161        access_mode: Option<AccessMode>,
162    ) -> Result<T, TransactionError<E>>
163    where
164        F: for<'c> FnOnce(
165                &'c DatabaseTransaction,
166            ) -> Pin<Box<dyn Future<Output = Result<T, E>> + Send + 'c>>
167            + Send,
168        T: Send,
169        E: std::fmt::Display + std::fmt::Debug + Send;
170}