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