#[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 {
}
#[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 {})
}
}