sea_orm/database/
connection.rs

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