ormer 0.2.8

A minimalist ORM framework that supports SQLite, PostgreSQL, MySQL, and SqlServer
use std::marker::PhantomData;
#[cfg(feature = "sqlite")]
use std::sync::Arc;
#[cfg(feature = "duckdb")]
use std::sync::Arc as DuckDbArc;

/// 统一的流式查询连接持有者
///
/// 该枚举统一管理各后端的数据库连接,确保连接在流式查询结束后正确释放。
/// 使用 RAII 模式管理连接生命周期,避免连接泄漏。
///
/// # 各后端的连接管理策略
///
/// ## SQLite/Turso
///
/// 使用 `Arc<turso::Connection>` 共享所有权。多个流式查询可以共享同一个连接,
/// 当最后一个 Arc 引用被 drop 时,连接会自动释放。
///
/// ## PostgreSQL
///
/// 使用 `bb8::PooledConnection<'a, PostgresConnectionManager>` 借用连接。
/// 连接的生命周期由bb8连接池管理,当PooledConnection被drop时会自动返回连接池。
///
/// ## MySQL
///
/// 使用 `mysql_async::Conn` 拥有连接所有权。当 `StreamConnection` 被 drop 时,
/// 连接会自动返回到连接池。这是 mysql_async 库的内置行为。
///
/// # 示例
///
/// 流式查询完成后,连接会自动释放:
///
/// ```text
/// let mut stream = db.select::<User>().stream().into_iter().await?;
/// while let Some(result) = stream.next().await {
///     let user = result?;
///     // 处理用户数据
/// }
/// // stream 在这里被 drop,连接自动释放
/// ```
pub enum StreamConnection<'a> {
    /// SQLite/Turso 连接 - 使用 Arc 共享所有权
    #[cfg(feature = "sqlite")]
    Sqlite(Arc<turso::Connection>),

    /// DuckDB connection. Queries are materialized by the backend before
    /// entering the async iterator.
    #[cfg(feature = "duckdb")]
    DuckDB(DuckDbArc<super::super::duckdb_backend::duckcompat::Connection>),

    /// PostgreSQL 连接 - 使用Client引用
    #[cfg(feature = "postgresql")]
    PostgreSQL(&'a tokio_postgres::Client),

    /// MySQL 连接 - 拥有连接所有权,Drop 时自动返回连接池
    #[cfg(feature = "mysql")]
    MySQL(mysql_async::Conn),

    /// MSSQL 连接 - 使用Client引用
    #[cfg(feature = "mssql")]
    MSSQL(&'a tiberius::Client<tokio_util::compat::Compat<tokio::net::TcpStream>>),

    #[doc(hidden)]
    __Lifetime(PhantomData<&'a ()>),
}

impl<'a> StreamConnection<'a> {
    #[cfg(feature = "sqlite")]
    pub fn expect_sqlite(&self) -> &Arc<turso::Connection> {
        match self {
            StreamConnection::Sqlite(conn) => conn,
            _ => unreachable!("Expected Sqlite connection"),
        }
    }

    #[cfg(feature = "postgresql")]
    pub fn expect_postgresql(&self) -> &&'a tokio_postgres::Client {
        match self {
            StreamConnection::PostgreSQL(client) => client,
            _ => unreachable!("Expected PostgreSQL connection"),
        }
    }

    #[cfg(feature = "duckdb")]
    pub fn expect_duckdb(
        &self,
    ) -> &DuckDbArc<super::super::duckdb_backend::duckcompat::Connection> {
        match self {
            StreamConnection::DuckDB(conn) => conn,
            _ => unreachable!("Expected DuckDB connection"),
        }
    }
}

impl<'a> Drop for StreamConnection<'a> {
    fn drop(&mut self) {
        match self {
            #[cfg(feature = "sqlite")]
            StreamConnection::Sqlite(_) => {
                // Arc 会在最后一个引用释放时自动清理
                // 不需要显式操作
            }

            #[cfg(feature = "duckdb")]
            StreamConnection::DuckDB(_) => {}

            #[cfg(feature = "postgresql")]
            StreamConnection::PostgreSQL(_) => {
                // bb8::PooledConnection 在 Drop 时会自动返回连接池
                // 不需要显式释放
            }

            #[cfg(feature = "mysql")]
            StreamConnection::MySQL(conn) => {
                // mysql_async::Conn 在 Drop 时会自动返回连接池
                // 显式 drop 确保立即释放
                let _ = conn;
            }

            #[cfg(feature = "mssql")]
            StreamConnection::MSSQL(_) => {
                // tiberius::Client 引用,生命周期结束时自动释放
                // 不需要显式操作
            }

            StreamConnection::__Lifetime(_) => {}
        }
    }
}