sea_orm/database/
connection.rs

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