parsql_sqlite/
crud_ops.rs

1use rusqlite::{types::FromSql, Error, Row, ToSql};
2
3use crate::traits::{CrudOps, FromRow, SqlCommand, SqlParams, SqlQuery, UpdateParams};
4
5// CrudOps trait implementasyonu rusqlite::Connection için
6impl CrudOps for rusqlite::Connection {
7    fn insert<T: SqlCommand + SqlParams, P: for<'a> FromSql + Send + Sync>(
8        &self,
9        entity: T,
10    ) -> Result<P, Error> {
11        insert(self, entity)
12    }
13
14    fn update<T: SqlCommand + UpdateParams>(&self, entity: T) -> Result<usize, Error> {
15        update(self, entity)
16    }
17
18    fn delete<T: SqlCommand + SqlParams>(&self, entity: T) -> Result<usize, Error> {
19        delete(self, entity)
20    }
21
22    fn fetch<P, R>(&self, params: &P) -> Result<R, Error>
23    where
24        P: SqlQuery<R> + SqlParams,
25        R: FromRow,
26    {
27        fetch(self, params)
28    }
29
30    fn fetch_all<P, R>(&self, params: &P) -> Result<Vec<R>, Error>
31    where
32        P: SqlQuery<R> + SqlParams,
33        R: FromRow,
34    {
35        fetch_all(self, params)
36    }
37
38    fn select<T: SqlQuery<T> + SqlParams, F, R>(&self, entity: &T, to_model: F) -> Result<R, Error>
39    where
40        F: Fn(&Row) -> Result<R, Error>,
41    {
42        let sql = T::query();
43        if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
44            println!("[PARSQL-SQLITE] Execute SQL: {}", sql);
45        }
46
47        let params = entity.params();
48        let param_refs: Vec<&dyn ToSql> = params.iter().map(|p| *p as &dyn ToSql).collect();
49        self.query_row(&sql, param_refs.as_slice(), to_model)
50    }
51
52    fn select_all<T: SqlQuery<T> + SqlParams, F, R>(
53        &self,
54        entity: &T,
55        to_model: F,
56    ) -> Result<Vec<R>, Error>
57    where
58        F: Fn(&Row) -> Result<R, Error>,
59    {
60        let sql = T::query();
61        if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
62            println!("[PARSQL-SQLITE] Execute SQL: {}", sql);
63        }
64
65        let params = entity.params();
66        let param_refs: Vec<&dyn ToSql> = params.iter().map(|p| *p as &dyn ToSql).collect();
67        let mut stmt = self.prepare(&sql)?;
68        let rows = stmt.query_map(param_refs.as_slice(), to_model)?;
69
70        let mut results = Vec::new();
71        for row in rows {
72            results.push(row?);
73        }
74
75        Ok(results)
76    }
77}
78
79/// # insert
80///
81/// Inserts a new record into the SQLite database.
82///
83/// ## Parameters
84/// - `conn`: SQLite database connection
85/// - `entity`: Data object to be inserted (must implement SqlCommand and SqlParams traits)
86///
87/// ## Return Value
88/// - `Result<usize, rusqlite::Error>`: On success, returns the number of inserted records; on failure, returns Error
89///
90/// ## Struct Definition
91/// Structs used with this function should be annotated with the following derive macros:
92///
93/// ```rust,no_run
94/// #[derive(Insertable, SqlParams)]  // Required macros
95/// #[table("table_name")]            // Table name to insert into
96/// pub struct MyEntity {
97///     pub field1: String,
98///     pub field2: i32,
99///     // ...
100/// }
101/// ```
102///
103/// - `Insertable`: Automatically generates SQL INSERT statements
104/// - `SqlParams`: Automatically generates SQL parameters
105/// - `#[table("table_name")]`: Specifies the table name for the insertion
106///
107/// ## Example Usage
108///
109/// ```rust,no_run
110/// use rusqlite::{Connection, Result};
111/// use parsql_macros::{Insertable, SqlParams};
112/// use parsql_sqlite::insert;
113///
114/// fn main() -> Result<()> {
115///     // Create a database connection
116///     let conn = Connection::open("test.db")?;
117///
118///     // Create the table
119///     conn.execute("CREATE TABLE users (name TEXT, email TEXT, state INTEGER)", [])?;
120///
121///     // Define your entity with appropriate macros
122///     #[derive(Insertable, SqlParams)]
123///     #[table("users")]
124///     pub struct InsertUser {
125///         pub name: String,
126///         pub email: String,
127///         pub state: i16,
128///     }
129///
130///     // Create a new instance of your entity
131///     let insert_user = InsertUser {
132///         name: "John".to_string(),
133///         email: "john@example.com".to_string(),
134///         state: 1,
135///     };
136///
137///     // Insert into database
138///     let insert_result = insert(&conn, insert_user)?;
139///     println!("Insert result: {:?}", insert_result);
140///     Ok(())
141/// }
142/// ```
143pub fn insert<T: SqlCommand + SqlParams, P: for<'a> FromSql + Send + Sync>(
144    conn: &rusqlite::Connection,
145    entity: T,
146) -> Result<P, rusqlite::Error> {
147    let sql = T::query();
148    if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
149        println!("[PARSQL-SQLITE] Execute SQL: {}", sql);
150    }
151
152    let params = entity.params();
153    let param_refs: Vec<&dyn ToSql> = params.iter().map(|p| *p as &dyn ToSql).collect();
154
155    // Check if the SQL contains RETURNING clause
156    if sql.to_uppercase().contains("RETURNING") {
157        // Use query_row for RETURNING statements
158        conn.query_row(&sql, param_refs.as_slice(), |row| {
159            P::column_result(row.get_ref(0)?).map_err(|e| {
160                rusqlite::Error::FromSqlConversionFailure(
161                    0,
162                    rusqlite::types::Type::Integer,
163                    Box::new(e),
164                )
165            })
166        })
167    } else {
168        // Use execute for regular INSERT statements
169        conn.execute(&sql, param_refs.as_slice())?;
170
171        // Get the last inserted ID and use FromSql to convert it
172        let last_id = conn.last_insert_rowid();
173        P::column_result(rusqlite::types::ValueRef::Integer(last_id)).map_err(|e| {
174            rusqlite::Error::FromSqlConversionFailure(
175                0,
176                rusqlite::types::Type::Integer,
177                Box::new(e),
178            )
179        })
180    }
181}
182
183/// # update
184///
185/// Updates a record in the database.
186///
187/// ## Parameters
188/// - `conn`: SQLite database connection
189/// - `entity`: The entity to update (must implement SqlCommand and UpdateParams traits)
190///
191/// ## Return Value
192/// - `Result<usize, Error>`: On success, returns the number of rows affected; on failure, returns Error
193///
194/// ## Struct Definition
195/// Structs used with this function should be annotated with the following derive macros:
196///
197/// ```rust,no_run
198/// use parsql_macros::{Updateable, UpdateParams};
199///
200/// #[derive(Updateable, UpdateParams)]  // Required macros
201/// #[table("table_name")]              // Table name to update
202/// #[update("field1, field2")]         // Fields to update
203/// #[where_clause("id = ?")]           // Update condition
204/// pub struct MyEntity {
205///     pub id: i64,                    // Field used in the where clause
206///     pub field1: String,             // Fields to update
207///     pub field2: i32,
208/// }
209/// ```
210///
211/// ## Example Usage
212///
213/// ```rust,no_run
214/// use rusqlite::{Connection, Result};
215/// use parsql_macros::{Updateable, UpdateParams};
216/// use parsql_sqlite::update;
217///
218/// fn main() -> Result<()> {
219///     // Create database connection
220///     let conn = Connection::open("test.db")?;
221///     conn.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT, state INTEGER)", [])?;
222///     conn.execute("INSERT INTO users (id, name, email, state) VALUES (1, 'Old Name', 'old@example.com', 0)", [])?;
223///
224///     // Define an entity for updating
225///     #[derive(Updateable, UpdateParams)]
226///     #[table("users")]
227///     #[update("name, email")]
228///     #[where_clause("id = ?")]
229///     pub struct UpdateUser {
230///         pub id: i64,
231///         pub name: String,
232///         pub email: String,
233///         pub state: i16,  // Not included in the update
234///     }
235///
236///     // Create the update parameters (update user with id 1)
237///     let update_query = UpdateUser {
238///         id: 1,
239///         name: String::from("John Updated"),
240///         email: String::from("john.updated@example.com"),
241///         state: 1,
242///     };
243///
244///     // Execute update
245///     let update_result = update(&conn, update_query)?;
246///     println!("Update result: {:?}", update_result);
247///     Ok(())
248/// }
249/// ```
250pub fn update<T: SqlCommand + UpdateParams>(
251    conn: &rusqlite::Connection,
252    entity: T,
253) -> Result<usize, Error> {
254    let sql = T::query();
255    if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
256        println!("[PARSQL-SQLITE] Execute SQL: {}", sql);
257    }
258
259    let params = entity.params();
260    let param_refs: Vec<&dyn ToSql> = params.iter().map(|p| *p as &dyn ToSql).collect();
261    let affected_rows = conn.execute(&sql, param_refs.as_slice())?;
262    Ok(affected_rows)
263}
264
265/// # delete
266///
267/// Deletes a record from the database.
268///
269/// ## Parameters
270/// - `conn`: SQLite database connection
271/// - `entity`: Data object containing deletion parameters (must implement SqlCommand and SqlParams traits)
272///
273/// ## Return Value
274/// - `Result<usize, Error>`: On success, returns the number of deleted records; on failure, returns Error
275///
276/// ## Struct Definition
277/// Structs used with this function should be annotated with the following derive macros:
278///
279/// ```rust,no_run
280/// #[derive(Deletable, SqlParams)]   // Required macros
281/// #[table("table_name")]            // Table name to delete from
282/// #[where_clause("id = ?")]         // Delete condition
283/// pub struct MyEntity {
284///     pub id: i64,                  // Field used in the condition
285/// }
286/// ```
287///
288/// - `Deletable`: Automatically generates SQL DELETE statements
289/// - `SqlParams`: Automatically generates SQL parameters
290/// - `#[table("table_name")]`: Specifies the table name for the deletion
291/// - `#[where_clause("id = ?")]`: Specifies the delete condition (`?` will be replaced with parameter value)
292///
293/// ## Example Usage
294///
295/// ```rust,no_run
296/// use rusqlite::{Connection, Result};
297/// use parsql_macros::{Deletable, SqlParams};
298/// use parsql_sqlite::delete;
299///
300/// fn main() -> Result<()> {
301///     // Create database connection
302///     let conn = Connection::open("test.db")?;
303///     conn.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)", [])?;
304///     conn.execute("INSERT INTO users (id, name, email) VALUES (1, 'John', 'john@example.com')", [])?;
305///
306///     // Define a delete query
307///     #[derive(Deletable, SqlParams)]
308///     #[table("users")]
309///     #[where_clause("id = ?")]
310///     pub struct DeleteUser {
311///         pub id: i64,
312///     }
313///
314///     // Create delete parameters (delete user with ID 1)
315///     let delete_query = DeleteUser { id: 1 };
316///
317///     // Execute delete
318///     let delete_result = delete(&conn, delete_query)?;
319///     println!("Delete result: {:?}", delete_result);
320///     Ok(())
321/// }
322/// ```
323pub fn delete<T: SqlCommand + SqlParams>(
324    conn: &rusqlite::Connection,
325    entity: T,
326) -> Result<usize, Error> {
327    let sql = T::query();
328    if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
329        println!("[PARSQL-SQLITE] Execute SQL: {}", sql);
330    }
331
332    let params = entity.params();
333    let param_refs: Vec<&dyn ToSql> = params.iter().map(|p| *p as &dyn ToSql).collect();
334    let affected_rows = conn.execute(&sql, param_refs.as_slice())?;
335    Ok(affected_rows)
336}
337
338/// # fetch
339///
340/// Retrieves a single record from the database based on a specific condition.
341///
342/// ## Parameters
343/// - `conn`: SQLite database connection
344/// - `entity`: Query parameter object (must implement SqlQuery, FromRow, and SqlParams traits)
345///
346/// ## Return Value
347/// - `Result<T, Error>`: On success, returns the queried record; on failure, returns Error
348///
349/// ## Struct Definition
350/// Structs used with this function should be annotated with the following derive macros:
351///
352/// ```rust,no_run
353/// #[derive(Queryable, FromRow, SqlParams)]  // Required macros
354/// #[table("table_name")]                    // Table name to query
355/// #[where_clause("id = ?")]                 // Query condition
356/// pub struct MyEntity {
357///     pub id: i64,                          // Field used in the condition
358///     pub field1: String,                   // Fields to retrieve
359///     pub field2: i32,
360/// }
361/// ```
362///
363/// ## Example Usage
364///
365/// ```rust,no_run
366/// use rusqlite::{Connection, Result};
367/// use parsql_macros::{Queryable, FromRow, SqlParams};
368/// use parsql_sqlite::fetch;
369///
370/// fn main() -> Result<()> {
371///     // Create database connection
372///     let conn = Connection::open("test.db")?;
373///     conn.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)", [])?;
374///     conn.execute("INSERT INTO users (id, name, email) VALUES (1, 'John', 'john@example.com')", [])?;
375///
376///     // Define a query
377///     #[derive(Queryable, FromRow, SqlParams)]
378///     #[table("users")]
379///     #[where_clause("id = ?")]
380///     pub struct GetUser {
381///         pub id: i64,
382///         pub name: String,
383///         pub email: String,
384///     }
385///
386///     // Create query parameters (get user with ID 1)
387///     let get_query = GetUser {
388///         id: 1,
389///         name: String::new(),
390///         email: String::new(),
391///     };
392///
393///     // Execute query
394///     let user = fetch(&conn, &get_query)?;
395///     println!("User: {:?}", user);
396///     Ok(())
397/// }
398/// ```
399pub fn fetch<P, R>(conn: &rusqlite::Connection, params: &P) -> Result<R, Error>
400where
401    P: SqlQuery<R> + SqlParams,
402    R: FromRow,
403{
404    let sql = P::query();
405    if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
406        println!("[PARSQL-SQLITE] Execute SQL: {}", sql);
407    }
408
409    let query_params = params.params();
410    let param_refs: Vec<&dyn ToSql> = query_params.iter().map(|p| *p as &dyn ToSql).collect();
411    conn.query_row(&sql, param_refs.as_slice(), |row| R::from_row(row))
412}
413
414/// # fetch_all
415///
416/// Retrieves multiple records from the database based on a specific condition.
417///
418/// ## Parameters
419/// - `conn`: SQLite database connection
420/// - `entity`: Query parameter object (must implement SqlQuery, FromRow, and SqlParams traits)
421///
422/// ## Return Value
423/// - `Result<Vec<T>, Error>`: On success, returns a vector of records; on failure, returns Error
424///
425/// ## Example Usage
426///
427/// ```rust,no_run
428/// use rusqlite::{Connection, Result};
429/// use parsql_macros::{Queryable, FromRow, SqlParams};
430/// use parsql_sqlite::fetch_all;
431///
432/// fn main() -> Result<()> {
433///     // Create database connection
434///     let conn = Connection::open("test.db")?;
435///     conn.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT, active INTEGER)", [])?;
436///     conn.execute("INSERT INTO users (id, name, email, active) VALUES (1, 'John', 'john@example.com', 1)", [])?;
437///     conn.execute("INSERT INTO users (id, name, email, active) VALUES (2, 'Jane', 'jane@example.com', 1)", [])?;
438///
439///     // Define a query
440///     #[derive(Queryable, FromRow, SqlParams)]
441///     #[table("users")]
442///     #[where_clause("active = ?")]
443///     pub struct GetActiveUsers {
444///         pub id: i64,
445///         pub name: String,
446///         pub email: String,
447///         pub active: i32,
448///     }
449///
450///     // Create query parameters (get all active users)
451///     let query = GetActiveUsers {
452///         id: 0,
453///         name: String::new(),
454///         email: String::new(),
455///         active: 1,
456///     };
457///
458///     // Execute query
459///     let users = fetch_all(&conn, &query)?;
460///     println!("Active users: {:?}", users);
461///     Ok(())
462/// }
463/// ```
464pub fn fetch_all<P, R>(conn: &rusqlite::Connection, params: &P) -> Result<Vec<R>, Error>
465where
466    P: SqlQuery<R> + SqlParams,
467    R: FromRow,
468{
469    let sql = P::query();
470    if std::env::var("PARSQL_TRACE").unwrap_or_default() == "1" {
471        println!("[PARSQL-SQLITE] Execute SQL: {}", sql);
472    }
473
474    let query_params = params.params();
475    let param_refs: Vec<&dyn ToSql> = query_params.iter().map(|p| *p as &dyn ToSql).collect();
476    let mut stmt = conn.prepare(&sql)?;
477    let rows = stmt.query_map(param_refs.as_slice(), |row| R::from_row(row))?;
478
479    let mut results = Vec::new();
480    for row in rows {
481        results.push(row?);
482    }
483
484    Ok(results)
485}
486
487/// # get
488///
489/// Retrieves a single record from the database based on a specific condition.
490///
491/// # Deprecated
492/// This function has been renamed to `fetch`. Please use `fetch` instead.
493///
494/// ## Parameters
495/// - `conn`: SQLite database connection
496/// - `entity`: Query parameter object (must implement SqlQuery, FromRow, and SqlParams traits)
497///
498/// ## Return Value
499/// - `Result<T, Error>`: On success, returns the queried record; on failure, returns Error
500#[deprecated(
501    since = "0.3.7",
502    note = "Renamed to `fetch`. Please use `fetch` function instead."
503)]
504pub fn get<T: SqlQuery<T> + SqlParams, R>(
505    conn: &rusqlite::Connection,
506    entity: &T,
507) -> Result<R, Error>
508where
509    T: SqlQuery<R> + SqlParams,
510    R: FromRow,
511{
512    fetch(conn, entity)
513}
514
515/// # get_all
516///
517/// Retrieves multiple records from the database based on a specific condition.
518///
519/// # Deprecated
520/// This function has been renamed to `fetch_all`. Please use `fetch_all` instead.
521///
522/// ## Parameters
523/// - `conn`: SQLite database connection
524/// - `entity`: Query parameter object (must implement SqlQuery, FromRow, and SqlParams traits)
525///
526/// ## Return Value
527/// - `Result<Vec<T>, Error>`: On success, returns a vector of records; on failure, returns Error
528#[deprecated(
529    since = "0.3.7",
530    note = "Renamed to `fetch_all`. Please use `fetch_all` function instead."
531)]
532pub fn get_all<T: SqlQuery<T> + SqlParams, R>(
533    conn: &rusqlite::Connection,
534    entity: &T,
535) -> Result<Vec<R>, Error>
536where
537    T: SqlQuery<R> + SqlParams,
538    R: FromRow,
539{
540    fetch_all(conn, entity)
541}
542
543/// # select
544///
545/// Executes a custom SELECT query and maps the result to a model using a provided mapping function.
546///
547/// ## Parameters
548/// - `conn`: SQLite database connection
549/// - `entity`: Query parameter object (must implement SqlQuery and SqlParams traits)
550/// - `to_model`: Function to map a database row to your model type
551///
552/// ## Return Value
553/// - `Result<T, Error>`: On success, returns the mapped model; on failure, returns Error
554///
555/// ## Example Usage
556///
557/// ```rust,no_run
558/// use rusqlite::{Connection, Result, Row};
559/// use parsql_macros::{Queryable, SqlParams};
560/// use parsql_sqlite::select;
561///
562/// fn main() -> Result<()> {
563///     // Create database connection
564///     let conn = Connection::open("test.db")?;
565///     conn.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)", [])?;
566///     conn.execute("INSERT INTO users (id, name, email) VALUES (1, 'John', 'john@example.com')", [])?;
567///
568///     // Define your model
569///     #[derive(Debug)]
570///     pub struct User {
571///         pub id: i64,
572///         pub name: String,
573///         pub email: String,
574///     }
575///
576///     // Define a query
577///     #[derive(Queryable, SqlParams)]
578///     #[table("users")]
579///     #[where_clause("id = ?")]
580///     pub struct GetUser {
581///         pub id: i64,
582///     }
583///
584///     // Create query parameters
585///     let get_query = GetUser { id: 1 };
586///
587///     // Define row mapping function
588///     let to_user = |row: &Row| -> Result<User> {
589///         Ok(User {
590///             id: row.get(0)?,
591///             name: row.get(1)?,
592///             email: row.get(2)?,
593///         })
594///     };
595///
596///     // Execute query with custom mapping
597///     let user = select(&conn, &get_query, to_user)?;
598///     println!("User: {:?}", user);
599///     Ok(())
600/// }
601/// ```
602pub fn select<T: SqlQuery<T> + SqlParams, F, R>(
603    conn: &rusqlite::Connection,
604    entity: &T,
605    to_model: F,
606) -> Result<R, Error>
607where
608    F: Fn(&Row) -> Result<R, Error>,
609{
610    conn.select(entity, to_model)
611}
612
613/// # select_all
614///
615/// Executes a custom SELECT query and maps multiple results to models using a provided mapping function.
616///
617/// ## Parameters
618/// - `conn`: SQLite database connection
619/// - `entity`: Query parameter object (must implement SqlQuery and SqlParams traits)
620/// - `to_model`: Function to map a database row to your model type
621///
622/// ## Return Value
623/// - `Result<Vec<T>, Error>`: On success, returns a vector of mapped models; on failure, returns Error
624///
625/// ## Example Usage
626///
627/// ```rust,no_run
628/// use rusqlite::{Connection, Result, Row};
629/// use parsql_macros::{Queryable, SqlParams};
630/// use parsql_sqlite::select_all;
631///
632/// fn main() -> Result<()> {
633///     // Create database connection
634///     let conn = Connection::open("test.db")?;
635///     conn.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT, state INTEGER)", [])?;
636///     conn.execute("INSERT INTO users (name, email, state) VALUES ('John', 'john@example.com', 1)", [])?;
637///     conn.execute("INSERT INTO users (name, email, state) VALUES ('Jane', 'jane@example.com', 1)", [])?;
638///
639///     // Define your model
640///     #[derive(Debug)]
641///     pub struct User {
642///         pub id: i64,
643///         pub name: String,
644///         pub email: String,
645///         pub state: i16,
646///     }
647///
648///     // Define a query
649///     #[derive(Queryable, SqlParams)]
650///     #[table("users")]
651///     #[where_clause("state = ?")]
652///     pub struct GetActiveUsers {
653///         pub state: i16,
654///     }
655///
656///     // Create query parameters
657///     let get_query = GetActiveUsers { state: 1 };
658///
659///     // Define row mapping function
660///     let to_user = |row: &Row| -> Result<User> {
661///         Ok(User {
662///             id: row.get(0)?,
663///             name: row.get(1)?,
664///             email: row.get(2)?,
665///             state: row.get(3)?,
666///         })
667///     };
668///
669///     // Execute query with custom mapping
670///     let users = select_all(&conn, &get_query, to_user)?;
671///     println!("Active users: {:?}", users);
672///     Ok(())
673/// }
674/// ```
675pub fn select_all<T: SqlQuery<T> + SqlParams, F, R>(
676    conn: &rusqlite::Connection,
677    entity: &T,
678    to_model: F,
679) -> Result<Vec<R>, Error>
680where
681    F: Fn(&Row) -> Result<R, Error>,
682{
683    conn.select_all(entity, to_model)
684}