rustauth_core/options/storage.rs
1use std::future::Future;
2use std::pin::Pin;
3
4use crate::error::RustAuthError;
5
6pub type SecondaryStorageFuture<'a, T> =
7 Pin<Box<dyn Future<Output = Result<T, RustAuthError>> + Send + 'a>>;
8
9/// Async key-value storage for plugin data that can live outside the primary database.
10pub trait SecondaryStorage: Send + Sync + 'static {
11 fn get<'a>(&'a self, key: &'a str) -> SecondaryStorageFuture<'a, Option<String>>;
12
13 /// `ttl_seconds == Some(0)` means the value is already expired: implementations
14 /// must remove any existing key and must not store `value` without expiry.
15 fn set<'a>(
16 &'a self,
17 key: &'a str,
18 value: String,
19 ttl_seconds: Option<u64>,
20 ) -> SecondaryStorageFuture<'a, ()>;
21
22 /// Store `value` only when `key` is absent.
23 ///
24 /// Returns `Ok(true)` when the key was created, or `Ok(false)` when it already existed.
25 /// `ttl_seconds == Some(0)` means the value is already expired: implementations must
26 /// not create or delete the key and must return `Ok(false)`.
27 fn set_if_not_exists<'a>(
28 &'a self,
29 key: &'a str,
30 value: String,
31 ttl_seconds: Option<u64>,
32 ) -> SecondaryStorageFuture<'a, bool>;
33
34 fn delete<'a>(&'a self, key: &'a str) -> SecondaryStorageFuture<'a, ()>;
35
36 /// Atomically remove and return the stored value when present.
37 fn take<'a>(&'a self, key: &'a str) -> SecondaryStorageFuture<'a, Option<String>>;
38
39 /// Atomically replace the key only when the currently stored value matches
40 /// `expected`. `expected == None` means the key must be absent.
41 ///
42 /// Implementations must perform the comparison and replacement as a single
43 /// backend operation. A `get` followed by `set` is not sufficient for
44 /// shared or multi-process storage because concurrent writers can lose
45 /// updates between the read and write.
46 ///
47 /// Returns `Ok(true)` when the replacement was applied.
48 fn compare_and_set<'a>(
49 &'a self,
50 key: &'a str,
51 expected: Option<String>,
52 value: String,
53 ttl_seconds: Option<u64>,
54 ) -> SecondaryStorageFuture<'a, bool>;
55
56 /// Atomically delete the key only when the currently stored value matches
57 /// `expected`. `expected == None` means the key must already be absent and
58 /// therefore no deletion is performed.
59 ///
60 /// Implementations must perform the comparison and deletion as a single
61 /// backend operation. A `get` followed by `delete` is not sufficient for
62 /// shared or multi-process storage because concurrent writers can race the
63 /// deletion.
64 fn delete_if_value<'a>(
65 &'a self,
66 key: &'a str,
67 expected: Option<String>,
68 ) -> SecondaryStorageFuture<'a, bool>;
69}