1use crate::storage::{StorageError, StorageKey, StoragePrefix, StorageProvider};
60use serde_json::Value;
61use std::collections::HashMap;
62use std::sync::Arc;
63use tokio::sync::RwLock;
64
65#[derive(Clone)]
72pub struct InMemoryStorage {
73 data: Arc<RwLock<HashMap<String, HashMap<String, HashMap<String, Value>>>>>,
75}
76
77impl InMemoryStorage {
78 pub fn new() -> Self {
80 Self {
81 data: Arc::new(RwLock::new(HashMap::new())),
82 }
83 }
84
85 pub async fn stats(&self) -> InMemoryStorageStats {
87 let data_guard = self.data.read().await;
88 let mut tenant_count = 0;
89 let mut resource_type_count = 0;
90 let mut total_resources = 0;
91
92 for (_, tenant_data) in data_guard.iter() {
93 tenant_count += 1;
94 for (_, type_data) in tenant_data.iter() {
95 resource_type_count += 1;
96 total_resources += type_data.len();
97 }
98 }
99
100 InMemoryStorageStats {
101 tenant_count,
102 resource_type_count,
103 total_resources,
104 }
105 }
106
107 pub async fn clear(&self) {
109 let mut data_guard = self.data.write().await;
110 data_guard.clear();
111 }
112
113 pub async fn list_tenants(&self) -> Vec<String> {
115 let data_guard = self.data.read().await;
116 data_guard.keys().cloned().collect()
117 }
118
119 pub async fn list_resource_types(&self, tenant_id: &str) -> Vec<String> {
121 let data_guard = self.data.read().await;
122 data_guard
123 .get(tenant_id)
124 .map(|tenant_data| tenant_data.keys().cloned().collect())
125 .unwrap_or_default()
126 }
127
128 fn extract_attribute_value(data: &Value, attribute_path: &str) -> Option<String> {
130 let parts: Vec<&str> = attribute_path.split('.').collect();
131 let mut current = data;
132
133 for part in parts {
134 if let Ok(index) = part.parse::<usize>() {
135 current = current.get(index)?;
137 } else {
138 current = current.get(part)?;
140 }
141 }
142
143 match current {
145 Value::String(s) => Some(s.clone()),
146 Value::Number(n) => Some(n.to_string()),
147 Value::Bool(b) => Some(b.to_string()),
148 _ => current.as_str().map(|s| s.to_string()),
149 }
150 }
151}
152
153impl Default for InMemoryStorage {
154 fn default() -> Self {
155 Self::new()
156 }
157}
158
159impl StorageProvider for InMemoryStorage {
160 type Error = StorageError;
161
162 async fn put(&self, key: StorageKey, data: Value) -> Result<Value, Self::Error> {
163 let mut data_guard = self.data.write().await;
164
165 let tenant_data = data_guard
167 .entry(key.tenant_id().to_string())
168 .or_insert_with(HashMap::new);
169
170 let type_data = tenant_data
171 .entry(key.resource_type().to_string())
172 .or_insert_with(HashMap::new);
173
174 type_data.insert(key.resource_id().to_string(), data.clone());
176
177 Ok(data)
179 }
180
181 async fn get(&self, key: StorageKey) -> Result<Option<Value>, Self::Error> {
182 let data_guard = self.data.read().await;
183
184 let result = data_guard
185 .get(key.tenant_id())
186 .and_then(|tenant_data| tenant_data.get(key.resource_type()))
187 .and_then(|type_data| type_data.get(key.resource_id()))
188 .cloned();
189
190 Ok(result)
191 }
192
193 async fn delete(&self, key: StorageKey) -> Result<bool, Self::Error> {
194 let mut data_guard = self.data.write().await;
195
196 let existed = if let Some(tenant_data) = data_guard.get_mut(key.tenant_id()) {
197 if let Some(type_data) = tenant_data.get_mut(key.resource_type()) {
198 type_data.remove(key.resource_id()).is_some()
199 } else {
200 false
201 }
202 } else {
203 false
204 };
205
206 Ok(existed)
207 }
208
209 async fn list(
210 &self,
211 prefix: StoragePrefix,
212 offset: usize,
213 limit: usize,
214 ) -> Result<Vec<(StorageKey, Value)>, Self::Error> {
215 if limit == 0 {
216 return Ok(Vec::new());
217 }
218
219 let data_guard = self.data.read().await;
220
221 let type_data = match data_guard
222 .get(prefix.tenant_id())
223 .and_then(|tenant_data| tenant_data.get(prefix.resource_type()))
224 {
225 Some(data) => data,
226 None => return Ok(Vec::new()),
227 };
228
229 let mut keys: Vec<_> = type_data.keys().collect();
231 keys.sort();
232
233 let results: Vec<(StorageKey, Value)> = keys
235 .into_iter()
236 .skip(offset)
237 .take(limit)
238 .filter_map(|resource_id| {
239 type_data.get(resource_id).map(|data| {
240 (
241 StorageKey::new(prefix.tenant_id(), prefix.resource_type(), resource_id),
242 data.clone(),
243 )
244 })
245 })
246 .collect();
247
248 Ok(results)
249 }
250
251 async fn find_by_attribute(
252 &self,
253 prefix: StoragePrefix,
254 attribute: &str,
255 value: &str,
256 ) -> Result<Vec<(StorageKey, Value)>, Self::Error> {
257 let data_guard = self.data.read().await;
258
259 let type_data = match data_guard
260 .get(prefix.tenant_id())
261 .and_then(|tenant_data| tenant_data.get(prefix.resource_type()))
262 {
263 Some(data) => data,
264 None => return Ok(Vec::new()),
265 };
266
267 let mut results = Vec::new();
268
269 for (resource_id, resource_data) in type_data {
270 if let Some(attr_value) = Self::extract_attribute_value(resource_data, attribute) {
271 if attr_value == value {
272 results.push((
273 StorageKey::new(prefix.tenant_id(), prefix.resource_type(), resource_id),
274 resource_data.clone(),
275 ));
276 }
277 }
278 }
279
280 results.sort_by(|a, b| a.0.resource_id().cmp(b.0.resource_id()));
282
283 Ok(results)
284 }
285
286 async fn exists(&self, key: StorageKey) -> Result<bool, Self::Error> {
287 let data_guard = self.data.read().await;
288
289 let exists = data_guard
290 .get(key.tenant_id())
291 .and_then(|tenant_data| tenant_data.get(key.resource_type()))
292 .and_then(|type_data| type_data.get(key.resource_id()))
293 .is_some();
294
295 Ok(exists)
296 }
297
298 async fn count(&self, prefix: StoragePrefix) -> Result<usize, Self::Error> {
299 let data_guard = self.data.read().await;
300
301 let count = data_guard
302 .get(prefix.tenant_id())
303 .and_then(|tenant_data| tenant_data.get(prefix.resource_type()))
304 .map(|type_data| type_data.len())
305 .unwrap_or(0);
306
307 Ok(count)
308 }
309}
310
311#[derive(Debug, Clone, PartialEq, Eq)]
313pub struct InMemoryStorageStats {
314 pub tenant_count: usize,
316 pub resource_type_count: usize,
318 pub total_resources: usize,
320}
321
322#[cfg(test)]
323mod tests {
324 use super::*;
325 use serde_json::json;
326
327 #[tokio::test]
328 async fn test_put_and_get() {
329 let storage = InMemoryStorage::new();
330 let key = StorageKey::new("tenant1", "User", "123");
331 let data = json!({"id": "123", "name": "test"});
332
333 let stored = storage.put(key.clone(), data.clone()).await.unwrap();
335 assert_eq!(stored, data);
336
337 let retrieved = storage.get(key).await.unwrap();
339 assert_eq!(retrieved, Some(data));
340 }
341
342 #[tokio::test]
343 async fn test_get_nonexistent() {
344 let storage = InMemoryStorage::new();
345 let key = StorageKey::new("tenant1", "User", "999");
346
347 let result = storage.get(key).await.unwrap();
348 assert!(result.is_none());
349 }
350
351 #[tokio::test]
352 async fn test_delete() {
353 let storage = InMemoryStorage::new();
354 let key = StorageKey::new("tenant1", "User", "123");
355 let data = json!({"id": "123", "name": "test"});
356
357 storage.put(key.clone(), data).await.unwrap();
359
360 let deleted = storage.delete(key.clone()).await.unwrap();
362 assert!(deleted);
363
364 let retrieved = storage.get(key.clone()).await.unwrap();
366 assert!(retrieved.is_none());
367
368 let deleted_again = storage.delete(key).await.unwrap();
370 assert!(!deleted_again);
371 }
372
373 #[tokio::test]
374 async fn test_exists() {
375 let storage = InMemoryStorage::new();
376 let key = StorageKey::new("tenant1", "User", "123");
377 let data = json!({"id": "123", "name": "test"});
378
379 assert!(!storage.exists(key.clone()).await.unwrap());
381
382 storage.put(key.clone(), data).await.unwrap();
384
385 assert!(storage.exists(key.clone()).await.unwrap());
387
388 storage.delete(key.clone()).await.unwrap();
390
391 assert!(!storage.exists(key).await.unwrap());
393 }
394
395 #[tokio::test]
396 async fn test_list_with_pagination() {
397 let storage = InMemoryStorage::new();
398 let prefix = StorageKey::prefix("tenant1", "User");
399
400 for i in 1..=5 {
402 let key = StorageKey::new("tenant1", "User", &format!("{}", i));
403 let data = json!({"id": i, "name": format!("user{}", i)});
404 storage.put(key, data).await.unwrap();
405 }
406
407 let page1 = storage.list(prefix.clone(), 0, 2).await.unwrap();
409 assert_eq!(page1.len(), 2);
410 assert_eq!(page1[0].0.resource_id(), "1");
411 assert_eq!(page1[1].0.resource_id(), "2");
412
413 let page2 = storage.list(prefix.clone(), 2, 2).await.unwrap();
414 assert_eq!(page2.len(), 2);
415 assert_eq!(page2[0].0.resource_id(), "3");
416 assert_eq!(page2[1].0.resource_id(), "4");
417
418 let page3 = storage.list(prefix, 4, 2).await.unwrap();
419 assert_eq!(page3.len(), 1);
420 assert_eq!(page3[0].0.resource_id(), "5");
421 }
422
423 #[tokio::test]
424 async fn test_find_by_attribute() {
425 let storage = InMemoryStorage::new();
426 let prefix = StorageKey::prefix("tenant1", "User");
427
428 let user1 = json!({
430 "id": "1",
431 "userName": "john.doe",
432 "emails": [{"value": "john@example.com", "primary": true}]
433 });
434 let user2 = json!({
435 "id": "2",
436 "userName": "jane.doe",
437 "emails": [{"value": "jane@example.com", "primary": true}]
438 });
439
440 storage
441 .put(StorageKey::new("tenant1", "User", "1"), user1)
442 .await
443 .unwrap();
444 storage
445 .put(StorageKey::new("tenant1", "User", "2"), user2)
446 .await
447 .unwrap();
448
449 let found = storage
451 .find_by_attribute(prefix.clone(), "userName", "john.doe")
452 .await
453 .unwrap();
454 assert_eq!(found.len(), 1);
455 assert_eq!(found[0].0.resource_id(), "1");
456
457 let found = storage
459 .find_by_attribute(prefix.clone(), "emails.0.value", "jane@example.com")
460 .await
461 .unwrap();
462 assert_eq!(found.len(), 1);
463 assert_eq!(found[0].0.resource_id(), "2");
464
465 let found = storage
467 .find_by_attribute(prefix, "userName", "nonexistent")
468 .await
469 .unwrap();
470 assert_eq!(found.len(), 0);
471 }
472
473 #[tokio::test]
474 async fn test_count() {
475 let storage = InMemoryStorage::new();
476 let prefix = StorageKey::prefix("tenant1", "User");
477
478 assert_eq!(storage.count(prefix.clone()).await.unwrap(), 0);
480
481 for i in 1..=3 {
483 let key = StorageKey::new("tenant1", "User", &format!("{}", i));
484 let data = json!({"id": i});
485 storage.put(key, data).await.unwrap();
486 }
487
488 assert_eq!(storage.count(prefix).await.unwrap(), 3);
489 }
490
491 #[tokio::test]
492 async fn test_tenant_isolation() {
493 let storage = InMemoryStorage::new();
494
495 let key1 = StorageKey::new("tenant1", "User", "123");
497 let key2 = StorageKey::new("tenant2", "User", "123");
498 let data1 = json!({"tenant": "1"});
499 let data2 = json!({"tenant": "2"});
500
501 storage.put(key1.clone(), data1.clone()).await.unwrap();
502 storage.put(key2.clone(), data2.clone()).await.unwrap();
503
504 assert_eq!(storage.get(key1).await.unwrap(), Some(data1));
506 assert_eq!(storage.get(key2).await.unwrap(), Some(data2));
507
508 assert_eq!(
510 storage
511 .count(StorageKey::prefix("tenant1", "User"))
512 .await
513 .unwrap(),
514 1
515 );
516 assert_eq!(
517 storage
518 .count(StorageKey::prefix("tenant2", "User"))
519 .await
520 .unwrap(),
521 1
522 );
523 }
524
525 #[tokio::test]
526 async fn test_stats() {
527 let storage = InMemoryStorage::new();
528
529 let stats = storage.stats().await;
531 assert_eq!(stats.tenant_count, 0);
532 assert_eq!(stats.resource_type_count, 0);
533 assert_eq!(stats.total_resources, 0);
534
535 storage
537 .put(StorageKey::new("tenant1", "User", "1"), json!({"id": "1"}))
538 .await
539 .unwrap();
540 storage
541 .put(StorageKey::new("tenant1", "User", "2"), json!({"id": "2"}))
542 .await
543 .unwrap();
544 storage
545 .put(StorageKey::new("tenant1", "Group", "1"), json!({"id": "1"}))
546 .await
547 .unwrap();
548 storage
549 .put(StorageKey::new("tenant2", "User", "1"), json!({"id": "1"}))
550 .await
551 .unwrap();
552
553 let stats = storage.stats().await;
554 assert_eq!(stats.tenant_count, 2);
555 assert_eq!(stats.resource_type_count, 3); assert_eq!(stats.total_resources, 4);
557 }
558
559 #[tokio::test]
560 async fn test_clear() {
561 let storage = InMemoryStorage::new();
562
563 storage
565 .put(StorageKey::new("tenant1", "User", "1"), json!({"id": "1"}))
566 .await
567 .unwrap();
568
569 assert_eq!(
571 storage
572 .count(StorageKey::prefix("tenant1", "User"))
573 .await
574 .unwrap(),
575 1
576 );
577
578 storage.clear().await;
580
581 assert_eq!(
583 storage
584 .count(StorageKey::prefix("tenant1", "User"))
585 .await
586 .unwrap(),
587 0
588 );
589 let stats = storage.stats().await;
590 assert_eq!(stats.total_resources, 0);
591 }
592
593 #[tokio::test]
594 async fn test_list_tenants_and_resource_types() {
595 let storage = InMemoryStorage::new();
596
597 storage
599 .put(StorageKey::new("tenant1", "User", "1"), json!({"id": "1"}))
600 .await
601 .unwrap();
602 storage
603 .put(StorageKey::new("tenant1", "Group", "1"), json!({"id": "1"}))
604 .await
605 .unwrap();
606 storage
607 .put(StorageKey::new("tenant2", "User", "1"), json!({"id": "1"}))
608 .await
609 .unwrap();
610
611 let mut tenants = storage.list_tenants().await;
613 tenants.sort();
614 assert_eq!(tenants, vec!["tenant1", "tenant2"]);
615
616 let mut types1 = storage.list_resource_types("tenant1").await;
618 types1.sort();
619 assert_eq!(types1, vec!["Group", "User"]);
620
621 let types2 = storage.list_resource_types("tenant2").await;
622 assert_eq!(types2, vec!["User"]);
623
624 let types_none = storage.list_resource_types("nonexistent").await;
626 assert!(types_none.is_empty());
627 }
628
629 #[tokio::test]
630 async fn test_extract_attribute_value() {
631 let data = json!({
632 "userName": "john.doe",
633 "emails": [
634 {"value": "john@example.com", "primary": true},
635 {"value": "john.doe@work.com", "primary": false}
636 ],
637 "address": {
638 "street": "123 Main St",
639 "city": "Anytown"
640 }
641 });
642
643 assert_eq!(
645 InMemoryStorage::extract_attribute_value(&data, "userName"),
646 Some("john.doe".to_string())
647 );
648
649 assert_eq!(
651 InMemoryStorage::extract_attribute_value(&data, "address.city"),
652 Some("Anytown".to_string())
653 );
654
655 assert_eq!(
657 InMemoryStorage::extract_attribute_value(&data, "emails.0.value"),
658 Some("john@example.com".to_string())
659 );
660
661 assert_eq!(
663 InMemoryStorage::extract_attribute_value(&data, "emails.0.primary"),
664 Some("true".to_string())
665 );
666
667 assert_eq!(
669 InMemoryStorage::extract_attribute_value(&data, "nonexistent"),
670 None
671 );
672
673 assert_eq!(
675 InMemoryStorage::extract_attribute_value(&data, "emails.99.value"),
676 None
677 );
678 }
679}