use super::queries::AllowedQuery;
use anyhow::{anyhow, Context, Result};
pub struct ReadOnlyPgConn {
client: tokio_postgres::Client,
}
impl ReadOnlyPgConn {
pub async fn connect(conn_str: &str) -> Result<Self> {
let (client, connection) = tokio_postgres::connect(conn_str, tokio_postgres::NoTls)
.await
.with_context(|| "tokio_postgres::connect failed (check conn string + reachability)")?;
tokio::spawn(async move {
if let Err(e) = connection.await {
eprintln!("tokio-postgres connection driver exited: {e}");
}
});
client
.execute("SET default_transaction_read_only = on", &[])
.await
.with_context(|| "failed to set default_transaction_read_only = on")?;
let row = client
.query_one(
"SELECT current_setting('default_transaction_read_only')",
&[],
)
.await
.with_context(|| "failed to verify default_transaction_read_only")?;
let setting: &str = row.get(0);
if setting != "on" {
return Err(anyhow!(
"refusing to proceed: default_transaction_read_only = {:?}, expected \"on\"",
setting
));
}
Ok(Self { client })
}
pub async fn query_allowed(&self, q: AllowedQuery) -> Result<Vec<tokio_postgres::Row>> {
let sql = q.sql();
self.client
.query(sql, &[])
.await
.with_context(|| format!("query_allowed failed for {:?}", q))
}
}