use std::sync::Mutex;
use chrono::Utc;
use rusqlite::{params, Connection};
use serde::Serialize;
use crate::error::StoreError;
use crate::schema;
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct ConfigEntry {
pub key: String,
pub value: String,
}
pub struct SqliteConfigStore {
conn: Mutex<Connection>,
}
impl SqliteConfigStore {
pub fn open(path: &str) -> Result<Self, StoreError> {
let conn = Connection::open(path)?;
schema::init(&conn)?;
Ok(Self {
conn: Mutex::new(conn),
})
}
pub fn open_in_memory() -> Result<Self, StoreError> {
let conn = Connection::open_in_memory()?;
schema::init(&conn)?;
Ok(Self {
conn: Mutex::new(conn),
})
}
pub fn set(&self, key: &str, value: &str) -> Result<ConfigEntry, StoreError> {
let updated_at = Utc::now().to_rfc3339();
let conn = self.conn.lock().unwrap();
conn.execute(
"INSERT INTO gateway_config (key, value, updated_at) VALUES (?1, ?2, ?3)
ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at",
params![key, value, updated_at],
)?;
Ok(ConfigEntry {
key: key.to_string(),
value: value.to_string(),
})
}
pub fn get(&self, key: &str) -> Result<Option<ConfigEntry>, StoreError> {
let conn = self.conn.lock().unwrap();
let mut stmt = conn.prepare("SELECT key, value FROM gateway_config WHERE key = ?1")?;
let mut rows = stmt.query(params![key])?;
if let Some(row) = rows.next()? {
Ok(Some(ConfigEntry {
key: row.get(0)?,
value: row.get(1)?,
}))
} else {
Ok(None)
}
}
pub fn delete(&self, key: &str) -> Result<bool, StoreError> {
let conn = self.conn.lock().unwrap();
let n = conn.execute("DELETE FROM gateway_config WHERE key = ?1", params![key])?;
Ok(n > 0)
}
pub fn list(&self) -> Result<Vec<ConfigEntry>, StoreError> {
let conn = self.conn.lock().unwrap();
let mut stmt = conn.prepare("SELECT key, value FROM gateway_config ORDER BY key")?;
let rows = stmt.query_map([], |row| {
Ok(ConfigEntry {
key: row.get(0)?,
value: row.get(1)?,
})
})?;
rows.collect::<Result<Vec<_>, _>>()
.map_err(StoreError::from)
}
}