//! sqlite 工具包
//! 
//! 使用示例见单元测试
//!
//! 使用navicat可以创建sqlite数据库文件，以及查看表数据情况
//! 
//! 方式一： 结构体使用派生宏，自动进行代码扩写
//! ```rust
//! // 注意：这里需引入了两个FromSqliteRow，一个用于注解，一个用于扩写后的代码使用
//! use mitoo::sqlite_util::{FromSqliteRow, SqliteClient};
//! use from_sqlite_row_macro::FromSqliteRow;
//! 
//! // 假设存在一个 users 表，定义对应的结构体
//! #[derive(Debug, FromSqliteRow)]
//! struct User {
//!     id: i64, // 不要使用i32(其没有实现对应的trait)
//!     name: String,
//! }
//! 
//! #[test]
//! fn it_works() {
//!     let client = SqliteClient::new("test.db").expect("Failed to create SqliteUtil");
//!     let user_results = client.query::<User>("SELECT id, name FROM users");
//!     println!("User results: {:?}", user_results);
//!     for item in user_results {
//!         println!("id = {}, name = {}", item.id, item.name);
//!     }
//! }
//! ```
//!
//! 方式二： 结构体自行进行实现FromSqliteRow
//! ```rust
//! use mitoo::sqlite_util::{FromSqliteRow, SqliteClient};
//! 
//! // 假设存在一个 users 表，定义对应的结构体
//! #[derive(Debug)]
//! struct User {
//!     id: i64, // 不要使用i32(其没有实现对应的trait)
//!     name: String,
//! }
//! 
//! // 为 User 结构体实现 FromSqliteRow trait
//! impl FromSqliteRow for User {
//!     fn from_row(row: &sqlite::Row) -> Self {
//!         User {
//!             id: row.read::<i64, _>("id"),
//!             name: row.read::<&str, _>("name").to_string(),
//!         }
//!     }
//! }
//! 
//! #[test]
//! fn it_works() {
//!     let client = SqliteClient::new("test.db").expect("Failed to create SqliteUtil");
//!     let user_results = client.query::<User>("SELECT id, name FROM users");
//!     println!("User results: {:?}", user_results);
//!     for item in user_results {
//!         println!("id = {}, name = {}", item.id, item.name);
//!     }
//! }
//! ```
use sqlite::{Connection, State};

/// 将sqlite::Row转换为指定的类型
pub trait FromSqliteRow {
    fn from_row(row: &sqlite::Row) -> Self;
}

/// SQLite 客户端，用于连接SQLite数据库，可以进行crud操作
pub struct SqliteClient {
    conn: Connection,
}

impl SqliteClient {
    /// 创建一个新的 SQLite 客户端实例
    ///
    /// 该函数会打开指定路径的 SQLite 数据库文件，如果文件不存在则会自动创建
    ///
    /// # 参数
    /// * `db_path` - 数据库文件的路径字符串引用
    ///
    /// # 返回值
    /// * `Ok(SqliteClient)` - 成功创建的 SQLite 客户端实例
    /// * `Err(sqlite::Error)` - 数据库连接过程中发生的错误
    ///
    /// # 示例
    /// ```
    /// let client = SqliteClient::new("database.db");
    /// ```
    pub fn new(db_path: &str) -> Result<Self, sqlite::Error> {
        let conn = Connection::open(db_path)?;
        Ok(SqliteClient { conn })
    }

    /// 执行SQL语句
    ///
    /// 该函数用于执行不返回结果集的SQL语句（如INSERT、UPDATE、DELETE等）。
    /// 如果SQL语句返回了结果集，则会返回错误。
    ///
    /// # 参数
    /// * `sql` - 要执行的SQL语句字符串
    ///
    /// # 返回值
    /// * `Ok(())` - SQL语句执行成功
    /// * `Err(sqlite::Error)` - SQL语句执行失败或返回了结果集
    ///
    /// # 错误
    /// 当SQL语句返回结果集时，会返回ExecuteReturnedResults错误，
    /// 此时应该使用query系列函数来处理
    pub fn execute(&self, sql: &str) -> Result<(), sqlite::Error> {
        // 准备SQL语句
        let mut stmt = self.conn.prepare(sql)?;
        // 执行SQL语句并检查执行状态
        match stmt.next()? {
            State::Done => Ok(()),
            _ => Err(sqlite::Error {
                code: None,
                message: Some("ExecuteReturnedResults, please use query...".to_string()),
            }),
        }
    }

    /// 执行SQL查询并返回结果集
    ///
    /// 该函数用于执行给定的SQL查询语句，并将查询结果转换为指定类型的向量。
    /// 结果类型T必须实现FromSqliteRow trait，以便能够从数据库行中创建实例。
    ///
    /// # 参数
    /// * `sql` - 要执行的SQL查询语句字符串引用
    ///
    /// # 返回值
    /// 返回包含查询结果的Vec<T>，其中T是实现了FromSqliteRow trait的类型
    ///
    /// # 泛型约束
    /// T: FromSqliteRow - 结果类型必须实现从SQLite行数据转换的trait
    pub fn query<T: FromSqliteRow>(&self, sql: &str) -> Vec<T> {
        // 准备SQL语句
        let stmt = self.conn.prepare(sql).unwrap();
        let mut results = Vec::new();
        // 遍历查询结果，将每一行转换为指定类型并添加到结果集中
        for row in stmt.into_iter().map(|row| row.unwrap()) {
            results.push(T::from_row(&row));
        }
        results
    }
}

#[cfg(test)]
mod tests {

    use from_sqlite_row_macro::FromSqliteRow;

    use super::*;

    // 假设存在一个 users 表，定义对应的结构体
    #[derive(Debug, FromSqliteRow)]
    struct User {
        id: i64, // 不要使用i32(其没有实现对应的trait)
        name: String,
    }

    // 为 User 结构体实现 FromSqliteRow trait
    // impl FromSqliteRow for User {
    //     fn from_row(row: &sqlite::Row) -> Self {
    //         User {
    //             id: row.read::<i64, _>("id"),
    //             name: row.read::<&str, _>("name").to_string(),
    //         }
    //     }
    // }

    #[test]
    fn it_works() {
        let util = SqliteClient::new("docs/test.db").expect("Failed to create SqliteUtil");
        let user_results = util.query::<User>("SELECT id, name FROM users");
        println!("User results: {:?}", user_results);
        for item in user_results {
            println!("id = {}, name = {}", item.id, item.name);
        }
    }
}
