sea_orm_ffi/
transaction.rs1use crate::{
2 backend::FfiBackend,
3 connection::{
4 ConnectionVTable, execute_impl, execute_unprepared_impl, query_all_impl,
5 query_one_impl
6 },
7 db_err::FfiDbErr,
8 exec_result::FfiExecResult,
9 proxy_row::{FfiOptionalProxyRow, FfiProxyRow},
10 result::FfiResult,
11 statement::FfiStatement,
12 string::StringPtr,
13 vec::VecPtr
14};
15use async_compat::Compat;
16use async_ffi::{BorrowingFfiFuture, FfiFuture, FutureExt};
17use async_trait::async_trait;
18use futures_util::future::FutureExt as _;
19use sea_orm::{
20 ConnectionTrait, DatabaseBackend, DatabaseTransaction, DbErr, ExecResult,
21 QueryResult, Statement
22};
23use std::{ffi::c_void, future::Future, mem::ManuallyDrop};
24
25macro_rules! doc_safety {
27 () => {
28 concat!(
29 "\n",
30 "# Safety\n",
31 "\n",
32 "This function is only safe to be called on the same side of the FFI ",
33 "boundary that was used to construct the connection pointer using the ",
34 "[`new`](TransactionPtr::new) function, or any binary that was compiled ",
35 "using the exact same dependencies and the exact same compiler and linker."
36 )
37 };
38}
39
40#[repr(transparent)]
45struct TransactionPtr(*mut c_void);
46
47impl TransactionPtr {
48 fn new(inner: Box<Compat<DatabaseTransaction>>) -> Self {
49 Self(Box::into_raw(inner) as _)
50 }
51
52 #[doc = doc_safety!()]
54 unsafe fn get(&self) -> &DatabaseTransaction {
55 let ptr: *mut Compat<DatabaseTransaction> = self.0.cast();
56 (*ptr).get_ref()
57 }
58
59 #[doc = doc_safety!()]
61 #[allow(clippy::wrong_self_convention)] unsafe fn into_inner(&mut self) -> Box<Compat<DatabaseTransaction>> {
63 let ptr: *mut Compat<DatabaseTransaction> = self.0.cast();
64 Box::from_raw(ptr)
65 }
66}
67
68type DropTransaction = extern "C" fn(&mut TransactionPtr);
70
71#[doc = doc_safety!()]
73extern "C" fn drop_transaction(ptr: &mut TransactionPtr) {
74 drop(unsafe { ptr.into_inner() });
75}
76
77type CommitTransaction =
81 extern "C" fn(&mut TransactionPtr) -> FfiFuture<FfiResult<(), FfiDbErr>>;
82
83#[doc = doc_safety!()]
85extern "C" fn commit_transaction(
86 ptr: &mut TransactionPtr
87) -> FfiFuture<FfiResult<(), FfiDbErr>> {
88 let conn = unsafe { ptr.into_inner() };
89 Compat::new(
90 async move { conn.into_inner().commit().await.map_err(Into::into).into() }
91 )
92 .into_ffi()
93}
94
95#[doc = doc_safety!()]
97extern "C" fn rollback_transaction(
98 ptr: &mut TransactionPtr
99) -> FfiFuture<FfiResult<(), FfiDbErr>> {
100 let conn = unsafe { ptr.into_inner() };
101 Compat::new(async move {
102 conn.into_inner()
103 .rollback()
104 .await
105 .map_err(Into::into)
106 .into()
107 })
108 .into_ffi()
109}
110
111#[doc = doc_safety!()]
113extern "C" fn get_database_backend(ptr: &TransactionPtr) -> FfiBackend {
114 unsafe { ptr.get() }.get_database_backend().into()
115}
116
117#[doc = doc_safety!()]
119extern "C" fn execute(
120 ptr: &TransactionPtr,
121 stmt: FfiStatement
122) -> BorrowingFfiFuture<'_, FfiResult<FfiExecResult, FfiDbErr>> {
123 execute_impl(unsafe { ptr.get() }, stmt)
124}
125
126#[doc = doc_safety!()]
128extern "C" fn execute_unprepared(
129 ptr: &TransactionPtr,
130 sql: StringPtr
131) -> BorrowingFfiFuture<'_, FfiResult<FfiExecResult, FfiDbErr>> {
132 execute_unprepared_impl(unsafe { ptr.get() }, sql)
133}
134
135#[doc = doc_safety!()]
137extern "C" fn query_one(
138 ptr: &TransactionPtr,
139 stmt: FfiStatement
140) -> BorrowingFfiFuture<'_, FfiResult<FfiOptionalProxyRow, FfiDbErr>> {
141 query_one_impl(unsafe { ptr.get() }, stmt)
142}
143
144#[doc = doc_safety!()]
146extern "C" fn query_all(
147 ptr: &TransactionPtr,
148 stmt: FfiStatement
149) -> BorrowingFfiFuture<'_, FfiResult<VecPtr<FfiProxyRow>, FfiDbErr>> {
150 query_all_impl(unsafe { ptr.get() }, stmt)
151}
152
153#[doc = doc_safety!()]
155extern "C" fn is_mock_connection(ptr: &TransactionPtr) -> bool {
156 unsafe { ptr.get() }.is_mock_connection()
157}
158
159#[repr(C)]
165pub struct FfiTransaction {
166 ptr: TransactionPtr,
167 drop: DropTransaction,
168 commit: CommitTransaction,
169 rollback: CommitTransaction,
170 vtable: ConnectionVTable<TransactionPtr>
171}
172
173impl FfiTransaction {
174 pub(crate) fn new(inner: DatabaseTransaction) -> Self {
175 Self {
176 ptr: TransactionPtr::new(Box::new(Compat::new(inner))),
177 drop: drop_transaction,
178 commit: commit_transaction,
179 rollback: rollback_transaction,
180 vtable: ConnectionVTable {
181 backend: get_database_backend,
182 execute,
183 execute_unprepared,
184 query_one,
185 query_all,
186 is_mock_connection
187 }
188 }
189 }
190
191 pub fn commit(self) -> impl Future<Output = Result<(), DbErr>> + Send {
192 let mut this = ManuallyDrop::new(self);
193 (this.commit)(&mut this.ptr)
194 .map(|res: FfiResult<(), FfiDbErr>| res.into_result().map_err(Into::into))
195 }
196
197 pub fn rollback(self) -> impl Future<Output = Result<(), DbErr>> + Send {
198 let mut this = ManuallyDrop::new(self);
199 (this.commit)(&mut this.ptr)
200 .map(|res: FfiResult<(), FfiDbErr>| res.into_result().map_err(Into::into))
201 }
202}
203
204impl Drop for FfiTransaction {
205 fn drop(&mut self) {
206 (self.drop)(&mut self.ptr)
207 }
208}
209
210unsafe impl Send for TransactionPtr {}
213unsafe impl Sync for TransactionPtr {}
214unsafe impl Send for FfiTransaction {}
215unsafe impl Sync for FfiTransaction {}
216
217#[async_trait]
218impl ConnectionTrait for FfiTransaction {
219 fn get_database_backend(&self) -> DatabaseBackend {
220 self.vtable.get_database_backend(&self.ptr)
221 }
222
223 async fn execute(&self, stmt: Statement) -> Result<ExecResult, DbErr> {
224 self.vtable.execute(&self.ptr, stmt).await
225 }
226
227 async fn execute_unprepared(&self, sql: &str) -> Result<ExecResult, DbErr> {
228 self.vtable.execute_unprepared(&self.ptr, sql).await
229 }
230
231 async fn query_one(&self, stmt: Statement) -> Result<Option<QueryResult>, DbErr> {
232 self.vtable.query_one(&self.ptr, stmt).await
233 }
234
235 async fn query_all(&self, stmt: Statement) -> Result<Vec<QueryResult>, DbErr> {
236 self.vtable.query_all(&self.ptr, stmt).await
237 }
238
239 fn is_mock_connection(&self) -> bool {
240 self.vtable.is_mock_connection(&self.ptr)
241 }
242}