104 lines
2.7 KiB
Rust
104 lines
2.7 KiB
Rust
|
use serde::Serialize;
|
||
|
use serde::de::DeserializeOwned;
|
||
|
use sqlx::SqlitePool;
|
||
|
|
||
|
use crate::errors::*;
|
||
|
|
||
|
|
||
|
pub async fn save<T>(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<T>(pool: &SqlitePool, name: &str) -> Result<Option<T>, 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<Option<Vec<u8>>, 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<const N: usize>(
|
||
|
// pool: &SqlitePool,
|
||
|
// names: [&str; N],
|
||
|
// ) -> Result<Option<[Vec<u8>; N]>, sqlx::Error> {
|
||
|
// // just use multiple queries, who cares
|
||
|
// let res: [Vec<u8>; 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<Option<_>>, 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)
|
||
|
// },
|
||
|
// )*
|
||
|
// )
|
||
|
// })()
|
||
|
// }
|
||
|
// }
|