use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use crate::httpx::client::Client;
use crate::queryx::error;
use crate::queryx::error::Error;
use crate::queryx::query::Query;
use crate::queryx::query_options::QueryOptions;
use crate::queryx::query_respreader::QueryRespReader;
#[derive(Clone, Debug, Default)]
pub struct PreparedStatementCache {
cache: HashMap<String, String>,
}
impl PreparedStatementCache {
pub fn get(&self, statement: &str) -> Option<&String> {
self.cache.get(statement)
}
pub fn put(&mut self, statement: &str, prepared_name: &str) {
self.cache
.insert(statement.to_string(), prepared_name.to_string());
}
}
pub struct PreparedQuery<C: Client> {
pub executor: Query<C>,
pub cache: Arc<Mutex<PreparedStatementCache>>,
}
impl<C: Client> PreparedQuery<C> {
pub async fn prepared_query(&self, opts: &QueryOptions) -> error::Result<QueryRespReader> {
let mut opts = (*opts).clone();
if let Some(ae) = opts.auto_execute {
if ae {
return self.executor.query(&opts).await;
}
}
let statement = if let Some(statement) = opts.statement {
statement
} else {
return Err(Error::new_invalid_argument_error(
"statement must be present if auto_execute is true",
Some("statement".to_string()),
));
};
let cached;
{
let cache = self.cache.lock().unwrap();
cached = cache.get(&statement).cloned();
}
if let Some(cached_statement) = cached {
opts.statement = None;
opts.prepared = Some(cached_statement);
let res = self.executor.query(&opts).await;
if let Ok(reader) = res {
return Ok(reader);
}
};
opts.statement = Some(format!("PREPARE {}", &statement));
opts.auto_execute = Some(true);
let res = self.executor.query(&opts).await?;
let early_metadata = res.early_metadata();
if let Some(prepared) = &early_metadata.prepared {
let mut cache = self.cache.lock().unwrap();
cache.put(&statement, prepared);
drop(cache);
}
Ok(res)
}
}