parsql_postgres/
crud_ops.rs

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