parsql_postgres/
lib.rs

1//! # parsql-postgres
2//!
3//! Synchronous PostgreSQL integration for parsql.
4//! This crate provides synchronous APIs for working with PostgreSQL databases.
5//!
6//! ## Features
7//!
8//! - Synchronous PostgreSQL operations
9//! - Automatic SQL query generation
10//! - Secure parameter management
11//! - Generic CRUD operations
12//! - Transaction support
13//! - Extension methods for the Client object
14//!
15//! ## Usage
16//!
17//! ```rust,no_run
18//! use postgres::{Client, NoTls, Error};
19//! use parsql::postgres::{get, insert};
20//!
21//! #[derive(Insertable, SqlParams)]
22//! #[table("users")]
23//! pub struct InsertUser {
24//!     pub name: String,
25//!     pub email: String,
26//! }
27//!
28//! #[derive(Queryable, SqlParams, FromRow)]
29//! #[table("users")]
30//! #[where_clause("id = $")]
31//! pub struct GetUser {
32//!     pub id: i32,
33//!     pub name: String,
34//!     pub email: String,
35//! }
36//!
37//! fn main() -> Result<(), Error> {
38//!     let mut client = Client::connect(
39//!         "host=localhost user=postgres dbname=test",
40//!         NoTls,
41//!     )?;
42//!     
43//!     // Insert a new user
44//!     let insert_user = InsertUser {
45//!         name: "John".to_string(),
46//!         email: "john@example.com".to_string(),
47//!     };
48//!     
49//!     let id = insert(&mut client, insert_user)?;
50//!     
51//!     // Get the user back
52//!     let get_user = GetUser::new(id as i32);
53//!     let user = get(&mut client, &get_user)?;
54//!     
55//!     println!("User: {:?}", user);
56//!     Ok(())
57//! }
58//! ```
59//!
60//! ## Using Extension Methods
61//!
62//! You can also use the extension methods directly on the Client object:
63//!
64//! ```rust,no_run
65//! use postgres::{Client, NoTls, Error};
66//! use parsql::postgres::CrudOps;  // Import the trait
67//! use parsql::macros::{Insertable, SqlParams, Queryable, FromRow};
68//!
69//! #[derive(Insertable, SqlParams)]
70//! #[table("users")]
71//! pub struct InsertUser {
72//!     pub name: String,
73//!     pub email: String,
74//! }
75//!
76//! #[derive(Queryable, FromRow, SqlParams)]
77//! #[table("users")]
78//! #[where_clause("id = $1")]
79//! pub struct GetUser {
80//!     pub id: i32,
81//!     pub name: String,
82//!     pub email: String,
83//! }
84//!
85//! fn main() -> Result<(), Error> {
86//!     let mut client = Client::connect("host=localhost user=postgres", NoTls)?;
87//!     
88//!     // Insert a new user using extension method
89//!     let insert_user = InsertUser {
90//!         name: "John".to_string(),
91//!         email: "john@example.com".to_string(),
92//!     };
93//!     
94//!     let rows_affected = client.insert(insert_user)?;
95//!     
96//!     // Get the user back using extension method
97//!     let get_user = GetUser {
98//!         id: 1,
99//!         name: String::new(),
100//!         email: String::new(),
101//!     };
102//!     let user = client.get(&get_user)?;
103//!     
104//!     println!("User: {:?}", user);
105//!     Ok(())
106//! }
107//! ```
108//!
109//! ## Using Transactions
110//!
111//! This crate supports transaction operations in two ways: through the `CrudOps` trait
112//! methods directly on a `Transaction` object, or through the helper functions provided
113//! in the `transactional` module.
114//!
115//! ### Using CrudOps with Transaction
116//!
117//! ```rust,no_run
118//! use postgres::{Client, NoTls, Error};
119//! use parsql::postgres::CrudOps;
120//! use parsql::macros::{Insertable, SqlParams, Updateable, UpdateParams};
121//!
122//! #[derive(Insertable, SqlParams)]
123//! #[table("users")]
124//! struct InsertUser {
125//!     name: String,
126//!     email: String,
127//! }
128//!
129//! #[derive(Updateable, UpdateParams)]
130//! #[table("users")]
131//! #[update("email")]
132//! #[where_clause("id = $")]
133//! struct UpdateUser {
134//!     id: i32,
135//!     email: String,
136//! }
137//!
138//! fn main() -> Result<(), Error> {
139//!     let mut client = Client::connect("host=localhost user=postgres", NoTls)?;
140//!     
141//!     // Start a transaction
142//!     let mut tx = client.transaction()?;
143//!     
144//!     // Use CrudOps methods directly on the transaction
145//!     let insert_user = InsertUser {
146//!         name: "John".to_string(),
147//!         email: "john@example.com".to_string(),
148//!     };
149//!     let rows_affected = tx.insert(insert_user)?;
150//!     
151//!     let update_user = UpdateUser {
152//!         id: 1,
153//!         email: "john.updated@example.com".to_string(),
154//!     };
155//!     let rows_updated = tx.update(update_user)?;
156//!     
157//!     // Commit the transaction
158//!     tx.commit()?;
159//!     Ok(())
160//! }
161//! ```
162//!
163//! ### Using Transaction Helper Functions
164//!
165//! ```rust,no_run
166//! use postgres::{Client, NoTls, Error};
167//! use parsql::postgres::transactional::{begin, tx_insert, tx_update};
168//! use parsql::macros::{Insertable, SqlParams, Updateable, UpdateParams};
169//!
170//! #[derive(Insertable, SqlParams)]
171//! #[table("users")]
172//! struct InsertUser {
173//!     name: String,
174//!     email: String,
175//! }
176//!
177//! #[derive(Updateable, UpdateParams)]
178//! #[table("users")]
179//! #[update("email")]
180//! #[where_clause("id = $")]
181//! struct UpdateUser {
182//!     id: i32,
183//!     email: String,
184//! }
185//!
186//! fn main() -> Result<(), Error> {
187//!     let mut client = Client::connect("host=localhost user=postgres", NoTls)?;
188//!     
189//!     // Begin a transaction
190//!     let tx = begin(&mut client)?;
191//!     
192//!     // Chain transaction operations
193//!     let insert_user = InsertUser {
194//!         name: "John".to_string(),
195//!         email: "john@example.com".to_string(),
196//!     };
197//!     
198//!     let (tx, _) = tx_insert(tx, insert_user)?;
199//!     
200//!     let update_user = UpdateUser {
201//!         id: 1,
202//!         email: "john.updated@example.com".to_string(),
203//!     };
204//!     
205//!     let (tx, _) = tx_update(tx, update_user)?;
206//!     
207//!     // Commit the transaction
208//!     tx.commit()?;
209//!     Ok(())
210//! }
211//! ```
212
213pub mod crud_ops;
214pub mod transaction_ops;
215
216pub use postgres::types::ToSql;
217pub use postgres::Transaction;
218pub use postgres::{Client, Error, Row};
219
220// Re-export crud operations
221pub use crud_ops::{
222    delete, get, get_all, get_by_query, insert, select, select_all, update, CrudOps,
223};
224
225// Re-export transaction operations in a transactional module
226pub mod transactional {
227    pub use crate::transaction_ops::{
228        begin, tx_delete, tx_get, tx_get_all, tx_insert, tx_select, tx_select_all, tx_update,
229    };
230}
231
232pub use parsql_macros as macros;
233
234/// Trait for generating SQL queries.
235/// This trait is implemented by the derive macro `Queryable`, `Insertable`, `Updateable`, and `Deletable`.
236pub trait SqlQuery {
237    /// Returns the SQL query string.
238    fn query() -> String;
239}
240
241/// Trait for providing SQL parameters.
242/// This trait is implemented by the derive macro `SqlParams`.
243pub trait SqlParams {
244    /// Returns a vector of references to SQL parameters.
245    fn params(&self) -> Vec<&(dyn postgres::types::ToSql + Sync)>;
246}
247
248/// Trait for providing UPDATE parameters.
249/// This trait is implemented by the derive macro `UpdateParams`.
250pub trait UpdateParams {
251    /// Returns a vector of references to SQL parameters for UPDATE operations.
252    fn params(&self) -> Vec<&(dyn postgres::types::ToSql + Sync)>;
253}
254
255/// Trait for converting database rows to Rust structs.
256/// This trait is implemented by the derive macro `FromRow`.
257pub trait FromRow {
258    /// Converts a database row to a Rust struct.
259    ///
260    /// # Arguments
261    /// * `row` - A reference to a database row
262    ///
263    /// # Returns
264    /// * `Result<Self, Error>` - The converted struct or an error
265    fn from_row(row: &postgres::Row) -> Result<Self, postgres::Error>
266    where
267        Self: Sized;
268}