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}