use std::fmt;
use serde::de::DeserializeOwned;
use serde::ser::Serialize;
use url::Url;
use crate::commons::storage;
use crate::commons::storage::{Backend, Ident, Transaction};
#[derive(Debug)]
pub struct KeyValueStore {
inner: Backend,
}
impl KeyValueStore {
pub fn create(
storage_uri: &Url,
namespace: &Ident,
) -> Result<Self, KeyValueError> {
Ok(Self {
inner: Backend::new(storage_uri, namespace)?.ok_or_else(|| {
KeyValueError::UnknownScheme(storage_uri.scheme().into())
})?
})
}
pub fn is_empty(&self) -> Result<bool, KeyValueError> {
self.inner.is_empty().map_err(KeyValueError::Inner)
}
pub fn wipe(&self) -> Result<(), KeyValueError> {
self.execute(None, |kv| kv.clear())
}
pub fn execute<F, T>(
&self,
scope: Option<&Ident>,
op: F,
) -> Result<T, KeyValueError>
where
F: Fn(&mut Transaction) -> Result<T, storage::Error>,
{
self.inner.execute(scope, op).map_err(KeyValueError::Inner)
}
}
impl KeyValueStore {
pub fn store<V: Serialize>(
&self,
scope: Option<&Ident>,
key: &Ident,
value: &V,
) -> Result<(), KeyValueError> {
self.execute(
scope,
|kv| kv.store(scope, key, value),
)
}
pub fn store_new<V: Serialize>(
&self,
scope: Option<&Ident>,
key: &Ident,
value: &V,
) -> Result<(), KeyValueError> {
self.execute(
scope,
|kv| {
if kv.has(scope, key)? {
Ok(Err(KeyValueError::duplicate_key(scope, key)))
}
else {
kv.store(scope, key, value)?;
Ok(Ok(()))
}
}
)?
}
pub fn get<V: DeserializeOwned>(
&self, scope: Option<&Ident>, key: &Ident,
) -> Result<Option<V>, KeyValueError> {
self.execute(scope, |kv| {
kv.get(scope, key)
})
}
pub fn has(
&self, scope: Option<&Ident>, key: &Ident
) -> Result<bool, KeyValueError> {
self.execute(scope, |kv| kv.has(scope, key))
}
pub fn drop_key(
&self, scope: Option<&Ident>, key: &Ident
) -> Result<(), KeyValueError> {
self.execute(scope, |kv| kv.delete(scope, key))
}
pub fn keys(
&self, scope: Option<&Ident>, contains: &str,
) -> Result<Vec<Box<Ident>>, KeyValueError> {
self.execute(scope, |kv| {
kv.list_keys(scope).map(|mut res| {
res.retain(|item| item.as_str().contains(contains));
res
})
})
}
}
impl KeyValueStore {
pub fn has_scope(
&self, scope: &Ident
) -> Result<bool, KeyValueError> {
self.execute(None, |kv| kv.has_scope(scope))
}
pub fn drop_scope(
&self, scope: &Ident
) -> Result<(), KeyValueError> {
self.execute(None, |kv| kv.delete_scope(scope))
}
pub fn scopes(&self) -> Result<Vec<Box<Ident>>, KeyValueError> {
self.execute(None, |kv| kv.list_scopes())
}
}
impl KeyValueStore {
pub fn create_upgrade_store(
storage_uri: &Url,
namespace: &Ident,
) -> Result<Self, KeyValueError> {
Self::create(
storage_uri,
&Self::prefixed_namespace(
namespace, const { Ident::make("upgrade") }
)
)
}
fn prefixed_namespace(
namespace: &Ident,
prefix: &Ident,
) -> Box<Ident> {
Ident::builder(prefix).push_ident(
const { Ident::make("_") }
).push_ident(
namespace
).finish()
}
pub fn migrate_to_archive(
&mut self,
storage_uri: &Url,
namespace: &Ident,
) -> Result<(), KeyValueError> {
let archive_ns = Self::prefixed_namespace(
namespace, const { Ident::make("archive") }
);
KeyValueStore::create(storage_uri, &archive_ns)?.wipe()?;
self.inner.migrate_namespace(&archive_ns)?;
Ok(())
}
pub fn migrate_to_current(
&mut self,
storage_uri: &Url,
namespace: &Ident,
) -> Result<(), KeyValueError> {
let current_store = KeyValueStore::create(storage_uri, namespace)?;
if !current_store.is_empty()? {
Err(KeyValueError::Other(format!(
"Abort migrate upgraded store for {namespace} to current. The current store was not archived."
)))
} else {
self.inner
.migrate_namespace(namespace)
.map_err(KeyValueError::Inner)
}
}
pub fn import(
&self,
other: &Self,
) -> Result<(), KeyValueError> {
let mut scopes: Vec<_>
= other.scopes()?.into_iter().map(Some).collect();
scopes.push(None);
for scope in scopes {
for key in other.keys(scope.as_deref(), "")? {
if let Some(value)
= other.inner.get_any(scope.as_deref(), &key)?
{
self.inner.store_any(scope.as_deref(), &key, &value)?
}
}
}
Ok(())
}
}
#[derive(Debug)]
pub enum KeyValueError {
UnknownScheme(String),
DuplicateKey(Option<Box<Ident>>, Box<Ident>),
Inner(storage::Error),
Other(String),
}
impl KeyValueError {
fn duplicate_key(scope: Option<&Ident>, key: &Ident) -> Self {
Self::DuplicateKey(scope.map(Into::into), key.into())
}
}
impl From<storage::Error> for KeyValueError {
fn from(e: storage::Error) -> Self {
KeyValueError::Inner(e)
}
}
impl fmt::Display for KeyValueError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
KeyValueError::UnknownScheme(e) => {
write!(f, "Unknown Scheme: {e}")
}
KeyValueError::DuplicateKey(scope, key) => {
match scope {
Some(scope) => {
write!(f, "Duplicate key {key} in scope {scope}")
}
None => {
write!(f, "Duplicate key {key} in global scope")
}
}
}
KeyValueError::Inner(e) => write!(f, "Store error: {e}"),
KeyValueError::Other(msg) => write!(f, "{msg}"),
}
}
}