use foundation_core::valtron::ThreadedValue;
use super::types::ResourceState;
use crate::core::errors::StorageError;
pub type StateStoreStream<T> = Box<dyn Iterator<Item = ThreadedValue<T, StorageError>> + Send>;
pub trait StateStore: Send + Sync {
fn init(&self) -> Result<(), StorageError>;
fn list(&self) -> Result<StateStoreStream<String>, StorageError>;
fn count(&self) -> Result<StateStoreStream<usize>, StorageError>;
fn get(
&self,
resource_id: &str,
) -> Result<StateStoreStream<Option<ResourceState>>, StorageError>;
fn get_batch(&self, ids: &[&str]) -> Result<StateStoreStream<ResourceState>, StorageError>;
fn all(&self) -> Result<StateStoreStream<ResourceState>, StorageError>;
fn set(
&self,
resource_id: &str,
state: &ResourceState,
) -> Result<StateStoreStream<()>, StorageError>;
fn delete(&self, resource_id: &str) -> Result<StateStoreStream<()>, StorageError>;
fn sync_remote(&self) -> Result<(), StorageError> {
Ok(())
}
fn list_by_prefix(&self, prefix: &str) -> Result<StateStoreStream<String>, StorageError> {
let prefix = prefix.to_string();
let all = self.list()?;
Ok(Box::new(all.filter_map(move |item| match item {
ThreadedValue::Value(Ok(id)) if id.starts_with(&prefix) => {
Some(ThreadedValue::Value(Ok(id)))
}
ThreadedValue::Value(Ok(_)) => None,
ThreadedValue::Value(Err(e)) => Some(ThreadedValue::Value(Err(e))),
ThreadedValue::Waiting => None,
})))
}
fn count_by_prefix(&self, prefix: &str) -> Result<StateStoreStream<usize>, StorageError> {
let prefix = prefix.to_string();
let mut all = self.list()?;
let count = all.try_fold(0usize, |n, item| match item {
ThreadedValue::Value(Ok(id)) if id.starts_with(&prefix) => Ok(n + 1),
ThreadedValue::Value(Ok(_)) => Ok(n),
ThreadedValue::Value(Err(e)) => Err(e),
ThreadedValue::Waiting => Ok(n),
});
Ok(Box::new(std::iter::once(ThreadedValue::Value(count))))
}
fn all_by_prefix(&self, prefix: &str) -> Result<StateStoreStream<ResourceState>, StorageError> {
let prefix = prefix.to_string();
let all = self.all()?;
Ok(Box::new(all.filter_map(move |item| match item {
ThreadedValue::Value(Ok(state)) if state.id.starts_with(&prefix) => {
Some(ThreadedValue::Value(Ok(state)))
}
ThreadedValue::Value(Ok(_)) => None,
ThreadedValue::Value(Err(e)) => Some(ThreadedValue::Value(Err(e))),
ThreadedValue::Waiting => None,
})))
}
fn find_by_kind(&self, kind: &str) -> Result<StateStoreStream<ResourceState>, StorageError> {
let kind = kind.to_string();
let all = self.all()?;
Ok(Box::new(all.filter_map(move |item| match item {
ThreadedValue::Value(Ok(state)) if state.kind == kind => {
Some(ThreadedValue::Value(Ok(state)))
}
ThreadedValue::Value(Ok(_)) => None,
ThreadedValue::Value(Err(e)) => Some(ThreadedValue::Value(Err(e))),
ThreadedValue::Waiting => None,
})))
}
fn find_by_status(
&self,
status: &str,
) -> Result<StateStoreStream<ResourceState>, StorageError> {
let status = status.to_string();
let all = self.all()?;
Ok(Box::new(all.filter_map(move |item| match item {
ThreadedValue::Value(Ok(state)) => {
let status_str = state.status.to_string();
if status_str == status {
Some(ThreadedValue::Value(Ok(state)))
} else {
None
}
}
ThreadedValue::Value(Err(e)) => Some(ThreadedValue::Value(Err(e))),
ThreadedValue::Waiting => None,
})))
}
fn find_by_provider(
&self,
provider: &str,
) -> Result<StateStoreStream<ResourceState>, StorageError> {
let provider = provider.to_string();
let all = self.all()?;
Ok(Box::new(all.filter_map(move |item| match item {
ThreadedValue::Value(Ok(state)) if state.provider == provider => {
Some(ThreadedValue::Value(Ok(state)))
}
ThreadedValue::Value(Ok(_)) => None,
ThreadedValue::Value(Err(e)) => Some(ThreadedValue::Value(Err(e))),
ThreadedValue::Waiting => None,
})))
}
fn delete_by_prefix(&self, prefix: &str) -> Result<StateStoreStream<usize>, StorageError> {
let ids: Vec<String> = self
.list_by_prefix(prefix)?
.filter_map(|item| match item {
ThreadedValue::Value(Ok(id)) => Some(Ok(id)),
ThreadedValue::Value(Err(e)) => Some(Err(e)),
ThreadedValue::Waiting => None,
})
.collect::<Result<Vec<_>, _>>()?;
let mut count = 0;
for id in &ids {
let stream = self.delete(id)?;
for item in stream {
if let ThreadedValue::Value(Err(e)) = item {
return Err(e);
}
}
count += 1;
}
Ok(Box::new(std::iter::once(ThreadedValue::Value(Ok(count)))))
}
}