parsql_sqlite/
lib.rs

1//! # parsql-sqlite
2//! 
3//! SQLite integration for parsql.
4//! This crate provides synchronous APIs for working with SQLite databases.
5//! 
6//! ## Features
7//! 
8//! - Synchronous SQLite operations
9//! - Automatic SQL query generation
10//! - Secure parameter management
11//! - Generic CRUD operations
12//! - Transaction support
13//! - Extension methods for the Connection object
14//! 
15//! ## Usage
16//! 
17//! ```rust,no_run
18//! use rusqlite::{Connection, Result};
19//! use parsql::sqlite::{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<()> {
38//!     let conn = Connection::open("test.db")?;
39//!     
40//!     // Insert a new user
41//!     let insert_user = InsertUser {
42//!         name: "John".to_string(),
43//!         email: "john@example.com".to_string(),
44//!     };
45//!     
46//!     let id = insert(&conn, insert_user)?;
47//!     
48//!     // Get the user back
49//!     let get_user = GetUser::new(id as i32);
50//!     let user = get(&conn, &get_user)?;
51//!     
52//!     println!("User: {:?}", user);
53//!     Ok(())
54//! }
55//! ```
56//!
57//! ## Using Extension Methods
58//!
59//! You can also use the extension methods directly on the Connection object:
60//!
61//! ```rust,no_run
62//! use rusqlite::{Connection, Result};
63//! use parsql::sqlite::CrudOps;  // Import the trait
64//! use parsql::sqlite::macros::{Insertable, SqlParams, Queryable, FromRow};
65//!
66//! #[derive(Insertable, SqlParams)]
67//! #[table("users")]
68//! pub struct InsertUser {
69//!     pub name: String,
70//!     pub email: String,
71//! }
72//!
73//! #[derive(Queryable, FromRow, SqlParams)]
74//! #[table("users")]
75//! #[where_clause("id = ?")]
76//! pub struct GetUser {
77//!     pub id: i32,
78//!     pub name: String,
79//!     pub email: String,
80//! }
81//!
82//! fn main() -> Result<()> {
83//!     let conn = Connection::open("test.db")?;
84//!     
85//!     // Insert a new user using extension method
86//!     let insert_user = InsertUser {
87//!         name: "John".to_string(),
88//!         email: "john@example.com".to_string(),
89//!     };
90//!     
91//!     let rows_affected = conn.insert(insert_user)?;
92//!     
93//!     // Get the user back using extension method
94//!     let get_user = GetUser {
95//!         id: 1,
96//!         name: String::new(),
97//!         email: String::new(),
98//!     };
99//!     let user = conn.get(&get_user)?;
100//!     
101//!     println!("User: {:?}", user);
102//!     Ok(())
103//! }
104//! ```
105//!
106//! ## Using Transactions
107//! 
108//! You can perform database operations within a transaction to ensure atomicity:
109//! 
110//! ```rust,no_run
111//! use rusqlite::{Connection, Result};
112//! use parsql::sqlite::transactional;
113//! use parsql::macros::{Insertable, SqlParams, Updateable, UpdateParams};
114//! 
115//! #[derive(Insertable, SqlParams)]
116//! #[table("users")]
117//! struct InsertUser {
118//!     name: String,
119//!     email: String,
120//! }
121//! 
122//! #[derive(Updateable, UpdateParams)]
123//! #[table("users")]
124//! #[update("email")]
125//! #[where_clause("id = ?")]
126//! struct UpdateUser {
127//!     id: i64,
128//!     email: String,
129//! }
130//! 
131//! fn main() -> Result<()> {
132//!     let conn = Connection::open("test.db")?;
133//!     
134//!     // Begin a transaction
135//!     let tx = transactional::begin(&conn)?;
136//!     
137//!     // Insert a user within the transaction
138//!     let insert_user = InsertUser {
139//!         name: "John".to_string(),
140//!         email: "john@example.com".to_string(),
141//!     };
142//!     let (tx, _) = transactional::tx_insert(tx, insert_user)?;
143//!     
144//!     // Update the user within the same transaction
145//!     let update_user = UpdateUser {
146//!         id: 1,
147//!         email: "john.updated@example.com".to_string(),
148//!     };
149//!     let (tx, _) = transactional::tx_update(tx, update_user)?;
150//!     
151//!     // Commit the transaction - both operations succeed or fail together
152//!     tx.commit()?;
153//!     
154//!     Ok(())
155//! }
156//! ```
157
158pub mod crud_ops;
159pub mod transactional_ops;
160
161// Re-export sqlite types that might be needed
162pub use rusqlite::{Connection, Error, Row};
163pub use rusqlite::types::ToSql;
164
165// Re-export crud operations
166pub use crud_ops::{
167    insert, 
168    select, 
169    select_all, 
170    update, 
171    delete, 
172    get, 
173    get_all,
174    CrudOps,
175};
176
177// Re-export transaction operations
178pub use transactional_ops as transactional;
179
180pub use parsql_macros as macros;
181
182/// Trait for generating SQL queries.
183/// This trait is implemented by the derive macro `Queryable`, `Insertable`, `Updateable`, and `Deletable`.
184pub trait SqlQuery {
185    /// Returns the SQL query string.
186    fn query() -> String;
187}
188
189/// Trait for providing SQL parameters.
190/// This trait is implemented by the derive macro `SqlParams`.
191pub trait SqlParams {
192    /// Returns a vector of references to SQL parameters.
193    fn params(&self) -> Vec<&(dyn ToSql + Sync)>;
194}
195
196/// Trait for providing UPDATE parameters.
197/// This trait is implemented by the derive macro `UpdateParams`.
198pub trait UpdateParams {
199    /// Returns a vector of references to SQL parameters for UPDATE operations.
200    fn params(&self) -> Vec<&(dyn ToSql + Sync)>;
201}
202
203/// Trait for converting database rows to Rust structs.
204/// This trait is implemented by the derive macro `FromRow`.
205pub trait FromRow {
206    /// Converts a database row to a Rust struct.
207    /// 
208    /// # Arguments
209    /// * `row` - A reference to a database row
210    /// 
211    /// # Returns
212    /// * `Result<Self, Error>` - The converted struct or an error
213    fn from_row(row: &Row) -> Result<Self, Error>
214    where
215        Self: Sized;
216}