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_attr(coverage_nightly, coverage(off))]
14#[cfg(test)]
15mod tests_of_data_acc {
16    use super::*;
17    use crate::{AsyncGroup, DataSrc, TxnFailureReport};
18    use std::cell::RefCell;
19    use std::rc::Rc;
20    use std::sync::{Arc, Mutex};
21
22    struct FooDataConn {
23        id: i8,
24        text: String,
25        committed: bool,
26        logger: Arc<Mutex<Vec<String>>>,
27    }
28
29    impl FooDataConn {
30        fn new(id: i8, s: &str, logger: Arc<Mutex<Vec<String>>>) -> Self {
31            {
32                let mut logger = logger.lock().unwrap();
33                logger.push(format!("FooDataConn::new {}", id));
34            }
35            Self {
36                id,
37                text: s.to_string(),
38                logger,
39                committed: false,
40            }
41        }
42        fn get_text(&self) -> String {
43            let mut logger = self.logger.lock().unwrap();
44            logger.push(format!("FooDataConn::get_text {}", self.id));
45            self.text.clone()
46        }
47    }
48    impl Drop for FooDataConn {
49        fn drop(&mut self) {
50            let mut logger = self.logger.lock().unwrap();
51            logger.push(format!("FooDataConn::drop {}", self.id));
52        }
53    }
54    impl DataConn for FooDataConn {
55        fn commit(&mut self, _ag: &mut AsyncGroup) -> errs::Result<()> {
56            self.committed = true;
57            let mut logger = self.logger.lock().unwrap();
58            logger.push(format!("FooDataConn::commit {}", self.id));
59            Ok(())
60        }
61        fn pre_commit(&mut self, _ag: &mut AsyncGroup) -> errs::Result<()> {
62            let mut logger = self.logger.lock().unwrap();
63            logger.push(format!("FooDataConn::pre_commit {}", self.id));
64            Ok(())
65        }
66        fn post_commit(&mut self, _ag: &mut AsyncGroup) -> errs::Result<()> {
67            let mut logger = self.logger.lock().unwrap();
68            logger.push(format!("FooDataConn::post_commit {}", self.id));
69            Ok(())
70        }
71        fn is_committed(&self) -> bool {
72            self.committed
73        }
74        fn rollback(&mut self, _ag: &mut AsyncGroup) -> errs::Result<()> {
75            let mut logger = self.logger.lock().unwrap();
76            logger.push(format!("FooDataConn::rollback {}", self.id));
77            Ok(())
78        }
79        fn on_txn_failure(&mut self, _ag: &mut AsyncGroup, _reports: &[TxnFailureReport]) {
80            let mut logger = self.logger.lock().unwrap();
81            logger.push(format!("FooDataConn::on_txn_failure {}", 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) -> errs::Result<()> {
200            let mut logger = self.logger.lock().unwrap();
201            logger.push(format!("BarDataConn::post_commit {}", self.id));
202            Ok(())
203        }
204        fn is_committed(&self) -> bool {
205            self.committed
206        }
207        fn rollback(&mut self, _ag: &mut AsyncGroup) -> errs::Result<()> {
208            let mut logger = self.logger.lock().unwrap();
209            logger.push(format!("BarDataConn::rollback {}", self.id));
210            Ok(())
211        }
212        fn on_txn_failure(&mut self, _ag: &mut AsyncGroup, _reports: &[TxnFailureReport]) {
213            let mut logger = self.logger.lock().unwrap();
214            logger.push(format!("BarDataConn::on_txn_failure {}", self.id));
215        }
216        fn close(&mut self) {
217            let mut logger = self.logger.lock().unwrap();
218            logger.push(format!("BarDataConn.text = {}", self.text.clone().unwrap()));
219            logger.push(format!("BarDataConn::close {}", self.id));
220        }
221    }
222
223    struct BarDataSrc {
224        id: i8,
225        text: Rc<RefCell<String>>,
226        logger: Arc<Mutex<Vec<String>>>,
227    }
228    impl BarDataSrc {
229        fn new(id: i8, logger: Arc<Mutex<Vec<String>>>) -> Self {
230            {
231                let mut logger = logger.lock().unwrap();
232                logger.push(format!("BarDataSrc::new {}", id));
233            }
234            Self {
235                id,
236                text: Rc::new(RefCell::new(String::new())),
237                logger,
238            }
239        }
240    }
241    impl Drop for BarDataSrc {
242        fn drop(&mut self) {
243            let mut logger = self.logger.lock().unwrap();
244            logger.push(format!("BarDataSrc::drop {}", self.id));
245        }
246    }
247    impl DataSrc<BarDataConn> for BarDataSrc {
248        fn setup(&mut self, _ag: &mut AsyncGroup) -> errs::Result<()> {
249            let mut logger = self.logger.lock().unwrap();
250            logger.push(format!("BarDataSrc::setup {}", self.id));
251            Ok(())
252        }
253        fn close(&mut self) {
254            let mut logger = self.logger.lock().unwrap();
255            logger.push(format!("BarDataSrc.text = {}", self.text.borrow()));
256            logger.push(format!("BarDataSrc::close {}", self.id));
257        }
258        fn create_data_conn(&mut self) -> errs::Result<Box<BarDataConn>> {
259            {
260                let mut logger = self.logger.lock().unwrap();
261                logger.push(format!("BarDataSrc::create_data_src {}", self.id));
262            }
263            let conn = BarDataConn::new(self.id, self.text.clone(), self.logger.clone());
264            Ok(Box::new(conn))
265        }
266    }
267
268    mod test_run_method {
269        use super::*;
270        use override_macro::{overridable, override_with};
271
272        #[overridable(mod = test_run_method)]
273        trait SampleData {
274            fn get_value(&mut self) -> errs::Result<String>;
275            fn set_value(&mut self, v: &str) -> errs::Result<()>;
276        }
277
278        fn sample_logic(data: &mut impl SampleData) -> errs::Result<()> {
279            let v = data.get_value()?;
280            let _ = data.set_value(&v);
281            let v = data.get_value()?;
282            let _ = data.set_value(&v);
283            Ok(())
284        }
285
286        #[overridable(mod = test_run_method)]
287        trait FooDataAcc: DataAcc {
288            fn get_value(&mut self) -> errs::Result<String> {
289                let conn = self.get_data_conn::<FooDataConn>("foo")?;
290                Ok(conn.get_text())
291            }
292        }
293
294        impl FooDataAcc for DataHub {}
295
296        #[overridable(mod = test_run_method)]
297        trait BarDataAcc: DataAcc {
298            fn set_value(&mut self, text: &str) -> errs::Result<()> {
299                let conn = self.get_data_conn::<BarDataConn>("bar")?;
300                conn.set_text(text);
301                Ok(())
302            }
303        }
304
305        impl BarDataAcc for DataHub {}
306
307        #[override_with(test_run_method::FooDataAcc, test_run_method::BarDataAcc)]
308        impl SampleData for DataHub {}
309
310        #[test]
311        fn test() {
312            let logger = Arc::new(Mutex::new(Vec::new()));
313
314            {
315                let mut data = DataHub::new();
316
317                data.uses("foo", FooDataSrc::new(1, "hello", logger.clone(), false));
318                data.uses("bar", BarDataSrc::new(2, logger.clone()));
319
320                if let Err(_) = data.run(sample_logic) {
321                    panic!();
322                }
323            }
324
325            assert_eq!(
326                *logger.lock().unwrap(),
327                vec![
328                    "FooDataSrc::new 1",
329                    "BarDataSrc::new 2",
330                    "FooDataSrc::setup 1",
331                    "BarDataSrc::setup 2",
332                    "FooDataSrc::create_data_src 1",
333                    "FooDataConn::new 1",
334                    "FooDataConn::get_text 1",
335                    "BarDataSrc::create_data_src 2",
336                    "BarDataConn::new 2",
337                    "BarDataConn::set_text 2",
338                    "FooDataConn::get_text 1",
339                    "BarDataConn::set_text 2",
340                    "BarDataConn.text = hello",
341                    "BarDataConn::close 2",
342                    "BarDataConn::drop 2",
343                    "FooDataConn::close 1",
344                    "FooDataConn::drop 1",
345                    "BarDataSrc.text = ", // because not committed
346                    "BarDataSrc::close 2",
347                    "BarDataSrc::drop 2",
348                    "FooDataSrc::close 1",
349                    "FooDataSrc::drop 1",
350                ],
351            );
352        }
353    }
354
355    mod test_txn_method {
356        use super::*;
357        use override_macro::{overridable, override_with};
358
359        #[overridable(mod = test_txn_method)]
360        trait SampleData {
361            fn get_value(&mut self) -> errs::Result<String>;
362            fn set_value(&mut self, v: &str) -> errs::Result<()>;
363        }
364
365        fn sample_logic(data: &mut impl SampleData) -> errs::Result<()> {
366            let v = data.get_value()?;
367            let _ = data.set_value(&v);
368            let v = data.get_value()?;
369            let _ = data.set_value(&v);
370            Ok(())
371        }
372
373        #[overridable(mod = test_txn_method)]
374        trait FooDataAcc: DataAcc {
375            fn get_value(&mut self) -> errs::Result<String> {
376                let conn = self.get_data_conn::<FooDataConn>("foo")?;
377                Ok(conn.get_text())
378            }
379        }
380
381        impl FooDataAcc for DataHub {}
382
383        #[overridable(mod = test_txn_method)]
384        trait BarDataAcc: DataAcc {
385            fn set_value(&mut self, text: &str) -> errs::Result<()> {
386                let conn = self.get_data_conn::<BarDataConn>("bar")?;
387                conn.set_text(text);
388                Ok(())
389            }
390        }
391
392        impl BarDataAcc for DataHub {}
393
394        #[override_with(test_txn_method::FooDataAcc, test_txn_method::BarDataAcc)]
395        impl test_txn_method::SampleData for DataHub {}
396
397        #[test]
398        fn test() {
399            let logger = Arc::new(Mutex::new(Vec::new()));
400
401            {
402                let mut data = DataHub::new();
403
404                data.uses("foo", FooDataSrc::new(1, "hello", logger.clone(), false));
405                data.uses("bar", BarDataSrc::new(2, logger.clone()));
406
407                if let Err(_) = data.txn(sample_logic) {
408                    panic!();
409                }
410            }
411
412            assert_eq!(
413                *logger.lock().unwrap(),
414                vec![
415                    "FooDataSrc::new 1",
416                    "BarDataSrc::new 2",
417                    "FooDataSrc::setup 1",
418                    "BarDataSrc::setup 2",
419                    "FooDataSrc::create_data_src 1",
420                    "FooDataConn::new 1",
421                    "FooDataConn::get_text 1",
422                    "BarDataSrc::create_data_src 2",
423                    "BarDataConn::new 2",
424                    "BarDataConn::set_text 2",
425                    "FooDataConn::get_text 1",
426                    "BarDataConn::set_text 2",
427                    "FooDataConn::pre_commit 1",
428                    "BarDataConn::pre_commit 2",
429                    "FooDataConn::commit 1",
430                    "BarDataConn::commit 2",
431                    "FooDataConn::post_commit 1",
432                    "BarDataConn::post_commit 2",
433                    "BarDataConn.text = hello",
434                    "BarDataConn::close 2",
435                    "BarDataConn::drop 2",
436                    "FooDataConn::close 1",
437                    "FooDataConn::drop 1",
438                    "BarDataSrc.text = hello", // because committed
439                    "BarDataSrc::close 2",
440                    "BarDataSrc::drop 2",
441                    "FooDataSrc::close 1",
442                    "FooDataSrc::drop 1",
443                ],
444            );
445        }
446    }
447}