1use std::sync::Arc;
4
5use chrono::Utc;
6use serde::{de::DeserializeOwned, Serialize};
7
8use crate::{
9 Capabilities, Codec, CodecExt, Collection, CollectionName, DeleteOptions, Driver, JsonCodec,
10 Key, Namespace, ReadOptions, Result, ScanOptions, StoredValue, ValueMetadata, WriteOptions,
11 YugenDbError,
12};
13
14#[derive(Clone)]
16pub struct Store {
17 driver: Arc<dyn Driver>,
18 codec: Arc<dyn Codec>,
19 namespace: Namespace,
20 default_collection: CollectionName,
21}
22
23impl Store {
24 #[must_use]
26 pub fn builder() -> StoreBuilder {
27 StoreBuilder::default()
28 }
29
30 #[must_use]
32 pub fn from_parts(
33 driver: Arc<dyn Driver>,
34 codec: Arc<dyn Codec>,
35 namespace: Namespace,
36 ) -> Self {
37 Self {
38 driver,
39 codec,
40 namespace,
41 default_collection: CollectionName::default(),
42 }
43 }
44
45 pub async fn initialise(&self) -> Result<()> {
47 self.driver.initialise().await
48 }
49
50 pub async fn finalise(&self) -> Result<()> {
52 self.driver.finalise().await
53 }
54
55 #[must_use]
57 pub fn namespace(&self) -> &Namespace {
58 &self.namespace
59 }
60
61 #[must_use]
63 pub fn capabilities(&self) -> Capabilities {
64 self.driver.capabilities()
65 }
66
67 pub async fn get<T, K>(&self, key: K) -> Result<Option<T>>
69 where
70 T: DeserializeOwned,
71 K: TryInto<Key>,
72 YugenDbError: From<K::Error>,
73 {
74 self.get_from_collection(&self.default_collection, key)
75 .await
76 }
77
78 pub async fn set<T, K>(&self, key: K, value: &T) -> Result<()>
80 where
81 T: Serialize,
82 K: TryInto<Key>,
83 YugenDbError: From<K::Error>,
84 {
85 self.set_in_collection(&self.default_collection, key, value)
86 .await
87 }
88
89 pub async fn delete<K>(&self, key: K) -> Result<bool>
91 where
92 K: TryInto<Key>,
93 YugenDbError: From<K::Error>,
94 {
95 self.delete_from_collection(&self.default_collection, key)
96 .await
97 }
98
99 pub async fn exists<K>(&self, key: K) -> Result<bool>
101 where
102 K: TryInto<Key>,
103 YugenDbError: From<K::Error>,
104 {
105 self.exists_in_collection(&self.default_collection, key)
106 .await
107 }
108
109 pub async fn scan_prefix<T>(&self, prefix: impl Into<String>) -> Result<Vec<(Key, T)>>
111 where
112 T: DeserializeOwned,
113 {
114 self.scan_prefix_in_collection(&self.default_collection, prefix)
115 .await
116 }
117
118 pub fn collection<T, C>(&self, name: C) -> Result<Collection<T>>
120 where
121 C: TryInto<CollectionName>,
122 YugenDbError: From<C::Error>,
123 {
124 let name = name.try_into()?;
125 Ok(Collection::new(self.clone(), name))
126 }
127
128 pub async fn get_from_collection<T, K>(
130 &self,
131 collection: &CollectionName,
132 key: K,
133 ) -> Result<Option<T>>
134 where
135 T: DeserializeOwned,
136 K: TryInto<Key>,
137 YugenDbError: From<K::Error>,
138 {
139 let key = key.try_into()?;
140 let options = ReadOptions::default();
141 let Some(stored) = self
142 .driver
143 .get(&self.namespace, collection, &key, &options)
144 .await?
145 else {
146 return Ok(None);
147 };
148
149 if stored.is_expired() && !options.allow_expired {
150 return Ok(None);
151 }
152
153 self.codec.deserialise(&stored.bytes).map(Some)
154 }
155
156 pub async fn set_in_collection<T, K>(
158 &self,
159 collection: &CollectionName,
160 key: K,
161 value: &T,
162 ) -> Result<()>
163 where
164 T: Serialize,
165 K: TryInto<Key>,
166 YugenDbError: From<K::Error>,
167 {
168 self.set_in_collection_with_options(collection, key, value, WriteOptions::default())
169 .await
170 }
171
172 pub async fn set_in_collection_with_options<T, K>(
174 &self,
175 collection: &CollectionName,
176 key: K,
177 value: &T,
178 options: WriteOptions,
179 ) -> Result<()>
180 where
181 T: Serialize,
182 K: TryInto<Key>,
183 YugenDbError: From<K::Error>,
184 {
185 let key = key.try_into()?;
186 let bytes = self.codec.serialise(value)?;
187 let now = Utc::now();
188 let expires_at = match options.ttl {
189 Some(ttl) => {
190 let ttl = chrono::Duration::from_std(ttl)
191 .map_err(|_| YugenDbError::invalid_value("ttl duration is too large"))?;
192 Some(now + ttl)
193 }
194 None => None,
195 };
196 let metadata = ValueMetadata::new(self.codec.name(), now, expires_at);
197 let stored = StoredValue::new(bytes, metadata);
198 self.driver
199 .set(&self.namespace, collection, &key, stored, &options)
200 .await
201 }
202
203 pub async fn delete_from_collection<K>(
205 &self,
206 collection: &CollectionName,
207 key: K,
208 ) -> Result<bool>
209 where
210 K: TryInto<Key>,
211 YugenDbError: From<K::Error>,
212 {
213 let key = key.try_into()?;
214 self.driver
215 .delete(&self.namespace, collection, &key, &DeleteOptions::default())
216 .await
217 }
218
219 pub async fn exists_in_collection<K>(&self, collection: &CollectionName, key: K) -> Result<bool>
221 where
222 K: TryInto<Key>,
223 YugenDbError: From<K::Error>,
224 {
225 let key = key.try_into()?;
226 self.driver.exists(&self.namespace, collection, &key).await
227 }
228
229 pub async fn scan_prefix_in_collection<T>(
231 &self,
232 collection: &CollectionName,
233 prefix: impl Into<String>,
234 ) -> Result<Vec<(Key, T)>>
235 where
236 T: DeserializeOwned,
237 {
238 let options = ScanOptions {
239 prefix: Some(prefix.into()),
240 ..ScanOptions::default()
241 };
242 let stored_values = self
243 .driver
244 .scan_prefix(&self.namespace, collection, &options)
245 .await?;
246
247 stored_values
248 .into_iter()
249 .filter(|(_, stored)| options.include_expired || !stored.is_expired())
250 .map(|(key, stored)| {
251 self.codec
252 .deserialise(&stored.bytes)
253 .map(|value| (key, value))
254 })
255 .collect()
256 }
257}
258
259#[derive(Clone)]
261pub struct StoreBuilder {
262 driver: Option<Arc<dyn Driver>>,
263 codec: Arc<dyn Codec>,
264 namespace: Namespace,
265}
266
267impl Default for StoreBuilder {
268 fn default() -> Self {
269 Self {
270 driver: None,
271 codec: Arc::new(JsonCodec),
272 namespace: Namespace::default(),
273 }
274 }
275}
276
277impl StoreBuilder {
278 #[must_use]
280 pub fn driver<D>(mut self, driver: D) -> Self
281 where
282 D: Driver + 'static,
283 {
284 self.driver = Some(Arc::new(driver));
285 self
286 }
287
288 #[must_use]
290 pub fn driver_arc(mut self, driver: Arc<dyn Driver>) -> Self {
291 self.driver = Some(driver);
292 self
293 }
294
295 #[must_use]
297 pub fn codec<C>(mut self, codec: C) -> Self
298 where
299 C: Codec + 'static,
300 {
301 self.codec = Arc::new(codec);
302 self
303 }
304
305 pub fn namespace<N>(mut self, namespace: N) -> Result<Self>
307 where
308 N: TryInto<Namespace>,
309 YugenDbError: From<N::Error>,
310 {
311 self.namespace = namespace.try_into()?;
312 Ok(self)
313 }
314
315 pub async fn connect(self) -> Result<Store> {
317 let store = self.build()?;
318 store.initialise().await?;
319 Ok(store)
320 }
321
322 pub fn build(self) -> Result<Store> {
324 let Some(driver) = self.driver else {
325 return Err(YugenDbError::invalid_value("store driver is required"));
326 };
327
328 Ok(Store::from_parts(driver, self.codec, self.namespace))
329 }
330}