burncloud-database-impl 0.1.0

Database implementations for multiple backends (PostgreSQL, MySQL, SQLite, MongoDB) for BurnCloud
Documentation
#[cfg(feature = "postgres")]
use sqlx::{PgPool, Row, Column};
use burncloud_database_core::{
    DatabaseConnection, QueryExecutor,
    TransactionManager, Transaction, QueryContext, QueryOptions, QueryResult, QueryParam
};
use burncloud_database_core::error::{DatabaseResult, DatabaseError};
use async_trait::async_trait;
use std::collections::HashMap;

#[cfg(feature = "postgres")]
pub struct PostgresConnection {
    pool: Option<PgPool>,
    connection_string: String,
}

#[cfg(feature = "postgres")]
impl PostgresConnection {
    pub fn new(connection_string: String) -> Self {
        Self {
            pool: None,
            connection_string,
        }
    }
}

#[cfg(feature = "postgres")]
#[async_trait]
impl DatabaseConnection for PostgresConnection {
    async fn connect(&mut self) -> DatabaseResult<()> {
        let pool = PgPool::connect(&self.connection_string)
            .await
            .map_err(|e| DatabaseError::ConnectionFailed(e.to_string()))?;

        self.pool = Some(pool);
        Ok(())
    }

    async fn disconnect(&mut self) -> DatabaseResult<()> {
        if let Some(pool) = self.pool.take() {
            pool.close().await;
        }
        Ok(())
    }

    async fn is_connected(&self) -> bool {
        self.pool.is_some()
    }

    async fn ping(&self) -> DatabaseResult<()> {
        if let Some(pool) = &self.pool {
            sqlx::query("SELECT 1")
                .execute(pool)
                .await
                .map_err(|e| DatabaseError::QueryFailed(e.to_string()))?;
            Ok(())
        } else {
            Err(DatabaseError::ConnectionFailed("Not connected".to_string()))
        }
    }
}

#[cfg(feature = "postgres")]
#[async_trait]
impl QueryExecutor for PostgresConnection {
    async fn execute_query(
        &self,
        query: &str,
        _params: &[&dyn QueryParam],
        _context: &QueryContext,
    ) -> DatabaseResult<QueryResult> {
        if let Some(pool) = &self.pool {
            let rows = sqlx::query(query)
                .fetch_all(pool)
                .await
                .map_err(|e| DatabaseError::QueryFailed(e.to_string()))?;

            let mut result_rows = Vec::new();
            for row in rows {
                let mut row_map = HashMap::new();
                for (i, column) in row.columns().iter().enumerate() {
                    let value: serde_json::Value = row.try_get(i)
                        .unwrap_or(serde_json::Value::Null);
                    row_map.insert(column.name().to_string(), value);
                }
                result_rows.push(row_map);
            }

            Ok(QueryResult {
                rows: result_rows,
                rows_affected: 0,
                last_insert_id: None,
            })
        } else {
            Err(DatabaseError::ConnectionFailed("Not connected".to_string()))
        }
    }

    async fn execute_query_with_options(
        &self,
        query: &str,
        params: &[&dyn QueryParam],
        _options: &QueryOptions,
        context: &QueryContext,
    ) -> DatabaseResult<QueryResult> {
        self.execute_query(query, params, context).await
    }
}

#[cfg(feature = "postgres")]
pub struct PostgresTransaction {
    // Simplified for example
}

#[cfg(feature = "postgres")]
#[async_trait]
impl Transaction for PostgresTransaction {
    async fn commit(self) -> DatabaseResult<()> {
        Ok(())
    }

    async fn rollback(self) -> DatabaseResult<()> {
        Ok(())
    }

    async fn execute_query(
        &self,
        _query: &str,
        _params: &[&dyn QueryParam],
    ) -> DatabaseResult<QueryResult> {
        Ok(QueryResult {
            rows: Vec::new(),
            rows_affected: 0,
            last_insert_id: None,
        })
    }
}

#[cfg(feature = "postgres")]
#[async_trait]
impl TransactionManager for PostgresConnection {
    type Transaction = PostgresTransaction;

    async fn begin_transaction(&self, _context: &QueryContext) -> DatabaseResult<Self::Transaction> {
        Ok(PostgresTransaction {})
    }
}