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, ¶ms).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, ¶ms).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, ¶ms).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, ¶ms).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, ¶ms).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, ¶ms).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, ¶ms).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}