parsql_postgres/
crud_ops.rs

1use postgres::{types::{FromSql, ToSql}, Client, Error, Row};
2use crate::traits::{SqlQuery, SqlParams, FromRow, UpdateParams, CrudOps};
3
4
5// CrudOps trait implementasyonu postgres::Client için
6impl CrudOps for Client {
7    fn insert<T: SqlQuery + SqlParams, P:for<'a> FromSql<'a> + Send + Sync>(&mut self, entity: T) -> Result<P, Error> {
8        insert::<T, P>(self, entity)
9    }
10
11    fn update<T: SqlQuery + UpdateParams>(&mut self, entity: T) -> Result<u64, Error> {
12        update(self, entity)
13    }
14
15    fn delete<T: SqlQuery + SqlParams>(&mut self, entity: T) -> Result<u64, Error> {
16        delete(self, entity)
17    }
18
19    fn fetch<T: SqlQuery + FromRow + SqlParams>(&mut self, entity: &T) -> Result<T, Error> {
20        fetch(self, entity)
21    }
22
23    fn fetch_all<T: SqlQuery + FromRow + SqlParams>(&mut self, entity: &T) -> Result<Vec<T>, Error> {
24        fetch_all(self, entity)
25    }
26
27    fn select<T, F, R>(&mut self, entity: &T, to_model: F) -> Result<R, Error>
28    where
29        T: SqlQuery + SqlParams,
30        F: FnOnce(&Row) -> Result<R, Error>,
31    {
32        let sql = T::query();
33        
34        if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
35            println!("[PARSQL-POSTGRES] Execute SQL: {}", sql);
36        }
37
38        let params = entity.params();
39        let row = self.query_one(&sql, &params)?;
40        to_model(&row)
41    }
42
43    fn select_all<T, F, R>(&mut self, entity: &T, to_model: F) -> Result<Vec<R>, Error>
44    where
45        T: SqlQuery + SqlParams,
46        F: FnMut(&Row) -> Result<R, Error>,
47    {
48        let sql = T::query();
49        
50        if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
51            println!("[PARSQL-POSTGRES] Execute SQL: {}", sql);
52        }
53
54        let params = entity.params();
55        let rows = self.query(&sql, &params)?;
56        
57        rows.iter().map(to_model).collect()
58    }
59}
60
61/// # insert
62/// 
63/// Inserts a new record into the database.
64/// 
65/// ## Parameters
66/// - `client`: Database connection client
67/// - `entity`: Data object to be inserted (must implement SqlQuery and SqlParams traits)
68/// 
69/// ## Return Value
70/// - `Result<u64, Error>`: On success, returns the number of inserted records; on failure, returns Error
71/// 
72/// ## Struct Definition
73/// Structs used with this function should be annotated with the following derive macros:
74/// 
75/// ```rust,no_run
76/// #[derive(Insertable, SqlParams)]  // Required macros
77/// #[table("table_name")]            // Table name to insert into
78/// pub struct MyEntity {
79///     pub field1: String,
80///     pub field2: i32,
81///     // ...
82/// }
83/// ```
84/// 
85/// - `Insertable`: Automatically generates SQL INSERT statements
86/// - `SqlParams`: Automatically generates SQL parameters
87/// - `#[table("table_name")]`: Specifies the table name for the insertion
88/// 
89/// ## Example Usage
90/// ```rust,no_run
91/// use postgres::{Client, NoTls, Error};
92/// use parsql::postgres::insert;
93/// 
94/// #[derive(Insertable, SqlParams)]
95/// #[table("users")]
96/// pub struct InsertUser {
97///     pub name: String,
98///     pub email: String,
99///     pub state: i16,
100/// }
101///
102/// fn main() -> Result<(), Error> {
103///     let mut client = Client::connect(
104///         "host=localhost user=postgres dbname=test",
105///         NoTls,
106///     )?;
107///
108///     let insert_user = InsertUser {
109///         name: "John".to_string(),
110///         email: "[email protected]".to_string(),
111///         state: 1_i16,
112///     };
113///
114///     let insert_result = insert(&mut client, insert_user)?;
115///     println!("Insert result: {:?}", insert_result);
116///     Ok(())
117/// }
118/// ```
119pub fn insert<T: SqlQuery + SqlParams, P:for<'a> FromSql<'a> + Send + Sync>(client: &mut Client, entity: T) -> Result<P, Error> {
120    let sql = T::query();
121    if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
122        println!("[PARSQL-POSTGRES] Execute SQL: {}", sql);
123    }
124
125    let params = entity.params();
126    let row = client.query_one(&sql, &params)?;
127    row.try_get::<_, P>(0)
128}
129
130/// # update
131/// 
132/// Updates an existing record in the database.
133/// 
134/// ## Parameters
135/// - `client`: Database connection client
136/// - `entity`: Data object containing the update information (must implement SqlQuery and UpdateParams traits)
137/// 
138/// ## Return Value
139/// - `Result<u64, Error>`: On success, returns the number of updated records; on failure, returns Error
140/// 
141/// ## Struct Definition
142/// Structs used with this function should be annotated with the following derive macros:
143/// 
144/// ```rust,no_run
145/// #[derive(Updateable, UpdateParams)]  // Required macros
146/// #[table("table_name")]               // Table name to update
147/// #[update("field1, field2")]          // Fields to update (optional)
148/// #[where_clause("id = $")]            // Update condition
149/// pub struct MyEntity {
150///     pub id: i32,                     // Fields used in the condition
151///     pub field1: String,              // Fields to be updated
152///     pub field2: i32,                 // Fields to be updated
153///     // ...
154/// }
155/// ```
156/// 
157/// - `Updateable`: Automatically generates SQL UPDATE statements
158/// - `UpdateParams`: Automatically generates update parameters
159/// - `#[table("table_name")]`: Specifies the table name for the update
160/// - `#[update("field1, field2")]`: Specifies which fields should be updated (if omitted, all fields will be updated)
161/// - `#[where_clause("id = $")]`: Specifies the update condition (`$` will be replaced with parameter value)
162/// 
163/// ## Example Usage
164/// ```rust,no_run
165/// use postgres::{Client, NoTls, Error};
166/// use parsql::postgres::update;
167/// 
168/// #[derive(Updateable, UpdateParams)]
169/// #[table("users")]
170/// #[update("name, email")]
171/// #[where_clause("id = $")]
172/// pub struct UpdateUser {
173///     pub id: i32,
174///     pub name: String,
175///     pub email: String,
176///     pub state: i16,  // This field won't be updated as it's not specified in the update attribute
177/// }
178///
179/// fn main() -> Result<(), Error> {
180///     let mut client = Client::connect(
181///         "host=localhost user=postgres dbname=test",
182///         NoTls,
183///     )?;
184///
185///     let update_user = UpdateUser {
186///         id: 1,
187///         name: String::from("John"),
188///         email: String::from("[email protected]"),
189///         state: 2,
190///     };
191///
192///     let update_result = update(&mut client, update_user)?;
193///     println!("Update result: {:?}", update_result);
194///     Ok(())
195/// }
196/// ```
197pub fn update<T: SqlQuery + UpdateParams>(
198    client: &mut postgres::Client,
199    entity: T,
200) -> Result<u64, Error> {
201    let sql = T::query();
202    if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
203        println!("[PARSQL-POSTGRES] Execute SQL: {}", sql);
204    }
205
206    let params = entity.params();
207    match client.execute(&sql, &params) {
208        Ok(rows_affected) => Ok(rows_affected),
209        Err(e) => Err(e),
210    }
211}
212
213/// # delete
214/// 
215/// Deletes a record from the database.
216/// 
217/// ## Parameters
218/// - `client`: Database connection client
219/// - `entity`: Data object containing the deletion information (must implement SqlQuery and SqlParams traits)
220/// 
221/// ## Return Value
222/// - `Result<u64, Error>`: On success, returns the number of deleted records; on failure, returns Error
223/// 
224/// ## Struct Definition
225/// Structs used with this function should be annotated with the following derive macros:
226/// 
227/// ```rust,no_run
228/// #[derive(Deletable, SqlParams)]   // Required macros
229/// #[table("table_name")]             // Table name to delete from
230/// #[where_clause("id = $")]          // Delete condition
231/// pub struct MyEntity {
232///     pub id: i32,                   // Fields used in the condition
233///     // Other fields can be added, but typically only condition fields are necessary
234/// }
235/// ```
236/// 
237/// - `Deletable`: Automatically generates SQL DELETE statements
238/// - `SqlParams`: Automatically generates SQL parameters
239/// - `#[table("table_name")]`: Specifies the table name for the deletion
240/// - `#[where_clause("id = $")]`: Specifies the delete condition (`$` will be replaced with parameter value)
241/// 
242/// ## Example Usage
243/// ```rust,no_run
244/// use postgres::{Client, NoTls, Error};
245/// use parsql::postgres::delete;
246/// 
247/// #[derive(Deletable, SqlParams)]
248/// #[table("users")]
249/// #[where_clause("id = $")]
250/// pub struct DeleteUser {
251///     pub id: i32,
252/// }
253/// 
254/// fn main() -> Result<(), Error> {
255///     let mut client = Client::connect(
256///         "host=localhost user=postgres dbname=test",
257///         NoTls,
258///     )?;
259///
260///     let delete_user = DeleteUser { id: 6 };
261///     let delete_result = delete(&mut client, delete_user)?;
262///     
263///     println!("Delete result: {:?}", delete_result);
264///     Ok(())
265/// }
266/// ```
267pub fn delete<T: SqlQuery + SqlParams>(
268    client: &mut postgres::Client,
269    entity: T,
270) -> Result<u64, Error> {
271    let sql = T::query();
272    if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
273        println!("[PARSQL-POSTGRES] Execute SQL: {}", sql);
274    }
275
276    let params = entity.params();
277    match client.execute(&sql, &params) {
278        Ok(rows_affected) => Ok(rows_affected),
279        Err(e) => Err(e),
280    }
281}
282
283/// # fetch
284/// 
285/// Retrieves a single record from the database.
286/// 
287/// ## Parameters
288/// - `client`: Database connection client
289/// - `params`: Query parameters (must implement SqlQuery, FromRow, and SqlParams traits)
290/// 
291/// ## Return Value
292/// - `Result<T, Error>`: On success, returns the retrieved record; on failure, returns Error
293/// 
294/// ## Struct Definition
295/// Structs used with this function should be annotated with the following derive macros:
296/// 
297/// ```rust,no_run
298/// #[derive(Queryable, FromRow, SqlParams)]  // Required macros
299/// #[table("table_name")]                    // Table name to query
300/// #[where_clause("id = $1")]                // WHERE clause with parameter placeholders
301/// struct GetUser {
302///     id: i32,                              // Parameter for the WHERE clause
303///     name: String,                         // Field to retrieve
304///     email: String,                        // Field to retrieve
305/// }
306/// ```
307pub fn fetch<T: SqlQuery + FromRow + SqlParams>(
308    client: &mut Client,
309    params: &T,
310) -> Result<T, Error> {
311    let sql = T::query();
312    
313    if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
314        println!("[PARSQL-POSTGRES] Execute SQL: {}", sql);
315    }
316
317    let query_params = params.params();
318    let row = client.query_one(&sql, &query_params)?;
319    T::from_row(&row)
320}
321
322/// # fetch_all
323/// 
324/// Retrieves multiple records from the database.
325/// 
326/// ## Parameters
327/// - `client`: Database connection client
328/// - `params`: Query parameters (must implement SqlQuery, FromRow, and SqlParams traits)
329/// 
330/// ## Return Value
331/// - `Result<Vec<T>, Error>`: On success, returns a vector of records; on failure, returns Error
332/// 
333/// ## Struct Definition
334/// Structs used with this function should be annotated with the following derive macros:
335/// 
336/// ```rust,no_run
337/// #[derive(Queryable, FromRow, SqlParams)]  // Required macros
338/// #[table("users")]                         // Table name to query
339/// #[where_clause("active = $1")]            // WHERE clause with parameter placeholders
340/// struct GetUsers {
341///     active: bool,                         // Parameter for the WHERE clause
342///     id: i32,                              // Field to retrieve
343///     name: String,                         // Field to retrieve
344///     email: String,                        // Field to retrieve
345/// }
346/// ```
347pub fn fetch_all<T: SqlQuery + FromRow + SqlParams>(
348    client: &mut Client,
349    params: &T,
350) -> Result<Vec<T>, Error> {
351    let sql = T::query();
352    
353    if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
354        println!("[PARSQL-POSTGRES] Execute SQL: {}", sql);
355    }
356
357    let query_params = params.params();
358    let rows = client.query(&sql, &query_params)?;
359    
360    let mut results = Vec::with_capacity(rows.len());
361    for row in &rows {
362        results.push(T::from_row(row)?);
363    }
364    
365    Ok(results)
366}
367
368/// # get_by_query
369/// 
370/// Retrieves multiple records from the database using a custom SQL query.
371/// 
372/// ## Parameters
373/// - `client`: Database connection client
374/// - `query`: Custom SQL query string
375/// - `params`: Array of query parameters
376/// 
377/// ## Return Value
378/// - `Result<Vec<T>, Error>`: On success, returns the list of found records; on failure, returns Error
379/// 
380/// ## Example Usage
381/// ```rust,no_run
382/// use postgres::{Client, NoTls, Error};
383/// use parsql::postgres::get_by_query;
384/// 
385/// #[derive(FromRow, Debug)]
386/// pub struct UserStats {
387///     pub state: i16,
388///     pub user_count: i64,
389/// }
390///
391/// fn main() -> Result<(), Error> {
392///     let mut client = Client::connect(
393///         "host=localhost user=postgres dbname=test",
394///         NoTls,
395///     )?;
396///
397///     let query = "SELECT state, COUNT(*) as user_count FROM users GROUP BY state HAVING COUNT(*) > $1";
398///     let min_count = 5;
399///     
400///     let stats = get_by_query::<UserStats>(&mut client, query, &[&min_count])?;
401///     println!("User stats: {:?}", stats);
402///     Ok(())
403/// }
404/// ```
405pub fn get_by_query<T: FromRow>(
406    client: &mut Client,
407    query: &str,
408    params: &[&(dyn ToSql + Sync)],
409) -> Result<Vec<T>, Error> {
410    if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
411        println!("[PARSQL-POSTGRES] Execute SQL: {}", query);
412    }
413
414    let rows = client.query(query, params)?;
415    rows.iter()
416        .map(|row| T::from_row(row))
417        .collect::<Result<Vec<_>, _>>()
418}
419
420/// # select
421/// 
422/// Retrieves a single record from the database using a custom transformation function.
423/// This is useful when you want to use a custom transformation function instead of the FromRow trait.
424/// 
425/// ## Parameters
426/// - `client`: Database connection client
427/// - `entity`: Query parameter object (must implement SqlQuery and SqlParams traits)
428/// - `to_model`: Function to convert a Row object to the target object type
429/// 
430/// ## Return Value
431/// - `Result<T, Error>`: On success, returns the transformed object; on failure, returns Error
432/// 
433/// ## Struct Definition
434/// Structs used with this function should be annotated with the following derive macros:
435/// 
436/// ```rust,no_run
437/// #[derive(Queryable, SqlParams)]          // Required macros (FromRow is not needed)
438/// #[table("table_name")]                   // Table name to query
439/// #[where_clause("id = $")]                // Query condition
440/// pub struct MyQueryEntity {
441///     pub id: i32,                         // Field used in the query condition
442///     // Other fields can be added if necessary for the query condition
443/// }
444/// 
445/// // A separate struct can be used for the return value
446/// pub struct MyResultEntity {
447///     pub id: i32,
448///     pub name: String,
449///     pub count: i64,
450/// }
451/// ```
452/// 
453/// - `Queryable`: Automatically generates SQL SELECT statements
454/// - `SqlParams`: Automatically generates SQL parameters
455/// - `#[table("table_name")]`: Specifies the table name for the query
456/// - `#[where_clause("id = $")]`: Specifies the query condition (`$` will be replaced with parameter value)
457/// 
458/// ## Example Usage
459/// ```rust,no_run
460/// use postgres::{Client, NoTls, Error};
461/// use parsql::postgres::select;
462/// 
463/// #[derive(Queryable, SqlParams)]
464/// #[table("users")]
465/// #[where_clause("id = $")]
466/// pub struct UserQuery {
467///     pub id: i32,
468/// }
469/// 
470/// impl UserQuery {
471///     pub fn new(id: i32) -> Self {
472///         Self { id }
473///     }
474/// }
475/// 
476/// // Different return structure
477/// pub struct User {
478///     pub id: i32,
479///     pub name: String,
480/// }
481///
482/// fn main() -> Result<(), Error> {
483///     let mut client = Client::connect(
484///         "host=localhost user=postgres dbname=test",
485///         NoTls,
486///     )?;
487///
488///     // A custom model transformation function is required
489///     let user_query = UserQuery::new(1);
490///     let user = select(&mut client, user_query, |row| {
491///         let id: i32 = row.get("id");
492///         let name: String = row.get("name");
493///         Ok(User { id, name })
494///     })?;
495///     
496///     println!("User: {:?}", user);
497///     Ok(())
498/// }
499/// ```
500pub fn select<T: SqlQuery + SqlParams, F>(
501    client: &mut postgres::Client,
502    entity: T,
503    to_model: F,
504) -> Result<T, Error>
505where
506    F: Fn(&Row) -> Result<T, Error>,
507{
508    let sql = T::query();
509    if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
510        println!("[PARSQL-POSTGRES] Execute SQL: {}", sql);
511    }
512
513    let params = entity.params();
514
515    match client.query_one(&sql, &params) {
516        Ok(_row) => to_model(&_row),
517        Err(e) => Err(e),
518    }
519}
520
521/// # select_all
522/// 
523/// Retrieves multiple records from the database using a custom transformation function.
524/// This is useful when you want to use a custom transformation function instead of the FromRow trait.
525/// 
526/// ## Parameters
527/// - `client`: Database connection client
528/// - `entity`: Query parameter object (must implement SqlQuery and SqlParams traits)
529/// - `to_model`: Function to convert a Row object to the target object type
530/// 
531/// ## Return Value
532/// - `Result<Vec<T>, Error>`: On success, returns the list of transformed objects; on failure, returns Error
533/// 
534/// ## Struct Definition
535/// Structs used with this function should be annotated with the following derive macros:
536/// 
537/// ```rust,no_run
538/// #[derive(Queryable, SqlParams)]          // Required macros (FromRow is not needed)
539/// #[table("table_name")]                   // Table name to query
540/// #[select("id, name, COUNT(*) as count")] // Custom SELECT statement (optional)
541/// #[where_clause("active = $")]            // Query condition
542/// pub struct MyQueryEntity {
543///     pub active: bool,                    // Field used in the query condition
544///     // Other fields can be added if necessary for the query condition
545/// }
546/// 
547/// // A separate struct can be used for the return value
548/// pub struct MyResultEntity {
549///     pub id: i32,
550///     pub name: String,
551///     pub count: i64,
552/// }
553/// ```
554/// 
555/// - `Queryable`: Automatically generates SQL SELECT statements
556/// - `SqlParams`: Automatically generates SQL parameters
557/// - `#[table("table_name")]`: Specifies the table name for the query
558/// - `#[select("...")]`: Creates a custom SELECT statement (if omitted, all fields will be selected)
559/// - `#[where_clause("active = $")]`: Specifies the query condition (`$` will be replaced with parameter value)
560/// 
561/// ## Example Usage
562/// ```rust,no_run
563/// use postgres::{Client, NoTls, Error};
564/// use parsql::postgres::select_all;
565/// 
566/// #[derive(Queryable, SqlParams)]
567/// #[table("users")]
568/// #[select("id, name, email")]
569/// pub struct UsersQuery {
570///     // Can be empty for a parameterless query
571/// }
572/// 
573/// impl UsersQuery {
574///     pub fn new() -> Self {
575///         Self {}
576///     }
577/// }
578/// 
579/// // Different return structure
580/// pub struct User {
581///     pub id: i32,
582///     pub name: String,
583/// }
584///
585/// fn main() -> Result<(), Error> {
586///     let mut client = Client::connect(
587///         "host=localhost user=postgres dbname=test",
588///         NoTls,
589///     )?;
590///
591///     // A custom model transformation function is required
592///     let users_query = UsersQuery::new();
593///     let users = select_all(&mut client, users_query, |row| {
594///         let id: i32 = row.get("id");
595///         let name: String = row.get("name");
596///         User { id, name }
597///     })?;
598///     
599///     println!("Users: {:?}", users);
600///     Ok(())
601/// }
602/// ```
603pub fn select_all<T: SqlQuery + SqlParams, F>(
604    client: &mut postgres::Client,
605    entity: T,
606    to_model: F,
607) -> Result<Vec<T>, Error>
608where
609    F: Fn(&Row) -> Result<T, Error>,
610{
611    let sql = T::query();
612    if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
613        println!("[PARSQL-POSTGRES] Execute SQL: {}", sql);
614    }
615
616    let params = entity.params();
617
618    let rows = client.query(&sql, &params)?;
619
620    rows.iter()
621        .map(|row| to_model(row))
622        .collect::<Result<Vec<_>, _>>()
623}
624
625// Geriye dönük uyumluluk için eski get fonksiyonunu koruyalım
626#[deprecated(
627    since = "0.2.0",
628    note = "Renamed to `fetch`. Please use `fetch` function instead."
629)]
630/// # get
631/// 
632/// Retrieves a single record from the database.
633/// 
634/// This function is deprecated. Please use `fetch` instead.
635pub fn get<T: SqlQuery + FromRow + SqlParams>(
636    client: &mut Client,
637    params: &T,
638) -> Result<T, Error> {
639    fetch(client, params)
640}
641
642// Geriye dönük uyumluluk için eski get_all fonksiyonunu koruyalım
643#[deprecated(
644    since = "0.2.0",
645    note = "Renamed to `fetch_all`. Please use `fetch_all` function instead."
646)]
647/// # get_all
648/// 
649/// Retrieves multiple records from the database.
650/// 
651/// This function is deprecated. Please use `fetch_all` instead.
652pub fn get_all<T: SqlQuery + FromRow + SqlParams>(
653    client: &mut Client,
654    params: &T,
655) -> Result<Vec<T>, Error> {
656    fetch_all(client, params)
657}