pub mod errors;
pub mod in_memory;
pub mod sqlite;
#[cfg(test)]
pub mod tests;
pub use errors::StorageError;
pub use in_memory::InMemoryStorage;
pub use sqlite::SqliteStorage;
use serde_json::Value;
use std::fmt;
use std::future::Future;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StorageStats {
pub tenant_count: usize,
pub resource_type_count: usize,
pub total_resources: usize,
}
#[derive(Debug, Clone)]
pub struct ProviderStats {
pub tenant_count: usize,
pub total_resources: usize,
pub resource_type_count: usize,
pub resource_types: Vec<String>,
}
impl ProviderStats {
pub fn new() -> Self {
Self {
tenant_count: 0,
total_resources: 0,
resource_type_count: 0,
resource_types: Vec::new(),
}
}
pub fn is_empty(&self) -> bool {
self.total_resources == 0
}
}
impl Default for ProviderStats {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct StorageKey {
tenant_id: String,
resource_type: String,
resource_id: String,
}
impl StorageKey {
pub fn new(
tenant_id: impl Into<String>,
resource_type: impl Into<String>,
resource_id: impl Into<String>,
) -> Self {
Self {
tenant_id: tenant_id.into(),
resource_type: resource_type.into(),
resource_id: resource_id.into(),
}
}
pub fn tenant_id(&self) -> &str {
&self.tenant_id
}
pub fn resource_type(&self) -> &str {
&self.resource_type
}
pub fn resource_id(&self) -> &str {
&self.resource_id
}
pub fn prefix(tenant_id: impl Into<String>, resource_type: impl Into<String>) -> StoragePrefix {
StoragePrefix {
tenant_id: tenant_id.into(),
resource_type: resource_type.into(),
}
}
}
impl fmt::Display for StorageKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}/{}/{}",
self.tenant_id, self.resource_type, self.resource_id
)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StoragePrefix {
tenant_id: String,
resource_type: String,
}
impl StoragePrefix {
pub fn tenant_id(&self) -> &str {
&self.tenant_id
}
pub fn resource_type(&self) -> &str {
&self.resource_type
}
}
impl fmt::Display for StoragePrefix {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}/{}", self.tenant_id, self.resource_type)
}
}
pub trait StorageProvider: Send + Sync {
type Error: std::error::Error + Send + Sync + 'static;
fn put(
&self,
key: StorageKey,
data: Value,
) -> impl Future<Output = Result<Value, Self::Error>> + Send;
fn get(
&self,
key: StorageKey,
) -> impl Future<Output = Result<Option<Value>, Self::Error>> + Send;
fn delete(&self, key: StorageKey) -> impl Future<Output = Result<bool, Self::Error>> + Send;
fn list(
&self,
prefix: StoragePrefix,
offset: usize,
limit: usize,
) -> impl Future<Output = Result<Vec<(StorageKey, Value)>, Self::Error>> + Send;
fn find_by_attribute(
&self,
prefix: StoragePrefix,
attribute: &str,
value: &str,
) -> impl Future<Output = Result<Vec<(StorageKey, Value)>, Self::Error>> + Send;
fn exists(&self, key: StorageKey) -> impl Future<Output = Result<bool, Self::Error>> + Send;
fn count(
&self,
prefix: StoragePrefix,
) -> impl Future<Output = Result<usize, Self::Error>> + Send;
fn list_tenants(&self) -> impl Future<Output = Result<Vec<String>, Self::Error>> + Send;
fn list_resource_types(
&self,
tenant_id: &str,
) -> impl Future<Output = Result<Vec<String>, Self::Error>> + Send;
fn list_all_resource_types(
&self,
) -> impl Future<Output = Result<Vec<String>, Self::Error>> + Send;
fn clear(&self) -> impl Future<Output = Result<(), Self::Error>> + Send;
fn stats(&self) -> impl Future<Output = Result<StorageStats, Self::Error>> + Send;
}