use crate::migration::AppliedStep;
use crate::migration::set::MigrationSet;
use crate::store::error::StorageResult;
use crate::store::meta::{PrefixMeta, SchemaSnapshot};
use crate::store::{CodecFormat, StoreCallback, SubscriptionId};
use crate::{MigrationReport, Store, SubscriptionKind};
use serde::{Serialize, de::DeserializeOwned};
use std::sync::Arc;
use uuid::Uuid;
pub trait MigrationBackendAdapter {
fn format(&self) -> CodecFormat;
fn get(&self, key: &str) -> StorageResult<Option<Vec<u8>>>;
fn set(&mut self, key: &str, value: &[u8]) -> StorageResult<()>;
fn delete(&mut self, key: &str) -> StorageResult<()>;
fn scan_prefix(&self, prefix: &str) -> StorageResult<Vec<(String, Vec<u8>)>>;
fn get_meta(&self, prefix: &str) -> StorageResult<Option<PrefixMeta>>;
fn set_meta(&mut self, prefix: &str, meta: &PrefixMeta) -> StorageResult<()>;
fn get_schema_snapshot(&self, prefix: &str) -> StorageResult<Option<SchemaSnapshot>>;
fn set_schema_snapshot(&mut self, prefix: &str, snapshot: &SchemaSnapshot)
-> StorageResult<()>;
fn get_migration_log(&self, prefix: &str) -> StorageResult<Option<Vec<AppliedStep>>>;
fn set_migration_log(&mut self, prefix: &str, log: &[AppliedStep]) -> StorageResult<()>;
}
pub trait SchemaAwareStore: StoreBackend {
fn run_migrations(&self, mset: MigrationSet) -> StorageResult<MigrationReport>;
}
pub trait StoreBackend: Send + Sync + 'static {
fn get_raw(&self, path: &str) -> StorageResult<Option<Vec<u8>>>;
fn set_erased(
&self,
path: &str,
value: &dyn erased_serde::Serialize,
source: Option<Uuid>,
) -> StorageResult<()>;
fn set_owned_erased(
&self,
path: Arc<str>,
value: &dyn erased_serde::Serialize,
source: Option<Uuid>,
) -> StorageResult<()>;
fn get_erased(
&self,
path: &str,
f: &mut dyn FnMut(&mut dyn erased_serde::Deserializer) -> StorageResult<()>,
) -> StorageResult<bool>;
fn decode_erased(
&self,
bytes: &[u8],
f: &mut dyn FnMut(&mut dyn erased_serde::Deserializer) -> StorageResult<()>,
) -> StorageResult<()>;
fn delete_with_source(&self, path: &str, source: Option<Uuid>) -> StorageResult<()>;
fn delete(&self, path: &str) -> StorageResult<()>;
fn delete_prefix_with_source(&self, prefix: &str, source: Option<Uuid>) -> StorageResult<()>;
fn delete_prefix(&self, prefix: &str) -> StorageResult<()> {
self.delete_prefix_with_source(prefix, None)
}
fn scan_prefix(&self, prefix: &str) -> StorageResult<Vec<(String, Vec<u8>)>>;
fn scan_keys(&self, prefix: &str) -> StorageResult<Vec<String>>;
fn save_now(&self) -> StorageResult<()>;
fn subscribe(&self, kind: SubscriptionKind, callback: StoreCallback) -> SubscriptionId;
fn unsubscribe(&self, id: SubscriptionId);
fn flush_prefix(&self, prefix: &str) -> StorageResult<()>;
fn flush_async(&self) -> crate::store::durable::Commit;
fn is_initialized(&self, namespace: &str) -> StorageResult<bool>;
fn mark_initialized(&self, namespace: &str) -> StorageResult<()>;
}
pub trait StoreExt: StoreBackend {
fn get<T: DeserializeOwned>(&self, path: &str) -> StorageResult<Option<T>> {
let mut out = None;
let found = self.get_erased(path, &mut |d| {
out = Some(erased_serde::deserialize::<T>(d).map_err(crate::codec::CodecError::from)?);
Ok(())
})?;
Ok(if found { out } else { None })
}
fn set<T: Serialize>(&self, path: &str, value: &T) -> StorageResult<()> {
self.set_erased(path, &value, None)
}
fn set_owned<T: Serialize>(&self, path: Arc<str>, value: &T) -> StorageResult<()> {
self.set_owned_erased(path, &value, None)
}
fn set_with_source<T: Serialize>(
&self,
path: &str,
value: &T,
source: Option<Uuid>,
) -> StorageResult<()> {
self.set_erased(path, &value, source)
}
fn set_owned_with_source<T: Serialize>(
&self,
path: Arc<str>,
value: &T,
source: Option<Uuid>,
) -> StorageResult<()> {
self.set_owned_erased(path, &value, source)
}
fn decode<T: DeserializeOwned + Default>(&self, bytes: &[u8]) -> StorageResult<T> {
let mut out = None;
let res = self.decode_erased(bytes, &mut |d| {
out = Some(erased_serde::deserialize::<T>(d).map_err(crate::codec::CodecError::from)?);
Ok(())
});
match res {
Ok(()) => Ok(out.unwrap_or_default()),
Err(e) => {
tracing::warn!(
target: "amethystate",
"Failed to decode field. Data is corrupted or type changed. Using Default value. Error: {e}"
);
Ok(T::default())
}
}
}
}
impl<S: StoreBackend + ?Sized> StoreExt for S {}
impl Store {
pub fn kv(&self) -> crate::store::Kv {
crate::store::Kv::new(self.clone())
}
}