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, ¶ms)?;
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, ¶ms)?;
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, ¶ms)?;
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, ¶ms) {
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, ¶ms) {
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, ¶ms) {
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, ¶ms)?;
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}