1use async_trait::async_trait;
2use origin_domain::Result;
3use serde::{Deserialize, Serialize};
4use std::fmt::Debug;
5use time::OffsetDateTime;
6
7#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
10pub struct StorageKey {
11 namespace: String,
12 key: String,
13}
14
15impl StorageKey {
16 pub fn new(namespace: impl Into<String>, key: impl Into<String>) -> Self {
17 Self {
18 namespace: namespace.into(),
19 key: key.into(),
20 }
21 }
22
23 pub fn namespace(&self) -> &str {
24 &self.namespace
25 }
26
27 pub fn key(&self) -> &str {
28 &self.key
29 }
30}
31
32#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
34pub struct Record {
35 pub value: String,
36 #[serde(with = "time::serde::rfc3339")]
37 pub stored_at: OffsetDateTime,
38 #[serde(with = "time::serde::rfc3339::option")]
39 pub expires_at: Option<OffsetDateTime>,
40}
41
42impl Record {
43 pub fn new(value: impl Into<String>, stored_at: OffsetDateTime) -> Self {
44 Self {
45 value: value.into(),
46 stored_at,
47 expires_at: None,
48 }
49 }
50
51 pub fn expiring_at(mut self, expires_at: OffsetDateTime) -> Self {
52 self.expires_at = Some(expires_at);
53 self
54 }
55
56 pub fn is_expired_at(&self, now: OffsetDateTime) -> bool {
58 self.expires_at.is_some_and(|expires_at| now >= expires_at)
59 }
60}
61
62#[async_trait]
64pub trait Storage: Debug + Send + Sync + 'static {
65 async fn get(&self, key: &StorageKey) -> Result<Option<Record>>;
68
69 async fn put(&self, key: &StorageKey, record: Record) -> Result<()>;
70
71 async fn delete(&self, key: &StorageKey) -> Result<()>;
73
74 async fn keys(&self, namespace: &str) -> Result<Vec<StorageKey>>;
76
77 async fn clear(&self, namespace: &str) -> Result<()>;
79
80 async fn clear_prefix(&self, prefix: &str) -> Result<usize>;
86}