use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use async_trait::async_trait;
use tokio_postgres::Statement;
use oxisql_core::{OxiSqlError, PreparedStatement, Row, ToSqlValue};
use crate::types::{pg_row_to_row, value_to_param, OwnedParam};
pub(crate) type StmtCache = Arc<Mutex<HashMap<String, Statement>>>;
fn build_owned(params: &[&dyn ToSqlValue]) -> Vec<OwnedParam> {
params
.iter()
.map(|p| value_to_param(&p.to_value()))
.collect()
}
fn owned_refs(owned: &[OwnedParam]) -> Vec<&(dyn tokio_postgres::types::ToSql + Sync)> {
owned.iter().map(|p| p as _).collect()
}
pub struct PgPrepared {
pub(crate) client: Arc<tokio::sync::Mutex<tokio_postgres::Client>>,
pub(crate) stmt: Statement,
pub(crate) sql_text: String,
}
#[async_trait]
impl PreparedStatement for PgPrepared {
async fn execute(&mut self, params: &[&dyn ToSqlValue]) -> Result<u64, OxiSqlError> {
let owned = build_owned(params);
let refs = owned_refs(&owned);
let client = self.client.lock().await;
client
.execute(&self.stmt, refs.as_slice())
.await
.map_err(|e| OxiSqlError::Execution(e.to_string()))
}
async fn query(&mut self, params: &[&dyn ToSqlValue]) -> Result<Vec<Row>, OxiSqlError> {
let owned = build_owned(params);
let refs = owned_refs(&owned);
let client = self.client.lock().await;
let pg_rows = client
.query(&self.stmt, refs.as_slice())
.await
.map_err(|e| OxiSqlError::Execution(e.to_string()))?;
pg_rows
.into_iter()
.map(|r| pg_row_to_row(r).map_err(OxiSqlError::from))
.collect()
}
fn sql(&self) -> &str {
&self.sql_text
}
}