sea_orm/database/
connection.rs

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