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::{fetch, 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 = fetch(&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.fetch(&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//!
158//! ## Installation
159//!
160//! Add to your Cargo.toml file as follows:
161//!
162//! ```toml
163//! [dependencies]
164//! parsql = { version = "0.3.7", features = ["sqlite"] }
165//! ```
166//!
167//! or if you want to use this package directly:
168//!
169//! ```toml
170//! [dependencies]
171//! parsql-sqlite = "0.3.7"
172//! parsql-macros = "0.3.7"
173//! ```
174
175pub mod crud_ops;
176pub mod transactional_ops;
177
178// Re-export sqlite types that might be needed
179pub use rusqlite::{Connection, Error, Row};
180pub use rusqlite::types::ToSql;
181
182// Re-export crud operations
183pub use crud_ops::{
184 insert,
185 select,
186 select_all,
187 update,
188 delete,
189 fetch,
190 fetch_all,
191 CrudOps,
192};
193
194// Re-export transaction operations
195pub use transactional_ops as transactional;
196
197pub use parsql_macros as macros;
198
199/// Trait for generating SQL queries.
200/// This trait is implemented by the derive macro `Queryable`, `Insertable`, `Updateable`, and `Deletable`.
201pub trait SqlQuery {
202 /// Returns the SQL query string.
203 fn query() -> String;
204}
205
206/// Trait for providing SQL parameters.
207/// This trait is implemented by the derive macro `SqlParams`.
208pub trait SqlParams {
209 /// Returns a vector of references to SQL parameters.
210 fn params(&self) -> Vec<&(dyn ToSql + Sync)>;
211}
212
213/// Trait for providing UPDATE parameters.
214/// This trait is implemented by the derive macro `UpdateParams`.
215pub trait UpdateParams {
216 /// Returns a vector of references to SQL parameters for UPDATE operations.
217 fn params(&self) -> Vec<&(dyn ToSql + Sync)>;
218}
219
220/// Trait for converting database rows to Rust structs.
221/// This trait is implemented by the derive macro `FromRow`.
222pub trait FromRow {
223 /// Converts a database row to a Rust struct.
224 ///
225 /// # Arguments
226 /// * `row` - A reference to a database row
227 ///
228 /// # Returns
229 /// * `Result<Self, Error>` - The converted struct or an error
230 fn from_row(row: &Row) -> Result<Self, Error>
231 where
232 Self: Sized;
233}