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::{PerformRead, ReadAction, Resource, data_layer::DataLayer};
10
11type State =
12 LazyLock<Arc<RwLock<HashMap<TypeId, HashMap<String, Box<dyn Any + Send + Sync + 'static>>>>>>;
13
14static STATE: State = LazyLock::new(Arc::default);
15
16#[derive(Debug)]
17pub struct InMemoryDataLayer {}
18impl InMemoryDataLayer {
19 pub(crate) fn new() -> Self {
20 Self {}
21 }
22
23 pub async fn load_all<R: Resource + 'static>(&self) -> Vec<R> {
30 let state = STATE.clone();
31 let state = state.read().await;
32
33 state
34 .get(&TypeId::of::<R>())
35 .into_iter()
36 .flat_map(|map| map.values())
37 .filter_map(|boxed| boxed.downcast_ref::<R>())
38 .cloned()
39 .collect()
40 }
41}
42
43impl<R: Resource + 'static> DataLayer<R> for InMemoryDataLayer {
44 async fn create(&self, resource: R) -> crate::Result<R> {
45 let state = STATE.clone();
46 let mut state = state.write().await;
47
48 let map = state.entry(TypeId::of::<R>()).or_default();
49 map.insert(
50 resource.primary_key().to_string(),
51 Box::new(resource.clone()),
52 );
53
54 Ok(resource)
55 }
56
57 async fn read(&self, primary_key: &R::PrimaryKey) -> crate::Result<R> {
58 let state = STATE.clone();
59 let state = state.read().await;
60
61 let key = primary_key.to_string();
62
63 state
64 .get(&TypeId::of::<R>())
65 .and_then(|map| map.get(&key))
66 .and_then(|boxed| boxed.downcast_ref::<R>())
67 .cloned()
68 .ok_or_else(|| format!("resource not found for primary key `{key}`").into())
69 }
70
71 async fn update(&self, resource: R) -> crate::Result<()> {
72 let state = STATE.clone();
73 let mut state = state.write().await;
74
75 let key = resource.primary_key().to_string();
76
77 let map = state
78 .get_mut(&TypeId::of::<R>())
79 .ok_or_else(|| format!("resource not found for primary key `{key}`"))?;
80
81 if !map.contains_key(&key) {
82 return Err(format!("resource not found for primary key `{key}`").into());
83 }
84
85 map.insert(key, Box::new(resource.clone()));
86
87 Ok(())
88 }
89
90 async fn destroy(&self, primary_key: &R::PrimaryKey) -> crate::Result<R> {
91 let state = STATE.clone();
92 let mut state = state.write().await;
93
94 let key = primary_key.to_string();
95
96 let map = state
97 .get_mut(&TypeId::of::<R>())
98 .ok_or_else(|| format!("resource not found for primary key `{key}`"))?;
99
100 let boxed = map
101 .remove(&key)
102 .ok_or_else(|| format!("resource not found for primary key `{key}`"))?;
103
104 boxed
105 .downcast::<R>()
106 .map(|r| *r)
107 .map_err(|_| "failed to downcast destroyed resource".into())
108 }
109}
110
111pub trait InMemoryReadAction: ReadAction {
114 fn filter(row: &Self::Output, args: &Self::Arguments) -> bool;
115}
116
117pub trait InMemoryPagedReadAction: ReadAction {
121 fn filter(row: &Self::Output, args: &Self::Arguments) -> bool;
122}
123
124pub trait InMemoryPerformRead: ReadAction {
132 fn execute(
133 all: impl Iterator<Item = Self::Output>,
134 args: &Self::Arguments,
135 ) -> Self::Response;
136}
137
138impl<R, A> PerformRead<A> for InMemoryDataLayer
141where
142 R: Resource + 'static,
143 A: ReadAction<Output = R> + InMemoryPerformRead + 'static,
144{
145 async fn read(&self, args: &A::Arguments) -> crate::Result<A::Response> {
146 let state = STATE.clone();
147 let state = state.read().await;
148
149 let type_map = state.get(&TypeId::of::<R>());
150 let all = type_map
151 .iter()
152 .flat_map(|map| map.values())
153 .filter_map(|boxed| boxed.downcast_ref::<R>())
154 .cloned();
155
156 Ok(A::execute(all, args))
157 }
158}