use rusqlite::params;
use crate::identifier::validate_identifier;
use crate::{ConfigEasyError, ConfigMenu, SettingRow, SettingsQuery, SettingsStore};
pub struct RusqliteStore<'a> {
conn: &'a rusqlite::Connection,
}
impl<'a> RusqliteStore<'a> {
pub fn new(conn: &'a rusqlite::Connection) -> Self {
Self { conn }
}
}
impl SettingsStore for RusqliteStore<'_> {
fn load_settings(
&self,
query: &SettingsQuery<'_>,
) -> Result<Vec<SettingRow>, Box<dyn std::error::Error + Send + Sync>> {
validate_query(query)?;
let sql = format!(
"SELECT {}, {} FROM {} ORDER BY {}",
query.key_column, query.value_column, query.table, query.order_by
);
let mut statement = self.conn.prepare(&sql)?;
let rows = statement.query_map([], |row| {
Ok(SettingRow {
key: row.get(0)?,
value: row.get(1)?,
})
})?;
Ok(rows.collect::<Result<Vec<_>, _>>()?)
}
fn update_setting(
&self,
query: &SettingsQuery<'_>,
key: &str,
value: &str,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
validate_query(query)?;
let sql = format!(
"UPDATE {} SET {} = ?1 WHERE {} = ?2",
query.table, query.value_column, query.key_column
);
self.conn.execute(&sql, params![value, key])?;
Ok(())
}
}
pub fn builder<'a>(conn: &'a rusqlite::Connection) -> ConfigMenu<'a, RusqliteStore<'a>> {
crate::builder(RusqliteStore::new(conn))
}
pub fn run(conn: &rusqlite::Connection) -> Result<(), ConfigEasyError> {
builder(conn).run()
}
fn validate_query(query: &SettingsQuery<'_>) -> Result<(), ConfigEasyError> {
validate_identifier(query.table)?;
validate_identifier(query.key_column)?;
validate_identifier(query.value_column)?;
validate_identifier(query.order_by)?;
Ok(())
}
#[cfg(test)]
mod tests;