parsql_deadpool_postgres/transactional_ops.rs
1// use parsql_core::{Deleteable, Insertable, Queryable, Updateable};
2use deadpool_postgres::{Transaction, Client};
3use tokio_postgres::Error;
4// Makrolar sadece dokümantasyon için kullanılıyor, gerçek kodda SqlQuery kullanılmalı
5// use parsql_macros::{Insertable, Updateable};
6
7use crate::traits::{SqlQuery, SqlParams, FromRow};
8
9/// # begin
10///
11/// Starts a new database transaction from a pool client.
12///
13/// ## Parameters
14/// - `client`: Pool client to start the transaction from
15///
16/// ## Return Value
17/// - `Result<Transaction<'_>, Error>`: On success, returns the new transaction
18///
19/// ## Example Usage
20/// ```rust,no_run
21/// use tokio_postgres::{NoTls, Error};
22/// use deadpool_postgres::{Config, Runtime};
23/// use parsql::deadpool_postgres::transactional::begin;
24///
25/// #[tokio::main]
26/// async fn main() -> Result<(), Error> {
27/// let mut cfg = Config::new();
28/// cfg.host = Some("localhost".to_string());
29/// cfg.dbname = Some("test".to_string());
30///
31/// let pool = cfg.create_pool(Some(Runtime::Tokio1), NoTls)?;
32/// let mut client = pool.get().await?;
33///
34/// let tx = begin(&mut client).await?;
35/// // Now you can use the transaction
36///
37/// // Commit the transaction
38/// tx.commit().await?;
39///
40/// Ok(())
41/// }
42/// ```
43pub async fn begin(client: &mut Client) -> Result<Transaction<'_>, Error> {
44 let tx = client.transaction().await?;
45
46 if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
47 println!("[PARSQL-TOKIO-POSTGRES-TX] Begin Transaction");
48 }
49
50 Ok(tx)
51}
52
53/// # begin_from_pool
54///
55/// Starts a new database transaction directly from a connection pool.
56///
57/// ## Parameters
58/// - `pool`: Connection pool to start the transaction from
59///
60/// ## Return Value
61/// - `Result<(Client, Transaction<'_>), Error>`: On success, returns the client and transaction
62///
63/// ## Example Usage
64/// ```rust,no_run
65/// use tokio_postgres::{NoTls, Error};
66/// use deadpool_postgres::{Config, Runtime};
67/// use parsql::deadpool_postgres::transactional::begin_from_pool;
68///
69/// #[tokio::main]
70/// async fn main() -> Result<(), Error> {
71/// let mut cfg = Config::new();
72/// cfg.host = Some("localhost".to_string());
73/// cfg.dbname = Some("test".to_string());
74///
75/// let pool = cfg.create_pool(Some(Runtime::Tokio1), NoTls)?;
76///
77/// // Instead of using begin_from_pool, we'll get a client and start a transaction
78/// let client = pool.get().await.unwrap();
79/// let tx = client.transaction().await?;
80///
81/// // Now you can use the transaction
82///
83/// // Commit the transaction
84/// tx.commit().await?;
85/// // Client will be dropped and returned to the pool automatically
86///
87/// Ok(())
88/// }
89/// ```
90// Bu fonksiyon lifetime sorunları nedeniyle kaldırıldı
91// Bunun yerine client'ı manuel olarak alıp, üzerinde transaction başlatmak daha uygun
92
93/// # tx_update
94///
95/// Updates a record within a transaction.
96///
97/// ## Parameters
98/// - `transaction`: Active transaction object
99/// - `entity`: Data object containing the update information (must implement Updateable and SqlParams traits)
100///
101/// ## Return Value
102/// - `Result<(Transaction<'_>, u64), Error>`: On success, returns the transaction and number of updated records
103///
104/// ## Example Usage
105/// ```rust,no_run
106/// use tokio_postgres::{NoTls, Error};
107/// use deadpool_postgres::{Config, Runtime};
108/// use parsql::deadpool_postgres::transactional::tx_update;
109///
110/// #[derive(Updateable, UpdateParams)]
111/// #[table("users")]
112/// #[update("name, email")]
113/// #[where_clause("id = $")]
114/// pub struct UpdateUser {
115/// pub id: i32,
116/// pub name: String,
117/// pub email: String,
118/// }
119///
120/// #[tokio::main]
121/// async fn main() -> Result<(), Error> {
122/// let mut cfg = Config::new();
123/// cfg.host = Some("localhost".to_string());
124/// cfg.dbname = Some("test".to_string());
125///
126/// let pool = cfg.create_pool(Some(Runtime::Tokio1), NoTls)?;
127/// let client = pool.get().await?;
128///
129/// let mut tx = client.transaction().await?;
130///
131/// let update_user = UpdateUser {
132/// id: 1,
133/// name: String::from("John"),
134/// email: String::from("john@example.com"),
135/// };
136///
137/// let (tx, rows_affected) = tx_update(tx, update_user).await?;
138/// tx.commit().await?;
139///
140/// println!("Updated {} rows", rows_affected);
141/// Ok(())
142/// }
143/// ```
144pub async fn tx_update<T: SqlQuery + SqlParams>(
145 transaction: Transaction<'_>,
146 entity: T,
147) -> Result<(Transaction<'_>, u64), Error> {
148 let sql = T::query();
149
150 if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
151 println!("[PARSQL-TOKIO-POSTGRES-TX] Execute SQL: {}", sql);
152 }
153
154 let params = entity.params();
155 let result = transaction.execute(&sql, ¶ms).await?;
156 Ok((transaction, result))
157}
158
159/// # tx_insert
160///
161/// Inserts a record within a transaction.
162///
163/// ## Parameters
164/// - `transaction`: Active transaction object
165/// - `entity`: Data object to be inserted (must implement Insertable and SqlParams traits)
166///
167/// ## Return Value
168/// - `Result<(Transaction<'_>, u64), Error>`: On success, returns the transaction and number of inserted records
169///
170/// ## Example Usage
171/// ```rust,no_run
172/// use tokio_postgres::{NoTls, Error};
173/// use deadpool_postgres::{Config, Runtime};
174/// use parsql::deadpool_postgres::transactional::tx_insert;
175///
176/// #[derive(Insertable, SqlParams)]
177/// #[table("users")]
178/// pub struct InsertUser {
179/// pub name: String,
180/// pub email: String,
181/// pub state: i16,
182/// }
183///
184/// #[tokio::main]
185/// async fn main() -> Result<(), Error> {
186/// let mut cfg = Config::new();
187/// cfg.host = Some("localhost".to_string());
188/// cfg.dbname = Some("test".to_string());
189///
190/// let pool = cfg.create_pool(Some(Runtime::Tokio1), NoTls)?;
191/// let client = pool.get().await?;
192///
193/// let mut tx = client.transaction().await?;
194///
195/// let insert_user = InsertUser {
196/// name: "John".to_string(),
197/// email: "john@example.com".to_string(),
198/// state: 1,
199/// };
200///
201/// let (tx, rows_affected) = tx_insert(tx, insert_user).await?;
202/// tx.commit().await?;
203///
204/// println!("Inserted {} rows", rows_affected);
205/// Ok(())
206/// }
207/// ```
208pub async fn tx_insert<T: SqlQuery + SqlParams>(
209 transaction: Transaction<'_>,
210 entity: T,
211) -> Result<(Transaction<'_>, u64), Error> {
212 let sql = T::query();
213
214 if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
215 println!("[PARSQL-TOKIO-POSTGRES-TX] Execute SQL: {}", sql);
216 }
217
218 let params = entity.params();
219 let result = transaction.execute(&sql, ¶ms).await?;
220 Ok((transaction, result))
221}
222
223/// # tx_delete
224///
225/// Deletes a record within a transaction.
226///
227/// ## Parameters
228/// - `transaction`: Active transaction object
229/// - `entity`: Data object identifying the record to delete (must implement Deletable and SqlParams traits)
230///
231/// ## Return Value
232/// - `Result<(Transaction<'_>, u64), Error>`: On success, returns the transaction and number of deleted records
233pub async fn tx_delete<T: SqlQuery + SqlParams>(
234 transaction: Transaction<'_>,
235 entity: T,
236) -> Result<(Transaction<'_>, u64), Error> {
237 let sql = T::query();
238
239 if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
240 println!("[PARSQL-TOKIO-POSTGRES-TX] Execute SQL: {}", sql);
241 }
242
243 let params = entity.params();
244 let result = transaction.execute(&sql, ¶ms).await?;
245 Ok((transaction, result))
246}
247
248/// # tx_get
249///
250/// Retrieves a single record within a transaction.
251///
252/// ## Parameters
253/// - `transaction`: Active transaction object
254/// - `params`: Query parameters (must implement SqlQuery, FromRow and SqlParams traits)
255///
256/// ## Return Value
257/// - `Result<(Transaction<'_>, T), Error>`: On success, returns the transaction and the retrieved record
258pub async fn tx_get<'a, T>(
259 transaction: Transaction<'a>,
260 params: &T,
261) -> Result<(Transaction<'a>, T), Error>
262where
263 T: SqlQuery + FromRow + SqlParams,
264{
265 let sql = T::query();
266
267 if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
268 println!("[PARSQL-TOKIO-POSTGRES-TX] Execute SQL: {}", sql);
269 }
270
271 let query_params = params.params();
272 let row = transaction.query_one(&sql, &query_params).await?;
273 let result = T::from_row(&row)?;
274
275 Ok((transaction, result))
276}
277
278/// # tx_get_all
279///
280/// Retrieves multiple records within a transaction.
281///
282/// ## Parameters
283/// - `transaction`: Active transaction object
284/// - `params`: Query parameters (must implement SqlQuery, FromRow and SqlParams traits)
285///
286/// ## Return Value
287/// - `Result<(Transaction<'_>, Vec<T>), Error>`: On success, returns the transaction and the retrieved records
288pub async fn tx_get_all<'a, T>(
289 transaction: Transaction<'a>,
290 params: &T,
291) -> Result<(Transaction<'a>, Vec<T>), Error>
292where
293 T: SqlQuery + FromRow + SqlParams,
294{
295 let sql = T::query();
296
297 if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
298 println!("[PARSQL-TOKIO-POSTGRES-TX] Execute SQL: {}", sql);
299 }
300
301 let query_params = params.params();
302 let rows = transaction.query(&sql, &query_params).await?;
303
304 let mut results = Vec::with_capacity(rows.len());
305 for row in rows {
306 results.push(T::from_row(&row)?);
307 }
308
309 Ok((transaction, results))
310}
311
312/// # tx_select
313///
314/// Retrieves a single record using a custom transformation function within a transaction.
315///
316/// ## Parameters
317/// - `transaction`: Active transaction object
318/// - `entity`: Query parameters (must implement SqlQuery and SqlParams traits)
319/// - `to_model`: Function to transform the row into the desired type
320///
321/// ## Return Value
322/// - `Result<(Transaction<'_>, R), Error>`: On success, returns the transaction and the transformed record
323pub async fn tx_select<'a, T, R, F>(
324 transaction: Transaction<'a>,
325 entity: T,
326 to_model: F,
327) -> Result<(Transaction<'a>, R), Error>
328where
329 T: SqlQuery + SqlParams,
330 F: FnOnce(&tokio_postgres::Row) -> Result<R, Error>,
331{
332 let sql = T::query();
333
334 if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
335 println!("[PARSQL-TOKIO-POSTGRES-TX] Execute SQL: {}", sql);
336 }
337
338 let params = entity.params();
339 let row = transaction.query_one(&sql, ¶ms).await?;
340 let result = to_model(&row)?;
341
342 Ok((transaction, result))
343}
344
345/// # tx_select_all
346///
347/// Retrieves multiple records using a custom transformation function within a transaction.
348///
349/// ## Parameters
350/// - `transaction`: Active transaction object
351/// - `entity`: Query parameters (must implement SqlQuery and SqlParams traits)
352/// - `to_model`: Function to transform each row into the desired type
353///
354/// ## Return Value
355/// - `Result<(Transaction<'_>, Vec<R>), Error>`: On success, returns the transaction and the transformed records
356pub async fn tx_select_all<'a, T, R, F>(
357 transaction: Transaction<'a>,
358 entity: T,
359 to_model: F,
360) -> Result<(Transaction<'a>, Vec<R>), Error>
361where
362 T: SqlQuery + SqlParams,
363 F: Fn(&tokio_postgres::Row) -> R,
364{
365 let sql = T::query();
366
367 if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
368 println!("[PARSQL-TOKIO-POSTGRES-TX] Execute SQL: {}", sql);
369 }
370
371 let params = entity.params();
372 let rows = transaction.query(&sql, ¶ms).await?;
373
374 let mut results = Vec::with_capacity(rows.len());
375 for row in rows {
376 results.push(to_model(&row));
377 }
378
379 Ok((transaction, results))
380}