Skip to main content

sabi/
data_acc.rs

1// Copyright (C) 2024-2026 Takayuki Sato. All Rights Reserved.
2// This program is free software under MIT License.
3// See the file LICENSE in this distribution for more details.
4
5use crate::{DataAcc, DataConn, DataHub};
6
7impl DataAcc for DataHub {
8    fn get_data_conn<C: DataConn + 'static>(&mut self, name: &str) -> errs::Result<&mut C> {
9        DataHub::get_data_conn(self, name)
10    }
11}
12
13#[cfg(test)]
14mod tests_of_data_acc {
15    use super::*;
16    use crate::{AsyncGroup, DataSrc};
17    use std::cell::RefCell;
18    use std::rc::Rc;
19    use std::sync::{Arc, Mutex};
20
21    struct FooDataConn {
22        id: i8,
23        text: String,
24        committed: bool,
25        logger: Arc<Mutex<Vec<String>>>,
26    }
27
28    impl FooDataConn {
29        fn new(id: i8, s: &str, logger: Arc<Mutex<Vec<String>>>) -> Self {
30            {
31                let mut logger = logger.lock().unwrap();
32                logger.push(format!("FooDataConn::new {}", id));
33            }
34            Self {
35                id,
36                text: s.to_string(),
37                logger,
38                committed: false,
39            }
40        }
41        fn get_text(&self) -> String {
42            let mut logger = self.logger.lock().unwrap();
43            logger.push(format!("FooDataConn::get_text {}", self.id));
44            self.text.clone()
45        }
46    }
47    impl Drop for FooDataConn {
48        fn drop(&mut self) {
49            let mut logger = self.logger.lock().unwrap();
50            logger.push(format!("FooDataConn::drop {}", self.id));
51        }
52    }
53    impl DataConn for FooDataConn {
54        fn commit(&mut self, _ag: &mut AsyncGroup) -> errs::Result<()> {
55            self.committed = true;
56            let mut logger = self.logger.lock().unwrap();
57            logger.push(format!("FooDataConn::commit {}", self.id));
58            Ok(())
59        }
60        fn pre_commit(&mut self, _ag: &mut AsyncGroup) -> errs::Result<()> {
61            let mut logger = self.logger.lock().unwrap();
62            logger.push(format!("FooDataConn::pre_commit {}", self.id));
63            Ok(())
64        }
65        fn post_commit(&mut self, _ag: &mut AsyncGroup) {
66            let mut logger = self.logger.lock().unwrap();
67            logger.push(format!("FooDataConn::post_commit {}", self.id));
68        }
69        fn should_force_back(&self) -> bool {
70            self.committed
71        }
72        fn rollback(&mut self, _ag: &mut AsyncGroup) {
73            let mut logger = self.logger.lock().unwrap();
74            logger.push(format!("FooDataConn::rollback {}", self.id));
75        }
76        fn force_back(&mut self, _ag: &mut AsyncGroup) {
77            let mut logger = self.logger.lock().unwrap();
78            logger.push(format!("FooDataConn::force_back {}", self.id));
79        }
80        fn close(&mut self) {
81            let mut logger = self.logger.lock().unwrap();
82            logger.push(format!("FooDataConn::close {}", self.id));
83        }
84    }
85
86    struct FooDataSrc {
87        id: i8,
88        logger: Arc<Mutex<Vec<String>>>,
89        fail: bool,
90        text: String,
91    }
92    impl FooDataSrc {
93        fn new(id: i8, s: &str, logger: Arc<Mutex<Vec<String>>>, fail: bool) -> Self {
94            {
95                let mut logger = logger.lock().unwrap();
96                logger.push(format!("FooDataSrc::new {}", id));
97            }
98            Self {
99                id,
100                logger,
101                fail,
102                text: s.to_string(),
103            }
104        }
105    }
106    impl Drop for FooDataSrc {
107        fn drop(&mut self) {
108            let mut logger = self.logger.lock().unwrap();
109            logger.push(format!("FooDataSrc::drop {}", self.id));
110        }
111    }
112    impl DataSrc<FooDataConn> for FooDataSrc {
113        fn setup(&mut self, _ag: &mut AsyncGroup) -> errs::Result<()> {
114            if self.fail {
115                {
116                    let mut logger = self.logger.lock().unwrap();
117                    logger.push(format!("FooDataSrc::setup {} failed", self.id));
118                }
119                return Err(errs::Err::new("XXX".to_string()));
120            }
121            {
122                let mut logger = self.logger.lock().unwrap();
123                logger.push(format!("FooDataSrc::setup {}", self.id));
124            }
125            Ok(())
126        }
127        fn close(&mut self) {
128            let mut logger = self.logger.lock().unwrap();
129            logger.push(format!("FooDataSrc::close {}", self.id));
130        }
131        fn create_data_conn(&mut self) -> errs::Result<Box<FooDataConn>> {
132            {
133                let mut logger = self.logger.lock().unwrap();
134                logger.push(format!("FooDataSrc::create_data_src {}", self.id));
135            }
136            let conn = FooDataConn::new(self.id, &self.text, self.logger.clone());
137            Ok(Box::new(conn))
138        }
139    }
140
141    struct BarDataConn {
142        id: i8,
143        text: Option<String>,
144        ds_text: Rc<RefCell<String>>,
145        committed: bool,
146        logger: Arc<Mutex<Vec<String>>>,
147    }
148    impl BarDataConn {
149        fn new(id: i8, ds_text: Rc<RefCell<String>>, logger: Arc<Mutex<Vec<String>>>) -> Self {
150            {
151                let mut logger = logger.lock().unwrap();
152                logger.push(format!("BarDataConn::new {}", id));
153            }
154            Self {
155                id,
156                text: None,
157                ds_text,
158                logger,
159                committed: false,
160            }
161        }
162        fn set_text(&mut self, s: &str) {
163            let mut logger = self.logger.lock().unwrap();
164            logger.push(format!("BarDataConn::set_text {}", self.id));
165            self.text = Some(s.to_string());
166        }
167    }
168    impl Drop for BarDataConn {
169        fn drop(&mut self) {
170            let mut logger = self.logger.lock().unwrap();
171            logger.push(format!("BarDataConn::drop {}", self.id));
172        }
173    }
174    impl DataConn for BarDataConn {
175        fn commit(&mut self, _ag: &mut AsyncGroup) -> errs::Result<()> {
176            self.committed = true;
177            match &self.text {
178                Some(s) => {
179                    *self.ds_text.borrow_mut() = s.to_string();
180                }
181                None => {
182                    *self.ds_text.borrow_mut() = "".to_string();
183                }
184            }
185            self.logger
186                .lock()
187                .unwrap()
188                .push(format!("BarDataConn::commit {}", self.id));
189            Ok(())
190        }
191        fn pre_commit(&mut self, _ag: &mut AsyncGroup) -> errs::Result<()> {
192            let mut logger = self.logger.lock().unwrap();
193            logger.push(format!("BarDataConn::pre_commit {}", self.id));
194            Ok(())
195        }
196        fn post_commit(&mut self, _ag: &mut AsyncGroup) {
197            let mut logger = self.logger.lock().unwrap();
198            logger.push(format!("BarDataConn::post_commit {}", self.id));
199        }
200        fn should_force_back(&self) -> bool {
201            self.committed
202        }
203        fn rollback(&mut self, _ag: &mut AsyncGroup) {
204            let mut logger = self.logger.lock().unwrap();
205            logger.push(format!("BarDataConn::rollback {}", self.id));
206        }
207        fn force_back(&mut self, _ag: &mut AsyncGroup) {
208            let mut logger = self.logger.lock().unwrap();
209            logger.push(format!("BarDataConn::force_back {}", self.id));
210        }
211        fn close(&mut self) {
212            let mut logger = self.logger.lock().unwrap();
213            logger.push(format!("BarDataConn.text = {}", self.text.clone().unwrap()));
214            logger.push(format!("BarDataConn::close {}", self.id));
215        }
216    }
217
218    struct BarDataSrc {
219        id: i8,
220        text: Rc<RefCell<String>>,
221        logger: Arc<Mutex<Vec<String>>>,
222    }
223    impl BarDataSrc {
224        fn new(id: i8, logger: Arc<Mutex<Vec<String>>>) -> Self {
225            {
226                let mut logger = logger.lock().unwrap();
227                logger.push(format!("BarDataSrc::new {}", id));
228            }
229            Self {
230                id,
231                text: Rc::new(RefCell::new(String::new())),
232                logger,
233            }
234        }
235    }
236    impl Drop for BarDataSrc {
237        fn drop(&mut self) {
238            let mut logger = self.logger.lock().unwrap();
239            logger.push(format!("BarDataSrc::drop {}", self.id));
240        }
241    }
242    impl DataSrc<BarDataConn> for BarDataSrc {
243        fn setup(&mut self, _ag: &mut AsyncGroup) -> errs::Result<()> {
244            let mut logger = self.logger.lock().unwrap();
245            logger.push(format!("BarDataSrc::setup {}", self.id));
246            Ok(())
247        }
248        fn close(&mut self) {
249            let mut logger = self.logger.lock().unwrap();
250            logger.push(format!("BarDataSrc.text = {}", self.text.borrow()));
251            logger.push(format!("BarDataSrc::close {}", self.id));
252        }
253        fn create_data_conn(&mut self) -> errs::Result<Box<BarDataConn>> {
254            {
255                let mut logger = self.logger.lock().unwrap();
256                logger.push(format!("BarDataSrc::create_data_src {}", self.id));
257            }
258            let conn = BarDataConn::new(self.id, self.text.clone(), self.logger.clone());
259            Ok(Box::new(conn))
260        }
261    }
262
263    mod test_run_method {
264        use super::*;
265        use override_macro::{overridable, override_with};
266
267        #[overridable(mod = test_run_method)]
268        trait SampleData {
269            fn get_value(&mut self) -> errs::Result<String>;
270            fn set_value(&mut self, v: &str) -> errs::Result<()>;
271        }
272
273        fn sample_logic(data: &mut impl SampleData) -> errs::Result<()> {
274            let v = data.get_value()?;
275            let _ = data.set_value(&v);
276            let v = data.get_value()?;
277            let _ = data.set_value(&v);
278            Ok(())
279        }
280
281        #[overridable(mod = test_run_method)]
282        trait FooDataAcc: DataAcc {
283            fn get_value(&mut self) -> errs::Result<String> {
284                let conn = self.get_data_conn::<FooDataConn>("foo")?;
285                Ok(conn.get_text())
286            }
287        }
288
289        impl FooDataAcc for DataHub {}
290
291        #[overridable(mod = test_run_method)]
292        trait BarDataAcc: DataAcc {
293            fn set_value(&mut self, text: &str) -> errs::Result<()> {
294                let conn = self.get_data_conn::<BarDataConn>("bar")?;
295                conn.set_text(text);
296                Ok(())
297            }
298        }
299
300        impl BarDataAcc for DataHub {}
301
302        #[override_with(test_run_method::FooDataAcc, test_run_method::BarDataAcc)]
303        impl SampleData for DataHub {}
304
305        #[test]
306        fn test() {
307            let logger = Arc::new(Mutex::new(Vec::new()));
308
309            {
310                let mut data = DataHub::new();
311
312                data.uses("foo", FooDataSrc::new(1, "hello", logger.clone(), false));
313                data.uses("bar", BarDataSrc::new(2, logger.clone()));
314
315                if let Err(_) = data.run(sample_logic) {
316                    panic!();
317                }
318            }
319
320            assert_eq!(
321                *logger.lock().unwrap(),
322                vec![
323                    "FooDataSrc::new 1",
324                    "BarDataSrc::new 2",
325                    "FooDataSrc::setup 1",
326                    "BarDataSrc::setup 2",
327                    "FooDataSrc::create_data_src 1",
328                    "FooDataConn::new 1",
329                    "FooDataConn::get_text 1",
330                    "BarDataSrc::create_data_src 2",
331                    "BarDataConn::new 2",
332                    "BarDataConn::set_text 2",
333                    "FooDataConn::get_text 1",
334                    "BarDataConn::set_text 2",
335                    "FooDataConn::close 1",
336                    "FooDataConn::drop 1",
337                    "BarDataConn.text = hello",
338                    "BarDataConn::close 2",
339                    "BarDataConn::drop 2",
340                    "BarDataSrc.text = ", // because not committed
341                    "BarDataSrc::close 2",
342                    "BarDataSrc::drop 2",
343                    "FooDataSrc::close 1",
344                    "FooDataSrc::drop 1",
345                ],
346            );
347        }
348    }
349
350    mod test_txn_method {
351        use super::*;
352        use override_macro::{overridable, override_with};
353
354        #[overridable(mod = test_txn_method)]
355        trait SampleData {
356            fn get_value(&mut self) -> errs::Result<String>;
357            fn set_value(&mut self, v: &str) -> errs::Result<()>;
358        }
359
360        fn sample_logic(data: &mut impl SampleData) -> errs::Result<()> {
361            let v = data.get_value()?;
362            let _ = data.set_value(&v);
363            let v = data.get_value()?;
364            let _ = data.set_value(&v);
365            Ok(())
366        }
367
368        #[overridable(mod = test_txn_method)]
369        trait FooDataAcc: DataAcc {
370            fn get_value(&mut self) -> errs::Result<String> {
371                let conn = self.get_data_conn::<FooDataConn>("foo")?;
372                Ok(conn.get_text())
373            }
374        }
375
376        impl FooDataAcc for DataHub {}
377
378        #[overridable(mod = test_txn_method)]
379        trait BarDataAcc: DataAcc {
380            fn set_value(&mut self, text: &str) -> errs::Result<()> {
381                let conn = self.get_data_conn::<BarDataConn>("bar")?;
382                conn.set_text(text);
383                Ok(())
384            }
385        }
386
387        impl BarDataAcc for DataHub {}
388
389        #[override_with(test_txn_method::FooDataAcc, test_txn_method::BarDataAcc)]
390        impl test_txn_method::SampleData for DataHub {}
391
392        #[test]
393        fn test() {
394            let logger = Arc::new(Mutex::new(Vec::new()));
395
396            {
397                let mut data = DataHub::new();
398
399                data.uses("foo", FooDataSrc::new(1, "hello", logger.clone(), false));
400                data.uses("bar", BarDataSrc::new(2, logger.clone()));
401
402                if let Err(_) = data.txn(sample_logic) {
403                    panic!();
404                }
405            }
406
407            assert_eq!(
408                *logger.lock().unwrap(),
409                vec![
410                    "FooDataSrc::new 1",
411                    "BarDataSrc::new 2",
412                    "FooDataSrc::setup 1",
413                    "BarDataSrc::setup 2",
414                    "FooDataSrc::create_data_src 1",
415                    "FooDataConn::new 1",
416                    "FooDataConn::get_text 1",
417                    "BarDataSrc::create_data_src 2",
418                    "BarDataConn::new 2",
419                    "BarDataConn::set_text 2",
420                    "FooDataConn::get_text 1",
421                    "BarDataConn::set_text 2",
422                    "FooDataConn::pre_commit 1",
423                    "BarDataConn::pre_commit 2",
424                    "FooDataConn::commit 1",
425                    "BarDataConn::commit 2",
426                    "FooDataConn::post_commit 1",
427                    "BarDataConn::post_commit 2",
428                    "FooDataConn::close 1",
429                    "FooDataConn::drop 1",
430                    "BarDataConn.text = hello",
431                    "BarDataConn::close 2",
432                    "BarDataConn::drop 2",
433                    "BarDataSrc.text = hello", // because committed
434                    "BarDataSrc::close 2",
435                    "BarDataSrc::drop 2",
436                    "FooDataSrc::close 1",
437                    "FooDataSrc::drop 1",
438                ],
439            );
440        }
441    }
442}