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