use serde::Serialize; use serde::de::DeserializeOwned; use sqlx::SqlitePool; use crate::errors::*; pub async fn save(pool: &SqlitePool, name: &str, value: &T) -> Result<(), sqlx::Error> where T: Serialize { let bytes = serde_json::to_vec(value).unwrap(); save_bytes(pool, name, &bytes).await } pub async fn save_bytes(pool: &SqlitePool, name: &str, bytes: &[u8]) -> Result<(), sqlx::Error> { sqlx::query!( "INSERT INTO kv (name, value) VALUES (?, ?) ON CONFLICT(name) DO UPDATE SET value = excluded.value;", name, bytes, ).execute(pool).await?; Ok(()) } pub async fn load(pool: &SqlitePool, name: &str) -> Result, LoadKvError> where T: DeserializeOwned { let v = load_bytes(pool, name) .await? .map(|bytes| serde_json::from_slice(&bytes)) .transpose()?; Ok(v) } pub async fn load_bytes(pool: &SqlitePool, name: &str) -> Result>, sqlx::Error> { sqlx::query!("SELECT name, value FROM kv WHERE name = ?", name) .map(|row| row.value) .fetch_optional(pool) .await .map(|o| o.flatten()) } // pub async fn load_bytes_multi( // pool: &SqlitePool, // names: [&str; N], // ) -> Result; N]>, sqlx::Error> { // // just use multiple queries, who cares // let res: [Vec; N] = Default::default(); // for (i, name) in names.as_slice().iter().enumerate() { // match load_bytes(pool, name).await? { // Some(bytes) => res[i] = bytes, // None => return Ok(None), // } // } // Ok(res); // } macro_rules! load_bytes_multi { ( $pool:ident, $($name:literal),* ) => { // wrap everything up in an immediately-invoked closure for easy short-circuiting (|| { // a tuple, with one item for each repetition of $name ( // repeat this match block for every name $( // load_bytes returns Result>, the Result is handled by // the ? and we match on the Option match load_bytes(pool, $name)? { Some(v) => v, None => return Ok(None) }, )* ) })() } } // macro_rules! load_multi { // ( // $pool:ident, // $($name:literal),* // ) => { // (|| { // ( // $( // match load(pool, $name)? { // Some(v) => v, // None => return Ok(None) // }, // )* // ) // })() // } // }