use async_trait::async_trait;
use origin_domain::Result;
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
use time::OffsetDateTime;
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
pub struct StorageKey {
namespace: String,
key: String,
}
impl StorageKey {
pub fn new(namespace: impl Into<String>, key: impl Into<String>) -> Self {
Self {
namespace: namespace.into(),
key: key.into(),
}
}
pub fn namespace(&self) -> &str {
&self.namespace
}
pub fn key(&self) -> &str {
&self.key
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Record {
pub value: String,
#[serde(with = "time::serde::rfc3339")]
pub stored_at: OffsetDateTime,
#[serde(with = "time::serde::rfc3339::option")]
pub expires_at: Option<OffsetDateTime>,
}
impl Record {
pub fn new(value: impl Into<String>, stored_at: OffsetDateTime) -> Self {
Self {
value: value.into(),
stored_at,
expires_at: None,
}
}
pub fn expiring_at(mut self, expires_at: OffsetDateTime) -> Self {
self.expires_at = Some(expires_at);
self
}
pub fn is_expired_at(&self, now: OffsetDateTime) -> bool {
self.expires_at.is_some_and(|expires_at| now >= expires_at)
}
}
#[async_trait]
pub trait Storage: Debug + Send + Sync + 'static {
async fn get(&self, key: &StorageKey) -> Result<Option<Record>>;
async fn put(&self, key: &StorageKey, record: Record) -> Result<()>;
async fn delete(&self, key: &StorageKey) -> Result<()>;
async fn keys(&self, namespace: &str) -> Result<Vec<StorageKey>>;
async fn clear(&self, namespace: &str) -> Result<()>;
async fn clear_prefix(&self, prefix: &str) -> Result<usize>;
}