dev_tool/
sqlite_util.rs

1//! sqlite 工具包
2//! 
3//! 使用示例见单元测试
4//!
5//! 使用navicat可以创建sqlite数据库文件,以及查看表数据情况
6//! 
7//! 方式一: 结构体使用派生宏,自动进行代码扩写
8//! ```rust
9//! // 注意:这里需引入了两个FromSqliteRow,一个用于注解,一个用于扩写后的代码使用
10//! use dev_tool::sqlite_util::{FromSqliteRow, SqliteClient};
11//! use from_sqlite_row_macro::FromSqliteRow;
12//! 
13//! // 假设存在一个 users 表,定义对应的结构体
14//! #[derive(Debug, FromSqliteRow)]
15//! struct User {
16//!     id: i64, // 不要使用i32(其没有实现对应的trait)
17//!     name: String,
18//! }
19//! 
20//! #[test]
21//! fn it_works() {
22//!     let client = SqliteClient::new("test.db").expect("Failed to create SqliteUtil");
23//!     let user_results = client.query::<User>("SELECT id, name FROM users");
24//!     println!("User results: {:?}", user_results);
25//!     for item in user_results {
26//!         println!("id = {}, name = {}", item.id, item.name);
27//!     }
28//! }
29//! ```
30//!
31//! 方式二: 结构体自行进行实现FromSqliteRow
32//! ```rust
33//! use dev_tool::sqlite_util::{FromSqliteRow, SqliteClient};
34//! 
35//! // 假设存在一个 users 表,定义对应的结构体
36//! #[derive(Debug)]
37//! struct User {
38//!     id: i64, // 不要使用i32(其没有实现对应的trait)
39//!     name: String,
40//! }
41//! 
42//! // 为 User 结构体实现 FromSqliteRow trait
43//! impl FromSqliteRow for User {
44//!     fn from_row(row: &sqlite::Row) -> Self {
45//!         User {
46//!             id: row.read::<i64, _>("id"),
47//!             name: row.read::<&str, _>("name").to_string(),
48//!         }
49//!     }
50//! }
51//! 
52//! #[test]
53//! fn it_works() {
54//!     let client = SqliteClient::new("test.db").expect("Failed to create SqliteUtil");
55//!     let user_results = client.query::<User>("SELECT id, name FROM users");
56//!     println!("User results: {:?}", user_results);
57//!     for item in user_results {
58//!         println!("id = {}, name = {}", item.id, item.name);
59//!     }
60//! }
61//! ```
62use sqlite::{Connection, State};
63
64/// 将sqlite::Row转换为指定的类型
65pub trait FromSqliteRow {
66    fn from_row(row: &sqlite::Row) -> Self;
67}
68
69/// SQLite 客户端,用于连接SQLite数据库,可以进行crud操作
70pub struct SqliteClient {
71    conn: Connection,
72}
73
74impl SqliteClient {
75    /// 创建一个新的 SQLite 客户端实例
76    ///
77    /// 该函数会打开指定路径的 SQLite 数据库文件,如果文件不存在则会自动创建
78    ///
79    /// # 参数
80    /// * `db_path` - 数据库文件的路径字符串引用
81    ///
82    /// # 返回值
83    /// * `Ok(SqliteClient)` - 成功创建的 SQLite 客户端实例
84    /// * `Err(sqlite::Error)` - 数据库连接过程中发生的错误
85    ///
86    /// # 示例
87    /// ```
88    /// let client = SqliteClient::new("database.db");
89    /// ```
90    pub fn new(db_path: &str) -> Result<Self, sqlite::Error> {
91        let conn = Connection::open(db_path)?;
92        Ok(SqliteClient { conn })
93    }
94
95    /// 执行SQL语句
96    ///
97    /// 该函数用于执行不返回结果集的SQL语句(如INSERT、UPDATE、DELETE等)。
98    /// 如果SQL语句返回了结果集,则会返回错误。
99    ///
100    /// # 参数
101    /// * `sql` - 要执行的SQL语句字符串
102    ///
103    /// # 返回值
104    /// * `Ok(())` - SQL语句执行成功
105    /// * `Err(sqlite::Error)` - SQL语句执行失败或返回了结果集
106    ///
107    /// # 错误
108    /// 当SQL语句返回结果集时,会返回ExecuteReturnedResults错误,
109    /// 此时应该使用query系列函数来处理
110    pub fn execute(&self, sql: &str) -> Result<(), sqlite::Error> {
111        // 准备SQL语句
112        let mut stmt = self.conn.prepare(sql)?;
113        // 执行SQL语句并检查执行状态
114        match stmt.next()? {
115            State::Done => Ok(()),
116            _ => Err(sqlite::Error {
117                code: None,
118                message: Some("ExecuteReturnedResults, please use query...".to_string()),
119            }),
120        }
121    }
122
123    /// 执行SQL查询并返回结果集
124    ///
125    /// 该函数用于执行给定的SQL查询语句,并将查询结果转换为指定类型的向量。
126    /// 结果类型T必须实现FromSqliteRow trait,以便能够从数据库行中创建实例。
127    ///
128    /// # 参数
129    /// * `sql` - 要执行的SQL查询语句字符串引用
130    ///
131    /// # 返回值
132    /// 返回包含查询结果的Vec<T>,其中T是实现了FromSqliteRow trait的类型
133    ///
134    /// # 泛型约束
135    /// T: FromSqliteRow - 结果类型必须实现从SQLite行数据转换的trait
136    pub fn query<T: FromSqliteRow>(&self, sql: &str) -> Vec<T> {
137        // 准备SQL语句
138        let stmt = self.conn.prepare(sql).unwrap();
139        let mut results = Vec::new();
140        // 遍历查询结果,将每一行转换为指定类型并添加到结果集中
141        for row in stmt.into_iter().map(|row| row.unwrap()) {
142            results.push(T::from_row(&row));
143        }
144        results
145    }
146}
147
148#[cfg(test)]
149mod tests {
150
151    use from_sqlite_row_macro::FromSqliteRow;
152
153    use super::*;
154
155    // 假设存在一个 users 表,定义对应的结构体
156    #[derive(Debug, FromSqliteRow)]
157    struct User {
158        id: i64, // 不要使用i32(其没有实现对应的trait)
159        name: String,
160    }
161
162    // 为 User 结构体实现 FromSqliteRow trait
163    // impl FromSqliteRow for User {
164    //     fn from_row(row: &sqlite::Row) -> Self {
165    //         User {
166    //             id: row.read::<i64, _>("id"),
167    //             name: row.read::<&str, _>("name").to_string(),
168    //         }
169    //     }
170    // }
171
172    #[test]
173    fn it_works() {
174        let util = SqliteClient::new("docs/test.db").expect("Failed to create SqliteUtil");
175        let user_results = util.query::<User>("SELECT id, name FROM users");
176        println!("User results: {:?}", user_results);
177        for item in user_results {
178            println!("id = {}, name = {}", item.id, item.name);
179        }
180    }
181}