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()) } macro_rules! load_bytes_multi { ( $pool:ident, $($name:literal),* ) => { // wrap everything up in an async block for easy short-circuiting... async { // ...returning a Result... Ok::<_, sqlx::Error>( //containing an Option... Some( // containing a tuple... ( // ...with one item for each repetition of $name $( // load_bytes returns Result>, the Result is handled by // the ? and we match on the Option match crate::kv::load_bytes($pool, $name).await? { Some(v) => v, None => return Ok(None) }, )* ) ) ) } } } pub(crate) use load_bytes_multi; // macro_rules! load_multi { // ( // $pool:ident, // $($name:literal),* // ) => { // (|| { // ( // $( // match load(pool, $name)? { // Some(v) => v, // None => return Ok(None) // }, // )* // ) // })() // } // }