parsql_deadpool_postgres/
crud_ops.rs

1use deadpool_postgres::{Pool, PoolError};
2use tokio_postgres::{Error, Row};
3use crate::{SqlQuery, SqlParams, UpdateParams, FromRow};
4
5// Daha basit bir yaklaşım: PoolError'dan genel bir Error oluştur
6fn pool_err_to_io_err(e: PoolError) -> Error {
7    // Bu özel fonksiyon tokio_postgres'in sağladığı timeout hatasını döndürür
8    // Güzel bir çözüm değil, ama çalışır bir örnek için kullanılabilir
9    let err = Error::__private_api_timeout();
10    
11    // Debug süreci için stderr'e hatayı yazdıralım
12    eprintln!("Pool bağlantı hatası: {}", e);
13    
14    err
15}
16
17/// # insert
18/// 
19/// Deadpool bağlantı havuzunu kullanarak veritabanına yeni bir kayıt ekler.
20/// 
21/// ## Parametreler
22/// - `pool`: Deadpool bağlantı havuzu
23/// - `entity`: Eklenecek veri nesnesi (SqlQuery ve SqlParams trait'lerini uygulamalıdır)
24/// 
25/// ## Dönüş Değeri
26/// - `Result<u64, Error>`: Başarılı olursa, eklenen kayıt sayısını döndürür; başarısız olursa, Error döndürür
27/// 
28/// ## Yapı Tanımı
29/// Bu fonksiyonla kullanılan yapılar aşağıdaki derive makrolarıyla işaretlenmelidir:
30/// 
31/// ```rust,no_run
32/// #[derive(Insertable, SqlParams)]  // Gerekli makrolar
33/// #[table("tablo_adi")]            // Ekleme yapılacak tablo adı
34/// pub struct VeriModeli {
35///     pub alan1: String,
36///     pub alan2: i32,
37///     // ...
38/// }
39/// ```
40/// 
41/// - `Insertable`: Otomatik olarak SQL INSERT ifadeleri oluşturur
42/// - `SqlParams`: Otomatik olarak SQL parametreleri oluşturur
43/// - `#[table("tablo_adi")]`: Ekleme yapılacak tablo adını belirtir
44/// 
45/// ## Kullanım Örneği
46/// ```rust,no_run
47/// use deadpool_postgres::{Config, Runtime, Pool};
48/// use tokio_postgres::{NoTls, Error};
49/// use parsql::tokio_postgres::pool_crud_ops::insert;
50/// 
51/// #[derive(Insertable, SqlParams)]
52/// #[table("users")]
53/// pub struct InsertUser {
54///     pub name: String,
55///     pub email: String,
56///     pub state: i16,
57/// }
58///
59/// #[tokio::main]
60/// async fn main() -> Result<(), Error> {
61///     let mut cfg = Config::new();
62///     cfg.host = Some("localhost".to_string());
63///     cfg.dbname = Some("test".to_string());
64///     
65///     let pool = cfg.create_pool(Some(Runtime::Tokio1), NoTls).unwrap();
66///
67///     let insert_user = InsertUser {
68///         name: "John".to_string(),
69///         email: "john@example.com".to_string(),
70///         state: 1_i16,
71///     };
72///
73///     let insert_result = insert(&pool, insert_user).await?;
74///     println!("Insert result: {:?}", insert_result);
75///     Ok(())
76/// }
77/// ```
78pub async fn insert<T: SqlQuery + SqlParams>(
79    pool: &Pool,
80    entity: T,
81) -> Result<u64, Error> {
82    let client = pool.get().await.map_err(pool_err_to_io_err)?;
83    let sql = T::query();
84    
85    if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
86        println!("[PARSQL-TOKIO-POSTGRES-POOL] Execute SQL: {}", sql);
87    }
88
89    let params = entity.params();
90    client.execute(&sql, &params).await
91}
92
93/// # update
94/// 
95/// Deadpool bağlantı havuzunu kullanarak veritabanındaki mevcut bir kaydı günceller.
96/// 
97/// ## Parametreler
98/// - `pool`: Deadpool bağlantı havuzu
99/// - `entity`: Güncelleme bilgilerini içeren veri nesnesi (SqlQuery ve UpdateParams trait'lerini uygulamalıdır)
100/// 
101/// ## Dönüş Değeri
102/// - `Result<bool, Error>`: Başarılı olursa, true döndürür; başarısız olursa, Error döndürür
103/// 
104/// ## Yapı Tanımı
105/// Bu fonksiyonla kullanılan yapılar aşağıdaki derive makrolarıyla işaretlenmelidir:
106/// 
107/// ```rust,no_run
108/// #[derive(Updateable, UpdateParams)]  // Gerekli makrolar
109/// #[table("tablo_adi")]               // Güncellenecek tablo adı
110/// #[update("alan1, alan2")]          // Güncellenecek alanlar (isteğe bağlı)
111/// #[where_clause("id = $")]            // Güncelleme koşulu
112/// pub struct VeriModeli {
113///     pub id: i32,                     // Koşulda kullanılan alanlar
114///     pub alan1: String,              // Güncellenecek alanlar
115///     pub alan2: i32,                 // Güncellenecek alanlar
116///     // ...
117/// }
118/// ```
119/// 
120/// - `Updateable`: Otomatik olarak SQL UPDATE ifadeleri oluşturur
121/// - `UpdateParams`: Otomatik olarak güncelleme parametreleri oluşturur
122/// - `#[table("tablo_adi")]`: Güncellenecek tablo adını belirtir
123/// - `#[update("alan1, alan2")]`: Hangi alanların güncelleneceğini belirtir (belirtilmezse, tüm alanlar güncellenir)
124/// - `#[where_clause("id = $")]`: Güncelleme koşulunu belirtir (`$` parametre değeri ile değiştirilir)
125/// 
126/// ## Kullanım Örneği
127/// ```rust,no_run
128/// use deadpool_postgres::{Config, Runtime, Pool};
129/// use tokio_postgres::{NoTls, Error};
130/// use parsql::tokio_postgres::pool_crud_ops::update;
131/// 
132/// #[derive(Updateable, UpdateParams)]
133/// #[table("users")]
134/// #[update("name, email")]
135/// #[where_clause("id = $")]
136/// pub struct UpdateUser {
137///     pub id: i32,
138///     pub name: String,
139///     pub email: String,
140///     pub state: i16,  // update özniteliğinde belirtilmediği için bu alan güncellenmez
141/// }
142///
143/// #[tokio::main]
144/// async fn main() -> Result<(), Error> {
145///     let mut cfg = Config::new();
146///     cfg.host = Some("localhost".to_string());
147///     cfg.dbname = Some("test".to_string());
148///     
149///     let pool = cfg.create_pool(Some(Runtime::Tokio1), NoTls).unwrap();
150///
151///     let update_user = UpdateUser {
152///         id: 1,
153///         name: String::from("John"),
154///         email: String::from("john@example.com"),
155///         state: 2,
156///     };
157///
158///     let update_result = update(&pool, update_user).await?;
159///     println!("Update result: {:?}", update_result);
160///     Ok(())
161/// }
162/// ```
163pub async fn update<T: SqlQuery + UpdateParams>(
164    pool: &Pool,
165    entity: T,
166) -> Result<bool, Error> {
167    let client = pool.get().await.map_err(pool_err_to_io_err)?;
168    let sql = T::query();
169    
170    if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
171        println!("[PARSQL-TOKIO-POSTGRES-POOL] Execute SQL: {}", sql);
172    }
173
174    let params = entity.params();
175    match client.execute(&sql, &params).await {
176        Ok(_) => Ok(true),
177        Err(e) => Err(e),
178    }
179}
180
181/// # delete
182/// 
183/// Deadpool bağlantı havuzunu kullanarak veritabanından bir kaydı siler.
184/// 
185/// ## Parametreler
186/// - `pool`: Deadpool bağlantı havuzu
187/// - `entity`: Silme bilgilerini içeren veri nesnesi (SqlQuery ve SqlParams trait'lerini uygulamalıdır)
188/// 
189/// ## Dönüş Değeri
190/// - `Result<u64, Error>`: Başarılı olursa, silinen kayıt sayısını döndürür; başarısız olursa, Error döndürür
191/// 
192/// ## Yapı Tanımı
193/// Bu fonksiyonla kullanılan yapılar aşağıdaki derive makrolarıyla işaretlenmelidir:
194/// 
195/// ```rust,no_run
196/// #[derive(Deletable, SqlParams)]   // Gerekli makrolar
197/// #[table("tablo_adi")]             // Silinecek tablo adı
198/// #[where_clause("id = $")]          // Silme koşulu
199/// pub struct VeriModeli {
200///     pub id: i32,                   // Koşulda kullanılan alanlar
201///     // Diğer alanlar eklenebilir, ancak genellikle sadece koşul alanları gereklidir
202/// }
203/// ```
204/// 
205/// - `Deletable`: Otomatik olarak SQL DELETE ifadeleri oluşturur
206/// - `SqlParams`: Otomatik olarak SQL parametreleri oluşturur
207/// - `#[table("tablo_adi")]`: Silinecek tablo adını belirtir
208/// - `#[where_clause("id = $")]`: Silme koşulunu belirtir (`$` parametre değeri ile değiştirilir)
209/// 
210/// ## Kullanım Örneği
211/// ```rust,no_run
212/// use deadpool_postgres::{Config, Runtime, Pool};
213/// use tokio_postgres::{NoTls, Error};
214/// use parsql::tokio_postgres::pool_crud_ops::delete;
215/// 
216/// #[derive(Deletable, SqlParams)]
217/// #[table("users")]
218/// #[where_clause("id = $")]
219/// pub struct DeleteUser {
220///     pub id: i32,
221/// }
222/// 
223/// #[tokio::main]
224/// async fn main() -> Result<(), Error> {
225///     let mut cfg = Config::new();
226///     cfg.host = Some("localhost".to_string());
227///     cfg.dbname = Some("test".to_string());
228///     
229///     let pool = cfg.create_pool(Some(Runtime::Tokio1), NoTls).unwrap();
230///
231///     let delete_user = DeleteUser { id: 6 };
232///     let delete_result = delete(&pool, delete_user).await?;
233///     
234///     println!("Delete result: {:?}", delete_result);
235///     Ok(())
236/// }
237/// ```
238pub async fn delete<T: SqlQuery + SqlParams>(
239    pool: &Pool,
240    entity: T,
241) -> Result<u64, Error> {
242    let client = pool.get().await.map_err(pool_err_to_io_err)?;
243    let sql = T::query();
244    
245    if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
246        println!("[PARSQL-TOKIO-POSTGRES-POOL] Execute SQL: {}", sql);
247    }
248
249    let params = entity.params();
250    match client.execute(&sql, &params).await {
251        Ok(rows_affected) => Ok(rows_affected),
252        Err(e) => Err(e),
253    }
254}
255
256/// # get
257/// 
258/// Deadpool bağlantı havuzunu kullanarak veritabanından bir kaydı alır.
259/// 
260/// ## Parametreler
261/// - `pool`: Deadpool bağlantı havuzu
262/// - `params`: Sorgu parametrelerini içeren veri nesnesi (SqlQuery, FromRow ve SqlParams trait'lerini uygulamalıdır)
263/// 
264/// ## Dönüş Değeri
265/// - `Result<T, Error>`: Başarılı olursa, alınan kaydı döndürür; başarısız olursa, Error döndürür
266/// 
267/// ## Yapı Tanımı
268/// Bu fonksiyonla kullanılan yapılar aşağıdaki derive makrolarıyla işaretlenmelidir:
269/// 
270/// ```rust,no_run
271/// #[derive(Queryable, SqlParams, FromRow)]   // Gerekli makrolar
272/// #[table("tablo_adi")]                     // Sorgulanacak tablo adı
273/// #[where_clause("id = $")]                  // Sorgu koşulu
274/// pub struct VeriModeli {
275///     pub id: i32,                          // Koşulda kullanılan alanlar
276///     pub alan1: String,                    // Getirilen veri alanları
277///     pub alan2: i32,                       // Getirilen veri alanları
278///     // ...
279/// }
280/// ```
281/// 
282/// - `Queryable`: Otomatik olarak SQL SELECT ifadeleri oluşturur
283/// - `SqlParams`: Otomatik olarak SQL parametreleri oluşturur
284/// - `FromRow`: Veritabanı satırını yapıya dönüştürür
285/// - `#[table("tablo_adi")]`: Sorgulanacak tablo adını belirtir
286/// - `#[where_clause("id = $")]`: Sorgu koşulunu belirtir (`$` parametre değeri ile değiştirilir)
287/// 
288/// ## Kullanım Örneği
289/// ```rust,no_run
290/// use deadpool_postgres::{Config, Runtime, Pool};
291/// use tokio_postgres::{NoTls, Error};
292/// use parsql::tokio_postgres::pool_crud_ops::get;
293/// 
294/// #[derive(Queryable, SqlParams, FromRow)]
295/// #[table("users")]
296/// #[where_clause("id = $")]
297/// pub struct GetUser {
298///     pub id: i32,
299///     pub name: String,
300///     pub email: String,
301///     pub state: i16,
302/// }
303///
304/// impl GetUser {
305///     pub fn new(id: i32) -> Self {
306///         Self {
307///             id,
308///             name: String::new(),
309///             email: String::new(),
310///             state: 0,
311///         }
312///     }
313/// }
314/// 
315/// #[tokio::main]
316/// async fn main() -> Result<(), Error> {
317///     let mut cfg = Config::new();
318///     cfg.host = Some("localhost".to_string());
319///     cfg.dbname = Some("test".to_string());
320///     
321///     let pool = cfg.create_pool(Some(Runtime::Tokio1), NoTls).unwrap();
322///
323///     let user_params = GetUser::new(1);
324///     let user = get(&pool, &user_params).await?;
325///     
326///     println!("User: {:?}", user);
327///     Ok(())
328/// }
329/// ```
330pub async fn get<T: SqlQuery + FromRow + SqlParams>(
331    pool: &Pool,
332    params: &T,
333) -> Result<T, Error> {
334    let client = pool.get().await.map_err(pool_err_to_io_err)?;
335    let sql = T::query();
336    
337    if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
338        println!("[PARSQL-TOKIO-POSTGRES-POOL] Execute SQL: {}", sql);
339    }
340
341    let params = params.params();
342    let row = client.query_one(&sql, &params).await?;
343    T::from_row(&row)
344}
345
346/// # get_all
347/// 
348/// Deadpool bağlantı havuzunu kullanarak veritabanından birden fazla kaydı alır.
349/// 
350/// ## Parametreler
351/// - `pool`: Deadpool bağlantı havuzu
352/// - `params`: Sorgu parametrelerini içeren veri nesnesi (SqlQuery, FromRow ve SqlParams trait'lerini uygulamalıdır)
353/// 
354/// ## Dönüş Değeri
355/// - `Result<Vec<T>, Error>`: Başarılı olursa, alınan kayıtları içeren bir vektör döndürür; başarısız olursa, Error döndürür
356/// 
357/// ## Yapı Tanımı
358/// Bu fonksiyonla kullanılan yapılar aşağıdaki derive makrolarıyla işaretlenmelidir:
359/// 
360/// ```rust,no_run
361/// #[derive(Queryable, SqlParams, FromRow)]   // Gerekli makrolar
362/// #[table("tablo_adi")]                     // Sorgulanacak tablo adı
363/// #[where_clause("state = $")]              // Sorgu koşulu
364/// pub struct VeriModeli {
365///     pub id: i32,                          // Alınacak alanlar
366///     pub alan1: String,                    // Alınacak alanlar
367///     pub alan2: i32,                       // Alınacak alanlar
368///     pub state: i16,                       // Koşulda kullanılan alanlar
369///     // ...
370/// }
371/// ```
372/// 
373/// - `Queryable`: Otomatik olarak SQL SELECT ifadeleri oluşturur
374/// - `SqlParams`: Otomatik olarak SQL parametreleri oluşturur
375/// - `FromRow`: Veritabanı satırını yapıya dönüştürür
376/// - `#[table("tablo_adi")]`: Sorgulanacak tablo adını belirtir
377/// - `#[where_clause("state = $")]`: Sorgu koşulunu belirtir (`$` parametre değeri ile değiştirilir)
378/// 
379/// ## Kullanım Örneği
380/// ```rust,no_run
381/// use deadpool_postgres::{Config, Runtime, Pool};
382/// use tokio_postgres::{NoTls, Error};
383/// use parsql::tokio_postgres::pool_crud_ops::get_all;
384/// 
385/// #[derive(Queryable, SqlParams, FromRow)]
386/// #[table("users")]
387/// #[where_clause("state = $")]
388/// pub struct ListUsers {
389///     pub id: i32,
390///     pub name: String,
391///     pub email: String,
392///     pub state: i16,
393/// }
394///
395/// impl ListUsers {
396///     pub fn new(state: i16) -> Self {
397///         Self {
398///             id: 0,
399///             name: String::new(),
400///             email: String::new(),
401///             state,
402///         }
403///     }
404/// }
405/// 
406/// #[tokio::main]
407/// async fn main() -> Result<(), Error> {
408///     let mut cfg = Config::new();
409///     cfg.host = Some("localhost".to_string());
410///     cfg.dbname = Some("test".to_string());
411///     
412///     let pool = cfg.create_pool(Some(Runtime::Tokio1), NoTls).unwrap();
413///
414///     let user_params = ListUsers::new(1);
415///     let users = get_all(&pool, &user_params).await?;
416///     
417///     println!("Users: {:?}", users);
418///     Ok(())
419/// }
420/// ```
421pub async fn get_all<T: SqlQuery + FromRow + SqlParams>(
422    pool: &Pool,
423    params: &T,
424) -> Result<Vec<T>, Error> {
425    let client = pool.get().await.map_err(pool_err_to_io_err)?;
426    let sql = T::query();
427    
428    if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
429        println!("[PARSQL-TOKIO-POSTGRES-POOL] Execute SQL: {}", sql);
430    }
431
432    let params = params.params();
433    let rows = client.query(&sql, &params).await?;
434    
435    let mut results = Vec::with_capacity(rows.len());
436    for row in rows {
437        results.push(T::from_row(&row)?);
438    }
439    
440    Ok(results)
441}
442
443/// # select
444/// 
445/// Deadpool bağlantı havuzunu kullanarak özel bir model dönüştürücü fonksiyon ile veritabanından bir kayıt seçer.
446/// 
447/// ## Parametreler
448/// - `pool`: Deadpool bağlantı havuzu
449/// - `entity`: Sorgu parametrelerini içeren veri nesnesi (SqlQuery ve SqlParams trait'lerini uygulamalıdır)
450/// - `to_model`: Satırı modele dönüştüren fonksiyon
451/// 
452/// ## Dönüş Değeri
453/// - `Result<R, Error>`: Başarılı olursa, dönüştürülen modeli döndürür; başarısız olursa, Error döndürür
454/// 
455/// ## Kullanım Örneği
456/// ```rust,no_run
457/// use deadpool_postgres::{Config, Runtime, Pool};
458/// use tokio_postgres::{NoTls, Error, Row};
459/// use parsql::tokio_postgres::pool_crud_ops::select;
460/// 
461/// #[derive(Queryable, SqlParams)]
462/// #[table("users")]
463/// #[where_clause("id = $")]
464/// pub struct UserQuery {
465///     pub id: i32,
466/// }
467///
468/// pub struct UserModel {
469///     pub id: i32,
470///     pub name: String,
471///     pub email: String,
472///     pub is_active: bool,
473/// }
474///
475/// impl UserQuery {
476///     pub fn new(id: i32) -> Self {
477///         Self { id }
478///     }
479/// }
480///
481/// fn row_to_user(row: &Row) -> Result<UserModel, Error> {
482///     Ok(UserModel {
483///         id: row.try_get("id")?,
484///         name: row.try_get("name")?,
485///         email: row.try_get("email")?,
486///         is_active: row.try_get::<_, i16>("state")? == 1,
487///     })
488/// }
489/// 
490/// #[tokio::main]
491/// async fn main() -> Result<(), Error> {
492///     let mut cfg = Config::new();
493///     cfg.host = Some("localhost".to_string());
494///     cfg.dbname = Some("test".to_string());
495///     
496///     let pool = cfg.create_pool(Some(Runtime::Tokio1), NoTls).unwrap();
497///
498///     let query = UserQuery::new(1);
499///     let user = select(&pool, query, row_to_user).await?;
500///     
501///     println!("User: {:?}", user);
502///     Ok(())
503/// }
504/// ```
505pub async fn select<T: SqlQuery + SqlParams, R, F>(
506    pool: &Pool,
507    entity: T,
508    to_model: F,
509) -> Result<R, Error>
510where
511    F: Fn(&Row) -> Result<R, Error>,
512{
513    let client = pool.get().await.map_err(pool_err_to_io_err)?;
514    let sql = T::query();
515    
516    if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
517        println!("[PARSQL-TOKIO-POSTGRES-POOL] Execute SQL: {}", sql);
518    }
519
520    let params = entity.params();
521    let row = client.query_one(&sql, &params).await?;
522    to_model(&row)
523}
524
525/// # select_all
526/// 
527/// Deadpool bağlantı havuzunu kullanarak özel bir model dönüştürücü fonksiyon ile veritabanından birden fazla kayıt seçer.
528/// 
529/// ## Parametreler
530/// - `pool`: Deadpool bağlantı havuzu
531/// - `entity`: Sorgu parametrelerini içeren veri nesnesi (SqlQuery ve SqlParams trait'lerini uygulamalıdır)
532/// - `to_model`: Satırı modele dönüştüren fonksiyon
533/// 
534/// ## Dönüş Değeri
535/// - `Result<Vec<R>, Error>`: Başarılı olursa, dönüştürülen modelleri içeren bir vektör döndürür; başarısız olursa, Error döndürür
536/// 
537/// ## Kullanım Örneği
538/// ```rust,no_run
539/// use deadpool_postgres::{Config, Runtime, Pool};
540/// use tokio_postgres::{NoTls, Error, Row};
541/// use parsql::tokio_postgres::pool_crud_ops::select_all;
542/// 
543/// #[derive(Queryable, SqlParams)]
544/// #[table("users")]
545/// #[where_clause("state = $")]
546/// pub struct UsersQuery {
547///     pub state: i16,
548/// }
549///
550/// pub struct UserModel {
551///     pub id: i32,
552///     pub name: String,
553///     pub email: String,
554///     pub is_active: bool,
555/// }
556///
557/// impl UsersQuery {
558///     pub fn new(state: i16) -> Self {
559///         Self { state }
560///     }
561/// }
562///
563/// fn row_to_user(row: &Row) -> UserModel {
564///     UserModel {
565///         id: row.get("id"),
566///         name: row.get("name"),
567///         email: row.get("email"),
568///         is_active: row.get::<_, i16>("state") == 1,
569///     }
570/// }
571/// 
572/// #[tokio::main]
573/// async fn main() -> Result<(), Error> {
574///     let mut cfg = Config::new();
575///     cfg.host = Some("localhost".to_string());
576///     cfg.dbname = Some("test".to_string());
577///     
578///     let pool = cfg.create_pool(Some(Runtime::Tokio1), NoTls).unwrap();
579///
580///     let query = UsersQuery::new(1);
581///     let users = select_all(&pool, query, row_to_user).await?;
582///     
583///     println!("Users: {:?}", users);
584///     Ok(())
585/// }
586/// ```
587pub async fn select_all<T: SqlQuery + SqlParams, R, F>(
588    pool: &Pool,
589    entity: T,
590    to_model: F,
591) -> Result<Vec<R>, Error>
592where
593    F: Fn(&Row) -> R,
594{
595    let client = pool.get().await.map_err(pool_err_to_io_err)?;
596    let sql = T::query();
597    
598    if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
599        println!("[PARSQL-TOKIO-POSTGRES-POOL] Execute SQL: {}", sql);
600    }
601
602    let params = entity.params();
603    let rows = client.query(&sql, &params).await?;
604    
605    let mut results = Vec::with_capacity(rows.len());
606    for row in rows {
607        results.push(to_model(&row));
608    }
609    
610    Ok(results)
611}