cinderblock_core/data_layer/
in_memory.rs1use std::{
2 any::{Any, TypeId},
3 collections::HashMap,
4 sync::{Arc, LazyLock},
5};
6
7use tokio::sync::RwLock;
8
9use crate::{
10 DestroyError, ListError, PerformRead, PerformReadOne, ReadAction, ReadError, Resource,
11 UpdateError, data_layer::DataLayer,
12};
13
14type State =
15 LazyLock<Arc<RwLock<HashMap<TypeId, HashMap<String, Box<dyn Any + Send + Sync + 'static>>>>>>;
16
17static STATE: State = LazyLock::new(Arc::default);
18
19#[derive(Debug)]
20pub struct InMemoryDataLayer {}
21impl InMemoryDataLayer {
22 pub(crate) fn new() -> Self {
23 Self {}
24 }
25
26 pub async fn load_all<R: Resource + 'static>(&self) -> Vec<R> {
33 let state = STATE.clone();
34 let state = state.read().await;
35
36 state
37 .get(&TypeId::of::<R>())
38 .into_iter()
39 .flat_map(|map| map.values())
40 .filter_map(|boxed| boxed.downcast_ref::<R>())
41 .cloned()
42 .collect()
43 }
44}
45
46impl<R: Resource + 'static> DataLayer<R> for InMemoryDataLayer {
47 async fn create(&self, resource: R) -> Result<R, crate::CreateError> {
48 let state = STATE.clone();
49 let mut state = state.write().await;
50
51 let map = state.entry(TypeId::of::<R>()).or_default();
52 map.insert(
53 resource.primary_key().to_string(),
54 Box::new(resource.clone()),
55 );
56
57 Ok(resource)
58 }
59
60 async fn read(&self, primary_key: &R::PrimaryKey) -> Result<R, crate::ReadError> {
61 let state = STATE.clone();
62 let state = state.read().await;
63
64 let key = primary_key.to_string();
65
66 state
67 .get(&TypeId::of::<R>())
68 .and_then(|map| map.get(&key))
69 .and_then(|boxed| boxed.downcast_ref::<R>())
70 .cloned()
71 .ok_or_else(|| ReadError::NotFound { primary_key: key })
72 }
73
74 async fn update(&self, resource: R) -> Result<(), crate::UpdateError> {
75 let state = STATE.clone();
76 let mut state = state.write().await;
77
78 let key = resource.primary_key().to_string();
79
80 let map = state
81 .get_mut(&TypeId::of::<R>())
82 .ok_or_else(|| UpdateError::NotFound {
83 primary_key: key.clone(),
84 })?;
85
86 if !map.contains_key(&key) {
87 return Err(UpdateError::NotFound { primary_key: key });
88 }
89
90 map.insert(key, Box::new(resource.clone()));
91
92 Ok(())
93 }
94
95 async fn destroy(&self, primary_key: &R::PrimaryKey) -> Result<R, crate::DestroyError> {
96 let state = STATE.clone();
97 let mut state = state.write().await;
98
99 let key = primary_key.to_string();
100
101 let map = state
102 .get_mut(&TypeId::of::<R>())
103 .ok_or_else(|| DestroyError::NotFound {
104 primary_key: key.clone(),
105 })?;
106
107 let boxed = map.remove(&key).ok_or_else(|| DestroyError::NotFound {
108 primary_key: key.clone(),
109 })?;
110
111 boxed
112 .downcast::<R>()
113 .map(|r| *r)
114 .map_err(|_| DestroyError::DataLayer("failed to downcast destroyed resource".into()))
115 }
116}
117
118pub trait InMemoryReadAction: ReadAction {
121 fn filter(row: &Self::Output, args: &Self::Arguments) -> bool;
122}
123
124pub trait InMemoryPagedReadAction: ReadAction {
128 fn filter(row: &Self::Output, args: &Self::Arguments) -> bool;
129}
130
131pub trait InMemoryPerformRead: ReadAction {
139 fn execute(all: impl Iterator<Item = Self::Output>, args: &Self::Arguments) -> Self::Response;
140}
141
142impl<R, A> PerformRead<A> for InMemoryDataLayer
145where
146 R: Resource + 'static,
147 A: ReadAction<Output = R> + InMemoryPerformRead + 'static,
148{
149 async fn read(&self, args: &A::Arguments) -> Result<A::Response, ListError> {
150 let state = STATE.clone();
151 let state = state.read().await;
152
153 let type_map = state.get(&TypeId::of::<R>());
154 let all = type_map
155 .iter()
156 .flat_map(|map| map.values())
157 .filter_map(|boxed| boxed.downcast_ref::<R>())
158 .cloned();
159
160 Ok(A::execute(all, args))
161 }
162}
163
164impl<R, A> PerformReadOne<A> for InMemoryDataLayer
170where
171 R: Resource + 'static,
172 A: ReadAction<Output = R, Arguments = R::PrimaryKey, Response = R> + 'static,
173{
174 async fn read_one(&self, args: &A::Arguments) -> Result<A::Response, ReadError> {
175 <Self as DataLayer<R>>::read(self, args).await
176 }
177}